Dynamic Implementation of functions to variables

I have an number of functions in an interface as shown below and want to create functions in the mathematical sense ( f(x)=stuff ). Is there a way in which I can dynamically implement functions to a variable while the program is running? i.e.

float y=Function[0].Component(Function[2].Component(Function[4].Component(x,2),1), Function[2].Component(x,2), 1); which is y=x²+2x+1

interface MathOperations
{
  float Component(float...comps);
}

MathOperations[] Function =
{
  new MathOperations() { 
    float Component(float...comps) {
      float add=0;
      for (float comp:comps){
        add+=comp;
      }
      return add; 
    }
  },
  new MathOperations() { 
    float Component(float...comps) {
      float substract=0;
      for (float comp:comps){
        substract-=comp;
      }
      return substract; 
    }
  },
  new MathOperations() { 
    float Component(float...comps) {
      float multiply=1;
      for (float comp:comps){
        multiply*=comp;
      }
      return multiply; 
    }
  },
  new MathOperations() { 
    float Component(float...comps) {
      float devide;
      devide=comps[0]/comps[1];
      return devide; 
    }
  },
  new MathOperations() {                //power: x, base
    float Component(float...comps) {
      return pow(comps[0],comps[1]);
    }
  },
  new MathOperations() {                //logarithm: base, x
    float Component(float...comps) {
      return log(comps[1])/log(comps[0]);
    }
  }, 
  new MathOperations() {                //root: x, degree
    float Component(float...comps) {
      return pow(comps[0], 1/comps[1]);
    }
  },
  new MathOperations() { 
    float Component(float...comps) {
      return sin(comps[0]); 
    }
  },
  new MathOperations() { 
    float Component(float...comps) {
      return cos(comps[0]); 
    }
  },
  new MathOperations() { 
    float Component(float...comps) {
      return tan(comps[0]); 
    }
  },
  new MathOperations() { 
    float Component(float...comps) {
      return atan(comps[0]); 
    }
  }
};

Answers

  • You could try the QScript or Jasmine libraries both can be installed through the PDE.

  • Thank you for your replies I think this doesn't really solve the problem. I want to deisign equations while the program is running and using the basic MathOperations I have posted create the wanted function. The point is to be able to compose any function within the program (given the basic components ie +,-,log,sin) and then graphically represent it but not define it in the code!

  • yes, QScript can do this

    just read in a string with your formula and eval it:

    Solver.evaluate("$x=2; println($x + ' cubed is ' + $x^3) ");

    or

    Solver.evaluate(myFormula);

  • edited July 2015

    I want to design equations while the program is running...

    Those proposed solutions are based on calling some eval()-like function over some on-the-fly "designed" String. Dunno what else could be more flexible than that! ^#(^

  • I have difficulty in passing variables from processing to Solver.evaluate. And I have not found an answer in QScript documentation... Also how can I store the output in a variable? When I write float y=Solver.evaluate() it outputs an error "cannot convert from Result to float"

  • edited July 2015 Answer ✓
    import org.qscript.eventsonfire.*;
    import org.qscript.events.*;
    import org.qscript.editor.*;
    import org.qscript.*;
    import org.qscript.operator.*;
    import org.qscript.errors.*;
    
    
    String task = "2+2";
    
    Result result1 = Solver.evaluate(task);
    
    
    String result2 = result1.toString();    
    
    if (result1.isValid()) {
      float y = float (result2);
      println (y*2); // test * 2
    }
    
    println (result2); 
    
  • edited July 2015
    import org.qscript.eventsonfire.*;
    import org.qscript.events.*;
    import org.qscript.editor.*;
    import org.qscript.*;
    import org.qscript.operator.*;
    import org.qscript.errors.*;
    
    
    String task;
    
    // try one of these: 
    task = "2+2";
    task = "12^2";  // power of
    task = "sqrt(16)"; // sq root
    task = "sqrt(5^2 + 12^2)"; // gives 13
    task = "log(3,2)";  // log(a, b) :  Returns the base b logarithm of a    
    task = "2 * 4";
    task = "8 / 2";
    task = "8 - 2";
    
    /* 
     String[] task1 = {
     "$maxPrime = 90", 
     "println('Prime numbers <= ' + $maxPrime)", 
     "println('2')", 
     "$n = 3", 
     "REPEAT", 
     "  $rootN = int(sqrt($n))", 
     "  $notPrime = false;", 
     "  $i = 3", 
     "  WHILE($i <= $rootN && NOT($notPrime))", 
     "    $notPrime = ($n % $i == 0)", 
     "    $i = $i + 1", 
     "  WEND", 
     "  IF($notPrime == false)", 
     "    println($n)", 
     "  ENDIF", 
     "  $n = $n + 2", 
     "UNTIL($n > $maxPrime)"
     };
    
     */
    
    
    Result result1 = Solver.evaluate(task);
    
    
    String result2 = result1.toString();    
    
    if (result1.isValid()) {
      float y = float (result2);
      println (y);
    }
    
    println (result2);
    
  • edited July 2015

    Thank you for your replies! I want to have something like task="x+2" where x will be taking values from processing, not be defined inside the script like task = "$x=2; x+2"

  • edited July 2015

    aha!

    I don't know

  • makes no sense, since the user doesn't know the names of the vars anyway

    instead implement the whole thing within QScript without the external vars...

    ;-)

  • edited July 2015

    It would be better to use the Jasmine library. This code draws the sine wave.

    import org.quark.jasmine.*;
    
    String equation = "100 * sin(x)";
    Expression e;
    float result, prevResult, y0;
    
    void setup() {
      size(400, 250);
      y0 = height/2;
      e = Compile.expression(equation, false);
      // Ready to use expression
      background(200, 255, 200);
      stroke(0);
      strokeWeight(1.2);
      // draw sin wave
      prevResult = e.eval(0).answer().toFloat() + y0;
      for (int i = 2; i < width; i += 2) {
        result = e.eval(i/TWO_PI).answer().toFloat() + y0;
        line(i-2, prevResult, i, result);
        prevResult = result;
      }
    }
    

    Produces

    sin

  • @quark

    I think he is looking for a way that the user enters string that gets evaluated but at the same time, the user can reference vars from the underlying sketch in the String and use them in his formula....

  • as a matter of fact I managed to do what I wanted with QScript (thank you very much for that) but for complex functions the program is slow. And with Solver$.evaluate() i am not getting a float but this "org.qscript.Solver$@a668bc ". I will give it a try with Jasmine to see if the calculations are done faster.

  • how did you do it then?

  • edited July 2015

    1.

    you wrote

    as a matter of fact I managed to do what I wanted with QScript

    how did you do it then?

    2.

    you wrote

    And with Solver$.evaluate() i am not getting a float but this "org.qscript.Solver$@a668bc ".

    did you try:

    Result result1 = Solver.evaluate(task);
    
    
    String result2 = result1.toString();    
    
    if (result1.isValid()) {
      float y = float (result2);
      println (y);
    }
    
    println (result2);
    
  • edited July 2015

    To enter Processing variables to the Solver.evaluate() function I exploited the String task. I broke it down as shown in the example below:

    String f="&x^2 + 3*$x + 8"
    String n="$x="+x+"; "+f;
    float y=float(Solver.evaluate(n).toString());
    

    String n contains the mathematical function I wanted and also takes values for x from the program and not from inside the script. This method however is slow for more complex functions like

     String f = "sqrt(2*$x^3 - 3*$x^2 + 8) / sqrt($x^2 - 5*$x + 4)";
    

    And slows the whole program down. In the QScript documentation the function Solver$.evaluate() is suggested for shorter execution time. However this function introduces the problem descibed above and is therefore unusable. The execution time is the only problem so far and for that reason I will also try the Jasmine library

  • No luck with Jasmine either. It is worse in terms of speed than QScript. Is there anything I can do about that?

  • edited July 2015

    A number of points here

    1) In QScript it is possible to
    a) create a Script object using a String to represent the equation
    b) then initialise the variables in the equation
    c) then evaluate the equation
    d) retrieve the values in any variables in the equation
    the last three steps can be repeated as often as required.
    In the latest version you don't need the $ to identify variables

    2) Jasmine can do the same but the syntax is different.

    3) Jasmine is faster than QScript and I can say that in all confidence because I created both libraries. In fact Jasmine is of the same order of execution speed as pure Java. If it is not fast enough for you then you are either doing something wrong or expecting the impossible. The two programs below both calculate the hypotenuse of 3 right-angle triangles, the first uses QScript and takes 3ms and the second uses Jasmine and takes 0ms (i.e. less than 1ms) when measured on my machine.

    4) Statements like

    No luck with Jasmine either. It is worse in terms of speed than QScript. Is there anything I can do about that?

    without code or other information are absolutely useless. In fact it appears that you have made the assumption that the lack of speed is down to the actual libraries rather than with your code.

    // Calculate the hypotenuse of three different
    // right-angle triangles using QScript
    import org.qscript.eventsonfire.*;
    import org.qscript.events.*;
    import org.qscript.editor.*;
    import org.qscript.*;
    import org.qscript.operator.*;
    import org.qscript.errors.*;
    
    float h;
    
    void setup() {
      String[] code = {
        "hyp = sqrt(a^2 + b^2)",
      };
      // Create and parse the script
      Script script = new Script(code);
      script.parse();
    
      int t = millis();
    
      script.storeVariable("a", 5);
      script.storeVariable("b", 12);
      script.evaluate();
      h = script.getVariable("hyp").toFloat();
      println("Hypot = " + h);
    
      script.storeVariable("a", 4);
      script.storeVariable("b", 3);
      script.evaluate();
      h = script.getVariable("hyp").toFloat();
      println("Hypot = " + h);
    
      script.storeVariable("a", 15);
      script.storeVariable("b", 8);
      script.evaluate();
      h = script.getVariable("hyp").toFloat();
      println("Hypot = " + h);
    
      t = millis() - t;
      println("Took " + t + "ms");
    }
    

    =====================

    // Calculate the hypotenuse of three different
    // right-angle triangles using Jasmine
    import org.quark.jasmine.*;
    
    String equation = "sqrt(a^2 + b^2)";
    Expression e;
    float h;
    
    void setup() {
      e = Compile.expression(equation, false);
    
      int t = millis();
    
      h = e.eval(5, 12).answer().toFloat();
      println("Hypot = " + h);
    
      h = e.eval(4, 3).answer().toFloat();
      println("Hypot = " + h);
    
      h = e.eval(15, 8).answer().toFloat();
      println("Hypot = " + h);
    
     t = millis() - t;
      println("Took " + t + "ms");
    }
    
  • edited July 2015

    I never ment to offend you and I am sorry if I did. Both libraries are, if anything, awesome and I am grateful to you for writing them and distributing them freely.

    You are right about that, i did not phrase what I wanted to say correctly. What I meant is that using either of the libraries inside a loop that repeats 400 times is (as I have witnessed in my computer) slower that writing (for example)

     float y=sqrt(pow(x,2)+5);
    

    which is understandable, acceptable and expected.

  • Answer ✓

    The trick with using these libraries is to understand that the slow part is parsing or compiling the expression. That's line 18 in the QScript example and line 10 in the Jasmine example from my last post. If you do these inside a loop then it will be significantly slower than Java and should be avoided.

    The posted QScript and Jasmine examples as well as the sine wave example show how you can parse/compile the equation once and then use it many times without slowing the program noticeably.

    BTW QScript parsing is generally faster than Jasmine compiling but Jasmine is VERY MUCH faster when evaluating the equation.

    I suggest that you create some simple sketches to experiment and get used to using these libraries and if you have questions post them here with the your code. :D

  • edited July 2015

    Wow! The execution time has improved greatly and there is no lag. I am parsing the script once in draw()

     if (!parse){
       fx = new Script(f);
       fx.parse();
       parse=true;
     }
    

    If and when the equation is changed I can simply change the boolean to parse=false and reparse fx.

  • edited July 2015

    I encountered the following in my program.

      fx.storeVariable("x", x);
      fx.evaluate(); 
      println(x+"      "+fx.evaluate());
      float y=fx.getVariable("y").toFloat();
    

    x is a float variable. The equation is y=x but when I retrieve the variable y, its values have error when x does not. Here is a part of the output

    19.6 19.600000381469727 19.65 19.649999618530273 19.7 19.700000762939453 19.75 19.75 19.8 19.799999237060547 19.85 19.850000381469727 19.9 19.899999618530273 19.95 19.950000762939453

    I know that float variables are not always precise and there are techniques to make them so (as per this link https://processing.org/reference/float.html). But are there any techniques for removing the error from this function?

  • Never mind! Variable y does not have error...!!

Sign In or Register to comment.