/// <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>
        /// Factor the expression.
        /// </summary>
        /// <param name="sv"></param>
        /// <returns></returns>
        public static SymbolicVariable FactorWithCommonFactor(SymbolicVariable sv)
        {
            var map = sv.GetCommonFactorsMap();


            // get all keys  sorted by number of elements

            var keys = (from mk in map
                        orderby mk.Value.Count descending
                        where mk.Key.Equals(One) == false && mk.Value.Count > 1 && mk.Key.IsCoeffecientOnly == false
                        select mk.Key).ToArray();



            if (keys.Length == 0)
            {
                return(sv.Clone());
            }
            // ignore the 1 key

            // imagine a*x+a*y  result is a*(x+y)

            SymbolicVariable result = SymbolicVariable.One.Clone();

            var term_key = keys[0];  // the biggest values count   as shown above in the query statement

            var term_indices = map[term_key];

            List <SymbolicVariable> Common_Factors_Keys = new List <SymbolicVariable>();

            Common_Factors_Keys.Add(term_key);

            // find the other keys that has the same indices like this key
            for (int i = 1; i < keys.Length; i++)
            {
                var target_indices = map[keys[i]];
                if (target_indices.Count == term_indices.Count)
                {
                    // compare indices toghether
                    foreach (var idc in term_indices)
                    {
                        if (!target_indices.Contains(idc))
                        {
                            continue;
                        }
                    }

                    // reaching this line indicates that the two arrays contains the same indices

                    // so we save this key as another common factor for the expression
                    Common_Factors_Keys.Add(keys[i]);
                }

                if (target_indices.Count < term_indices.Count)
                {
                    break;                                            // the array is ordered from higher count to low count so there is no point in comparing more results .. break the loop
                }
            }

            //Common_Factors_Keys  now contains the factors that I will work on it.

            SymbolicVariable common_multipliers = SymbolicVariable.Zero.Clone();
            SymbolicVariable rest_multipliers   = SymbolicVariable.Zero.Clone();

            for (int i = 0; i < sv.TermsCount; i++)
            {
                if (term_indices.Contains(i))
                {
                    // remove the common factor and add the result into the common_multipliers
                    var term = sv[i].Clone();
                    foreach (SymbolicVariable ke in Common_Factors_Keys)
                    {
                        term = SymbolicVariable.Divide(term, ke);   // divide by factor to remove it from the term.

                        /*
                         * if (term.Symbol == ke.Symbol)
                         * {
                         *  term.SymbolPower = 0;
                         *  AdjustZeroPowerTerms(term);
                         * }
                         * else
                         * {
                         *  // remove from the fused symbols
                         *  term._FusedSymbols.Remove(ke.ToString());
                         * }
                         */
                    }

                    common_multipliers += term;
                }
                else
                {
                    // doesn't contain the variable we want to remove so we store the term into the rest of the expressions to be added at the end of this procedure
                    rest_multipliers += sv[i].Clone();
                }
            }

            // at last alter the symbolic variable instant so that it contains the new shape
            foreach (var ke in Common_Factors_Keys)
            {
                result = result * ke;
            }

            result.FusedSymbols.Add(common_multipliers.ToString(), new HybridVariable {
                NumericalVariable = 1.0
            });

            result = result + rest_multipliers;

            return(result);
        }
 public static SymbolicVariable operator /(SymbolicVariable a, SymbolicVariable b)
 {
     return(SymbolicVariable.Divide(a, b));
 }
        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.º 5
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.º 6
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);
        }