Package ket.math

Source Code of ket.math.ArgumentTools

/*
* Copyright (C) 2011  Alasdair C. Hamilton
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

package ket.math;

import geom.Offset;
import geom.Position;

import java.awt.*;
import java.util.*;

import ket.display.ColourScheme;
import ket.display.ColourSchemeDecorator;
import ket.math.Argument;
import ket.math.Branch;
import ket.math.Function;
import ket.math.Token;
import ket.math.convert.Like;
import ketUI.Ket;




/**
* Various helper methods to aid in the processing of arguments that are
* suitably self contained as to be separately implemented as static methods
* without state.
*/
public class ArgumentTools {

  /*-
  public static Argument[][] asTable(Branch branch)  {
    if (Type.sequenceType(branch.getFunction())) {
      Vector<Argument> args = branch.getChildren();
      return asTable(args);
    } else {
      return null;
    }
  }
  */

  public static Argument[][] asTable(Vector<Argument> args, boolean transpose)  {
    if (!isRectangle(args)) return null;
    Function commonFunction = getCommonFunction(args);
    if (!Type.sequenceType(commonFunction)) return null;
    Argument[][] table = toTable(args);
    if (table==null) return null;
    return transpose ? calcTranspose(table) : table;
  }

  public static Argument[][] toTable(Vector<Argument> args) {
    // Children are all branches with a (positive integer), consistent number of arguments.
    if (args.size()==0) {
      return null;
    }
    Argument[] row = toRow(args.firstElement());
    if (row==null) {
      return null;
    }
    int size = row.length;
    Argument[][] table = new Argument[args.size()][size];
    table[0] = row;
    for (int i=1; i<args.size(); i++) {
      Argument child = args.get(i);
      row = toRow(child);
      if (row==null || size!=row.length) {
        return null;
      }
      table[i] = row;
    }
    return table;
  }

  /**
   * Iterate through every element of a list and if every element shares
   * a common function, return it.
   */
  public static Function getCommonFunction(Vector<Argument> args) {
    if (args.size()==0) {
      return null;
    }
    Function commonFunction = args.firstElement().getFunction();
    if (commonFunction==null) {
      return null;
    }
    for (int i=1; i<args.size(); i++) {
      Argument next = args.get(i);
      Function function = next.getFunction();
      if (commonFunction!=function) {
        return null;
      }
    }
    return commonFunction;
  }

  /**
   * Check that the size of each element of args is the same and return it, and -1 otherwise.
   */
  public static int getCommonSize(Vector<Argument> args) {
    if (args.size()==0) {
      return -1;
    }
    Argument first = args.firstElement();
    if (first instanceof Token) {
      return -1;
    }
    int commonSize = first.asBranch().size();
    for (int i=1; i<args.size(); i++) {
      Argument next = args.get(i);
      if (next instanceof Token) {
        return -1;
      }
      int size = next.asBranch().size();
      if (size!=commonSize) {
        return -1;
      }
    }
    return commonSize;
  }

  public static Argument[] toRow(Argument argument) {
    // TODO: Does the function type matter: currently commas, vectors, and anything are allowed, but this means that a*b*c -> [a,b,c].
    if (argument==null || argument instanceof Token) {
      return null;
    }
    Branch rowBranch = (Branch) argument;
    if (rowBranch.size()==0) {
      return null
    }
    Argument[] row = new Argument[rowBranch.size()];
    for (int i=0; i<row.length; i++) {
      row[i] = rowBranch.getChild(i);
    }
    return row;
  }

  public static Argument[][] calcTranspose(Argument[][] table) {
    int nrows = table.length;
    int ncols = table[0].length;
    Argument[][] transpose = new Argument[ncols][nrows];
    for (int j=0; j<ncols; j++) {
      for (int i=0; i<nrows; i++) {
        transpose[j][i] = table[i][j];
      }
    }
    return transpose;
  }

  /**
   * All arguments have an equal number of arguments and the number of
   * elements, and their number of arguments are all non-zero.
   */
  public static boolean isRectangle(Vector<Argument> args) {
    return getCommonSize(args) != -1;
  }

  /**
   * Return the subset of args that have no ancestor within args.  If no
   * ancestor is found an argument is a 'root branch'.  Note that a root
   * branch can be a token or a branch.
   */
  public static Vector<Argument> getRootBranches(Vector<Argument> args) {
    Vector<Argument> roots = new Vector<Argument>();
    for (Argument next : args) {
      if ( ! containsAncestor(next, args) ) {
        roots.add(next);
      }
    }
    return roots;
  }

  /**
   * Return true if any ancestor of next is inside args.
   */
  private static boolean containsAncestor(Argument next, Vector<Argument> args) {
    for (Branch ancestor : next.getAncestors()) {
      for (Argument a : args) {
        if (a==ancestor) {
          return true;
        }
      }
    }
    return false;
  }

  /**
   * Return true if both arguments share a common ancestor.
   */
  public static boolean commonAncestry(Argument a, Argument b) {
    if (a.getDepth()!=b.getDepth()) {
      return false;
    }
    Vector<Branch> aAncestors = a.getAncestors();
    Vector<Branch> bAncestors = b.getAncestors();
    for (int k=0; k<aAncestors.size(); k++) {
      Branch aNext = aAncestors.get(k);
      Branch bNext = bAncestors.get(k);
      if ( ! aNext.elementEquals(bNext) ) {
        return false;
      }
    }
    return true;
  }

  /**
   * For each ancestor pair, check that the indices of the ancestors match.
   */
  public static boolean commonAncestryIndex(Argument a, Argument b) {
    if (a.getDepth()!=b.getDepth()) {
      return false;
    }
    Vector<Branch> aAncestors = a.getAncestors();
    Vector<Branch> bAncestors = b.getAncestors();
    for (int k=0; k<aAncestors.size(); k++) {
      Branch aNext = aAncestors.get(k);
      Branch bNext = bAncestors.get(k);
      if (aNext.getIndex()!=bNext.getIndex()) {
        return false;
      }
    }
    return true;
  }

  /**
   * For a given argument, look for all desendents with the same function.
   * TODO: Move this to argument range?
   */
  public static Vector<Branch> getSimilarDescendents(Branch branch) {
    Vector<Branch> matches = new Vector<Branch>();
    Function function = branch.getFunction();
    for (Argument child : branch.getChildren()) {
      if (child.getFunction()==function) {
        matches.add((Branch) child);
        matches.addAll(getSimilarDescendents((Branch) child));
      }
    }
    return matches;
  }

  public static Branch getSameFunctionAncestor(Branch branch) { // dangerous for non-branches.
    Function function = branch.getFunction();
    Vector<Branch> ancestors = branch.getAncestors();
    Branch root = branch;
    for (Branch a : ancestors) {
      if (a.getFunction()==function) {
        root = a;
      } else {
        return root;
      }
    }
    return root;
  }

  // Cast didn't work here: why?
  public static IdentityHashMap<Argument, Argument> convertToArgumentMap(IdentityHashMap<Token, Token> map) {
    IdentityHashMap<Argument, Argument> clone = new IdentityHashMap<Argument, Argument>();
    for (Argument a : map.keySet()) {
      clone.put( (Argument) a, (Argument) map.get(a) );
    }
    return clone;
  }

  // Cast didn't work here: why?
  public static IdentityHashMap<Token, Token> convertToTokenMap(IdentityHashMap<Argument, Argument> map) {
    IdentityHashMap<Token, Token> clone = new IdentityHashMap<Token, Token>();
    for (Argument a : map.keySet()) {
      clone.put( (Token) a, (Token) map.get(a) );
    }
    return clone;
  }

  /**
   * Match target to the LHS of identity and return identity's RHS having
   * substituted for relevent tokens that differ between identity and target.
   */
  public static Argument identityLike(Argument target, Argument identity) {
    Argument[] pair = Like.equalPairLike(identity);
    if (pair==null) { // c
      return null;
    }
    // The identity is of the form "pair[0] = pair[1]".
    Argument pattern = pair[0];
    Argument expansion = pair[1];
    // In practice, an indentity may appear using different letters
    // and even numbers.  Find the cypher to map from 'pattern' to
    // 'target' and apply the cypher to 'expansion'.
    IdentityHashMap<Token, Token> cypher = pattern.cypherEquals(target);
    if (cypher==null) {
      return null;
    }
    for (Token t : cypher.keySet()) {
    }
    Argument result = Like.substitute(expansion, convertToArgumentMap(cypher));
    return result;
  }

  public static boolean parentsEquals(Argument before, Argument after) {
    if (before.isRoot() || after.isRoot()) {
      return before.isRoot() && after.isRoot();
    } else {
      Branch beforeParent = before.getParentBranch();
      Branch afterParent = after.getParentBranch();
      return beforeParent!=null && beforeParent.elementEquals(afterParent);
    }
  }

  public static boolean childrenElementsEqual(Argument before, Argument after) {
    if (before instanceof Branch ^ after instanceof Branch) {
      // One is a branch and the other is a token.
      return false;
    } else if (before instanceof Token) {
      // Both are tokens
      return true;
    } else {
      // Both are branches
      Branch beforeBranch = (Branch) before;
      Branch afterBranch = (Branch) after;
      return beforeBranch.childElementsEqual(afterBranch);
    }
  }


  /**
   * Append an element to the mapping's value, a list.
   */
  public static void appendToMapValue(HashMap<Set<Integer>,Set<Integer>> map, Set<Integer> key, int element) {
    // Roughtly: map[key].append(element)
    Set<Integer> value = map.get(key);
    if (value==null) {
      value = new HashSet<Integer>();
      map.put(key, value);
    }
    value.add(element);
  }

  /**
   * Return the most specific common ancestor this shares with argument.
   */
  public static Branch getCommonAncestor(Argument a, Argument b) {
    if (a==null || b==null) {
      return null;
    }
    Vector<Branch> aAncestors = a.getAncestors();
    Vector<Branch> bAncestors = b.getAncestors();
    for (Branch aa : aAncestors) {
      if (aa.isIn(bAncestors)) {
        return aa;
      }
    }
    return null;
  }


  // TODO: [CLARIFY DEFINITION]
  /**
   * Iterate through the ancestors of 'a' until 'top' is reached
   * returning the composition of the various (unitary) operations
   * performed on 'a'.  For example, the composition of the product of a
   * fraction is the reciprocal (denoted by FRACTION).  While the sum of
   * a sum is itself a sum (denoted by ADD).
   */
  public static Function effectiveUnitaryAncestorOperation(Argument target, Branch top) {
    //D Ket.out.println("Route:");
    //D Ket.out.println("\targument: " + (target!=null?target:null));
    //D Ket.out.println("\ttop: " + (top!=null?top:null));
    Branch parent = target.getParentBranch();
    Function unitary = Type.getUnitaryFunction(target);
    if (unitary==null) {
      //D Ket.out.println("\t !!! Null unitary function !!! ");
      return null;
    }
    //D Ket.out.println("\tunitary function = '" + unitary.getName() + "'");
    Function composition=unitary;
    while (parent!=null && parent!=top) {
      //D Ket.out.println("\tparent = '" + parent + "'");
      target = parent;
      parent = parent.getParentBranch();
      if (parent==null || parent==top) {
        break;
      }
      unitary = Type.getUnitaryFunction(target);
      if (unitary==null) {
        //D Ket.out.println("\t !!! Null unitary function !!! ");
        return null;
      }
      //D Ket.out.println("\tunitary function = '" + unitary.getName() + "'");
      composition = Type.getComposition(composition, unitary);
      if (composition==null) {
        //D Ket.out.println("\t !!! Null composition !!! ");
        return null; // Too complicated, e.g. sin(x^2) or (x+3)*2
      }
      //D Ket.out.println("\tcomposition = '" + composition.getName() + "'");
    }
    //D Ket.out.println();
    return composition;
  }

  public static Vector<Vector<Argument>> getRepeatedIndices(Branch parentBranch) { // Is this clear enough?
    return getRepeatedIndices(parentBranch.getChildren());
  }

  /**
   * Search through a list of arguments and return those that are (sub-branch) equal to one another.
   */
  // TODO: Use throughout Calculate, but call once and pass the result throughout.
  public static Vector<Vector<Argument>> getRepeatedIndices(Vector<Argument> args) {
    IdentityHashMap<Argument, Vector<Argument>> map = new IdentityHashMap<Argument, Vector<Argument>>();
    for (Argument a : args) {
      boolean otherwise = true;
      for (Argument t : map.keySet()) { // Match an existing expression.
        if (t.subBranchEquals(a)) {
          map.get(t).add(a);
          otherwise = false;
          break;
        }
      }
      if (otherwise) { // Add a new expression to compare against in the future.
        map.put(a, new Vector<Argument>(Arrays.asList(a)));
      }
    }
    Vector<Vector<Argument>> nonNullValuesVector = new Vector<Vector<Argument>>();
    for (Vector<Argument> matches : map.values()) {
      if (matches.size()>1) {
        nonNullValuesVector.add(matches);
      }
    }
    return nonNullValuesVector;
  }

  /**
   * Return the composition of recursively moving out of source to
   * a common ancestor (inverting) and into a second argument.
   */
  public static Function getRelativeOperation(Argument source, Argument destination, Branch common) {
    Ket.out.println("> relative operation");
    boolean invert = Type.assignType(common) || Type.inequalityType(common);
    if (!invert) {
      Ket.out.println(" !!! Can't invert: common function ("+common.getFunction()+") must be an assign or [in]equality.");
      return null;
    }
    // TODO: Use or remove getRelativeOperation().invert
    Function sourceOperation = source.getPathOperation(common);
    Function destinationOperation = destination.getPathOperation(common);
    Ket.out.println("> source = " + source + " -> " + sourceOperation);
    Ket.out.println("> destination = " + destination + " -> " + destinationOperation);
    return getRelativeOperation(sourceOperation, destinationOperation, invert);
  }

  /**
   * Return the composition of recursively moving out of one function to
   * a common ancestor (inverting) and into a second path.
   */
  public static Function getRelativeOperation(Function sourceOperation, Function destinationOperation, boolean invert) {
    if (sourceOperation!=null && destinationOperation!=null) { // a*x=b*y -> a=b*y/x
      Ket.out.println(">> ... -> ...");
      if (invert) {
        //- return Type.getComposition(destinationOperation, sourceOperation.getInverse());
        return Type.getComposition(destinationOperation, Type.getInverse(sourceOperation));
      } else {
        return Type.getComposition(destinationOperation, sourceOperation);
      }
    } else if (sourceOperation!=null) { // a+x=y -> a=y-x   ; y=x^2 -> sqrt(y)=x
      Ket.out.println(">> ... -> null");
      if (invert) {
        //- return sourceOperation.getInverse();
        return Type.getInverse(sourceOperation);
      } else {
        return sourceOperation;
      }
    } else if (destinationOperation!=null) { // x=a*y -> 1=a*y/x
      Ket.out.println(">> null -> ...");
      if (invert) {
        //- return destinationOperation.getInverse();
        return Type.getInverse(destinationOperation);
      } else {
        return destinationOperation;
      }
    } else {
      Ket.out.println(">> null -> null");
      return null;
    }
  }

}
TOP

Related Classes of ket.math.ArgumentTools

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.