/// <summary>
        /// Converts the symbolic variable into a state of separate simle terms with different denominators
        /// </summary>
        /// <param name="sv"></param>
        /// <returns></returns>
        public static SymbolicVariable[] SeparateWithDifferentDenominators(SymbolicVariable sv)
        {
            List <SymbolicVariable> SeparatedVariabls = new List <SymbolicVariable>();

            for (int i = 0; i < sv.TermsCount; i++)
            {
                SymbolicVariable ordered;
                SymbolicVariable.ReOrderNegativeSymbols(sv[i], out ordered);

                SeparatedVariabls.Add(ordered);
            }

            foreach (var eTerm in sv.ExtraTerms)
            {
                for (int i = 0; i < eTerm.Term.TermsCount; i++)
                {
                    SymbolicVariable ordered;
                    SymbolicVariable.ReOrderNegativeSymbols(eTerm.Term[i], out ordered);

                    if (eTerm.Negative)
                    {
                        ordered = SymbolicVariable.Multiply(SymbolicVariable.NegativeOne, ordered);
                    }

                    SeparatedVariabls.Add(ordered);
                }
            }

            return(SeparatedVariabls.ToArray());
        }
        /// <summary>
        /// Raise to specified power.
        /// </summary>
        /// <param name="power"></param>
        /// <returns></returns>
        public SymbolicVariable Power(int power)
        {
            if (power == 0)
            {
                return(SymbolicVariable._One);
            }

            SymbolicVariable total = this.Clone();
            int pw = Math.Abs(power);

            while (pw > 1)
            {
                if (this.IsFunction && this.FunctionName.Equals("Sqrt", StringComparison.OrdinalIgnoreCase))
                {
                    //
                    var parameterpower = power * 0.5;

                    total = this.FunctionParameters[0].Power(parameterpower);

                    pw = 0; // to end the loop
                }
                else
                {
                    total = SymbolicVariable.Multiply(total, this);
                    pw--;
                }
            }

            if (power < 0)
            {
                total = SymbolicVariable.Divide(SymbolicVariable._One, total);
            }

            return(total);
        }
        /// <summary>
        /// Reorders the negative symbols and gets them into DividedTerm object.
        /// for example 4*x^-2*y^6*u^-4  will get u^4*x^2  and 5/a  will get a
        /// works only in single term doesn't include extra terms
        /// </summary>
        /// <param name="sVariable">source symbolic variable (processed in one term only)</param>
        /// <param name="reOrderedVariable"></param>
        /// <returns></returns>
        public static SymbolicVariable ReOrderNegativeSymbols(SymbolicVariable sVariable, out SymbolicVariable reOrderedVariable)
        {
            SymbolicVariable denominator = SymbolicVariable.One.Clone();

            reOrderedVariable = sVariable.Clone();

            if (sVariable.SymbolPower < 0)
            {
                // transfer symbols into the divided term
                denominator.SymbolPower = Math.Abs(sVariable.SymbolPower);
                denominator.Symbol      = sVariable.Symbol;

                if (sVariable._SymbolPowerTerm != null) //include the symbol power term also but invert its sign
                {
                    denominator._SymbolPowerTerm = SymbolicVariable.Multiply(SymbolicVariable.NegativeOne, sVariable._SymbolPowerTerm);
                }


                // fix the reordered variable by removing this symbol information because it will appear later
                //   in the divided term.

                reOrderedVariable.SymbolPower      = 0;
                reOrderedVariable._SymbolPowerTerm = null;
                reOrderedVariable.Symbol           = string.Empty;
            }

            foreach (var fs in sVariable.FusedSymbols)
            {
                if (fs.Value.IsNegative)
                {
                    var siv = new SymbolicVariable(fs.Key);
                    if (fs.Value.SymbolicVariable != null)
                    {
                        siv._SymbolPowerTerm =
                            SymbolicVariable.Multiply(SymbolicVariable.NegativeOne, fs.Value.SymbolicVariable);
                    }
                    else
                    {
                        siv.SymbolPower = Math.Abs(fs.Value.NumericalVariable);
                    }

                    denominator = SymbolicVariable.Multiply(denominator, siv);  // accumulate negative power symbols here

                    // remove this fused symbol from reOrdered variable
                    reOrderedVariable.FusedSymbols.Remove(fs.Key);
                }
            }


            reOrderedVariable.DividedTerm = SymbolicVariable.Multiply(reOrderedVariable.DividedTerm, denominator);

            return(denominator);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Converts the symbolic variable into a state of separate simple terms with different denominators
        /// </summary>
        /// <param name="sv"></param>
        /// <returns></returns>
        public static SymbolicVariable[] SeparateWithDifferentDenominators(SymbolicVariable sv)
        {
            List <SymbolicVariable> SeparatedVariabls = new List <SymbolicVariable>();


            var svclone = sv.Clone(true);
            var divisor = svclone._DividedTerm;

            svclone._DividedTerm = SymbolicVariable.One;
            for (int i = 0; i < svclone.TermsCount; i++)
            {
                SymbolicVariable ordered;
                SymbolicVariable.ReOrderNegativeSymbols(svclone[i], out ordered);
                ordered._DividedTerm = SymbolicVariable.Multiply(divisor, ordered._DividedTerm);
                SeparatedVariabls.Add(ordered);
            }

            var extraTerms = sv.ExtraTerms;

            foreach (var eTerm in extraTerms)
            {
                /*
                 * for (int i = 0; i < eTerm.Term.TermsCount; i++)
                 * {
                 *  SymbolicVariable ordered;
                 *  SymbolicVariable.ReOrderNegativeSymbols(eTerm.Term[i], out ordered);
                 *
                 *  if (eTerm.Negative)
                 *  {
                 *      ordered = SymbolicVariable.Multiply(SymbolicVariable.NegativeOne, ordered);
                 *  }
                 *
                 *  SeparatedVariabls.Add(ordered);
                 * }
                 */

                SeparatedVariabls.AddRange(SeparateWithDifferentDenominators(eTerm.Term));
            }

            return(SeparatedVariabls.ToArray());
        }
        /// <summary>
        /// Works on expressions of extra terms to get an expression unified in denominator
        /// </summary>
        /// <param name="sv"></param>
        /// <returns></returns>
        public static SymbolicVariable UnifyDenominators(SymbolicVariable sv)
        {
            var terms = SeparateWithDifferentDenominators(sv);

            SymbolicVariable OrderedVariable = SymbolicVariable.Zero;

            foreach (var exTerm in terms)
            {
                // multipy the OrderedVariable divided term in the target extra term

                var exNumerator   = SymbolicVariable.Multiply(OrderedVariable.DividedTerm, exTerm.Numerator);
                var exDenominator = SymbolicVariable.Multiply(OrderedVariable.DividedTerm, exTerm.Denominator);

                var OrdNumerator = SymbolicVariable.Multiply(exTerm.Denominator, OrderedVariable.Numerator);


                OrderedVariable = SymbolicVariable.Add(OrdNumerator, exNumerator);

                OrderedVariable._DividedTerm = exDenominator;
            }


            return(OrderedVariable);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Works on expressions of extra terms to get an expression unified in denominator
        /// </summary>
        /// <param name="sv"></param>
        /// <returns></returns>
        public static SymbolicVariable UnifyDenominators(SymbolicVariable sv)
        {
            var terms = SeparateWithDifferentDenominators(sv);

            SymbolicVariable OrderedVariable = SymbolicVariable.Zero;

            foreach (var exTerm in terms)
            {
                var proTerm = exTerm.Clone();
                if (exTerm._DividedTerm.ExtraTerms.Count > 0)
                {
                    // the denominator needs to be unified also

                    var unif = UnifyDenominators(exTerm._DividedTerm);

                    proTerm._DividedTerm = unif.Numerator;

                    proTerm = SymbolicVariable.Multiply(proTerm, unif.Denominator);
                }

                // multipy the OrderedVariable divided term in the target extra term

                var exNumerator   = SymbolicVariable.Multiply(OrderedVariable.DividedTerm, proTerm.Numerator);
                var exDenominator = SymbolicVariable.Multiply(OrderedVariable.DividedTerm, proTerm.Denominator);

                var OrdNumerator = SymbolicVariable.Multiply(proTerm.Denominator, OrderedVariable.Numerator);


                OrderedVariable = SymbolicVariable.Add(OrdNumerator, exNumerator);

                OrderedVariable._DividedTerm = exDenominator;
            }


            return(OrderedVariable);
        }
Exemplo n.º 7
0
        public static SymbolicVariable DiffBFunction(SymbolicVariable fv, string parameter)
        {
            var pa = fv.GetFunctionParameters()[0];

            var ps = SymbolicVariable.Multiply(pa, pa);

            var func = fv.FunctionName;

            var dpa = pa.Differentiate(parameter);


            if (string.Equals(func, "asin", StringComparison.OrdinalIgnoreCase))
            {
                //asin(x) → 1 / sqrt(1-x^2)

                return(SymbolicVariable.Parse(dpa.ToString() + "/sqrt(1-(" + ps.ToString() + "))"));
            }

            if (string.Equals(func, "acos", StringComparison.OrdinalIgnoreCase))
            {
                return(SymbolicVariable.Parse("-" + dpa.ToString() + "/sqrt(1-(" + ps.ToString() + "))"));
            }

            if (string.Equals(func, "atan", StringComparison.OrdinalIgnoreCase))
            {
                return(SymbolicVariable.Parse(dpa.ToString() + "/(" + ps.ToString() + "+1)"));
            }

            if (string.Equals(func, "acot", StringComparison.OrdinalIgnoreCase))
            {
                return(SymbolicVariable.Parse("-" + dpa.ToString() + "/(" + ps.ToString() + "+1)"));
            }

            if (string.Equals(func, "asec", StringComparison.OrdinalIgnoreCase))
            {
                return(SymbolicVariable.Parse(dpa.ToString() + "/(sqrt(1-1/(" + ps.ToString() + "))*" + ps.ToString() + ")"));
            }

            if (string.Equals(func, "acsc", StringComparison.OrdinalIgnoreCase))
            {
                return(SymbolicVariable.Parse("-" + dpa.ToString() + "/(sqrt(1-1/(" + ps.ToString() + "))*" + ps.ToString() + ")"));
            }



            #region hyperbolic functions
            if (string.Equals(func, "asinh", StringComparison.OrdinalIgnoreCase))
            {
                //asin(x) → 1 / sqrt(x^2+1)

                return(SymbolicVariable.Parse(dpa.ToString() + "/sqrt(" + ps.ToString() + "+1)"));
            }

            if (string.Equals(func, "acosh", StringComparison.OrdinalIgnoreCase))
            {
                return(SymbolicVariable.Parse("-" + dpa.ToString() + "/sqrt(" + ps.ToString() + "-1)"));
            }

            if (string.Equals(func, "atanh", StringComparison.OrdinalIgnoreCase))
            {
                return(SymbolicVariable.Parse(dpa.ToString() + "/(1-(" + ps.ToString() + "))"));
            }

            if (string.Equals(func, "acoth", StringComparison.OrdinalIgnoreCase))
            {
                return(SymbolicVariable.Parse("-" + dpa.ToString() + "/(" + ps.ToString() + "-1)"));
            }

            if (string.Equals(func, "asech", StringComparison.OrdinalIgnoreCase))
            {
                return(SymbolicVariable.Parse("-" + dpa.ToString() + "/(sqrt(1/" + ps.ToString() + "-1)*" + ps.ToString() + ")"));
            }

            if (string.Equals(func, "acsch", StringComparison.OrdinalIgnoreCase))
            {
                return(SymbolicVariable.Parse("-" + dpa.ToString() + "/(sqrt(1/" + ps.ToString() + "+1)*" + ps.ToString() + ")"));
            }

            #endregion
            throw new SymbolicException(fv.FunctionName + " differentiation not implemented yet");
        }
 public static SymbolicVariable operator *(SymbolicVariable a, SymbolicVariable b)
 {
     return(SymbolicVariable.Multiply(a, b));
 }
        /// <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);
        }
        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 + "'");
        }
Exemplo n.º 11
0
        private static SymbolicVariable DiffBigTerm(SymbolicVariable sv, string parameter)
        {
            // now result contains only one term
            // -----------------------------------

            // we need to differentiate multiplied terms   in this  ONE TERM
            // every term is differentiated and multiplied by other terms  if  x*y*z  then == dx*y*z+x*dy+z+x*y*dz

            int MultipliedTermsCount = sv.FusedSymbols.Count + sv.FusedConstants.Count + 1; // last one is the basic symbol and coeffecient in the instant

            SymbolicVariable SvDividedTerm = sv.DividedTerm;                                // here we isolate the divided term for later calculations

            sv.DividedTerm = One;

            // separate all terms into array by flatting them
            List <MultipliedTerm> MultipliedTerms = new List <MultipliedTerm>(MultipliedTermsCount);

            Action <SymbolicVariable> SpliBaseTerm = (rr) =>
            {
                var basicterm = rr.Clone();
                basicterm._FusedConstants = null;
                basicterm._FusedSymbols   = null;

                // split coeffecient and its associated symbol

                if (basicterm.CoeffecientPowerTerm != null)
                {
                    // coefficient
                    SymbolicVariable CoeffecientOnly = new SymbolicVariable("");
                    CoeffecientOnly._CoeffecientPowerTerm = basicterm.CoeffecientPowerTerm;
                    CoeffecientOnly.Coeffecient           = basicterm.Coeffecient;
                    MultipliedTerms.Add(new MultipliedTerm(CoeffecientOnly));

                    // multiplied symbol
                    if (!string.IsNullOrEmpty(basicterm.SymbolBaseKey))
                    {
                        MultipliedTerms.Add(new MultipliedTerm(SymbolicVariable.Parse(basicterm.WholeValueBaseKey)));
                    }
                }
                else
                {
                    MultipliedTerms.Add(new MultipliedTerm(basicterm));
                }
            };

            Action <SymbolicVariable> SpliFusedConstants = (rr) =>
            {
                var basicterm = rr.Clone();

                var FCConstants = basicterm._FusedConstants;

                // Key  is the coefficient
                //  value contains the power  which always will be symbolic power or null
                foreach (var FC in FCConstants)
                {
                    SymbolicVariable CoeffecientOnly = new SymbolicVariable("");
                    CoeffecientOnly._CoeffecientPowerTerm = FC.Value.SymbolicVariable.Clone();
                    CoeffecientOnly.Coeffecient           = FC.Key;

                    MultipliedTerms.Add(new MultipliedTerm(CoeffecientOnly));
                }
            };

            Action <SymbolicVariable> SplitFusedSymbols = (rr) =>
            {
                var basicterm = rr.Clone();

                var FSymbols = basicterm._FusedSymbols;

                // Key  is the coefficient
                //  value contains the power  which always will be symbolic power or null
                foreach (var FS in FSymbols)
                {
                    var ss = new SymbolicVariable(FS.Key);
                    ss.SymbolPower = FS.Value.NumericalVariable;
                    if (FS.Value.SymbolicVariable != null)
                    {
                        ss._SymbolPowerTerm = FS.Value.SymbolicVariable.Clone();
                    }

                    MultipliedTerms.Add(new MultipliedTerm(ss));
                }
            };

            SpliBaseTerm(sv);
            if (sv.FusedConstants.Count > 0)
            {
                SpliFusedConstants(sv);
            }
            if (sv.FusedSymbols.Count > 0)
            {
                SplitFusedSymbols(sv);
            }

            List <SymbolicVariable> CalculatedDiffs = new List <SymbolicVariable>(MultipliedTermsCount);

            // get all differentials of all terms                       // x*y*z ==>  dx  dy  dz
            for (int ix = 0; ix < MultipliedTerms.Count; ix++)
            {
                CalculatedDiffs.Add(DiffTerm(MultipliedTerms[ix].Term, parameter));
            }

            // what about divided term ??
            if (!SvDividedTerm.IsOne)
            {
                /*
                 * diff(f(x)*g(x)/h(x),x);
                 *      -(f(x)*g(x)*('diff(h(x),x,1)))/h(x)^2       <== notice the negative sign here and the squared denominator
                 *      +(f(x)*('diff(g(x),x,1)))/h(x)
                 *      +(g(x)*('diff(f(x),x,1)))/h(x)
                 */
                var dvr = Subtract(Zero, SvDividedTerm.Differentiate(parameter));  //differential of divided takes minus sign because it wil
                CalculatedDiffs.Add(dvr);

                // add the divided term but in negative  value because it is divided and in differentiation it will have -ve power
                MultipliedTerms.Add(new MultipliedTerm(SvDividedTerm, true));
            }

            // every result of calculated differentials should be multiplied by the other terms.
            for (int ix = 0; ix < CalculatedDiffs.Count; ix++)
            {
                var term = CalculatedDiffs[ix];

                if (term.IsZero)
                {
                    continue;
                }
                var mt   = One;
                int mltc = MultipliedTerms.Count;

                //if (!SvDividedTerm.IsOne) mltc++;

                for (int iy = 0; iy < mltc; iy++)
                {
                    if (iy == ix)
                    {
                        continue;
                    }

                    if (MultipliedTerms[iy].Divided)
                    {
                        mt = SymbolicVariable.Divide(mt, MultipliedTerms[iy].Term);
                    }
                    else
                    {
                        mt = SymbolicVariable.Multiply(mt, MultipliedTerms[iy].Term);
                    }
                }

                // term *mt
                CalculatedDiffs[ix] = SymbolicVariable.Multiply(mt, term);
            }

            //       dx*y*z     dy*x*z       dz*x*y
            var total = Zero;

            foreach (var cc in CalculatedDiffs)
            {
                if (cc.IsZero)
                {
                    continue;
                }

                total = SymbolicVariable.Add(total, cc);
            }

            if (!SvDividedTerm.IsOne)
            {
                total.DividedTerm = Multiply(SvDividedTerm, SvDividedTerm);
            }

            return(total);
        }
Exemplo n.º 12
0
        /// <summary>
        /// Derive one pure term.
        /// </summary>
        /// <param name="sv"></param>
        /// <param name="parameter"></param>
        private static SymbolicVariable DiffTerm(SymbolicVariable term, string parameter)
        {
            var sv = term.Clone();

            bool symbolpowercontainParameter = false;

            if (sv._SymbolPowerTerm != null)
            {
                if (sv._SymbolPowerTerm.InvolvedSymbols.Contains(parameter, StringComparer.OrdinalIgnoreCase))
                {
                    symbolpowercontainParameter = true;
                }
                else
                {
                    int prcount = sv._SymbolPowerTerm.FusedSymbols.Count(p => p.Key.Equals(parameter, StringComparison.OrdinalIgnoreCase));
                    symbolpowercontainParameter = prcount > 0;
                }
            }

            bool cc = false;

            if (sv.BaseVariable != null)
            {
                cc = sv.BaseVariable.InvolvedSymbols.Contains(parameter, StringComparer.OrdinalIgnoreCase);                       // case of base variable
            }
            else if (sv.IsFunction && symbolpowercontainParameter == true)
            {
                // search if a parameter contains the same parameter
                foreach (var pf in sv.FunctionParameters)
                {
                    if (pf.Symbol.Equals(parameter, StringComparison.OrdinalIgnoreCase))
                    {
                        cc = true;
                        break;
                    }
                }
            }
            else
            {
                cc = sv.Symbol.Equals(parameter, StringComparison.OrdinalIgnoreCase);
            }

            // x^3*y^2*z^5    , diff to x;
            if (cc)
            {
                if (sv._SymbolPowerTerm == null)
                {
                    sv.Coeffecient  *= sv._SymbolPower;
                    sv._SymbolPower -= 1;
                    if (sv._SymbolPower == 0)
                    {
                        sv._Symbol = "";
                    }
                }
                else
                {
                    if (symbolpowercontainParameter)
                    {
                        // here is the case when base and power are the same with the parameter we are differentiating with
                        //  i.e.  x^x|x
                        // Logarithmic Differentiation
                        var lnterm  = new SymbolicVariable("log(" + sv.ToString() + ")");
                        var dlnterm = lnterm.Differentiate(parameter);
                        sv = Multiply(sv, dlnterm);
                    }
                    else
                    {
                        // symbol power term exist
                        SymbolicVariable oldPower = sv._SymbolPowerTerm;
                        sv._SymbolPowerTerm = Subtract(sv._SymbolPowerTerm, One);
                        sv = Multiply(sv, oldPower);
                    }
                }
            }
            else if (symbolpowercontainParameter)
            {
                // this case is when the power term is the same
                var log = new SymbolicVariable(lnText + "(" + sv.Symbol + ")");
                var dp  = sv._SymbolPowerTerm.Differentiate(parameter);
                sv = SymbolicVariable.Multiply(log, SymbolicVariable.Multiply(dp, sv));
            }
            else
            {
                // try in the fused variables
                HybridVariable hv;
                if (sv.FusedSymbols.TryGetValue(parameter, out hv))
                {
                    if (hv.SymbolicVariable == null)
                    {
                        sv.Coeffecient       *= hv.NumericalVariable;
                        hv.NumericalVariable -= 1;
                        if (hv.NumericalVariable == 0)
                        {
                            sv._FusedSymbols.Remove(parameter);
                        }
                        else
                        {
                            sv._FusedSymbols[parameter] = hv;
                        }
                    }
                    else
                    {
                        // symbol power term exist
                        SymbolicVariable oldPower = hv.SymbolicVariable;

                        hv.SymbolicVariable         = Subtract(hv.SymbolicVariable, One);
                        sv._FusedSymbols[parameter] = hv;

                        sv = Multiply(sv, oldPower);
                    }
                }
                else
                {
                    if (sv.IsFunction)
                    {
                        var fv = sv.Clone();

                        // remove the power term in this copied function term
                        fv._SymbolPowerTerm = null;
                        fv.SymbolPower      = 1.0;
                        fv.Coeffecient      = 1.0;


                        if (fv.FunctionName.Equals(lnText, StringComparison.OrdinalIgnoreCase))
                        {
                            if (fv.FunctionParameters.Length != 1)
                            {
                                throw new SymbolicException("Log function must have one parameter for differentiation to be done.");
                            }

                            // d/dx ( ln( g(x) ) ) = g'(x)/g(x)

                            var pa  = fv.FunctionParameters[0];
                            var dpa = pa.Differentiate(parameter);
                            fv = SymbolicVariable.Divide(dpa, pa);
                        }
                        else if (fv.FunctionName.Equals("sqrt", StringComparison.OrdinalIgnoreCase))
                        {
                            // d/dx ( sqrt( g(x) ) ) = g'(x) / 2* sqrt(g(x))
                            if (fv.FunctionParameters.Length != 1)
                            {
                                throw new SymbolicException("Sqrt function must have one parameter for differentiation to be done.");
                            }

                            var pa  = fv.FunctionParameters[0];
                            var dpa = pa.Differentiate(parameter);
                            var den = Multiply(Two, fv);
                            fv = Divide(dpa, den);
                        }
                        else if (FunctionDiff.BFunctions.Contains(fv.FunctionName, StringComparer.OrdinalIgnoreCase))
                        {
                            fv = FunctionDiff.DiffBFunction(fv, parameter);
                        }
                        else
                        {
                            // triogonometric functions
                            bool     IsNegativeResult;
                            string[] newfuntions = FunctionDiff.DiffFFunction(fv, out IsNegativeResult);

                            if (newfuntions != null)
                            {
                                //if(IsNegative)
                                // get the parameters in the function and differentiate them
                                if (fv.FunctionParameters.Length == 0)
                                {
                                    throw new SymbolicException("Special function without any parameters is not suitable for differentiation");
                                }
                                else if (fv.FunctionParameters.Length == 1)
                                {
                                    var pa      = fv.FunctionParameters[0];
                                    var presult = pa.Differentiate(parameter);
                                    fv.SetFunctionName(newfuntions);

                                    if (IsNegativeResult)
                                    {
                                        fv = SymbolicVariable.Multiply(presult, SymbolicAlgebra.SymbolicVariable.NegativeOne * fv);
                                    }
                                    else
                                    {
                                        fv = SymbolicVariable.Multiply(presult, fv);
                                    }
                                }
                                else
                                {
                                    throw new SymbolicException("more than one parameter is not normal for this special function");
                                }
                            }
                            else
                            {
                                // the function is not a special function like sin, cos, and log.
                                // search for the function in the running context.


                                var extendedFunction = Functions.Keys.FirstOrDefault(c => c.StartsWith(fv.FunctionName, StringComparison.OrdinalIgnoreCase));
                                if (!string.IsNullOrEmpty(extendedFunction))
                                {
                                    string[] fps = extendedFunction.Substring(extendedFunction.IndexOf("(")).TrimStart('(').TrimEnd(')').Split(',');

                                    if (fps.Length != fv.RawFunctionParameters.Length)
                                    {
                                        throw new SymbolicException("Insufficient function parameters");
                                    }

                                    // replace parameters
                                    var dsf = Functions[extendedFunction].ToString();

                                    for (int ipxf = 0; ipxf < fps.Length; ipxf++)
                                    {
                                        dsf = dsf.Replace(fps[ipxf], fv.RawFunctionParameters[ipxf]);
                                    }

                                    fv = SymbolicVariable.Parse(dsf).Differentiate(parameter);
                                }
                                else
                                {
                                    throw new SymbolicException("This function is not a special function, and I haven't implemented storing user functions in the running context");
                                }
                            }
                        }

                        // second treat the function normally as if it is one big symbol
                        if (sv._SymbolPowerTerm == null)
                        {
                            sv.Coeffecient  *= sv._SymbolPower;
                            sv._SymbolPower -= 1;
                            if (sv._SymbolPower == 0)
                            {
                                sv._Symbol = "";
                            }
                        }
                        else
                        {
                            // symbol power term exist
                            SymbolicVariable oldPower = sv._SymbolPowerTerm;
                            sv._SymbolPowerTerm = Subtract(sv._SymbolPowerTerm, One);
                            sv = Multiply(sv, oldPower);
                        }


                        sv = SymbolicVariable.Multiply(fv, sv);
                    }
                    else if (sv.IsCoeffecientOnly && sv._CoeffecientPowerTerm != null)
                    {
                        // hint: the coeffecient only term has power of 1 or symbolic power should exist in case of raise to symbolic power

                        // get log(coeffeniect)
                        var log = new SymbolicVariable(lnText + "(" + sv.Coeffecient.ToString(CultureInfo.InvariantCulture) + ")");
                        var dp  = sv._CoeffecientPowerTerm.Differentiate(parameter);
                        sv = SymbolicVariable.Multiply(log, SymbolicVariable.Multiply(dp, sv));
                    }
                    else
                    {
                        // the whole term will be converted to zero.
                        // empty everything :)
                        sv._SymbolPowerTerm      = null;
                        sv._CoeffecientPowerTerm = null;
                        sv._SymbolPower          = 1;
                        sv.Coeffecient           = 0;
                        //sv._DividedTerm = null;
                        sv._BaseVariable = null;
                        sv._Symbol       = string.Empty;
                        if (sv._SymbolPowerTerm != null)
                        {
                            sv._FusedSymbols.Clear();
                            sv._FusedSymbols = null;
                        }
                    }
                }
            }

            return(sv);
        }