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); }
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 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 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]); }
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; }
protected void PushFunction(string mathFunction) { var lastArgsCount = ArgsCount[ArgsCount.Count - 1]; var args = new MathFuncNode[lastArgsCount]; for (int i = 0; i < lastArgsCount; i++) { args[lastArgsCount - 1 - i] = Nodes.Pop(); } Nodes.Push(new FuncNode(mathFunction, args)); ArgsCount.RemoveAt(ArgsCount.Count - 1); ArgsFuncTypes.RemoveAt(ArgsFuncTypes.Count - 1); }
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; }
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); }
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; } }
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 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); }
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; }
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 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); } }
protected void PushFunction(string mathFunction) { var lastArgsCount = ArgsCount[ArgsCount.Count - 1]; var args = new MathFuncNode[lastArgsCount]; for (int i = 0; i < lastArgsCount; i++) args[lastArgsCount - 1 - i] = Nodes.Pop(); Nodes.Push(new FuncNode(mathFunction, args)); ArgsCount.RemoveAt(ArgsCount.Count - 1); ArgsFuncTypes.RemoveAt(ArgsFuncTypes.Count - 1); }
private MathFuncNode UnderPowerExpr(MathFuncNode node) { return (node.Type == MathNodeType.Function && ((FuncNode)node).FunctionType == KnownFuncType.Exp) ? node.Childs[0] : node; }
private MathFuncNode PowerExpr(MathFuncNode node) { return (node.Type == MathNodeType.Function && ((FuncNode)node).FunctionType == KnownFuncType.Exp) ? node.Childs[1] : new ValueNode(1); }
private MathFuncNode MultValues(MathFuncNode funcNode) { var values = funcNode.Childs .Where(child => child.Type == MathNodeType.Value) .Select(valueChild => ((ValueNode)valueChild).Value); values = values.Concat(funcNode.Childs .Where(child => child.Type == MathNodeType.Function && ((FuncNode)child).FunctionType == KnownFuncType.Neg) .Select(valueChild => new Rational<long>(-1, 1))); Rational<long> result = 1; foreach (var value in values) result *= value; if (result == 0) return new ValueNode(0); var notValuesNodes = funcNode.Childs .Where(child => child.Type != MathNodeType.Value && !(child.Type == MathNodeType.Function && ((FuncNode)child).FunctionType == KnownFuncType.Neg)) .Concat(funcNode.Childs .Where(child => child.Type == MathNodeType.Function && ((FuncNode)child).FunctionType == KnownFuncType.Neg) .Select(negChild => negChild.Childs[0])).ToList(); if (result == 1) { return notValuesNodes.Count == 0 ? new ValueNode(1) : notValuesNodes.Count == 1 ? notValuesNodes.First() : new FuncNode(KnownFuncType.Mult, notValuesNodes); } else if (result == -1) { return notValuesNodes.Count == 0 ? (MathFuncNode)(new ValueNode(-1)) : notValuesNodes.Count == 1 ? new FuncNode(KnownFuncType.Neg, notValuesNodes.First()) : new FuncNode(KnownFuncType.Neg, new FuncNode(KnownFuncType.Mult, notValuesNodes)); } else { if (notValuesNodes.Count == 0) return new ValueNode(result); else { if (result < 0) { notValuesNodes.Add(new ValueNode(-result)); return new FuncNode(KnownFuncType.Neg, new FuncNode(KnownFuncType.Mult, notValuesNodes)); } else { notValuesNodes.Add(new ValueNode(result)); return new FuncNode(KnownFuncType.Mult, notValuesNodes); } } } }
private MathFuncNode MakeSubstitution(MathFuncNode node) { int ind = -1; for (int j = 0; j < LeftNode.Childs.Count; j++) if (LeftNode.Childs[j].Name == node.Name) { ind = j; break; } if (ind != -1) { if (_currentFunc.Childs[ind].IsTerminal) return _currentFunc.Childs[ind]; else return new FuncNode((FuncNode)_currentFunc.Childs[ind]); } MathFuncNode result; switch (node.Type) { case MathNodeType.Calculated: result = new CalculatedNode(((CalculatedNode)node).Value); break; case MathNodeType.Value: result = new ValueNode((ValueNode)node); break; case MathNodeType.Constant: case MathNodeType.Variable: result = node; break; default: case MathNodeType.Function: result = ((FuncNode)node).FunctionType != null ? new FuncNode((KnownFuncType)((FuncNode)node).FunctionType) : new FuncNode(node.Name); break; } for (int i = 0; i < node.Childs.Count; i++) switch (node.Childs[i].Type) { case MathNodeType.Calculated: result.Childs.Add(new CalculatedNode((CalculatedNode)node.Childs[i])); break; case MathNodeType.Value: result.Childs.Add(new ValueNode((ValueNode)node.Childs[i])); break; case MathNodeType.Constant: case MathNodeType.Variable: result.Childs.Add(node.Childs[i]); break; case MathNodeType.Function: result.Childs.Add(MakeSubstitution((FuncNode)node.Childs[i])); break; } return result; }
private MathFuncNode MakeSubstitution(MathFuncNode left, MathFuncNode right, FuncNode currentFunc) { LeftNode = left; RightNode = right; _currentFunc = currentFunc; return MakeSubstitution(right); }
private MathFuncNode ReduceAddition(MathFuncNode node1, MathFuncNode node2) { var node1neg = node1.Type == MathNodeType.Function && (node1 as FuncNode).FunctionType == KnownFuncType.Neg; var node2neg = node2.Type == MathNodeType.Function && (node2 as FuncNode).FunctionType == KnownFuncType.Neg; var node11 = node1neg ? node1.Childs[0] : node1; var node21 = node2neg ? node2.Childs[0] : node2; MathFuncNode valueNode1 = null; if (node11.Type == MathNodeType.Function && (node11 as FuncNode).FunctionType == KnownFuncType.Mult) valueNode1 = node11.Childs.Where(child => child.IsValueOrCalculated).FirstOrDefault(); if (valueNode1 == null) valueNode1 = node11.IsValueOrCalculated ? node11 : new ValueNode(new Rational<long>(1, 1)); var value1 = ((ValueNode)valueNode1).Value; if (node1neg) value1 *= -1; MathFuncNode valueNode2 = null; if (node21.Type == MathNodeType.Function && (node21 as FuncNode).FunctionType == KnownFuncType.Mult) valueNode2 = node21.Childs.Where(child => child.IsValueOrCalculated).FirstOrDefault(); if (valueNode2 == null) valueNode2 = node21.IsValueOrCalculated ? node21 : new ValueNode(new Rational<long>(1, 1)); var value2 = ((ValueNode)valueNode2).Value; if (node2neg) value2 *= -1; var notValueNodes1 = node11.Type == MathNodeType.Function && (node11 as FuncNode).FunctionType == KnownFuncType.Mult ? node11.Childs.Where(child => !child.IsValueOrCalculated).ToList() : node11.IsValueOrCalculated ? new List<MathFuncNode>() { } : new List<MathFuncNode>() { node11 }; var notValueNodes2 = node21.Type == MathNodeType.Function && (node21 as FuncNode).FunctionType == KnownFuncType.Mult ? node21.Childs.Where(child => !child.IsValueOrCalculated).ToList() : node21.IsValueOrCalculated ? new List<MathFuncNode>() { } : new List<MathFuncNode>() { node21 }; var mult1 = new FuncNode(KnownFuncType.Mult, notValueNodes1.ToList()); var mult2 = new FuncNode(KnownFuncType.Mult, notValueNodes2.ToList()); mult1.Sort(); mult2.Sort(); if (mult1.Equals(mult2)) { var resultNodes = new List<MathFuncNode>(); resultNodes.Add(new ValueNode(value1 + value2)); resultNodes.AddRange(notValueNodes1); return Simplify(new FuncNode(KnownFuncType.Mult, resultNodes)); } else return null; }
private MathFuncNode Simplify(MathFuncNode node) { var funcNode = node as FuncNode; if (funcNode != null) { for (int i = 0; i < funcNode.Childs.Count; i++) funcNode.Childs[i] = Simplify(funcNode.Childs[i]); switch (funcNode.FunctionType) { case KnownFuncType.Neg: if (funcNode.Childs[0].Type == MathNodeType.Value) return new ValueNode(-((ValueNode)funcNode.Childs[0]).Value); else if (funcNode.Childs[0].Type == MathNodeType.Function && ((FuncNode)funcNode.Childs[0]).FunctionType == KnownFuncType.Neg) return funcNode.Childs[0].Childs[0]; break; case KnownFuncType.Add: BuildMultichildTree(funcNode); ReduceSummands(funcNode); return FoldValues(funcNode); case KnownFuncType.Mult: BuildMultichildTree(funcNode); var addResult = BreakOnAddNodes(funcNode); var multResult = MultValues(funcNode); bool isNeg = multResult.Type == MathNodeType.Function && ((FuncNode)multResult).FunctionType == KnownFuncType.Neg; var powerNode = ReducePowers(isNeg ? multResult.Childs[0] : multResult); powerNode.Childs = powerNode.Childs.Except(powerNode.Childs.Where(child => child.Type == MathNodeType.Value && ((ValueNode)child).Value == 1)).ToList(); return addResult != null && addResult.NodeCount <= (isNeg ? powerNode.NodeCount + 1 : powerNode.NodeCount) ? addResult : (isNeg ? (powerNode.Type == MathNodeType.Value ? (MathFuncNode)(new ValueNode(-((ValueNode)powerNode).Value)) : new FuncNode(KnownFuncType.Neg, powerNode)) : powerNode); case KnownFuncType.Exp: if (funcNode.Childs[0].Type == MathNodeType.Function) { if ((funcNode.Childs[0] as FuncNode).FunctionType == KnownFuncType.Exp) { funcNode.Childs[1] = Simplify( new FuncNode(KnownFuncType.Mult, funcNode.Childs[0].Childs[1], funcNode.Childs[1])); funcNode.Childs[0] = funcNode.Childs[0].Childs[0]; return ExpValue(funcNode); } else if ((funcNode.Childs[0] as FuncNode).FunctionType == KnownFuncType.Mult) { var expResult = ExpValue(funcNode); var multNode = PowerIntoMult(funcNode.Childs[0].Childs, funcNode.Childs[1]); return (multNode.NodeCount <= expResult.NodeCount) ? multNode : expResult; } } return ExpValue(funcNode); /*case KnownFuncType.Diff: return Simplify(GetDerivative(funcNode.Childs[0]));*/ default: if (funcNode.Childs.All(child => child.Type == MathNodeType.Value)) return (MathFuncNode)SimplifyValues(funcNode.FunctionType, funcNode.Childs.Select(child => (ValueNode)child).ToList()) ?? (MathFuncNode)funcNode; break; } return funcNode; } return node; }
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.Exp, 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; }
public FuncNode(KnownFuncType type, MathFuncNode arg) : this(type, new List<MathFuncNode>() { arg }) { }
private MathFuncNode PowerIntoMult(IEnumerable<MathFuncNode> multChilds, MathFuncNode expNode) { var newChilds = multChilds.Select(child => Simplify(new FuncNode(KnownFuncType.Exp, child, expNode))); return Simplify(new FuncNode(KnownFuncType.Mult, newChilds.ToList())); }
public FuncNode(KnownFuncType type, MathFuncNode arg1, MathFuncNode arg2, MathFuncNode arg3) : this(type, new List<MathFuncNode>() { arg1, arg2, arg3 }) { }
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 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; }