Skip to content

Commit

Permalink
Add generalized method to parse expressions, refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrei Arekhva committed Apr 17, 2017
1 parent aa59345 commit 2c4946d
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 67 deletions.
24 changes: 20 additions & 4 deletions MathExpressionsNet.Tests/CodeDomTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ public class CodeDomTests
[Test]
public void StringsToExpressionsTest()
{
var f0 = CodeDom.ParseExpression<Func<double>>("2+5*4").Compile();
Assert.That(f0(), Is.EqualTo(22));

var f1 = ((Expression<Func<double, double>>)CodeDom.GetExpressionFrom("x=>0")).Compile();
VerifyFunctions(f1, functions.LeftBoundCond);

f1 = ((Expression<Func<double, double>>)CodeDom.GetExpressionFrom("t=>t+3*t*t")).Compile();
f1 = CodeDom.ParseExpression<Func<double, double>>("t+3*t*t", "t").Compile();
VerifyFunctions(f1, functions.RightBoundCond);

var f2 = ((Expression<Func<double, double, double>>)CodeDom.GetExpressionFrom("(x,t)=>x*x*t+3*x*t*t")).Compile();
Expand All @@ -27,9 +30,6 @@ public void StringsToExpressionsTest()

var f3 = ((Expression<Func<double, double, double, double>>)CodeDom.GetExpressionFrom("(x,t,u)=>x*x*t+u*u")).Compile();
VerifyFunctions(f3, functions.K);

f3 = ((Expression<Func<double, double, double, double>>)CodeDom.GetExpressionFrom("(x,t,u)=>x*x+6*x*t-2*u*Math.Pow(2*x*t+3*t*t,2)-2*t*(x*x*t+u*u)")).Compile();
VerifyFunctions(f3, functions.g);
}

private void VerifyFunctions(Func<double, double> generatedFunc, Func<double, double> expectedFunc)
Expand All @@ -53,6 +53,22 @@ private void VerifyFunctions(Func<double, double, double, double> generatedFunc,
Assert.That(generatedFunc(a, b, c), Is.EqualTo(expectedFunc(a, b, c)));
}

[Test]
public void MakeNewFunction()
{
var exprU = CodeDom.ParseExpression<Func<double, double, double>>("x * x * t + 3 * x * t * t", "x", "t");
var exprK = CodeDom.ParseExpression<Func<double, double, double, double>>("x * x * t + u * u", "x", "t", "u");
string du_dt = exprU.Derive("t").Simplify().Body.ToString();
string dK_du = exprK.Derive("u").Simplify().Body.ToString();
var dudx = exprU.Derive("x").Simplify();
string du_dx = dudx.Body.ToString();
string d2u_dx2 = dudx.Derive("x").Simplify().Body.ToString();
string g = $"{du_dt}-{dK_du}*Math.Pow({du_dx},2)-{d2u_dx2}*{exprK.Simplify().Body}".Replace(" ", "");
Assert.That(g, Is.EqualTo("((x*x)+(6*(x*t)))-(2*u)*Math.Pow(((2*(x*t))+(3*(t*t))),2)-(2*t)*(((x*x)*t)+(u*u))"));
var gFunc = CodeDom.ParseExpression<Func<double, double, double, double>>(g, "x", "t", "u").Compile();
VerifyFunctions(gFunc, functions.g);
}

[Test]
public void ThrowingException()
{
Expand Down
4 changes: 0 additions & 4 deletions MathExpressionsNet.Tests/Functions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,10 @@ namespace MathExpressionsNet.Tests
public class Functions
{
public Func<double, double, double, double> K => (x, t, u) => x * x * t + u * u;
public Func<double, double, double, double> dK_du => (x, t, u) => 2 * u;
public Func<double, double, double, double> g => (x, t, u) => x * x + 6 * x * t - 2 * u * Math.Pow(2 * x * t + 3 * t * t, 2) - 2 * t * (x * x * t + u * u);
public Func<double, double> LeftBoundCond => t => 0;
public Func<double, double> RightBoundCond => t => t + 3 * t * t;

public Func<double, double, double> u => (x, t) => x * x * t + 3 * x * t * t;
public Func<double, double, double> du_dx => (x, t) => 2 * x * t + 3 * t * t;
public Func<double, double, double> d2u_dx2 => (x, t) => 2 * t;
public Func<double, double, double> du_dt => (x, t) => x * x + 6 * x * t;
}
}
4 changes: 2 additions & 2 deletions MathExpressionsNet.Tests/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("1.0.1.0")]
[assembly: AssemblyFileVersion("1.0.1.0")]
34 changes: 21 additions & 13 deletions MathExpressionsNet/CodeDom.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ namespace MathExpressionsNet
{
public class CodeDom
{
const string TYPE_NAME = "TemporaryNamespace.Temporary";
const string METHOD_NAME = "Get";
const string CODE_HEADER = @"
private const string TypeName = "TemporaryNamespace.Temporary";
private const string MethodName = "Get";

private const string CodeHeader = @"
namespace TemporaryNamespace
{
using System;
Expand All @@ -25,10 +26,12 @@ public Expression Get()
{
return New(
";
const string CODE_FOOTER = @"

private const string CodeFooter = @"
);
}
static Expression New(Expression<Func<double>> e) { return e; }
static Expression New(Expression<Func<double, double>> e) { return e; }
static Expression New(Expression<Func<double, double, double>> e) { return e; }
static Expression New(Expression<Func<double, double, double, double>> e) { return e; }
Expand All @@ -37,29 +40,28 @@ public Expression Get()
}
";

static CompilerResults Compile(string source)
private static CompilerResults Compile(string source)
{
CodeDomProvider provider = new CSharpCodeProvider(
new Dictionary<string, string> { { "CompilerVersion", "v3.5" } });

CompilerParameters cp = new CompilerParameters();
cp.GenerateInMemory = true;
var cp = new CompilerParameters { GenerateInMemory = true };
cp.ReferencedAssemblies.Add("System.Core.dll");

CompilerResults cr = provider.CompileAssemblyFromSource(
cp,
CODE_HEADER + source + CODE_FOOTER
CodeHeader + source + CodeFooter
);

return cr;
}

static Expression Execute(CompilerResults cr)
private static Expression Execute(CompilerResults cr)
{
Assembly asm = cr.CompiledAssembly;
Type myClass = asm.GetType(TYPE_NAME);
Type myClass = asm.GetType(TypeName);
Object o = Activator.CreateInstance(myClass);
MethodInfo mi = myClass.GetMethod(METHOD_NAME);
MethodInfo mi = myClass.GetMethod(MethodName);
return (Expression)mi.Invoke(o, null);
}

Expand All @@ -69,9 +71,9 @@ public static Expression GetExpressionFrom(string source)

if (cr.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.Append("Compilation failed: ");
Regex reg = new Regex(@":\serror\s(?<reason>.*)$");
var reg = new Regex(@":\serror\s(?<reason>.*)$");

foreach (var error in cr.Errors)
{
Expand All @@ -87,6 +89,12 @@ public static Expression GetExpressionFrom(string source)

return Execute(cr);
}

public static Expression<T> ParseExpression<T>(string func, params string[] variables)
{
var expr = (Expression<T>)GetExpressionFrom($"({string.Join(",", variables)}) => {func}");
return expr.Simplify();
}
}

public class ExpressionCodeDomException : Exception
Expand Down
10 changes: 6 additions & 4 deletions MathExpressionsNet/DifferentialOperator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace MathExpressionsNet
{
public class DifferentialOperator
{
Expression characteristic;
private Expression characteristic;

#region init

Expand All @@ -16,7 +16,7 @@ public class DifferentialOperator
/// <param name="paramName">parameter name</param>
public DifferentialOperator(string paramName)
{
this.characteristic = Expression.Parameter(typeof(double), paramName);
characteristic = Expression.Parameter(typeof(double), paramName);
}

/// <summary>
Expand All @@ -25,7 +25,7 @@ public DifferentialOperator(string paramName)
/// Laplacian = (∂/∂x)^2 + (∂/∂y)^2
/// </summary>
/// <param name="characteristic"></param>
DifferentialOperator(Expression characteristic)
private DifferentialOperator(Expression characteristic)
{
this.characteristic = characteristic;
}
Expand Down Expand Up @@ -55,6 +55,7 @@ public DifferentialOperator(
: this((Expression)e) { }

#endregion

#region apply operator

/// <summary>
Expand All @@ -65,7 +66,7 @@ public DifferentialOperator(
/// <returns>derivative</returns>
public Expression<T> Apply<T>(Expression<T> e)
{
return Apply(this.characteristic, e);
return Apply(characteristic, e);
}

/// <summary>
Expand Down Expand Up @@ -128,6 +129,7 @@ static public Expression<T> Apply<T>(Expression characteristic, Expression<T> e)
}

#endregion

#region operator

/// <summary>
Expand Down
Loading

0 comments on commit 2c4946d

Please sign in to comment.