Package ket.math

Source Code of ket.math.SymbolicFunction

/*
* 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 java.awt.*;
import java.util.*;

import ket.display.*;
import ket.math.Symbol;
import ket.display.box.Box;
import ket.display.box.BoxTools;
import ket.math.purpose.SymbolicState;
import ketUI.Ket;

/*
* An operation extends the concept of a function to include (all-optional)
* prefix, infix and postfix operators.  Although the name suggests they
* consist only of symbols, they can also contain compoundStates that in turn
* contain symbols.
*/
public class SymbolicFunction extends AbstractFunction implements Function {

  public static final Set<Symbol> MATCHES = new HashSet<Symbol>(Arrays.asList(new Symbol[]{Symbol.RE_ARGUMENT, Symbol.RE_FUNCTION, Symbol.RE_BRANCH}));

  final SymbolicState prefix; 
  final SymbolicState infix; 
  final SymbolicState postfix; 
  final int precedence;

  // Displays "\alpha:x" -> "&alpha(x)" not "&alpha x".
  final boolean hasBrackets;
 
  // Handle toBox() etc. with dependency injection or similar.
  private SymbolicFunctionForm form;


  public SymbolicFunction(
      String name,
      int[] numberOfArguments, // TODO: Rename to numberOfChildren.
      int precedence,
      SymbolicState prefix,
      SymbolicState infix,
      SymbolicState postfix,
      boolean hasBrackets,
      SymbolicFunctionForm form) {

    super(name, numberOfArguments);
    if (form==null) {
      form = new SymbolicFunctionForm(this);
    }
    setForm(form);
    this.precedence = precedence;
    this.prefix = prefix;
    this.infix = infix;
    this.postfix = postfix;
    this.hasBrackets = hasBrackets;
  }

  // How do you restrict a composition type in the sub-class?
  public void setForm(SymbolicFunctionForm form) {
    if (form!=null) {
      this.form = form;
      form.setFunction(this);
    }
  }

  @Override
  public boolean equals(Object object) {
    if ( ! (object instanceof SymbolicFunction) ) {
      return false;
    }
    SymbolicFunction symbolicFunction = (SymbolicFunction) object;
    boolean namesAndPrecidenceMatch = super.equals(symbolicFunction);
    SymbolicState thatPrefix = symbolicFunction.getPrefix();
    boolean prefixesMatch = prefix==null ? thatPrefix==null: prefix.equals(thatPrefix);
    SymbolicState thatInfix = symbolicFunction.getInfix();
    boolean infixesMatch = infix==null ? thatInfix==null: infix.equals(thatInfix);
    SymbolicState thatPostfix = symbolicFunction.getPostfix();
    boolean postfixesMatch = postfix==null ? thatPostfix==null: postfix.equals(thatPostfix);
    return namesAndPrecidenceMatch & prefixesMatch & infixesMatch & postfixesMatch;
  }

  @Override
  public String toVerboseString() {
    String string = "";
    if (isPrefix()) {
      string += prefix.getName();
    }
    string += " ? ";
    if (isInfix()) {
      string += infix.getName();
      string += " ? ";
    }
    if (isPostfix()) {
      string += postfix.getName();
    }
    return string;
  }

  public String toUnicodeString() {
    String string = "";
    if (isPrefix()) {
      string += prefix.toUnicode();
    }
    string += " ? ";
    if (isInfix()) {
      string += infix.toUnicode();
      string += " ? ";
    }
    if (isPostfix()) {
      string += postfix.toUnicode();
    }
    return string;
  }


  @Override
  public int getPrecedence() {
    return precedence;
  }

  public SymbolicState getPrefix() {
    return prefix;
  }
 
  public SymbolicState getInfix() {
    return infix;
  }

  public SymbolicState getPostfix() {
    return postfix;
  }

  public boolean isPrefixAndInfix() {
     return isPrefix() && isInfix();
  }

  public boolean isInfixAndPostfix() {
    return isInfix() && isPostfix();
  }

  public boolean isInfixOnly() {
    return !isPrefix() && isInfix() && !isPostfix();
  }
 
  public boolean isPrefixOnly() {
    return isPrefix() && !isInfix() && !isPostfix();
  }
 
  public boolean isPostfixOnly() {
    return !isPrefix() && !isInfix() && isPostfix();
  }
 
  public boolean isPrefix() {
    return prefix!=null;
  }
 
  public boolean isInfix() {
    return infix!=null;
  }
 
  public boolean isPostfix() {
    return postfix!=null;
  }

  @Override
  public boolean displayBrackets() {
    return hasBrackets;
  }

  /**
   * All defined prefix, infix and postfix operators can be accessed in a
   * vector using this method.  Undefined elements are ignored.
   */
  public Vector<SymbolicState> getSymbolicStates() {
    Vector<SymbolicState> symbols = new Vector<SymbolicState>();
    if (isPrefix()) {
      symbols.add(prefix);
    }
    if (isInfix()) {
      symbols.add(infix);
    }
    if (isPostfix()) {
      symbols.add(postfix);
    }
    return symbols;
  }

  public boolean isPrefixPossible() {
    return prefix!=null;
  }

  public boolean isInfixPossible() {
    return infix!=null;
  }

  public boolean isPostfixPossible() {
    return postfix!=null;
  }

  public boolean isPrefixNecessary() {
    return isPrefixPossible();
  }

  public boolean isInfixNecessary() {
    return isInfixPossible() && !(isPrefixPossible() && isPostfixPossible());
  }
  public boolean isPostfixNecessary() {
    return isPostfixPossible();
  }

  @Override
  public Set<Symbol> getMatchSymbols() {
    // This is only updated dynamically in case the prefix, infix
    // or posfix symbols are modified during runtime.
    Set<Symbol> set = new HashSet<Symbol>(MATCHES);
    for (SymbolicState fix : getSymbolicStates()) {
      set.addAll(fix.getMatchSymbols());
    }
    // Individual symbols are tokens, but a function is not.
    set.remove(Symbol.RE_TOKEN);
    return set;
  }

  public boolean split(Branch branch) {

    // TODO: Make more robust: This is too simplistic a treatment.
    // You need to take into account optional prefixes (e.g., ket
    // <?|?> or |?>) and optional infixes (e.g., [?] or [?, ?]).

    Vector<Argument> args = branch.getChildren();
    if (args.size()==0) {
      return false;
    }

    if (isPrefixOnly()) { // eg #3
      // iterate backwards to find inner function first: ln (ln x)
      int index = prefix.iterateToStateBackwards(args);
      if (index==-1) {
        return false;
      }
      branch.subBranchAfter(index, this);
      branch.removeChild(index);
      return true;
    } else if (isPostfixOnly()) { // eg 3!
      int index = postfix.iterateToStateForwards(args);
      if (index==-1) {
        return false;
      }
      //- int size = branch.size();
      branch.removeChild(index); // <--- THE RECENT CHANGE
      branch.subBranchBefore(index, this);
      return true;
    } else if (isPrefix() && !isInfix() && isPostfix()) {
      return splitPrefixAndPostfixOnly(branch, args);
    } else if (isInfixOnly()) {
      // Comma-like; a,b,c,d
      int[] indices = infix.findAllStateIndices(args, true, true);
      if (indices.length<=2) {
        return false;
      } else {
        branch.subBranchBetween(indices, this);
        return true;
      }
    } else if (isPrefix() && isInfix() && isPostfix()) {
      return splitPrefixInfixPostfix(branch, args);
    } else {
      Ket.out.println(" <--- unfinished:SymbolicFunction'"+
          getName()+"'.split() "+ isPrefix()+", "+
          isInfix()+", "+isPostfix()+" ---> ");
      return false;
    }
  }

  private boolean splitPrefixAndPostfixOnly(Branch branch, Vector<Argument> args) {
    if (prefix==postfix) {
      // modulus like |x|
      int start = prefix.iterateToStateForwards(args);
      int end = postfix.iterateToStateForwards(args, start+1);
      if (start!=-1 && end!=-1) {
        branch.subBranchBetween(start, end, this);
        branch.removeChild(start); // remove open
        branch.removeChild(start+1); // remove close
        return true;
      } else {
        return false;
      }
    } else {
      // bracket like (x)
      int start = prefix.iterateToStateForwards(args);
      if (start<0) {
        return false;
      }
      int nextClose, nextOpen;
      while (true) {
        nextClose = postfix.iterateToStateForwards(args, start+1);
        nextOpen = prefix.iterateToStateForwards(args, start+1);
        if (nextClose<0) {
          return false;
        } else if (nextOpen<0 || nextClose<nextOpen) {
          branch.subBranchBetween(start, nextClose, this);
          branch.removeChild(start); // remove open
          branch.removeChild(start+1); // remove close
          return true;
        } else if (nextClose > nextOpen) {
          start = nextOpen; 
        }
      }
    }
  }

  private boolean splitPrefixInfixPostfix(Branch branch, Vector<Argument> args) {
    // Note: Find the first innermost bracket.
    int start = prefix.iterateToStateForwards(args);
    if (start<0) {
      return false;
    }
    int from = start; // This is the index from which to search.

    Vector<Integer> infixVector = new Vector<Integer>();
    while (true) {
      int nextOpen = prefix.iterateToStateForwards(args, from+1);
      int nextInfix = infix.iterateToStateForwards(args, from+1);
      int nextClose = postfix.iterateToStateForwards(args, from+1);
      if (nextClose<0) {
        // Brackets cannot be closed.
        return false;
      } else if (nextInfix>start &&
          ((nextOpen<0 || nextInfix<nextOpen)
           && nextInfix<nextClose)) {
        // Infix is the next symbol.
        from = nextInfix;
        infixVector.add(new Integer(nextInfix));
      } else if (nextOpen<0 || nextClose<nextOpen) {
        // The next symbol is a postfix.
        int[] range = new int[infixVector.size()+2];
        range[0] = start;
        for (int i=0; i<range.length-2; i++) {
          range[i+1] = infixVector.get(i);
        }
        range[range.length-1] = nextClose;

        branch.subBranchBetween(range, this);
        branch.removeChild(start); // remove open
        branch.removeChild(start+1); // remove close
        return true;
      } else if (nextClose>nextOpen) {
        start = from = nextOpen; 
        infixVector = new Vector<Integer>();
      }
    }
  }

  protected Form getForm() {
    return form;
  }

}
TOP

Related Classes of ket.math.SymbolicFunction

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.