public MathFunc(string str, string v = null, bool simplify = true, bool precompile = false) { if (!Helper.Parser.Parse(str)) { throw new Exception("Impossible to parse input string"); } LeftNode = Helper.Parser.FirstStatement.LeftNode; RightNode = Helper.Parser.FirstStatement.RightNode; Root = RightNode; if (string.IsNullOrEmpty(v)) { ConstToVars(); } else { Variable = new VarNode(v); ConstToVar(Root); } FindParamsAndUnknownFuncs(Root); Root.Sort(); if (simplify) { Root = Simplify(Root); } if (precompile) { Root = Precompile(null, Root); } }
private void DefineLocals(MathFuncNode node) { var funcNode = node as FuncNode; if (funcNode == null) { return; } CountNumber value; var hash = funcNode.GetHashCode(); if (FuncNodes.TryGetValue(funcNode, out value)) { funcNode.Number = value.Number; FuncNodes[funcNode].Count += 1; } else { FuncNodes.Add(funcNode, new CountNumber() { Number = LocalVarNumber, Count = 1, Calculated = false }); funcNode.Number = LocalVarNumber; LocalVarNumber += funcNode.Childs.Count; } foreach (var child in node.Childs) { DefineLocals(child); } }
public MathFunc(MathFuncNode left, MathFuncNode right, VarNode variable = null, IEnumerable <ConstNode> parameters = null, bool simplify = true, bool calculateConstants = false) { LeftNode = left; RightNode = right; Root = RightNode; Variable = variable; if (Variable == null) { ConstToVars(); } if (parameters != null) { Parameters = parameters.Except(parameters.Where(p => p.Name == Variable.Name)).ToDictionary(node => node.Name); } FindParamsAndUnknownFuncs(Root); Root.Sort(); if (simplify) { Root = Simplify(Root); } if (calculateConstants) { Root = Precompile(null, Root); } }
public MathFunc(MathFuncNode root, VarNode variable = null, IEnumerable <ConstNode> parameters = null, bool calculateConstants = false, bool simplify = false) : this(new FuncNode("f", new List <MathFuncNode>() { variable }), root, variable, parameters, calculateConstants, simplify) { }
private MathFuncNode MakeSubstitution(MathFuncNode left, MathFuncNode right, FuncNode currentFunc) { LeftNode = left; RightNode = right; _currentFunc = currentFunc; return(MakeSubstitution(right)); }
private MathFuncNode PowerIntoMult(IEnumerable <MathFuncNode> multChilds, MathFuncNode expNode) { var newChilds = multChilds.Select(child => Simplify(new FuncNode(KnownFuncType.Pow, child, expNode))); return(Simplify(new FuncNode(KnownFuncType.Mult, newChilds.ToList()))); }
private FuncNode PrecompileExpFunc(MathFuncNode parent, FuncNode funcNode) { if ((parent == null || ((FuncNode)parent).FunctionType != KnownFuncType.Mult) && funcNode.Childs[1].LessThenZero()) { if (!funcNode.Childs[1].IsValueOrCalculated || funcNode.Childs[1].DoubleValue != -1.0) { FuncNode second; if (!funcNode.Childs[1].IsValueOrCalculated) { second = new FuncNode(KnownFuncType.Pow, funcNode.Childs[0], funcNode.Childs[1].Abs()); } else { second = Math.Abs(funcNode.Childs[1].DoubleValue) != 0.5 ? new FuncNode(KnownFuncType.Pow, funcNode.Childs[0], funcNode.Childs[1].Abs()) : new FuncNode(KnownFuncType.Sqrt, funcNode.Childs[0]); } return(new FuncNode(KnownFuncType.Div, new CalculatedNode(1.0), second)); } else { return(new FuncNode(KnownFuncType.Div, new CalculatedNode(1.0), funcNode.Childs[0])); } } if (funcNode.Childs[1].IsValueOrCalculated && funcNode.Childs[1].DoubleValue == 0.5) { return(new FuncNode(KnownFuncType.Sqrt, funcNode.Childs[0])); } return(funcNode); }
public MathFunc(string str, string v = null, bool simplify = true, bool precompile = false) { List <MathFunc> mathFuncs = new MathExprConverter().Convert(str); MathFunc first = mathFuncs.FirstOrDefault(); LeftNode = first.LeftNode; RightNode = first.RightNode; Root = RightNode; if (string.IsNullOrEmpty(v)) { ConstToVars(); } else { Variable = new VarNode(v); ConstToVar(Root); } FindParamsAndUnknownFuncs(Root); Root.Sort(); if (simplify) { Root = Simplify(Root); } if (precompile) { Root = Precompile(null, Root); } }
protected void GetFirstParam(MathFuncNode node) { if (Variable == null) { for (int i = 0; i < node.Childs.Count; i++) { if (Variable == null) { if (node.Childs[i].Type == MathNodeType.Constant) { Variable = new VarNode(node.Childs[i].Name); break; } else if (node.Childs[i].Type == MathNodeType.Variable) { Variable = (VarNode)node.Childs[i]; break; } else { GetFirstParam(node.Childs[i]); } } } } }
private MathFuncNode ReducePowers(MathFuncNode funcNode) { if (funcNode.Type != MathNodeType.Function) { return(funcNode); } var newChilds = new List <MathFuncNode>(); bool[] markedNodes = new bool[funcNode.Childs.Count]; for (int i = 0; i < funcNode.Childs.Count; i++) { var basis = UnderPowerExpr(funcNode.Childs[i]); var nodesWithSameBasis = new List <MathFuncNode>(); if (!markedNodes[i]) { nodesWithSameBasis.Add(funcNode.Childs[i]); } for (int j = i + 1; j < funcNode.Childs.Count; j++) { if (basis.Equals(UnderPowerExpr(funcNode.Childs[j])) && !markedNodes[j]) { nodesWithSameBasis.Add(funcNode.Childs[j]); markedNodes[j] = true; } } if (nodesWithSameBasis.Count > 1) { newChilds.Add(Simplify(new FuncNode(KnownFuncType.Pow, basis, Simplify(new FuncNode(KnownFuncType.Add, nodesWithSameBasis.Select(node => PowerExpr(node)).ToList())) ))); } else if (!markedNodes[i]) { newChilds.Add(funcNode.Childs[i]); } } if (funcNode.Childs.Count != newChilds.Count) { if (newChilds.Count == 1) { return(newChilds[0]); } else { return(new FuncNode(KnownFuncType.Mult, newChilds)); } } else { return(funcNode); } }
protected void SetParamsAndUnknownFuncsArgNumbers(MathFuncNode node) { foreach (var child in node.Children) { SetParamsAndUnknownFuncsArgNumbers(child); } if (node is FuncNode funcNode && !funcNode.IsKnown) { node.ArgNumber = UnknownFuncs[node.Name].ArgNumber; }
private bool ContainsNaNHelper(MathFuncNode node) { for (int i = 0; i < node.Children.Count; i++) { if (ContainsNaNHelper(node.Children[i])) { return(true); } } if (node is CalculatedNode calcNode && double.IsNaN(calcNode.DoubleValue)) { return(true); }
protected void FindParamsAndUnknownFuncs(MathFuncNode node) { foreach (MathFuncNode child in node.Children) { FindParamsAndUnknownFuncs(child); } if (node is FuncNode funcNode && !funcNode.IsKnown) { if (!UnknownFuncs.ContainsKey(node.Name)) { UnknownFuncs.Add(node.Name, funcNode); } }
private void InvertLocalVariablesNumbers(MathFuncNode node) { var funcNode = node as FuncNode; if (funcNode != null) { funcNode.Number = LocalVarNumber - funcNode.Number - funcNode.Childs.Count; FuncNodes[funcNode].Number = funcNode.Number; foreach (var child in funcNode.Childs) { InvertLocalVariablesNumbers(child); } } }
private bool EmitMultFunc(FuncNode funcNode) { MathFuncNode firstItem = null; firstItem = funcNode.Childs.FirstOrDefault(node => { var func = node as FuncNode; return(!(func != null && FuncNodes[func].Count == 1 && func.FunctionType == KnownFuncType.Pow && func.Childs[1].LessThenZero())); }); if (firstItem == null) { firstItem = funcNode.Childs[0]; } EmitNode(firstItem); for (int i = 0; i < funcNode.Childs.Count; i++) { if (funcNode.Childs[i] == firstItem) { continue; } var func = funcNode.Childs[i] as FuncNode; if (func != null && FuncNodes[func].Count == 1 && func.FunctionType == KnownFuncType.Pow && func.Childs[1].LessThenZero()) { EmitNode(funcNode.Childs[i], true); IlInstructions.Add(new OpCodeArg(OpCodes.Div)); } else { EmitNode(funcNode.Childs[i]); if (IlInstructions[IlInstructions.Count - 1].OpCode == OpCodes.Ldc_R8 && (double)IlInstructions[IlInstructions.Count - 1].Arg == 1.0) { IlInstructions.RemoveAt(IlInstructions.Count - 1); } else { IlInstructions.Add(new OpCodeArg(OpCodes.Mul)); } } } return(true); }
private void GetDerivatives(MathFuncNode root) { for (int i = 0; i < root.Children.Count; i++) { if (root.Children[i] is FuncNode funcNode) { if (funcNode.FunctionType == KnownFuncType.Diff) { root.Children[i] = GetDerivative(root.Children[i].Children[0]); } else { GetDerivatives(root.Children[i]); } } } }
private void GetDerivatives(MathFuncNode root) { for (int i = 0; i < root.Childs.Count; i++) { if (root.Childs[i].Type == MathNodeType.Function) { if (((FuncNode)root.Childs[i]).FunctionType == KnownFuncType.Diff) { root.Childs[i] = GetDerivative(root.Childs[i].Childs[0]); } else { GetDerivatives(root.Childs[i]); } } } }
protected void ConstToVar(MathFuncNode node) { for (int i = 0; i < node.Childs.Count; i++) { if (node.Childs[i] == null || node.Childs[i].Name == Variable.Name) { node.Childs[i] = Variable; } else if (node.Childs[i].Type == MathNodeType.Variable) { node.Childs[i] = new ConstNode(node.Childs[i].Name); } else { ConstToVar(node.Childs[i]); } } }
protected void ConstToVar(MathFuncNode node) { for (int i = 0; i < node.Children.Count; i++) { if (node.Children[i] == null || node.Children[i].Name == Variable.Name) { node.Children[i] = Variable; } else if (node.Children[i] is VarNode varNode) { node.Children[i] = new ConstNode(node.Children[i].Name); } else { ConstToVar(node.Children[i]); } } }
private MathFuncNode Precompile(MathFuncNode parent, MathFuncNode node) { if (node.Type == MathNodeType.Value) { return(new CalculatedNode(((ValueNode)node).Value)); } else if (node.Type == MathNodeType.Function) { for (int i = 0; i < node.Childs.Count; i++) { node.Childs[i] = Precompile(node, node.Childs[i]); } FuncNode func = (FuncNode)node; switch (func.FunctionType) { case KnownFuncType.Add: node = PrecompileAddFunc(func); break; case KnownFuncType.Mult: node = PrecompileMultFunc(func); break; case KnownFuncType.Pow: node = PrecompileExpFunc(parent, func); break; } if (node.Childs.Count > 0 && node.Childs.All(child => child.Type == MathNodeType.Value || child.Type == MathNodeType.Calculated)) { return((MathFuncNode)CalculateValues(((FuncNode)node).FunctionType, node.Childs) ?? (MathFuncNode)node); } else { return(node); } } else { return(node); } }
private MathFuncNode GetDerivative(MathFuncNode node) { switch (node) { case CalculatedNode calculatedNode: return(new CalculatedNode(0.0)); case ValueNode valueNode: case ConstNode constNode: return(new ValueNode(0)); case VarNode varNode: return(new ValueNode(1)); case FuncNode funcNode: return(GetFuncDerivative(funcNode)); } return(null); }
private MathFuncNode GetDerivative(MathFuncNode node) { switch (node.Type) { case MathNodeType.Calculated: return(new CalculatedNode(0.0)); case MathNodeType.Value: case MathNodeType.Constant: return(new ValueNode(0)); case MathNodeType.Variable: return(new ValueNode(1)); case MathNodeType.Function: return(GetFuncDerivative((FuncNode)node)); } return(null); }
protected void SetParamsAndUnknownFuncsArgNumbers(MathFuncNode node) { foreach (var child in node.Childs) { SetParamsAndUnknownFuncsArgNumbers(child); } if (node.Type == MathNodeType.Function && !((FuncNode)node).IsKnown) { node.ArgNumber = UnknownFuncs[node.Name].ArgNumber; } else if (node.Type == MathNodeType.Constant) { node.ArgNumber = Parameters[node.Name].ArgNumber; } else if (node.Type == MathNodeType.Variable) { node.ArgNumber = Variable.ArgNumber; } }
private bool ContainsNaNHelper(MathFuncNode node) { for (int i = 0; i < node.Childs.Count; i++) { if (ContainsNaNHelper(node.Childs[i])) { return(true); } } CalculatedNode calcNode = node as CalculatedNode; if (calcNode != null && double.IsNaN(calcNode.DoubleValue)) { return(true); } else { return(false); } }
public void ConstToVars() { if (LeftNode is VarNode varNode) { Variable = varNode; } if (LeftNode is ConstNode constNode) { Variable = new VarNode(LeftNode.Name); } else if (LeftNode is FuncNode funcNode) { Variable = null; if (LeftNode.Children.Count > 1 && funcNode.Children[1] != null) { var secondNode = funcNode.Children[1]; if (secondNode is ConstNode) { Variable = new VarNode(secondNode.Name); } else if (secondNode is VarNode secondVarNode) { Variable = secondVarNode; } } GetFirstParam(RightNode); if (Variable == null) { Variable = new VarNode("x"); } } ConstToVar(Root); if (Root.Name == Variable.Name) { Root = Variable; } }
private MathFuncNode PrecompileAddFunc(FuncNode funcNode) { MathFuncNode firstItem; MathFuncNode result = null; var funcNode2 = FoldCalculatedSummands(funcNode); firstItem = funcNode2.Childs.FirstOrDefault(node => { var func = node as FuncNode; return(!(func != null && func.LessThenZero())); }); if (firstItem == null) { firstItem = funcNode2.Childs[0]; } result = firstItem; for (int i = 0; i < funcNode2.Childs.Count; i++) { if (funcNode2.Childs[i] == firstItem) { continue; } if (funcNode2.Childs[i].LessThenZero()) { result = new FuncNode(KnownFuncType.Sub, result, funcNode2.Childs[i].Abs()); } else { result = new FuncNode(KnownFuncType.Add, result, funcNode2.Childs[i]); } } return(result); }
private void EmitNode(MathFuncNode node, bool negExpAbs = false) { switch (node.Type) { case MathNodeType.Calculated: IlInstructions.Add(new OpCodeArg(OpCodes.Ldc_R8, negExpAbs ? Math.Abs(((CalculatedNode)node).Value) : ((CalculatedNode)node).Value)); break; case MathNodeType.Value: IlInstructions.Add(new OpCodeArg(OpCodes.Ldc_R8, negExpAbs ? Math.Abs(((ValueNode)node).Value.ToDouble()) : ((ValueNode)node).Value.ToDouble())); break; case MathNodeType.Constant: case MathNodeType.Variable: IlInstructions.Add(new OpCodeArg(OpCodes.Ldarg, node.ArgNumber)); break; case MathNodeType.Function: var funcNode = node as FuncNode; var func = FuncNodes[funcNode]; if (!func.Calculated) { EmitFunc(funcNode, negExpAbs); func.Calculated = true; // if (FuncNodes[funcNode].Count > 1) TODO: this optimization disallowed due to derivatives. { IlInstructions.Add(new OpCodeArg(OpCodes.Stloc, funcNode.Number)); IlInstructions.Add(new OpCodeArg(OpCodes.Ldloc, funcNode.Number)); } } else { IlInstructions.Add(new OpCodeArg(OpCodes.Ldloc, funcNode.Number)); } break; } }
protected void FindParamsAndUnknownFuncs(MathFuncNode node) { foreach (var child in node.Childs) { FindParamsAndUnknownFuncs(child); } if (node.Type == MathNodeType.Function && !((FuncNode)node).IsKnown) { if (!UnknownFuncs.ContainsKey(node.Name)) { UnknownFuncs.Add(node.Name, (FuncNode)node); } } else if (node.Type == MathNodeType.Constant) { if (!Parameters.ContainsKey(node.Name)) { Parameters.Add(node.Name, (ConstNode)node); } } }
private bool EmitAddFunc(FuncNode funcNode) { MathFuncNode firstItem = null; firstItem = funcNode.Childs.FirstOrDefault(node => { var func = node as FuncNode; return(!(func != null && FuncNodes[func].Count == 1 && func.LessThenZero())); }); if (firstItem == null) { firstItem = funcNode.Childs[0]; } EmitNode(firstItem); for (int i = 0; i < funcNode.Childs.Count; i++) { if (funcNode.Childs[i] == firstItem) { continue; } var func = funcNode.Childs[i] as FuncNode; if (func != null && FuncNodes[func].Count == 1 && func.LessThenZero()) { EmitNode(func.Childs[0], true); IlInstructions.Add(new OpCodeArg(OpCodes.Sub)); } else { EmitNode(funcNode.Childs[i]); IlInstructions.Add(new OpCodeArg(OpCodes.Add)); } } return(true); }
public void ConstToVars() { if (LeftNode.Type == MathNodeType.Variable) { Variable = (VarNode)LeftNode; } if (LeftNode.Type == MathNodeType.Constant) { Variable = new VarNode(LeftNode.Name); } else if (LeftNode.Type == MathNodeType.Function) { Variable = null; if (LeftNode.Childs.Count > 1 && ((FuncNode)LeftNode).Childs[1] != null) { var secondNode = ((FuncNode)LeftNode).Childs[1]; if (secondNode.Type == MathNodeType.Constant) { Variable = new VarNode(secondNode.Name); } else if (secondNode.Type == MathNodeType.Variable) { Variable = (VarNode)secondNode; } } GetFirstParam(RightNode); if (Variable == null) { Variable = new VarNode("x"); } } ConstToVar(Root); if (Root.Name == Variable.Name) { Root = Variable; } }