コード例 #1
0
        /// <summary>
        /// Parse expression of variables and make SymbolicVariable
        /// </summary>
        /// <param name="expr"></param>
        /// <returns></returns>
        public static SymbolicVariable Parse(string expression)
        {
            var r = from zr in expression.Split(new string[] { ":=" }, StringSplitOptions.RemoveEmptyEntries)
                    where string.IsNullOrWhiteSpace(zr) == false
                    select zr.Trim();

            string[] rr = r.ToArray();

            string expr = string.Empty;

            if (rr.Length == 0)
            {
                return(null);
            }
            if (rr.Length > 1)
            {
                //function
                expr = rr[1];
            }
            else
            {
                expr = rr[0];
            }

            char[] separators = { '^', '*', '/', '+', '-', '(', '|' };
            char[] seps       = { '^', '*', '/', '+', '-', '|' };


            expr = expr.Replace(" ", "");

            //if (expression.StartsWith("-") ||expression.StartsWith("+")) expression = expression.Insert(1,"1*");

            // simple parsing
            // obeys the rules of priorities

            // Priorities
            //    ^  Power
            //    *  multiplication
            //    /  division
            //    +  Addition
            //    -  Subtraction


            bool NextGroupIsNegativeSign = false;

            // Tokenization is done by separating with operators
            SymbolicExpressionOperator Root = new SymbolicExpressionOperator();
            SymbolicExpressionOperator ep   = Root;

            StringBuilder TokenBuilder    = new StringBuilder();
            Stack <int>   PLevels         = new Stack <int>();
            bool          Inner           = false;
            bool          FunctionContext = false;

            for (int ix = 0; ix < expr.Length; ix++)
            {
                if (PLevels.Count == 0)
                {
                    // include the normal parsing when we are not in parenthesis group
                    if (separators.Contains(expr[ix]))
                    {
                        if ((expr[ix] == '-' || expr[ix] == '+') && ix == 0)
                        {
                            if (expr[ix] == '-')
                            {
                                // in case of -x  for example ..this will converted into operations
                                //  of -1 * x
                                ep.SymbolicExpression = SymbolicVariable.NegativeOne;
                                ep.Operation          = "*";

                                ep.Next = new SymbolicExpressionOperator();
                                ep      = ep.Next;      // advance the reference to the next node to make the linked list.

                                TokenBuilder = new StringBuilder();
                            }
                            else
                            {
                                // append the normal token
                                TokenBuilder.Append(expr[ix]);
                            }
                        }
                        else if (ix > 1 &&
                                 char.ToUpper(expr[ix - 1]) == 'E' && char.IsDigit(expr[ix - 2]) &&
                                 (expr[ix] == '-' || expr[ix] == '+'))
                        {
                            // case of 3e+2 4e-2  all cases with e in it.
                            TokenBuilder.Append(expr[ix]);
                        }
                        else if (expr[ix] == '(')
                        {
                            PLevels.Push(1);
                            var bb = ix > 0 ? separators.Contains(expr[ix - 1]) : true;
                            if (!bb)
                            {
                                //the previous charachter is normal word which indicates we reached a function
                                FunctionContext = true;
                                TokenBuilder.Append(expr[ix]);
                            }
                        }
                        else if (
                            seps.Contains(expr[ix - 1]) &&
                            (expr[ix] == '-' || expr[ix] == '+')
                            )
                        {
                            if (expr[ix + 1] == '(')
                            {
                                // so this sign is glued to the next parentheisis group

                                TokenBuilder.Append(expr[ix]);

                                // now TokenBuilder contains all signs before this

                                // and we need to preserve the information about next group
                                //   that it has a sign.

                                string signs = TokenBuilder.ToString();

                                int nve = signs.ToCharArray().Count(sign => sign == '-');

                                if ((nve % 2.0) != 0)
                                {
                                    // negative sign
                                    NextGroupIsNegativeSign = true;
                                }
                                TokenBuilder.Clear();
                            }
                            else
                            {
                                TokenBuilder.Append(expr[ix]);
                            }
                        }
                        else
                        {
                            // tokenize   when we reach any operator  or open '(' parenthesis
                            if (Inner)
                            {
                                ep.SymbolicExpression = Parse(TokenBuilder.ToString());

                                if (NextGroupIsNegativeSign)
                                {
                                    ep.SymbolicExpression = SymbolicVariable.Multiply(SymbolicVariable.NegativeOne, ep.SymbolicExpression);

                                    NextGroupIsNegativeSign = false;
                                }
                                Inner = false;
                            }
                            else
                            {
                                ep.SymbolicExpression = new SymbolicVariable(TokenBuilder.ToString());
                            }

                            TokenBuilder = new StringBuilder();

                            ep.Operation = expr[ix].ToString();
                            ep.Next      = new SymbolicExpressionOperator();
                            ep           = ep.Next; // advance the reference to the next node to make the linked list.
                        }
                    }
                    else
                    {
                        TokenBuilder.Append(expr[ix]);
                    }
                }
                else
                {
                    // we are in group
                    if (expr[ix] == '(')
                    {
                        PLevels.Push(1);
                    }
                    if (expr[ix] == ')')
                    {
                        PLevels.Pop();

                        if (PLevels.Count == 0)
                        {
                            Inner = true;
                            if (FunctionContext)
                            {
                                TokenBuilder.Append(expr[ix]);
                                FunctionContext = false;
                                Inner           = false; // because i am taking the function body as a whole in this parse pass.
                                // then inner parameters of the function will be parsed again
                            }
                        }
                        else
                        {
                            TokenBuilder.Append(expr[ix]);
                        }
                    }
                    else
                    {
                        TokenBuilder.Append(expr[ix]);
                    }
                }
            }

            // Last pass that escaped from the loop.
            if (Inner)
            {
                ep.SymbolicExpression = Parse(TokenBuilder.ToString());
                if (NextGroupIsNegativeSign)
                {
                    ep.SymbolicExpression = SymbolicVariable.Multiply(SymbolicVariable.NegativeOne, ep.SymbolicExpression);

                    NextGroupIsNegativeSign = false;
                }

                Inner = false;
            }
            else
            {
                ep.SymbolicExpression = new SymbolicVariable(TokenBuilder.ToString());
            }
            TokenBuilder = null;


            string[] Group = { "^"    /* Power for normal product '*' */
            };

            string[] SymGroup = { "|" /* Derivation operator */ };

            string[] Group1 = { "*" /* normal multiplication */,
                                "/" /* normal division */,
                                "%" /* modulus */ };


            string[] Group2 = { "+", "-" };

            /// Operator Groups Ordered by Priorities.
            string[][] OperatorGroups = { Group, SymGroup, Group1, Group2 };

            foreach (var opg in OperatorGroups)
            {
                SymbolicExpressionOperator eop = Root;

                //Pass for '[op]' and merge it  but from top to child :)  {forward)
                while (eop.Next != null)
                {
                    //if the operator in node found in the opg (current operator group) then execute the logic

                    if (opg.Count(c => c.Equals(eop.Operation, StringComparison.OrdinalIgnoreCase)) > 0)
                    {
                        short skip;
                        eop.SymbolicExpression = ArithExpression(eop, out skip);

                        //drop eop.Next
                        if (eop.Next.Next != null)
                        {
                            while (skip > 0)
                            {
                                eop.Operation = eop.Next.Operation;

                                eop.Next = eop.Next.Next;

                                skip--;
                            }
                        }
                        else
                        {
                            //no more nodes exit the loop

                            eop.Next      = null; //last item were processed.
                            eop.Operation = string.Empty;
                        }
                    }
                    else
                    {
                        eop = eop.Next;
                    }
                }
            }

            if (rr.Length > 1)
            {
                // there was a function defintion
                var fname = rr[0];

                Functions[fname] = Root.SymbolicExpression;
            }

            return(Root.SymbolicExpression);
        }
コード例 #2
0
        private static SymbolicVariable ArithExpression(SymbolicExpressionOperator eop, out short skip)
        {
            SymbolicVariable left  = eop.SymbolicExpression;
            string           op    = eop.Operation;
            SymbolicVariable right = eop.Next.SymbolicExpression;

            skip = 1;

            if (op == "|")
            {
                int    p  = (int)right.SymbolPower;
                string rp = right.Symbol;

                SymbolicVariable v = left;
                while (p > 0)
                {
                    v = v.Differentiate(rp);
                    p--;
                }
                return(v);
            }

            if (op == "^")
            {
                // This will be right associative operator
                // which means if more than one power appeared like this 3^2^4  then it will be processed like this 3^(2^4)

                if (eop.Next.Next != null)
                {
                    if (eop.Next.Operation == "^")
                    {
                        short iskip;
                        var   powerResult = SymbolicVariable.SymbolicPower(
                            left
                            , ArithExpression(eop.Next, out iskip)
                            );

                        skip += iskip;
                        return(powerResult);
                    }
                    else
                    {
                        return(SymbolicVariable.SymbolicPower(left, right));
                    }
                }
                else
                {
                    return(SymbolicVariable.SymbolicPower(left, right));
                }
            }

            if (op == "*")
            {
                return(SymbolicVariable.Multiply(left, right));
            }
            if (op == "/")
            {
                return(SymbolicVariable.Divide(left, right));
            }
            if (op == "+")
            {
                return(SymbolicVariable.Add(left, right));
            }
            if (op == "-")
            {
                return(SymbolicVariable.Subtract(left, right));
            }


            throw new NotSupportedException("Not Supported Operator '" + op + "'");
        }