Package miscellaneous

Source Code of miscellaneous.Functions

package miscellaneous;

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import lipstone.joshua.parser.Tokenizer;
import lipstone.joshua.parser.exceptions.InvalidOperationException;
import lipstone.joshua.parser.exceptions.ParserException;
import lipstone.joshua.parser.exceptions.PluginConflictException;
import lipstone.joshua.parser.exceptions.UndefinedResultException;
import lipstone.joshua.parser.plugin.ParserPlugin;
import lipstone.joshua.parser.plugin.helpdata.Operation;
import lipstone.joshua.parser.plugin.helpdata.Parameter;
import lipstone.joshua.parser.plugin.types.InputFilterPlugin;
import lipstone.joshua.parser.plugin.types.OperationPlugin;
import lipstone.joshua.parser.types.BigDec;
import lipstone.joshua.parser.util.ConsCell;
import lipstone.joshua.parser.util.ConsType;

import org.apfloat.Apfloat;

public class Functions extends ParserPlugin implements OperationPlugin, InputFilterPlugin {
 
  public BigDec round(ConsCell input) throws ParserException {
    ConsCell num = parser.run(input);
    if (num.length() != 1 || num.getCarType() != ConsType.NUMBER)
      throw new UndefinedResultException("The argument to the round function must evaluate to a number", this);
    Apfloat real = ((BigDec) num.getCar()).getInternal().real(), complex = ((BigDec) num.getCar()).getInternal().imag(), round = new Apfloat(0.5);
    return new BigDec(real.frac().compareTo(round) == -1 ? real.floor() : real.ceil(), complex.frac().compareTo(round) == -1 ? complex.floor() : complex.ceil());
  }
 
  public BigDec factorial(ConsCell input) throws ParserException {
    BigDec numFactorial = BigDec.ONE;
    ArrayList<ConsCell> parts = input.splitOnSeparator();
    if (parts.size() >= 2)
      numFactorial = round(parts.get(1));
    BigDec output = BigDec.ONE;
    ConsCell num = parser.run(parts.get(0));
    if (num.getCarType() != ConsType.NUMBER || !((BigDec) num.getCar()).isInt() || !((BigDec) num.getCar()).gteq(BigDec.ZERO))
      throw new ParserException("The factorial operation is only defined for arguments that evaluate to whole numbers", this);
    BigDec cap = (BigDec) num.getCar();
    if (cap.gteq(numFactorial))
      for (BigDec i = new BigDec(cap); i.gteq(BigDec.ONE); i = i.subtract(numFactorial))
        output = output.multiply(i);
    return output;
  }
 
  /**
   * Summation or Sigma of some function
   *
   * @param input
   *            ConsCell of the form equation, minimum, maximum, [delta]
   * @param parser
   *            the parser that called this method
   * @return the sum of this equation from [min, max] with delta defaulting to 1, delta as passed otherwise
   */
  public BigDec sum(ConsCell input) throws ParserException {
    BigDec output = BigDec.ZERO, min = BigDec.ZERO, max = BigDec.ONE, delta = BigDec.ONE;
    input = parser.run(input);
    ArrayList<ConsCell> parts = input.splitOnSeparator();
    if (parts.size() >= 3) {
      if (parts.get(1).getCarType() != ConsType.NUMBER || parts.get(2).getCarType() != ConsType.NUMBER || (parts.size() >= 4 && parts.get(3).getCarType() != ConsType.NUMBER))
        throw new UndefinedResultException("The sum function takes three or four arguments, the second and third and fourth of which must evaluate to numbers.", this);
      min = (BigDec) parts.get(1).getCar();
      max = (BigDec) parts.get(2).getCar();
      if (parts.size() >= 4)
        delta = (BigDec) parts.get(3).getCar();
      output = sum(parts.get(0), min, max, delta);
    }
    return output;
  }
 
  private BigDec sum(ConsCell equation, BigDec min, BigDec max, BigDec delta) throws ParserException {
    BigDec output = BigDec.ZERO;
    if (min.gt(max)) {
      BigDec temp = new BigDec(min);
      min = new BigDec(max);
      max = new BigDec(temp);
    }
    ArrayList<ConsCell> vars = equation.allInstancesOf(new ConsCell(parser.getVariables(equation).get(0), ConsType.IDENTIFIER));
    for (BigDec i = new BigDec(min); i.lteq(max); i = i.add(delta)) {
      for (ConsCell var : vars)
        var.replaceCar(new ConsCell(i, ConsType.NUMBER));
      output = output.add((BigDec) parser.run(equation).getCar());
    }
    return output;
  }
 
  private BigDec gcd(ConsCell input) throws ParserException {
    ArrayList<ConsCell> ints = input.splitOnSeparator();
    BigDec gcd = new BigDec(parser.run(ints.get(0)).toString());
    for (int i = 1; i < ints.size(); i++)
      gcd = gcd.gcd(new BigDec(parser.run(ints.get(i)).toString()));
    return gcd;
  }
 
  private BigDec lcm(ConsCell input) throws ParserException {
    ArrayList<ConsCell> ints = input.splitOnSeparator();
    BigDec lcm = new BigDec(parser.run(ints.get(0)).toString());
    for (int i = 1; i < ints.size(); i++)
      lcm = lcm.lcm(new BigDec(parser.run(ints.get(i)).toString()));
    return lcm;
  }
 
  /**
   * Processes a log function incorporating bases other than 10
   *
   * @param num
   *            interior of the log function including a possible base
   * @return the value of the log as a double.
   * @throws ParserException
   */
  public BigDec log(ConsCell num) throws ParserException {
    num = parser.run(num);
    ArrayList<ConsCell> sections = num.splitOnSeparator();
    if ((sections.get(0).getCarType() != ConsType.NUMBER || sections.get(0).length() != 1) && (sections.size() == 1 || (sections.size() > 1 && (sections.get(1).getCarType() != ConsType.NUMBER ||
        sections.get(1).length() != 1))))
      throw new UndefinedResultException("The log function accepts either one or two arguments, both of which must evaluate to numbers.", this);
    if (((BigDec) num.getCar()).lteq(BigDec.ZERO))
      throw new UndefinedResultException("The log function is only defined for values greater than 0.", this);
    return new BigDec(Math.log(((BigDec) (parser.run(sections.get(0)).getCar())).doubleValue()) / Math.log((sections.size() > 1 ?
        (BigDec) parser.run(sections.get(1)).getCar() : new BigDec(parser.getDefaultLogBase())).doubleValue()));
  }
 
  public BigDec sigfigs(ConsCell num) throws ParserException {
    String number = parser.run(num).toString();
    BigDec sigfigs = BigDec.ZERO;
    boolean start = false;
    for (int i = 0; i < number.length(); i++) {
      if (parser.isNumber(number.charAt(i))) {
        if (!start && number.charAt(i) != '0')
          start = true;
        if (start)
          sigfigs = sigfigs.pp();
      }
    }
    return sigfigs;
  }
 
  public String scientificNotation(String num) {
    String[] parts = scientificNotation(num, true);
    if (parts[1].equals("0"))
      return parts[0];
    else if (parts[1].equals("1"))
      return parts[0] + "*10";
    else
      return parts[0] + "*10^(" + parts[1] + ")";
  }
 
  public String[] scientificNotation(String num, boolean array) {
    String parts[] = new String[]{"", ""};//base, order
    if (!num.contains("."))
      num = num + ".0";
    while (num.charAt(0) == '0' && num.charAt(1) != '.')
      num = num.substring(1);
    if (num.length() > 1) {
      for (int i = 0; i < num.length(); i++)
        if (parser.isNumber(num.charAt(i)) && num.charAt(i) != '0' && num.charAt(i) != '.') {
          parts[1] = new BigDec(num.indexOf('.') - i - 1).toString();
          break;
        }
      parts[0] = num.substring(0, 1) + "." + num.substring(1).replaceAll("\\Q.\\E", "");
    }
    else
      return new String[]{num, "0"};
    return parts;
  }
 
  public String fromScientificNotation(String num) {
    String exp = "0";
    if (num.contains("E")) {
      exp = num.substring(num.indexOf("E") + 1);
      num = num.substring(0, num.indexOf("E"));
    }
    if (num.contains("10^")) {
      exp = num.substring(num.indexOf("*10^") + 4);
      num = num.substring(0, num.indexOf("*10^"));
    }
    if (num.contains(".")) {
      int index = num.indexOf("."), expo = new Double(exp).intValue();
      while (num.length() < expo + index + 1)
        num = num + "0";
      num = num.substring(0, index) + num.substring(index + 1, index + 1 + expo) + "." + num.substring(index + 1 + expo);
    }
    return num;
  }
 
  public BigDec phi(ConsCell num) throws ParserException {
    BigDec output = BigDec.ZERO;
    num = parser.run(num);
    ArrayList<ConsCell> factors = parser.getCAS().primeFactor(num).splitOnSeparator();
    String temp = num.toString();
    for (ConsCell factor : factors)
      temp = temp + "*(" + factor.toString() + "-1)";
    temp = temp + "/(";
    for (ConsCell factor : factors)
      temp = temp + factor.toString() + "*";
    temp = temp.substring(0, temp.length() - 1) + ")";
    output = new BigDec(((BigDec) parser.run(parser.preProcess(Tokenizer.tokenizeString(temp))).getCar()).intValue());
    return output;
  }
 
  public boolean isRelativelyPrime(ConsCell num) throws ParserException {
    num = parser.run(num);
    ArrayList<ConsCell> parts = num.splitOnSeparator();
    BigDec num1 = BigDec.ZERO, num2 = BigDec.ZERO;
    if (parts.get(0).getCarType() != ConsType.NUMBER || parts.get(1).getCarType() != ConsType.NUMBER)
      throw new InvalidOperationException("Both arguments to isRelativelyPrime must be numbers.", this, null, null);
    return isRelativelyPrime(num1, num2);
  }
 
  private boolean isRelativelyPrime(BigDec num1, BigDec num2) throws UndefinedResultException {
    if (num2.gteq(num1))
      return false;
    boolean shareFactors = false;
    ArrayList<BigDec> factors1 = parser.getCAS().findFactors(num1), factors2 = parser.getCAS().findFactors(num2);
    for (BigDec a : factors1)
      for (BigDec b : factors2)
        if (a.gt(BigDec.ONE) && a.gt(BigDec.ONE) && a.eq(b))
          shareFactors = true;
    return !shareFactors;
  }
 
  @Override
  public void loadOperations() throws PluginConflictException {
    ArrayList<Parameter> params = new ArrayList<Parameter>();
    params.add(new Parameter("x", "any real number", false));
    addOperation(new Operation("round", params, "the number (x) rounded using the half-up method", "The half-up method is the method most commonly taught in schools.", this));
    addOperation(new Operation("ceil", params, "the number (x) rounded up", "The ceiling function.", this));
    addOperation(new Operation("floor", params, "the number (x) rounded down", "The floor function.", this));
    params.add(new Parameter("decrement", "any positive, real integer, defaults to 1", true));
    addOperation(new Operation("factorial", params, "the factorial of x", "when the decrement is 1, this is the standard factorial", this));
    params.remove(1);
    params.add(new Parameter("base", "any real integer, defaults to 10", true));
    addOperation(new Operation("log", params, "the log [base] of x", "", this));
    params.remove(1);
    addOperation(new Operation("ln", params, "the natural log of x", "the natural log of x is equivalent to log(x, e)", this));
    params.remove(0);
    params.add(new Parameter("equation", "some algebraic expression", false));
    params.add(new Parameter("min", "minimum bound for the sum", false));
    params.add(new Parameter("max", "maximum bound for the sum", false));
    params.add(new Parameter("delta", "the step size for the sum, defaults to 1", true));
    addOperation(new Operation("sigma", params, "the sum of the function from [min, max]", "", this));
    addOperation(new Operation("sigma", params, "the sum of the function from [min, max]", "", this));
    params.clear();
    params.add(new Parameter("x", "any whole number", false));
    addOperation(new Operation("phi", params, "the number of whole numbers relatively prime to x", "Credits to Jacob for telling me about this function and helping me make it more efficient.", this));
    params.add(new Parameter("y", "any whole number", false));
    addOperation(new Operation("isRelativelyPrime", params, "whether x is relatively prime to y", "Credits to Jacob for telling me about this function.", new String[]{"relativelyPrime"}, this));
    params.clear();
    params.add(new Parameter("x", "any real number", false));
    addOperation(new Operation("sigfigs", params, "the number of significant figures in x", "uses the standard calculation methods", this));
    params.clear();
    params.add(new Parameter("integers", "a list of integers", false));
    addOperation(new Operation("gcd", params, "the greatest common divisor of the listed integers", "Credits to Jacob for explaining the highly efficient algorithm that makes this rational to implement.", this));
    addOperation(new Operation("lcm", params, "the least common multiple of the listed integers", "Credits to Jacob for explaining the highly efficient algorithm that makes this rational to implement.", this));
  }
 
  @Override
  public ConsCell runOperation(String operation, ConsCell input) throws ParserException {
    int numParams = input.splitOnSeparator().size();
    if (operation.equals("round"))
      return new ConsCell(round(input), ConsType.NUMBER);
    if (operation.equals("ceil"))
      return new ConsCell(new BigDec(Math.ceil(new Double(parser.run(input).toString()))), ConsType.NUMBER);
    if (operation.equals("floor"))
      return new ConsCell(new BigDec(Math.floor(new Double(parser.run(input).toString()))), ConsType.NUMBER);
    if (operation.equals("factorial"))
      return new ConsCell(factorial(input), ConsType.NUMBER);
    if (operation.equals("log"))
      return new ConsCell(log(input), ConsType.NUMBER);
    if (operation.equals("ln"))
      return new ConsCell(log(input.append(new ConsCell(",", ConsType.SEPARATOR, new ConsCell("e", ConsType.IDENTIFIER), ConsType.CONS_CELL)).getFirstConsCell()), ConsType.NUMBER);
    if ((operation.equals("sum") || operation.equals("sigma")) && (numParams == 3 || numParams == 4))
      return new ConsCell(sum(input), ConsType.NUMBER);
    if (operation.equals("phi"))
      return new ConsCell(phi(input), ConsType.NUMBER);
    if (operation.equals("isRelativelyPrime") || operation.equals("relativelyPrime") && numParams == 2)
      return new ConsCell(new Boolean(isRelativelyPrime(input)).toString(), ConsType.IDENTIFIER);
    if (operation.equals("sigfigs"))
      return new ConsCell(sigfigs(input), ConsType.NUMBER);
    if (operation.equals("gcd"))
      return new ConsCell(gcd(input), ConsType.NUMBER);
    if (operation.equals("lcm"))
      return new ConsCell(lcm(input), ConsType.NUMBER);
    return null;
  }
 
  @Override
  public void unloadOperations() {/* Nothing to do here */}
 
  @Override
  public ConsCell preProcess(ConsCell input) throws ParserException {
    Pattern factorial = Pattern.compile("[!]+");
    ConsCell current = input;
    if (current.getCdrType() == ConsType.CONS_CELL)
      current = current.getNextConsCell();
    do {
      if (current.getCarType() != ConsType.IDENTIFIER)
        continue;
      Matcher m = factorial.matcher((String) current.getCar());
      if (m.matches()) {
        //This line produces the following structure: factorial ([data before !'s] , [number of !'s])
        ConsCell replacement = new ConsCell("factorial", ConsType.IDENTIFIER, new ConsCell(new ConsCell(current.getPreviousConsCell().getCar(), current.getPreviousConsCell().getCarType(),
            new ConsCell(",", ConsType.SEPARATOR, new ConsCell(new BigDec(((String) current.getCar()).length()), ConsType.NUMBER))), ConsType.CONS_CELL));
        if (current.getPreviousConsCell() == input) {
          replacement.getLastConsCell().append(input.getNextConsCell(2));
          input = current = replacement;
        }
        else {
          current = current.getPreviousConsCell().remove();
          current.replaceCar(replacement);
        }
      }
    } while (!((current = current.getNextConsCell()).isNull())); //This steps current forward while checking for nulls
    return input; //Returns the first ConsCell in this list
  }
 
  @Override
  public void loadInputFilter() {/* Nothing to do here */}
 
  @Override
  public void unloadInputFilter() {/* Nothing to do here */}
}
TOP

Related Classes of miscellaneous.Functions

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.