Input string to math equation in C#

Hi,

I would like to ask if there is a way in c# how to convert an input string and evaluate as a math equation (including complex numbers, referencing library, etc.) without any external library?

I’m looking for equivalent commands as compile() and eval() in Python.

Thank you

The GH parser (what makes the expression components work) is in this namespace:


To reference another library you need a C# compiler.
1 Like

Thank you @Dani_Abalde I was already looking into the GH_ExpressionParser Class.

I’m still struggling with the complex number input. The format seams to be different from the native expression component.

@DavidRutten

The expression language contains some syntactic sugar which needs to be converted into proper code first. Try running your string through GH_ExpressionSyntaxWriter.RewriteAll() prior to calling Evaluate().

Thank you @DavidRutten,

running the string through GH_ExpressionSyntaxWriter.RewriteAll() works well.

My intention is to evaluate the same expression multiple times but I´m struggling to use the GH_ExpressionSyntaxWriter.RewriteAll() method outside the loop. I have already implemented the CatchedSymbols() method but it´s quite slow. Is there a way to reduce the calculation time even more?

Input string to math equation in C#.gh (12.0 KB)

Thank you

I’ll have a look, but note that the expression evaluator in Grasshopper 1.0 is pretty slow. It doesn’t compile the script into executable code, every statement is interpreted every time.

I’ve rewritten the code the way it was supposed to be used (with correct caching), but it really doesn’t matter all that much in terms of performance.

The trick with caching is that if you know you’ll run the same expression several times, you can set up the parser once ahead of time with cached symbols, and then call the Evaluate() overload which doesn’t take any arguments. It will use the cached symbols instead, shaving a few microseconds/milliseconds off each iteration.

  private void RunScript(string expression, ref object result)
  {
    var expr = GH_ExpressionSyntaxWriter.RewriteAll(expression);
    var parser = new GH_ExpressionParser();
    parser.CacheSymbols(expr);

    var c = new List<object>();
    for (int i = 0; i < 10000; i++)
    {
      var z = new Complex(i, i);
      parser.AddVariable("z", z);
      c.Add(parser.Evaluate());
    }
    result = c;
  }
1 Like

Even though the rewritten code doesn’t improve the calculation time significantly, thank you @DavidRutten.

It looks like I will have to look for some C# math parser which works with complex numbers.

.NET comes with a compiler out of the box. I use it to compile code in the script components.

How many inputs/outputs and how fast/slow are your computations?

In specific cases the C# component can be slower than .gha components when working with a lot of data, and you can win some performance by writing it as a gha plugin.

The rewritten C# script from @DavidRutten calculates 1M iterations over 2 minutes.

@DavidRutten, do you have any examples of the .NET compiler please?

I think basically this is what you need. You’ll need to surround your string with some boilerplate code to turn it into valid c#.

This may actually be a lot harder than I thought since you’re working with complex values here. So your original expression “sin(z*z) + {2, 2}” would have to be converted into something like:

using System.Numerics;
namespace ScriptNamespace
{
  public static class ScriptWrapper
  {
    public static object Execute(Complex z)
    {
      return Complex.Sin(z * z) + new Complex(2, 2);
    }
  }
}

And when I put it like that it hardly seems worth the trouble. I spend a long time getting this sort of stuff to work for gh2 expressions. I got there in the end, but boy was it hard.

What about making use of graph theory and functional programming?

Here is a quick solution on how you can decompose a expression string into a function graph which gets recursively evaluated.

 private void RunScript(object x, object y, ref object A)
  {
    // ({3,2} + {1,3}) - ({3,1} + {4,4})

    // Parser creates tree

    Node<Complex> root = new Node<Complex>(){ Function = result => (Complex) result[0] };

    Node<Complex> subNode = new Node<Complex>(){ Function = ComplexSub };
    Node<Complex> addNodeA = new Node<Complex>(){ Function = ComplexAdd };
    Node<Complex> addNodeB = new Node<Complex>(){ Function = ComplexAdd };
    Node<Complex> cinitNodeA = new Node<Complex>(){ ReturnValue = new Complex(3, 2) };
    Node<Complex> cinitNodeB = new Node<Complex>(){ ReturnValue = new Complex(1, 3) };
    Node<Complex> cinitNodeC = new Node<Complex>(){ ReturnValue = new Complex(3, 1) };
    Node<Complex> cinitNodeD = new Node<Complex>(){ ReturnValue = new Complex(4, 4) };


    root.Children.Add(subNode);
    subNode.Children.Add(addNodeA);
    subNode.Children.Add(addNodeB);
    addNodeA.Children.Add(cinitNodeA);
    addNodeA.Children.Add(cinitNodeB);
    addNodeB.Children.Add(cinitNodeC);
    addNodeB.Children.Add(cinitNodeD);

    root.Eval();

    A = root.ReturnValue;
  }

static  Func<object[], Complex> ComplexSub = arg => (Complex) arg[0] - (Complex) arg[1];
static  Func<object[], Complex> ComplexAdd = arg => (Complex) arg[0] + (Complex) arg[1];

public class Node<T>
{
    public Func<object[],T> Function {get; set;}
    public object ReturnValue {get; set;}
    public List<Node<T>> Children = new List<Node<T>>();


    public void Eval()
    {
      if (Function != null)
      {
        object[] returnValues = new object[Children.Count];
        int i = 0;
        foreach (Node<T> child in Children)
        {
          if (child.ReturnValue == null)
          {
            child.Eval();
          }
          returnValues[i] = child.ReturnValue;
          i++;
        }
        ReturnValue = (object) (T) Function(returnValues);
      }
    }
}

EDIT: 1 Million iterations takes around 1 sec to compute. So it depends on the text parsing I would say…

I have a program to evaluate function. It first make a graph then make a heap/stack of operation and data. it is similar to Reverse Polish notation


I have an abstract class for stack, it is derived for function (+, -, *, /, % ) for function (Sin…), constants (numbers) and for variables
 public abstract class FunctionOperationOnStack
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="arg_tab_stacks">Pile de valeurs</param>
        /// <param name="arg_tab_variablesValues">Pile de valeurs des variables</param>
        /// <param name="arg_positionOnStack">Index sur la pile</param>
        /// <param name="tolerance"></param>
        /// <returns></returns>
        public abstract int StackOperation(ref double[] arg_tab_stacks, double[] arg_tab_variablesValues, ref int arg_positionOnStack, double tolerance);
    }

The operation “eat” the stack, when there is just one number it is finished. Attachement with 1 million calculation in 5 s
2021-01-25 Calculate with default angles LD.gh (20.4 KB)

I really appreciate your help @DavidRutten @TomTom @laurent_delrieu but I’m quite new in C#. I don’t think I’m able to create a whole new math parser library which works with complex numbers, etc. :sweat_smile: yet.

My initial intention was while rewriting the Chimpanzee plug-in in C# to add an equation input for the Mandelbrot set component for the users.

Currently the Mandelbrot set component without an equation input calculates 1M points for 100 iterations in less than 5s (old laptop). :sweat_smile:

It looks like it would be much efficient to reference some external math parser library or don’t implement the thought.