Skip to content

Commit 6b9719b

Browse files
committed
Added MathAssembly for compiled expressions testing.
Fixed WolframAlphaUtils for checking expressions on equality. Fixed EmitAddFunc & EmitMultFunc.
1 parent 3315dfe commit 6b9719b

15 files changed

+298
-88
lines changed

MathFunctions.GUI/frmMain.Designer.cs

Lines changed: 0 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

MathFunctions.Tests/MathFuncCompilationTests.cs

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,45 +19,20 @@ public void Init()
1919
}
2020

2121
[Test]
22-
public double TestFunc(double x)
22+
public void TestFunc(double x)
2323
{
24-
return Math.Pow((2 * -x + 1), (2 * x + 1)) * Math.Sin((2 * x + 1) * (2 * x + 1) * (2 * x + 1));
24+
//return Math.Pow((2 * -x + 1), (2 * x + 1)) * Math.Sin((2 * x + 1) * (2 * x + 1) * (2 * x + 1));
2525
}
2626

2727
[Test]
28-
public void FindIdenticalFuncsTest()
28+
public void CompileFuncTest1()
2929
{
30-
double x = 3;
31-
double func, funcDer;
32-
CompileAndCalculate("Sin(x) + x ^ (Ln(5 * x) - 10 / x)", "x", x, out func, out funcDer);
33-
double expected = Math.Sin(x) + Math.Pow(x, Math.Log(5 * x) - 10 / x);
34-
Assert.AreEqual(expected, func);
35-
}
36-
37-
private bool CompileAndCalculate(string expression, string variable, double x,
38-
out double funcResult, out double funcDerivativeResult)
39-
{
40-
funcResult = double.NaN;
41-
funcDerivativeResult = double.NaN;
42-
string tempDllName = "MathFuncLib.dll";
43-
try
44-
{
45-
var mathAssembly = new MathFuncAssemblyCecil();
46-
mathAssembly.CompileFuncAndDerivative(expression, variable, "", tempDllName);
47-
var domain = AppDomain.CreateDomain("MathFuncDomain");
48-
var pathToDll = tempDllName;
49-
var mathFuncObj = domain.CreateInstanceFromAndUnwrap(pathToDll, mathAssembly.NamespaceName + "." + mathAssembly.ClassName);
50-
var mathFuncObjType = mathFuncObj.GetType();
51-
funcResult = (double)mathFuncObjType.GetMethod(mathAssembly.FuncName).Invoke(mathFuncObj, new object[] { x });
52-
funcDerivativeResult = (double)mathFuncObjType.GetMethod(mathAssembly.FuncDerivativeName).Invoke(mathFuncObj, new object[] { x });
53-
AppDomain.Unload(domain);
54-
File.Delete(tempDllName);
55-
}
56-
catch
30+
var expectedFunc = new Func<double, double>(x => Math.Sin(x) + Math.Pow(x, Math.Log(5 * x) - 10 / x));
31+
using (var mathAssembly = new MathAssembly("Sin(x) + x ^ (Ln(5 * x) - 10 / x)", "x"))
5732
{
58-
return false;
33+
for (int i = 1; i < 10; i++)
34+
Assert.AreEqual(expectedFunc(i), mathAssembly.SimpleFunc(i));
5935
}
60-
return true;
6136
}
6237
}
6338
}

MathFunctions.Tests/WolframAlphaUtils.cs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@ public static bool CheckEquality(string expression1, string expression2)
2121
{
2222
WolframAlpha wolfram = new WolframAlpha(ConfigurationManager.AppSettings["WolframAlphaAppId"]);
2323

24-
string query = expression1.Replace(" ", "") + "===" + expression2.Replace(" ", "");
24+
string query = "(" + expression1.Replace(" ", "") + ")-(" + expression2.Replace(" ", "") + ")";
2525
QueryResult result = wolfram.Query(query);
2626
result.RecalculateResults();
2727

2828
try
2929
{
30-
return Convert.ToBoolean(result.GetPrimaryPod().SubPods[0].Plaintext);
30+
double d;
31+
return double.TryParse(result.GetPrimaryPod().SubPods[0].Plaintext, out d) && d == 0.0;
3132
}
3233
catch
3334
{
@@ -43,15 +44,17 @@ public static bool CheckDerivative2(string expression, string derivative)
4344

4445
QueryResult result = wolfram.Query("diff(" + expression + ")");
4546
string answer = result.Pods[0].SubPods[0].Plaintext;
46-
string answerDer = answer.Remove(0, answer.IndexOf(" = ") + 3).Trim();
47+
string answerDer = answer.Remove(0, answer.IndexOf(" = ") + 3).Trim().Replace(" ", "");
4748

4849
result = wolfram.Query(derivative);
4950
var pod = result.GetPrimaryPod();
50-
if (pod == null)
51-
result.Pods.Where(p => p.ID == "AlternateForm").FirstOrDefault();
52-
var formattedDer = pod.SubPods[0].Plaintext;
5351

54-
return answerDer == formattedDer;
52+
if (answerDer == pod.SubPods[0].Plaintext.Replace(" ", ""))
53+
return true;
54+
55+
pod = result.Pods.Where(p => p.ID == "AlternateForm").FirstOrDefault();
56+
57+
return answerDer == pod.SubPods[0].Plaintext.Replace(" ", "");
5558
}
5659
catch
5760
{

MathFunctions.v11.suo

15.5 KB
Binary file not shown.

MathFunctions/MathAssembly.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Reflection;
6+
using System.Text;
7+
8+
namespace MathFunctions
9+
{
10+
public class MathAssembly : IDisposable
11+
{
12+
private AppDomain _domain;
13+
private string _fileName = "MathFuncLib.dll";
14+
private object _mathFuncObj;
15+
16+
public MethodInfo Func
17+
{
18+
get;
19+
private set;
20+
}
21+
22+
public MethodInfo FuncDerivative
23+
{
24+
get;
25+
private set;
26+
}
27+
28+
public double SimpleFunc(double x)
29+
{
30+
return (double)Func.Invoke(_mathFuncObj, new object[] { x });
31+
}
32+
33+
public double SimpleFuncDerivative(double x)
34+
{
35+
return (double)FuncDerivative.Invoke(_mathFuncObj, new object[] { x });
36+
}
37+
38+
public MathAssembly(string expression, string variable)
39+
{
40+
var mathAssembly = new MathFuncAssemblyCecil();
41+
mathAssembly.CompileFuncAndDerivative(expression, variable, "", _fileName);
42+
_domain = AppDomain.CreateDomain("MathFuncDomain");
43+
_mathFuncObj = _domain.CreateInstanceFromAndUnwrap(_fileName, mathAssembly.NamespaceName + "." + mathAssembly.ClassName);
44+
var mathFuncObjType = _mathFuncObj.GetType();
45+
Func = mathFuncObjType.GetMethod(mathAssembly.FuncName);
46+
FuncDerivative = mathFuncObjType.GetMethod(mathAssembly.FuncDerivativeName);
47+
}
48+
49+
public void Dispose()
50+
{
51+
if (_domain != null)
52+
AppDomain.Unload(_domain);
53+
File.Delete(_fileName);
54+
}
55+
}
56+
}

MathFunctions/MathFunc.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public MathFuncNode Root
3434
protected set;
3535
}
3636

37-
public MathFunc(string str, string v = null, bool simplify = true, bool calculateConstants = false)
37+
public MathFunc(string str, string v = null, bool simplify = true, bool precompile = false)
3838
{
3939
if (!Helper.Parser.Parse(str))
4040
throw new Exception("Impossible to parse input string");
@@ -56,7 +56,7 @@ public MathFunc(string str, string v = null, bool simplify = true, bool calculat
5656
Root.Sort();
5757
if (simplify)
5858
Root = Simplify(Root);
59-
if (calculateConstants)
59+
if (precompile)
6060
Root = RationalToDouble(Root);
6161
}
6262

@@ -68,7 +68,7 @@ public MathFunc(MathFuncNode root,
6868
{
6969
}
7070

71-
public MathFunc(MathFuncNode left, MathFuncNode right,
71+
public MathFunc(MathFuncNode left, MathFuncNode right,
7272
VarNode variable = null, IEnumerable<ConstNode> parameters = null,
7373
bool simplify = true, bool calculateConstants = false)
7474
{
@@ -91,7 +91,7 @@ public MathFunc(MathFuncNode left, MathFuncNode right,
9191
Root = RationalToDouble(Root);
9292
}
9393

94-
public MathFuncNode Calculate(KnownFuncType? funcType, IList<ValueNode> args)
94+
public ValueNode SimplifyValues(KnownFuncType? funcType, IList<ValueNode> args)
9595
{
9696
Rational<long> result;
9797
double temp = 0.0;
@@ -144,9 +144,6 @@ public MathFuncNode Calculate(KnownFuncType? funcType, IList<ValueNode> args)
144144
case KnownFuncType.Diff:
145145
return new ValueNode(0);
146146

147-
default:
148-
return null;
149-
150147
case KnownFuncType.Sqrt:
151148
temp = Math.Sqrt(args[0].DoubleValue);
152149
break;
@@ -214,6 +211,9 @@ public MathFuncNode Calculate(KnownFuncType? funcType, IList<ValueNode> args)
214211
case KnownFuncType.Abs:
215212
temp = Math.Abs(args[0].DoubleValue);
216213
break;
214+
215+
default:
216+
return null;
217217
}
218218

219219
if (Rational<long>.FromDecimal((decimal)temp, out result, 12, false, 2, 8))
@@ -306,7 +306,7 @@ public bool IsValue
306306
{
307307
get
308308
{
309-
return Root.IsValue;
309+
return Root.IsValueOrCalculated;
310310
}
311311
}
312312

MathFunctions/MathFuncAssemblyCecil.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public MathFuncAssemblyCecil(string namespaceName = "MathFuncLib", string classN
5050
public void CompileFuncAndDerivative(string expression, string variable, string path = "", string fileName = "")
5151
{
5252
var func = new MathFunc(expression, variable, true, true);
53-
var funcDer = func.GetDerivative().RationalToDouble();
53+
var funcDer = new MathFunc(expression, variable, true, false).GetDerivative().GetPrecompilied();
5454

5555
Init();
5656

MathFunctions/MathFuncCompilation.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,10 @@ private bool EmitAddFunc(FuncNode funcNode)
267267
return !(func != null && FuncNodes[func].Count == 1 && func.LessThenZero());
268268
});
269269

270-
if (firstItem != null)
271-
EmitNode(firstItem);
270+
if (firstItem == null)
271+
firstItem = funcNode.Childs[0];
272+
273+
EmitNode(firstItem);
272274

273275
for (int i = 0; i < funcNode.Childs.Count; i++)
274276
{
@@ -312,9 +314,10 @@ private bool EmitMultFunc(FuncNode funcNode)
312314
return !(func != null && FuncNodes[func].Count == 1 && func.FunctionType == KnownFuncType.Exp && func.Childs[1].LessThenZero());
313315
});
314316

317+
if (firstItem == null)
318+
firstItem = funcNode.Childs[0];
315319

316-
if (firstItem != null)
317-
EmitNode(firstItem);
320+
EmitNode(firstItem);
318321

319322
for (int i = 0; i < funcNode.Childs.Count; i++)
320323
{
@@ -364,9 +367,10 @@ private bool EmitNegFunc(FuncNode funcNode, bool negExpAbs)
364367

365368
private bool EmitExpFunc(FuncNode funcNode, bool negExpAbs)
366369
{
367-
if (funcNode.Childs[1].IsValue && ((ValueNode)funcNode.Childs[1]).Value.IsInteger)
370+
if ((funcNode.Childs[1].Type == MathNodeType.Value && ((ValueNode)funcNode.Childs[1]).Value.IsInteger) ||
371+
(funcNode.Childs[1].Type == MathNodeType.Calculated && ((CalculatedNode)funcNode.Childs[1]).Value % 1 == 0))
368372
{
369-
int powerValue = (int)((ValueNode)funcNode.Childs[1]).Value.Numerator;
373+
int powerValue = (int)funcNode.Childs[1].DoubleValue;
370374
int power = Math.Abs(powerValue);
371375
if (negExpAbs)
372376
powerValue = power;

MathFunctions/MathFuncDerivative.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ private MathFuncNode GetDerivative(MathFuncNode node)
2323
{
2424
switch (node.Type)
2525
{
26+
case MathNodeType.Calculated:
27+
return new CalculatedNode(0.0);
2628
case MathNodeType.Value:
2729
case MathNodeType.Constant:
2830
return new ValueNode(0);
@@ -76,14 +78,18 @@ private MathFuncNode GetFuncDerivative(FuncNode funcNode)
7678
}
7779
else if (funcNode.FunctionType == KnownFuncType.Exp)
7880
{
79-
var valueNode = funcNode.Childs[1] as ValueNode;
80-
if (valueNode != null)
81+
if (funcNode.Childs[1].IsValueOrCalculated)
8182
{
83+
var node1 = funcNode.Childs[1].Type == MathNodeType.Value ? (MathFuncNode)
84+
new ValueNode((ValueNode)funcNode.Childs[1]) :
85+
new CalculatedNode((CalculatedNode)funcNode.Childs[1]);
86+
var node2 = funcNode.Childs[1].Type == MathNodeType.Value ? (MathFuncNode)
87+
new ValueNode(((ValueNode)funcNode.Childs[1]).Value - 1) :
88+
new CalculatedNode(((CalculatedNode)funcNode.Childs[1]).Value - 1);
89+
8290
return new FuncNode(KnownFuncType.Mult,
83-
new ValueNode(valueNode.Value),
84-
new FuncNode(KnownFuncType.Exp,
85-
(MathFuncNode)funcNode.Childs[0].Clone(),
86-
new ValueNode(valueNode.Value - 1)),
91+
node1,
92+
new FuncNode(KnownFuncType.Exp, (MathFuncNode)funcNode.Childs[0].Clone(), node2),
8793
GetDerivative(funcNode.Childs[0]));
8894
}
8995

@@ -159,6 +165,9 @@ private MathFuncNode MakeSubstitution(MathFuncNode node)
159165
MathFuncNode result;
160166
switch (node.Type)
161167
{
168+
case MathNodeType.Calculated:
169+
result = new CalculatedNode(((CalculatedNode)node).Value);
170+
break;
162171
case MathNodeType.Value:
163172
result = new ValueNode((ValueNode)node);
164173
break;
@@ -177,6 +186,9 @@ private MathFuncNode MakeSubstitution(MathFuncNode node)
177186
for (int i = 0; i < node.Childs.Count; i++)
178187
switch (node.Childs[i].Type)
179188
{
189+
case MathNodeType.Calculated:
190+
result.Childs.Add(new CalculatedNode((CalculatedNode)node.Childs[i]));
191+
break;
180192
case MathNodeType.Value:
181193
result.Childs.Add(new ValueNode((ValueNode)node.Childs[i]));
182194
break;

0 commit comments

Comments
 (0)