예제 #1
0
        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);
            }
        }
예제 #3
0
        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);
            }
        }
예제 #4
0
 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);
 }
예제 #8
0
        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);
            }
        }
예제 #9
0
 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);
            }
예제 #13
0
        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]);
             }
         }
     }
 }
예제 #18
0
 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]);
         }
     }
 }
예제 #19
0
 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);
            }
        }
예제 #25
0
        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;
            }
        }
예제 #28
0
        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);
        }
예제 #30
0
        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;
            }
        }