using System.Linq; using System.Linq.Expressions; using System.Collections.Generic; using System; using System.Reflection; interface IRealNToRealVisitor { void Visit(RealNToReal obj); void PostVisit(RealNToReal obj); } abstract class RealNToReal { public abstract double Evaluate(); public abstract RealNToReal dfd(Variable x); public static RealNToReal operator +(RealNToReal a, RealNToReal b) { return new Add() { A = a, B = b }; } public static RealNToReal operator *(RealNToReal a, RealNToReal b) { return new Mult() { A = a, B = b }; } public static implicit operator RealNToReal(double d) { return new Constant() { Value = d }; } internal abstract Expression GetExpression(List vars); public LambdaExpression GetExpression() { var variables = new List(); var expression = GetExpression(variables); return Expression.Lambda(expression, variables.ToArray()); } public abstract void Accept(IRealNToRealVisitor visitor); } class Add : RealNToReal { public RealNToReal A, B; public override double Evaluate() { return A.Evaluate() + B.Evaluate(); } public override RealNToReal dfd(Variable x) { return A.dfd(x) + B.dfd(x); } internal override Expression GetExpression(List vars) { return Expression.Add(A.GetExpression(vars), B.GetExpression(vars)); } public override void Accept(IRealNToRealVisitor visitor) { visitor.Visit(this); A.Accept(visitor); B.Accept(visitor); visitor.PostVisit(this); } public override string ToString() { return "Add"; } } class Mult : RealNToReal { public RealNToReal A, B; public override double Evaluate() { return A.Evaluate() * B.Evaluate(); } public override RealNToReal dfd(Variable x) { return A.dfd(x) * B + A * B.dfd(x); } internal override Expression GetExpression(List vars) { return Expression.Multiply(A.GetExpression(vars), B.GetExpression(vars)); } public override void Accept(IRealNToRealVisitor visitor) { visitor.Visit(this); A.Accept(visitor); B.Accept(visitor); visitor.PostVisit(this); } public override string ToString() { return "Mult"; } } class Sine : RealNToReal { public RealNToReal Arg; public override double Evaluate() { return System.Math.Sin(Arg.Evaluate()); } public override RealNToReal dfd(Variable x) { return Arg.dfd(x) * new Cosine() { Arg = Arg }; } internal override Expression GetExpression(List vars) { MethodInfo sine = typeof(System.Math).GetMethod("Sin", new Type[] { typeof(double) }); return Expression.Call(null, sine, new Expression[] { Arg.GetExpression(vars) }); } public override void Accept(IRealNToRealVisitor visitor) { visitor.Visit(this); Arg.Accept(visitor); visitor.PostVisit(this); } public override string ToString() { return "Sin"; } } class Cosine : RealNToReal { public RealNToReal Arg; public override double Evaluate() { return System.Math.Cos(Arg.Evaluate()); } public override RealNToReal dfd(Variable x) { return -1 * Arg.dfd(x) * new Sine() { Arg = Arg }; } internal override Expression GetExpression(List vars) { MethodInfo cosine = typeof(System.Math).GetMethod("Cos", new Type[] { typeof(double) }); return Expression.Call(null, cosine, new Expression[] { Arg.GetExpression(vars) }); } public override void Accept(IRealNToRealVisitor visitor) { visitor.Visit(this); Arg.Accept(visitor); visitor.PostVisit(this); } public override string ToString() { return "Cos"; } } class Constant : RealNToReal { public double Value; public override double Evaluate() { return Value; } public override RealNToReal dfd(Variable x) { return new Constant() { Value = 0 }; } internal override Expression GetExpression(List vars) { return Expression.Constant(Value); } public override void Accept(IRealNToRealVisitor visitor) { visitor.Visit(this); visitor.PostVisit(this); } public override string ToString() { return "Constant ("+Value+")"; } } sealed class Variable : RealNToReal { public double Value; public string Name; public override double Evaluate() { return Value; } public override RealNToReal dfd(Variable x) { return new Constant() { Value = (x == this ? 1 : 0) }; } private ParameterExpression _expression; internal override Expression GetExpression(List vars) { if (_expression == null) { _expression = Expression.Parameter(typeof(double), Name); vars.Add(_expression); } return _expression; } public override void Accept(IRealNToRealVisitor visitor) { visitor.Visit(this); visitor.PostVisit(this); } public override string ToString() { return "Variable (" + Value + ")"; } } class Driver { class TreePrinter : IRealNToRealVisitor { int indent; public void Visit(RealNToReal obj) { for (int i = 0; i < indent; i++) Console.Write(' '); Console.WriteLine(obj); indent++; } public void PostVisit(RealNToReal obj) { indent--; } } public static void Main(string[] args) { Variable x = new Variable(), y = new Variable(); RealNToReal G = x * x + x * y + y * y; RealNToReal dGdx = G.dfd(x); // dG/dx RealNToReal dGdy = G.dfd(y); // dG/dy Func eval = (X, Y) => { x.Value = X; y.Value = Y; return dGdx.Evaluate(); }; var lambda = dGdx.GetExpression>(); var comp = (Func)lambda.Compile(); DateTime start; Console.ReadLine(); start = DateTime.Now; for (int i = 0; i < 1000000; i++) eval(i, 45); TimeSpan diff1 = DateTime.Now - start; start = DateTime.Now; for (int i = 0; i < 1000000; i++) comp(i, 45); TimeSpan diff2 = DateTime.Now - start; Console.WriteLine(diff1); Console.WriteLine(diff2); Console.ReadLine(); } }