Confirmation of the 10th Greenspun Act in C #

I am trying to implement an infrastructure in C # that would allow me to create arbitrary mathematical expressions. For example, I want to have an expression, for example

asin (sqrt (z - sin (x + y) ^ 2))

and turn it into an object that will allow me to evaluate it in terms of x, y and z, get derivatives and, possibly, make some kind of symbolic algebra on it. What do people think of a good model for this in C #?

I have my own take, which, I'm afraid, is being directed to the architecture of astronautics, so I want to make sure that this is not so.

Basically, functions like sin, +, sqrt, etc., have classes based on the base class:

Function

Function<TOut> : Function
    TOut Value

Function<Tin, TOut> : Function
    TOut Evaluate(TIn value)
    Function Derivative
    Function<TOut, TIn> INverse

Function<TInA, TInB, TOut> : Function
    TOut Evaluate(TInA valueA, TInB valueB)
    Function PartialDerivativeA
    Function PartialDerivativeB

. , . , - currying, , . , factory :

Function<TInA, TInB, TOut> -> 
           Function<TInA, Function<TInB, TOut>>

(Function<TInA, TInB, TOut>, Function<TInX, TInA>, null) -> 
           Function<TInX, Function<TInB, TOut>>

(Function<TInA, TInB, TOut>, Function<TInA>, Function<TInX, TInY, TInB>) -> 
           Function<TInX, Function<TInY, TInB>>

.. , ( , ), , , .

!

+5
4

, currying, .
, .


[] , . AST, , . , node; -

public class PlusNode : BinaryNode
{
    public PlusNode(Node left, Node right) { base(left, right); }
    public virtual double Evaluate() { return Left.Evaluate() + Right.Evaluate(); }
    public virtual Node BuildDerivative()
    {
        return new PlusNode(Left.BuildDerivative(), Right.BuildDerivative());
    }
}

public class SinNode : UnaryNode
{
    public SinNode(Node child) { base(child); }
    public virtual double Evaluate() { return Math.Sin(Child.Evaluate()); }
    public virtual Node BuildDerivative()
    {
        return new MultiplyNode(new CosNode(Child.Clone()), Child.BuildDerivative()); //chain rule
    }
}
0

? , ( " " "" )

0

Funny, I actually did it a few months ago in D, and it was not received as particularly interesting. My approach was to use template tree-like expression classes. I had a binary class template that could be created using +, *etc., a Unary class that could be created using sin, expetc. Derivatives worked mainly simply recursively applying the chain and product rules. For example:

class Binary(alias fun) : MathExpression {
    MathExpression left, right;

    MathExpression derivative() {
        static if(is(fun == add)) {
            return left.derivative + right.derivative;
        } else static if(is(fun == mul)) {
            return left.derivative * right + right.derivative * left;
        }
    }

    real opCall(real x) {
        return fun(left(x), right(x));
    }
}


class Unary(alias fun) : MathExpression {
    MathExpression inner;

    MathExpression derivative() {
        static if(is(fun == sin)) {
            return Unary!(sin)(inner.derivative);
        }
    }

    real opCall(real x) {
        return fun(inner(x));
    }
}

class Constant : MathExpression {

    real val;

    real opCall(real x) {
        return val;
    }

    real derivative() {
        return new Constant(0);
    }
}
0
source

All Articles