Package ketUI.modes

Source Code of ketUI.modes.Cycle

/*
* 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 ketUI.modes;

import java.util.*;
import javax.swing.*;
import java.io.*;
import java.awt.event.KeyEvent;


import ket.*;
import ket.display.HTMLTools;
import ket.display.box.Box;
import ket.math.*;
import ket.math.convert.*;
import ket.math.purpose.*;
import ket.math.purpose.Text;
import ket.treeDiff.*;
import ketUI.Clipboard;
import ketUI.Document;
import ketUI.DocumentManager;
import ketUI.Ket;
import ketUI.MenuEventHandler;
import ketUI.chord.Chord;
import ketUI.chord.KeyPress;
import ketUI.chord.KeyboardEventHandler;
import ketUI.chord.Macros;
import ketUI.panel.KetPanel;


/**
* Present a series of similar representations of a given expression and allow
* the user to toggle through them.
*/
public class Cycle implements Comparator<Argument> {

  public static final Purpose[][] FAMILIES = {
    {Function.FRACTION, Function.DIVIDE},
    {Function.SIN, Function.COS, Function.TAN, Function.SEC, Function.CSC, Function.COT, Function.SINH, Function.COSH, Function.TANH},
    {Function.DERIVATIVE, Function.PARTIAL_DERIVATIVE},
    {Function.INTEGRAL, Function.CINT},
    {Function.IN, Function.SUBSET, Function.SUPERSET, Function.UNION, Function.INTERSECTION},
    {Function.LN, Function.LOG},
    {Function.SQRT, Function.EXP, Function.POWER},
    {Function.SUM, Function.PRODUCT},
    {Function.DOT, Function.CROSS},
    {Function.LAPACIAN, Function.DIV, Function.GRAD, Function.CURL, Function.OUTER_PRODUCT},

    {Function.THUS, Function.TO, Function.EQUALS, Function.LESS_EQUALS, Function.GREATER_EQUALS, Function.PROP_TO},
    {Function.NOT_EQUALS, Function.GREATER_THAN, Function.LESS_THAN},
    {Function.COMMA, Function.SET, Function.MATRIX, Function.VECTOR},

    {Symbol.EMPTY, new IntegerValue(0), new IntegerValue(1), Symbol.INFINITY},
    {new Word("a"), new Word("A"), new Word("b"), new Word("B"), new Word("c"), new Word("C"), new Word("d"), new Word("D"),
      new Word("e"), new Word("E"), new Word("f"), new Word("F"), new Word("g"), new Word("G"), new Word("h"), new Word("H"),
      new Word("i"), new Word("I"), new Word("j"), new Word("J"), new Word("k"), new Word("K"), new Word("l"), new Word("L"),
      new Word("m"), new Word("M"), new Word("n"), new Word("N"), new Word("o"), new Word("O"), new Word("p"), new Word("P"),
      new Word("q"), new Word("Q"), new Word("r"), new Word("R"), new Word("s"), new Word("S"), new Word("t"), new Word("T"),
      new Word("u"), new Word("U"), new Word("v"), new Word("V"), new Word("w"), new Word("W"), new Word("x"), new Word("X"),
      new Word("y"), new Word("Y"), new Word("z"), new Word("Z"), Symbol.UNKNOWN},
    {Symbol.alpha, Symbol.Alpha, Symbol.beta,    Symbol.Beta,     Symbol.gamma,   Symbol.Gamma,
    Symbol.delta, Symbol.Delta, Symbol.epsilon, Symbol.Epsilon,  Symbol.zeta,    Symbol.Zeta,
    Symbol.eta,   Symbol.Eta,   Symbol.theta,   Symbol.Theta,    Symbol.iota,    Symbol.Iota,
    Symbol.kappa, Symbol.Kappa, Symbol.lambda,  Symbol.Lambda,   Symbol.mu,      Symbol.Mu,
    Symbol.nu,    Symbol.Nu,    Symbol.xi,      Symbol.Xi,       Symbol.omicron, Symbol.Omicron,
    Symbol.pi,    Symbol.Pi,    Symbol.rho,     Symbol.Rho,      Symbol.sigma,   Symbol.Sigma,
    Symbol.tau,   Symbol.Tau,   Symbol.upsilon, Symbol.Upsilon,  Symbol.phi,     Symbol.Phi,
    Symbol.chi,   Symbol.Chi,   Symbol.psi,     Symbol.Psi,      Symbol.omega,   Symbol.Omega}};


  static final int REPURPOSE           = 0x1;
  static final int REPLACE_INTEGER     = 0x2;
  static final int REPLACE_DOUBLE      = 0x3;
  static final int REPLACE_ADD         = 0x4;
  static final int REPLACE_MINUS       = 0x5;
  static final int REPLACE_POWER       = 0x6;
  static final int REPLACE_TIMES       = 0x7;
  static final int REPLACE_FRACTION    = 0x8;
  static final int REPLACE_DERIVATIVE  = 0x9;
  static final int REPLACE_INTEGRAL    = 0xa;
  static final int REPLACE_TEXT        = 0xb;
  static final int REPLACE_SUM         = 0xc;
  static final int REPLACE_PRODUCT     = 0xd;

  Address familyAddress;
  KnownArguments knownArguments;
  Vector<Argument> family;
  Vector<Argument> relations;
  int relationMode;


  public Cycle(KnownArguments knownArguments) {
    this.knownArguments = knownArguments;
    familyAddress = null;
    family = new Vector<Argument>();
    relations = new Vector<Argument>();
    relationMode = 0;
  }

  public Argument nextRelation() {
    if (relations.size()<2) {
      return null;
    }
    Argument argument = relations.remove(0);
    relations.add(argument);
    return relations.firstElement();
  }

  public Argument previousRelation() {
    if (relations.size()<2) {
      return null;
    }
    int last = relations.size()-1;
    Argument argument = relations.remove(last);
    relations.add(0, argument);
    return relations.firstElement();
  }

  public Argument cycleForward() {
    if (family.size()<2) {
      return null;
    }
    Argument argument = family.remove(0);
    family.add(argument);
    return family.firstElement();
  }

  public Argument cycleBack() {
    if (family.size()<2) {
      return null;
    }
    int last = family.size()-1;
    Argument argument = family.remove(last);
    family.add(0, argument);
    return family.firstElement();
  }

  public boolean isReplaceMode(int cycleMode) {
    return cycleMode==REPLACE_INTEGER ||
        cycleMode==REPLACE_DOUBLE ||
        cycleMode==REPLACE_POWER ||
        cycleMode==REPLACE_TIMES ||
        cycleMode==REPLACE_FRACTION ||
        cycleMode==REPLACE_DERIVATIVE ||
        cycleMode==REPLACE_INTEGRAL ||
        cycleMode==REPLACE_SUM ||
        cycleMode==REPLACE_PRODUCT ||
        cycleMode==REPLACE_TEXT ||
        cycleMode==REPLACE_ADD ||
        cycleMode==REPLACE_MINUS;
  }

  public Argument repurposeClone(Argument argument, Purpose purpose) {
    Argument clone = Argument.cloneArgument(argument);
    if (clone.isBranch()) {
      clone.asBranch().setFunction((Function) purpose);
    } else {
      clone.asToken().setState((State) purpose);
    }
    return clone;
  }

  public void populateAround(Purpose[] f, Argument current, int i) {
    for (int j=i; j<f.length; j++) {
      suggest(repurposeClone(current, f[j]));
    }
    for (int j=0; j<i; j++) {
      suggest(repurposeClone(current, f[j]));
    }
  }

  public void recognizeFamily(Argument current) {
    Purpose purpose = current.getPurpose();
    for (Purpose[] f : FAMILIES) {
      for (int i=0; i<f.length; i++) {
        // TODO: How are purposes systematically compared elsewhere?
        boolean stateEq = f[i] instanceof State && f[i].equals(purpose);
        boolean functionEq = f[i] instanceof Function && f[i]==purpose;
        if (stateEq || functionEq) {
          populateAround(f, current, i);
          return;
        }
      }
    }
  }

  public int purposeToMode(Purpose purpose) {
    boolean isFunction = purpose instanceof Function;
    boolean isSymbol   = purpose instanceof Symbol;
    boolean isWord     = purpose instanceof Word;
    boolean isText     = purpose instanceof Text;
    if (purpose==Function.ADD) {
      return REPLACE_ADD;
    } else if (purpose==Function.MINUS) {
      return REPLACE_MINUS;
    } else if (purpose==Function.POWER) {
      return REPLACE_POWER;
    } else if (purpose==Function.TIMES) {
      return REPLACE_TIMES;
    } else if (purpose==Function.FRACTION) {
      return REPLACE_FRACTION;
    } else if (purpose==Function.SUM) {
      return REPLACE_SUM;
    } else if (purpose==Function.PRODUCT) {
      return REPLACE_PRODUCT;
    } else if (purpose==Function.DERIVATIVE) {
      return REPLACE_DERIVATIVE;
    } else if (purpose==Function.INTEGRAL) {
      return REPLACE_INTEGRAL;
    } else if (isText) {
      return REPLACE_TEXT;
    } else if (purpose instanceof IntegerValue) {
      return REPLACE_INTEGER;
    } else if (purpose instanceof DoubleValue) {
      return REPLACE_DOUBLE;
    } else if (isFunction || isWord || isSymbol) {
      return REPURPOSE;
    } else {
      return 0; // ...
    }
  }



  public void suggest(Argument a) {
    if (a==null) return;
    family.add(a);
  }

  public void specialCases(int cycleMode, Argument current) {
    if (cycleMode==REPLACE_INTEGER) {
      Integer z = Like.getInteger(current);
      suggest(Transform.scientificNotation(z));
      suggest(new Token((double) z));
      suggest(Factorize.factorize(z, false));
      suggest(Factorize.factorize(z, true));
      suggest(new Token(new Text(""+z))); // "13" <-> 13
    } else if (cycleMode==REPLACE_DOUBLE) {
      double d = Like.getDouble(current);
      suggest(Transform.scientificNotation(d));
      suggest(new Token((int) d));
      //- suggest(new Token(1+(int) d));
      suggest(new Token(new Text(""+d))); // "13.6" <-> 13.6
    } else if (cycleMode==REPLACE_POWER) {
      suggest(Transform.powerToInteger(current)); // 10^3 -> 1000
      // (a+b)^c | (a*b)^c | (a/b)^c   see expandPower();
      suggest(Transform.powerOfProductExpand(current));
      if (current.isBranch()) {
        suggest(Transform.powerOfFractionExpand(current.asBranch()));
      }
      suggest(Transform.multinomialExpand(current));
    } else if (cycleMode==REPLACE_TIMES) {
      //System.out.println("[*]");
      if (Like.isScientificNotation(current)) { // m * (10^e)
        //System.out.println("[scientific]");
        Double m = Like.getNumber(current.asBranch().firstChild());
        Integer e =  Like.integerPowerOfTen(current.asBranch().lastChild());
        //System.out.println(m + " * 10 ^ " + e);
        if (m!=null && e!=null) {
          double value = m * Math.pow(10.0, e);
          //System.out.println("value = " + value);
          suggest(new Token(value));
          suggest(new Token((int) value));
        }
      }
      suggest(Transform.multiplyOut(current));
    } else if (cycleMode==REPLACE_SUM) {
      suggest(Transform.expandSeries(current));
    } else if (cycleMode==REPLACE_PRODUCT) {
      suggest(Transform.expandSeries(current));
    } else if (cycleMode==REPLACE_FRACTION) {
      suggest(Transform.toProperFraction(current));
      suggest(Transform.integerDivideFraction(current));
      suggest(Transform.divideFraction(current));
      suggest(Transform.fractionToScientificNotation(current));
      recognizeFamily(current);
    } else if (cycleMode==REPLACE_DERIVATIVE) {
      suggest(Transform.differentiate(current));
    } else if (cycleMode==REPLACE_INTEGRAL) {
      suggest(Transform.integrate(current));
    } else if (cycleMode==REPLACE_TEXT) {
      String text = Like.getString(current);
      Ket.out.println("text = " + text);
      Argument a = ArgumentParser.parseArgument(text, knownArguments, null, null);
      Ket.out.println("argument = " + a);
      if (!(a==null || a.getState() instanceof Text || a.getState() instanceof Word)) {
        family.add(a);
      }
    } else if (cycleMode==REPLACE_ADD) {
      suggest(Transform.expandChildArith(current)); // (a+b) + (a-b) -> a+b+a+(-b)
      suggest(Transform.sumFractions(current)); // a/b - c/d -> (a*d - c*b) / b*d.
      suggest(Transform.organizeAddType(current));
      if (Like.longSubtractionLike(current)) { // a+(-b) -> a-b
        suggest(Transform.contractSubtraction(current));
      }
    } else if (cycleMode==REPLACE_MINUS) {
      suggest(Transform.expandChildArith(current)); // (a+b) + (a-b) -> a+b+a+(-b)
      if (Like.shortSubtractionLike(current)) { // a-b -> a+(-b)
        suggest(Transform.expandSubtraction(current));
      }
      suggest(Transform.sumFractions(current)); // a/b + c/d -> (a*d + c*b) / b*d.
    }
  }

  /*-
  private Branch expandSeries(Argument current) {
    Branch currentBranch = current.asBranch();
    if (currentBranch==null) return null;
    if (currentBranch.size()!=3) return null;
    boolean asSum = currentBranch.getFunction()==Function.SUM;
    boolean asProduct = currentBranch.getFunction()==Function.PRODUCT;
    if (!asSum && !asProduct) return null;
    Branch base = currentBranch.getChildBranch(0);
    if (Like.lacksForm(base, Function.EQUALS, 2)) return null;
    Argument variable = base.firstChild().asToken();
    Integer from = Like.getInteger(base.lastChild());
    Integer to = Like.getInteger(currentBranch.getChild(1));
    if (from==null || to==null || variable==null) return null;
    Argument subject = currentBranch.lastChild();
    Branch sum = new Branch(asSum ? Function.ADD : Function.TIMES);
    Edit edit = new Edit(sum);
    for (int i=from; i<=to; i++) {
      Argument term = subject.cloneArgument();
      sum.append(term);
      edit.setCurrent(term);
      edit.substitute(variable, new Token(i));
    }
    return sum;
  }
  */

  private int abs(int x) {
    return x<0 ? -x : x;
  }

  /**
   * Remove duplicate elements.
   */
  public void distinct() {
    Ket.out.println("***family: "+family);
    // Remove nulls
    for (int i=family.size()-1; i>=0; i--) {
      if (family.get(i)==null) {
        family.remove(i);
      }
    }
    // Remove duplicates.
    for (int i=0; i<family.size(); i++) {
      for (int j=family.size()-1; j>i; j--) {
        if (family.get(i).equals(family.get(j))) {
          family.remove(j);
        }
      }
    }
    Ket.out.println("***family': "+family);
  }

  Address address = null;
  public void cycleRelation(boolean forward, Selection selection) {
    Ket.out.println(" --- relations --- ");
    Argument current = selection.getCurrent();
    Address currentAddress = current.getAddress();
    boolean search = relations.isEmpty() || !address.equals(currentAddress) || !current.equals(relations.firstElement());
    Ket.out.println("relations : " + relations);
    Ket.out.println("address : " + address);
    Ket.out.println("current address : " + currentAddress);
    Argument next = null;
    if (search) {
      Ket.out.println("[search]");
      address = current.getAddress();
      relations.clear();
      for (Equation e : current.getEquationList().getEquations()) {
        for (Argument argument : new ArgumentVector(e.getRoot(), ArgumentVector.INCLUDE_ROOT)) {
          Ket.out.println("try: " + argument);
          if (current.equals(argument)) continue;
          Ket.out.print(".");
          if (argument.size()>0) continue;
          Ket.out.print(".");
          if (argument.getEquation().isText()) continue;
          Ket.out.print(".");
          if (relations.contains(argument)) continue;
          Argument clone = Argument.cloneArgument(argument);
          Ket.out.println("add: " + clone);
          if (next==null) {
            next = clone;
          }
          relations.add(clone);
        }
      }
      Ket.out.println("relations: " + relations);
    } else {
      next = forward ? nextRelation() : previousRelation();
    }
    Ket.out.println("next = " + next);
    if (next!=null) {
      selection.replace(Argument.cloneArgument(next));
    }
  }

  public boolean again(Argument a) {
    if (familyAddress==null || family.size()<2) return false;
    return familyAddress.equals(a.getAddress()) && a.equals(family.firstElement());
  }

  public Vector<Argument> refresh(Argument current) {
    family.clear();
    suggest(Argument.cloneArgument(current));
    int cycleMode = purposeToMode(current.getPurpose());
    if (isReplaceMode(cycleMode)) {
      Ket.out.println("[replace mode]");
      specialCases(cycleMode, current);
    } else if (cycleMode==REPURPOSE) {
      Ket.out.println("[repurpose]");
      recognizeFamily(current);
    }
    Branch currentBranch = current.asBranch();
    if (currentBranch!=null) {
      suggest(Calculate.calculate(currentBranch, false, true));
      suggest(Calculate.calculate(currentBranch, true, true));
    }
    distinct();
    return family;
  }

  public void cycleFamily(boolean forward, Selection selection) {
    Argument current = selection.getCurrent();
    if (again(current)) {
      selection.replace(forward?cycleForward():cycleBack());
      return;
    }
    refresh(current);
    Argument next = forward ? cycleForward() : cycleBack();
    if (next==null) return;
    selection.replace(Argument.cloneArgument(next));
    familyAddress = selection.getCurrent().getAddress();
    Ket.out.println("family:");
    Ket.out.println(family);
  }

  public void togglePurpose(Argument current) {
    if (current.isBranch()) {
      Branch currentBranch = current.asBranch();
      VariableToken replacement = currentBranch.asVariableToken(knownArguments);
      suggest(replacement);
    } else {
      State state = current.getState();
      Function function = knownArguments.stateToFunction(state);
      if (function!=null) {
        suggest(new Branch(function));
      }
    }
  }

  public int compare(Argument o1, Argument o2) {
    if (o1.isBranch() && o2.isToken())
      return +1;
    if (o1.isToken() && o2.isBranch())
      return -1;
    if (o1.isBranch() && o2.isBranch())
      return o1.compareTo(o2);
    //otherwise: o1.isToken() && o2.isToken())
    // TODO: Move this bit to token.comparator or similar.

    Purpose p1 = o1.asToken().getState();
    Purpose p2 = o2.asToken().getState();
    return p1.getFullName().compareTo(p2.getFullName());
  }

  public boolean equals(Object obj) {
    return false;

  }


}
TOP

Related Classes of ketUI.modes.Cycle

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.