Esempio n. 1
0
 public static SymbolicVariable Abs(this SymbolicVariable sv)
 {
     if (sv.IsNegative)
     {
         return(sv * SymbolicVariable.NegativeOne);
     }
     else
     {
         return(sv.Clone());
     }
 }
        /// <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);
        }
        /// <summary>
        /// Trys to simplify the expression with trigonemtric rules.
        /// </summary>
        /// <param name="sv"></param>
        /// <returns></returns>
        public static SymbolicVariable TrigSimplify(SymbolicVariable sv)
        {
            if (sv.ExtraTerms.Count > 0)
            {
                return(sv.Clone());                         //prevent simplification in case of extra terms
            }
            var factorized = FactorWithCommonFactor(sv);

            SymbolicVariable total = SymbolicVariable.Zero.Clone();

            // facorized expressions contain their terms in the multiplied symbols
            for (int i = 0; i < factorized.TermsCount; i++)
            {
                // go through each term
                var term = factorized[i];

                for (int fui = 0; fui < term.FusedSymbols.Count; fui++)
                {
                    var ss = term.GetFusedTerm(fui);
                    var sp = ss;
                    if (!ss.IsOneTerm)
                    {
                        if (ss.CanBeFactored())
                        {
                            sp = TrigSimplify(ss);
                        }
                        else
                        {
                            sp = PartialTrigSimplify(ss);
                        }
                        if (sp.IsOne)  // if equals 1  then remove it
                        {
                            // remove this fused symbol from the structure
                            term._FusedSymbols.Remove(term.GetFusedKey(fui));
                        }
                        else
                        {
                            // replace with the new value in the fused symbols.
                            term._FusedSymbols.Add(sp.ToString(), term._FusedSymbols[term.GetFusedKey(fui)]);

                            term._FusedSymbols.Remove(term.GetFusedKey(fui));
                        }
                    }
                }

                total = total + term;
            }

            // so begin in the factorized
            var tsimp = PartialTrigSimplify(total);

            return(tsimp);
        }
Esempio 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());
        }
Esempio n. 5
0
        public static SymbolicVariable Divide(SymbolicVariable a, SymbolicVariable b)
        {
            if (a == null || b == null)
            {
                return(null);
            }

            SymbolicVariable SourceTerm = a.Clone();

            // if the divided term is more than on term
            // x^2/(y-x)  ==>
            if (b.AddedTerms.Count > 0 || (b._ExtraTerms != null && b._ExtraTerms.Count > 0))
            {
                if (a.Equals(b))
                {
                    return(new SymbolicVariable("1"));
                }

                //multiply divided term by this value
                if (!a.IsZero)
                {
                    SourceTerm.DividedTerm = Multiply(SourceTerm.DividedTerm, b);

                    return(SourceTerm);
                }
                else
                {
                    return(new SymbolicVariable("0"));
                }
            }


            SymbolicVariable TargetSubTerm = b.Clone();


            TargetSubTerm._AddedTerms = null;   // remove added variables to prevent its repeated calculations in second passes
            TargetSubTerm._ExtraTerms = null;
            // or to make sure nothing bad happens {my idiot design :S)

            if (a.BaseEquals(TargetSubTerm))
            {
                #region symbols are equal (I mean 2*x^3 = 2*X^3)

                DivideCoeffecients(ref SourceTerm, TargetSubTerm);

                if (a.SymbolPowerTerm != null || TargetSubTerm.SymbolPowerTerm != null)
                {
                    SourceTerm._SymbolPowerTerm = a.SymbolPowerTerm - TargetSubTerm.SymbolPowerTerm;
                }
                else
                {
                    SourceTerm.SymbolPower = SourceTerm.SymbolPower - TargetSubTerm.SymbolPower;
                }



                //fuse the fused symbols in b into sv
                foreach (var bfv in TargetSubTerm.FusedSymbols)
                {
                    if (SourceTerm.FusedSymbols.ContainsKey(bfv.Key))
                    {
                        SourceTerm.FusedSymbols[bfv.Key] -= bfv.Value;
                    }
                    else
                    {
                        SourceTerm.FusedSymbols.Add(bfv.Key, bfv.Value * -1);
                    }
                }
                #endregion
            }
            else
            {
                #region Symbols are different
                if (string.IsNullOrEmpty(SourceTerm.Symbol))
                {
                    #region First Case: Source primary symbol doesn't exist
                    // the instance have an empty primary variable so we should add it

                    if (TargetSubTerm._BaseVariable != null)
                    {
                        SourceTerm._BaseVariable = TargetSubTerm._BaseVariable;
                    }
                    else
                    {
                        SourceTerm.Symbol = TargetSubTerm.Symbol;
                    }

                    SourceTerm.SymbolPower = -1 * TargetSubTerm.SymbolPower;
                    if (TargetSubTerm.SymbolPowerTerm != null)
                    {
                        SourceTerm._SymbolPowerTerm = -1 * TargetSubTerm.SymbolPowerTerm.Clone();
                    }

                    //fuse the fusedvariables in b into sv
                    foreach (var bfv in TargetSubTerm.FusedSymbols)
                    {
                        if (SourceTerm.FusedSymbols.ContainsKey(bfv.Key))
                        {
                            SourceTerm.FusedSymbols[bfv.Key] -= bfv.Value;
                        }
                        else
                        {
                            SourceTerm.FusedSymbols.Add(bfv.Key, bfv.Value * -1);
                        }
                    }
                    #endregion
                }
                else
                {
                    if (SourceTerm.Symbol.Equals(TargetSubTerm.Symbol, StringComparison.OrdinalIgnoreCase))
                    {
                        #region Second Case: Primary symbol in both source and target exist and equal
                        if (SourceTerm._SymbolPowerTerm != null || TargetSubTerm._SymbolPowerTerm != null)
                        {
                            // make sure the object of symbol power term have values if they don't
                            if (SourceTerm._SymbolPowerTerm == null)
                            {
                                // transfer the numerical power into symbolic variable mode
                                SourceTerm._SymbolPowerTerm = new SymbolicVariable(SourceTerm.SymbolPower.ToString(CultureInfo.InvariantCulture));

                                // also revert the original symbol power into 1  for validation after this
                                SourceTerm.SymbolPower = 1;
                            }

                            if (TargetSubTerm._SymbolPowerTerm == null)
                            {
                                TargetSubTerm._SymbolPowerTerm = new SymbolicVariable(TargetSubTerm.SymbolPower.ToString(CultureInfo.InvariantCulture));

                                TargetSubTerm.SymbolPower = -1; // the target will always be dominator
                            }

                            SourceTerm._SymbolPowerTerm -= TargetSubTerm._SymbolPowerTerm;

                            if (SourceTerm._SymbolPowerTerm.IsCoeffecientOnly)
                            {
                                SourceTerm._SymbolPower     = SourceTerm._SymbolPowerTerm.Coeffecient;
                                SourceTerm._SymbolPowerTerm = null;  // remove it because we don't need symbolic when we reach co
                            }
                            else
                            {
                                // correct the source symbol power (because after division the power may still be positive
                                if (SourceTerm._SymbolPowerTerm.IsNegative)
                                {
                                    SourceTerm._SymbolPower = -1;

                                    SourceTerm._SymbolPowerTerm *= NegativeOne;
                                }
                            }
                        }
                        else
                        {
                            SourceTerm.SymbolPower -= TargetSubTerm.SymbolPower;
                        }

                        // also subtract the fused variables
                        foreach (var fv in TargetSubTerm.FusedSymbols)
                        {
                            if (SourceTerm.FusedSymbols.ContainsKey(fv.Key))
                            {
                                SourceTerm.FusedSymbols[fv.Key] -= fv.Value;
                            }
                            else
                            {
                                SourceTerm.FusedSymbols.Add(fv.Key, fv.Value * -1);
                            }
                        }
                        #endregion
                    }
                    else if (SourceTerm.FusedSymbols.ContainsKey(TargetSubTerm.Symbol))
                    {
                        #region Third Case: Target primary symbol exist in source fused variables

                        if (TargetSubTerm.SymbolPowerTerm != null)
                        {
                            SourceTerm.FusedSymbols[TargetSubTerm.Symbol] -= TargetSubTerm.SymbolPowerTerm;
                        }
                        else
                        {
                            SourceTerm.FusedSymbols[TargetSubTerm.Symbol] -= TargetSubTerm.SymbolPower;
                        }

                        // however primary symbol in source still the same so we need to add it to the value in target (if applicable)

                        // also

                        // there are still some fused variables in source that weren't altered by the target fused symbols
                        // go through every symbol in fused symbols and add it to the source fused symbols
                        foreach (var tfs in TargetSubTerm.FusedSymbols)
                        {
                            if (SourceTerm.FusedSymbols.ContainsKey(tfs.Key))
                            {
                                // symbol exist so accumulate it
                                SourceTerm._FusedSymbols[tfs.Key] -= tfs.Value;
                            }
                            else
                            {
                                // two cases here
                                // 1 the fused key equal the primary symbol in source
                                if (SourceTerm.Symbol.Equals(tfs.Key, StringComparison.OrdinalIgnoreCase))
                                {
                                    if (tfs.Value.SymbolicVariable != null)
                                    {
                                        if (SourceTerm._SymbolPowerTerm != null)
                                        {
                                            SourceTerm._SymbolPowerTerm -= tfs.Value.SymbolicVariable;
                                        }
                                        else
                                        {
                                            // sum the value in the numerical part to the value in symbolic part
                                            SourceTerm._SymbolPowerTerm = new SymbolicVariable(SourceTerm._SymbolPower.ToString(CultureInfo.InvariantCulture)) - tfs.Value.SymbolicVariable;
                                            // reset the value in numerical part
                                            SourceTerm._SymbolPower = -1;
                                        }

                                        if (SourceTerm._SymbolPowerTerm.IsCoeffecientOnly)
                                        {
                                            SourceTerm._SymbolPower     = SourceTerm._SymbolPowerTerm.Coeffecient;
                                            SourceTerm._SymbolPowerTerm = null;
                                        }
                                    }
                                    else
                                    {
                                        SourceTerm._SymbolPower -= tfs.Value.NumericalVariable;
                                    }
                                }
                                else
                                {
                                    // 2 no matching at all which needs to add the symbol in target into the fused symbols in source.
                                    SourceTerm.FusedSymbols.Add(tfs.Key, tfs.Value * -1);
                                }
                            }
                        }
                        #endregion
                    }
                    else
                    {
                        #region Fourth Case: Target primary symbol doesn't exist in Source Primary Symbol nor Source Fused symbols

                        // Add Target primary symbol to the fused symbols in source
                        SourceTerm.FusedSymbols.Add(
                            TargetSubTerm.Symbol,
                            new HybridVariable
                        {
                            NumericalVariable = -1 * TargetSubTerm.SymbolPower,
                            SymbolicVariable  = TargetSubTerm.SymbolPowerTerm == null ? null : -1 * (SymbolicVariable)TargetSubTerm.SymbolPowerTerm
                        });

                        // But the primary symbol of source may exist in the target fused variables.

                        foreach (var fsv in TargetSubTerm.FusedSymbols)
                        {
                            if (SourceTerm.FusedSymbols.ContainsKey(fsv.Key))
                            {
                                SourceTerm.FusedSymbols[fsv.Key] -= fsv.Value;
                            }
                            else
                            {
                                // 1- if symbol is the same as priamry source
                                if (SourceTerm.Symbol.Equals(fsv.Key, StringComparison.OrdinalIgnoreCase))
                                {
                                    if (fsv.Value.SymbolicVariable != null)
                                    {
                                        if (SourceTerm._SymbolPowerTerm != null)
                                        {
                                            SourceTerm._SymbolPowerTerm -= fsv.Value.SymbolicVariable;
                                        }
                                        else
                                        {
                                            // sum the value in the numerical part to the value in symbolic part
                                            SourceTerm._SymbolPowerTerm =
                                                new SymbolicVariable(SourceTerm._SymbolPower.ToString(CultureInfo.InvariantCulture)) - fsv.Value.SymbolicVariable;
                                            // reset the value in numerical part
                                            SourceTerm._SymbolPower = -1;
                                        }
                                    }
                                    else
                                    {
                                        if (SourceTerm.SymbolPowerTerm != null)
                                        {
                                            SourceTerm._SymbolPowerTerm -= new SymbolicVariable(fsv.Value.ToString());
                                        }
                                        else
                                        {
                                            SourceTerm._SymbolPower -= fsv.Value.NumericalVariable;
                                        }
                                    }
                                }
                                else
                                {
                                    SourceTerm.FusedSymbols.Add(fsv.Key, fsv.Value * -1);
                                }
                            }
                        }
                        #endregion
                    }
                }

                DivideCoeffecients(ref SourceTerm, TargetSubTerm);
                #endregion
            }

            if (SourceTerm.AddedTerms.Count > 0)
            {
                Dictionary <string, SymbolicVariable> newAddedVariables = new Dictionary <string, SymbolicVariable>(StringComparer.OrdinalIgnoreCase);
                foreach (var vv in SourceTerm.AddedTerms)
                {
                    // get rid of divided term here because I already include it for the source term above
                    var TSubTerm = TargetSubTerm.Numerator;

                    var newv = Divide(vv.Value, TSubTerm);
                    newAddedVariables.Add(newv.WholeValueBaseKey, newv);
                }
                SourceTerm._AddedTerms = newAddedVariables;
            }

            // Extra Terms of a
            if (SourceTerm.ExtraTerms.Count > 0)
            {
                List <ExtraTerm> newExtraTerms = new List <ExtraTerm>();
                foreach (var et in SourceTerm.ExtraTerms)
                {
                    var eterm = et.Term;
                    if (et.Negative)
                    {
                        eterm = Multiply(NegativeOne, eterm);
                    }

                    var newe = Divide(eterm, TargetSubTerm);
                    newExtraTerms.Add(new ExtraTerm {
                        Term = newe
                    });
                }
                SourceTerm._ExtraTerms = newExtraTerms;
            }


            int subIndex           = 0;
            SymbolicVariable total = SourceTerm;

            while (subIndex < b.AddedTerms.Count)
            {
                // we should multiply other parts also
                // then add it to the current instance

                // there are still terms to be consumed
                //   this new term is a sub term in b and will be added to all terms of a.
                TargetSubTerm = b.AddedTerms.ElementAt(subIndex).Value.Clone();

                TargetSubTerm.DividedTerm = b.DividedTerm;   // this line is important because I extracted this added term from a bigger term with the same divided term
                                                             // and when I did this the extracted term lost its divided term

                total    = total + Divide(a, TargetSubTerm);
                subIndex = subIndex + 1;  //increase
            }

            // for extra terms  {terms that has different divided term}
            int extraIndex = 0;
            while (extraIndex < b.ExtraTerms.Count)
            {
                var eTerm = b.ExtraTerms[extraIndex];
                TargetSubTerm = eTerm.Term;
                if (eTerm.Negative)
                {
                    TargetSubTerm = Multiply(NegativeOne, TargetSubTerm);
                }

                var TargetTermSubTotal = Divide(a, TargetSubTerm);
                total = Add(total, TargetTermSubTotal);
                extraIndex++;
            }


            AdjustSpecialFunctions(ref total);

            AdjustZeroPowerTerms(total);
            AdjustZeroCoeffecientTerms(ref total);


            return(total);
        }
        /// <summary>
        /// Simplify Trigonometric Functions
        /// </summary>
        /// <param name="sv"></param>
        public static SymbolicVariable PartialTrigSimplify(SymbolicVariable sv)
        {
            // please refer to TrigSimplification.txt for the algorithm

            Dictionary <string, ParameterSquareTrig> PSTS = new Dictionary <string, ParameterSquareTrig>();

            Func <string, ParameterSquareTrig> PST = (nm) =>
            {
                ParameterSquareTrig p;
                if (!PSTS.TryGetValue(nm, out p))
                {
                    p = new ParameterSquareTrig {
                        Parameter = nm
                    };
                    PSTS.Add(nm, p);
                    return(p);
                }
                else
                {
                    return(p);
                }
            };

            Action <SymbolicVariable> Loop2 = (termPart) =>
            {
                // first test the term then test its fused variables
                var TermsToBeTested = termPart.GetMultipliedTerms();

                foreach (var term in TermsToBeTested)
                {
                    if (term.IsFunction && term._SymbolPower == 2 && term.RawFunctionParameters.Length == 1)
                    {
                        if (term.FunctionName.Equals("Sin", StringComparison.OrdinalIgnoreCase))
                        {
                            PST(term.RawFunctionParameters[0]).Sin_2_Count++;
                        }
                        else if (term.FunctionName.Equals("Cos", StringComparison.OrdinalIgnoreCase))
                        {
                            PST(term.RawFunctionParameters[0]).Cos_2_Count++;
                        }
                        else
                        {
                            // not Trigonometric function
                        }
                    }
                }
            };

            Loop2(sv);
            if (sv._AddedTerms != null)
            {
                foreach (var term in sv._AddedTerms.Values)
                {
                    Loop2(term);
                }
            }


            // coduct the third operation .. final calulcation
            SymbolicVariable SimplifiedResult = sv.Clone();


            foreach (var pst in PSTS.Values)
            {
                while (pst.Cos_2_Count > 0 && pst.Sin_2_Count > 0)
                {
                    var tttt = SymbolicVariable.Add(SimplifiedResult, pst.NegativeSimplifyValue);

                    SimplifiedResult = tttt;

                    pst.Cos_2_Count--;
                    pst.Sin_2_Count--;
                }
            }


            return(SimplifiedResult);
        }
        /// <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);
        }
        /// <summary>
        /// Subtracts symbolic variable b from symbolic variable a
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static SymbolicVariable Subtract(SymbolicVariable a, SymbolicVariable b)
        {
            if (a == null || b == null)
            {
                return(null);
            }

            if (!a.DividedTerm.Equals(b.DividedTerm))
            {
                SymbolicVariable a_b       = a.Clone();
                bool             econsumed = false;
                if (a_b.ExtraTerms.Count > 0)
                {
                    // find if in extra terms there is an equality  of b into it
                    for (int iet = 0; iet < a_b.ExtraTerms.Count; iet++)
                    {
                        if (a_b.ExtraTerms[iet].Term.DividedTerm.Equals(b.DividedTerm))
                        {
                            a_b.ExtraTerms[iet].Term = Subtract(a_b.ExtraTerms[iet].Term, b);
                            econsumed = true;
                            break;
                        }
                    }
                }

                if (!econsumed)
                {
                    // add in the extra terms
                    var negative_b = b.Clone();

                    a_b.ExtraTerms.Add(new ExtraTerm {
                        Term = negative_b, Negative = true
                    });
                }
                AdjustZeroCoeffecientTerms(ref a_b);
                return(a_b);
            }


            SymbolicVariable subB = b.Clone();
            int sub = -1;

            SymbolicVariable sv = a.Clone();

NewPart:


            bool consumed = false;

            if (a.BaseEquals(subB))
            {
                if (a.CoeffecientPowerTerm == null && subB.CoeffecientPowerTerm == null)
                {
                    sv.Coeffecient = a.Coeffecient - subB.Coeffecient;
                    consumed       = true;
                }
                else if (a.CoeffecientPowerTerm != null && subB.CoeffecientPowerTerm != null)
                {
                    if (a.CoeffecientPowerTerm.Equals(subB.CoeffecientPowerTerm))
                    {
                        var cr = a.Coeffecient - subB.Coeffecient;
                        if (cr == 0)
                        {
                            sv.Coeffecient = cr;
                            consumed       = true;
                        }
                    }
                }
                else
                {
                    // nothing
                }
            }

            //so the equality doesn't exits or this instance have other terms also

            // there are two cases now
            //  1- the symbolic can be added to one of the existing terms (which will be perfect)
            //  2- there are no compatible term so we have to add it to the addedvariables of this instance.


            foreach (var av in a.AddedTerms)
            {
                if (av.Value.BaseEquals(subB))
                {
                    var iv = a.AddedTerms[av.Key].Clone();

                    if (iv.CoeffecientPowerTerm == null && subB.CoeffecientPowerTerm == null)
                    {
                        iv.Coeffecient        = iv.Coeffecient - subB.Coeffecient;
                        sv.AddedTerms[av.Key] = iv;
                        consumed = true;
                    }
                    else if (iv.CoeffecientPowerTerm != null && subB.CoeffecientPowerTerm != null)
                    {
                        if (iv.CoeffecientPowerTerm.Equals(subB.CoeffecientPowerTerm))
                        {
                            var cr = iv.Coeffecient - subB.Coeffecient;
                            if (cr == 0)
                            {
                                iv.Coeffecient        = cr;
                                sv.AddedTerms[av.Key] = iv;
                                consumed = true;
                            }
                        }
                    }
                    else
                    {
                    }
                }
            }


            if (!consumed)
            {
                // add it to the positive variables.

                SymbolicVariable pv;

                sv.AddedTerms.TryGetValue(subB.WholeValueBaseKey, out pv);

                if (pv == null)
                {
                    pv              = subB.Clone();
                    pv.Coeffecient *= -1;

                    var SubTerms = pv._AddedTerms; // store them for later use.
                    pv._AddedTerms = null;

                    pv.DividedTerm = One;

                    sv.AddedTerms.Add(pv.WholeValueBaseKey, pv);

                    if (SubTerms != null)
                    {
                        //then add the value added terms if exist
                        foreach (var at in pv.AddedTerms)
                        {
                            at.Value.Coeffecient *= -1;
                            sv.AddedTerms.Add(at.Value.WholeValueBaseKey, at.Value);
                        }
                    }
                }
                else
                {
                    //exist before add it to this variable.

                    sv.AddedTerms[subB.WholeValueBaseKey] = Subtract(sv.AddedTerms[subB.WholeValueBaseKey], subB);
                }
            }

            if (b.AddedTerms.Count > 0)
            {
                sub = sub + 1;  //increase
                if (sub < b.AddedTerms.Count)
                {
                    // there are still terms to be consumed
                    //   this new term is a sub term in b and will be added to all terms of a.
                    subB = b.AddedTerms.ElementAt(sub).Value;
                    goto NewPart;
                }
            }

            // reaching here indicates that we didn't sum up the value to any of the target extra terms
            // so we need to include extra terms here
            if (b._ExtraTerms != null && b._ExtraTerms.Count > 0)
            {
                // add extra terms of b into sv
                foreach (var eb in b._ExtraTerms)
                {
                    var eeb = eb.Clone();

                    if (eeb.Negative)
                    {
                        eeb.Negative = false;                // -- == +
                    }
                    sv.ExtraTerms.Add(eeb);
                }
            }


            AdjustSpecialFunctions(ref sv);
            AdjustZeroPowerTerms(sv);
            AdjustZeroCoeffecientTerms(ref sv);


            return(sv);
        }
        /// <summary>
        /// Multiply two symbolic variables
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static SymbolicVariable Multiply(SymbolicVariable a, SymbolicVariable b)
        {
            if (a == null || b == null)
            {
                return(null);
            }

            if (a.IsZero)
            {
                return(new SymbolicVariable("0"));
            }
            if (b.IsZero)
            {
                return(new SymbolicVariable("0"));
            }

            if (a.IsOne)
            {
                return(b.Clone());
            }
            if (b.IsOne)
            {
                return(a.Clone());
            }

            SymbolicVariable TargetSubTerm = b.Clone();

            TargetSubTerm._AddedTerms = null;   // remove added variables to prevent its repeated calculations in second passes
            TargetSubTerm._ExtraTerms = null;   // remove the extra terms also
            // or to make sure nothing bad happens {my idiot design :S)

            SymbolicVariable SourceTerm = a.Clone();

            if (a.BaseEquals(TargetSubTerm))
            {
                #region Symbols are Equal (I mean 2*x^3 = 2*X^3)


                MultiplyCoeffecients(ref SourceTerm, TargetSubTerm);


                if (a.SymbolPowerTerm != null || TargetSubTerm.SymbolPowerTerm != null)
                {
                    SourceTerm._SymbolPowerTerm = a.SymbolPowerTerm + TargetSubTerm.SymbolPowerTerm;
                }
                else
                {
                    SourceTerm.SymbolPower = SourceTerm.SymbolPower + TargetSubTerm.SymbolPower;
                }

                //fuse the fused variables in b into sv
                foreach (var bfv in TargetSubTerm.FusedSymbols)
                {
                    if (SourceTerm.FusedSymbols.ContainsKey(bfv.Key))
                    {
                        SourceTerm.FusedSymbols[bfv.Key] += bfv.Value;
                    }
                    else
                    {
                        SourceTerm.FusedSymbols.Add(bfv.Key, bfv.Value);
                    }
                }

                #endregion
            }
            else
            {
                #region Symbols are Different

                if (string.IsNullOrEmpty(SourceTerm.Symbol))
                {
                    #region First Case: Source primary symbol doesn't exist

                    //  so take the primary symbol from the target into source
                    //  and copy the symbol power to it  and symbolic power
                    //

                    // the instance have an empty primary variable so we should add it
                    if (TargetSubTerm._BaseVariable != null)
                    {
                        SourceTerm._BaseVariable = TargetSubTerm._BaseVariable;
                    }
                    else
                    {
                        SourceTerm.Symbol = TargetSubTerm.Symbol;
                    }

                    SourceTerm.SymbolPower = TargetSubTerm.SymbolPower;
                    if (TargetSubTerm.SymbolPowerTerm != null)
                    {
                        SourceTerm._SymbolPowerTerm = TargetSubTerm.SymbolPowerTerm.Clone();
                    }
                    else
                    {
                        SourceTerm._SymbolPowerTerm = null;
                    }



                    //fuse the fused variables in target into source
                    foreach (var fv in TargetSubTerm.FusedSymbols)
                    {
                        if (SourceTerm.FusedSymbols.ContainsKey(fv.Key))
                        {
                            SourceTerm.FusedSymbols[fv.Key] += fv.Value;
                        }
                        else
                        {
                            SourceTerm.FusedSymbols.Add(fv.Key, fv.Value);
                        }
                    }
                    #endregion
                }
                else
                {
                    #region Testing against symbol of targetsubterm
                    if (SourceTerm.Symbol.Equals(TargetSubTerm.Symbol, StringComparison.OrdinalIgnoreCase))
                    {
                        #region Second Case: Primary symbol in both source and target exist and equal

                        // which means the difference is only in fused variables.

                        // test for complex power (power that contains other symbolic variable)
                        if (SourceTerm._SymbolPowerTerm != null || TargetSubTerm._SymbolPowerTerm != null)
                        {
                            // make sure the object of symbol power term have values if they don't
                            if (SourceTerm._SymbolPowerTerm == null)
                            {
                                // transfer the numerical power into symbolic variable mode
                                SourceTerm._SymbolPowerTerm = new SymbolicVariable(SourceTerm.SymbolPower.ToString(CultureInfo.InvariantCulture));
                                // also revert the original symbol power into 1  for validation after this
                                SourceTerm.SymbolPower = 1;
                            }
                            if (TargetSubTerm._SymbolPowerTerm == null)
                            {
                                TargetSubTerm._SymbolPowerTerm = new SymbolicVariable(TargetSubTerm.SymbolPower.ToString(CultureInfo.InvariantCulture));
                                TargetSubTerm.SymbolPower      = 1;
                            }

                            // we used symbol power term
                            SourceTerm._SymbolPowerTerm += TargetSubTerm._SymbolPowerTerm;
                        }
                        else
                        {
                            SourceTerm.SymbolPower += TargetSubTerm.SymbolPower;
                        }

                        // then add the fused variables
                        foreach (var fv in TargetSubTerm.FusedSymbols)
                        {
                            if (SourceTerm.FusedSymbols.ContainsKey(fv.Key))
                            {
                                SourceTerm.FusedSymbols[fv.Key] += fv.Value;
                            }
                            else
                            {
                                SourceTerm.FusedSymbols.Add(fv.Key, fv.Value);
                            }
                        }
                        #endregion
                    }
                    else if (SourceTerm.FusedSymbols.ContainsKey(TargetSubTerm.Symbol))
                    {
                        #region Third Case: Target primary symbol exist in source fused variables

                        // fill the source symbol in fused variables from the primary symbol in Target term.
                        if (TargetSubTerm.SymbolPowerTerm != null)
                        {
                            SourceTerm.FusedSymbols[TargetSubTerm.Symbol] +=
                                new HybridVariable
                            {
                                NumericalVariable = TargetSubTerm.SymbolPower,
                                SymbolicVariable  = TargetSubTerm.SymbolPowerTerm
                            }
                        }
                        ;
                        else
                        {
                            SourceTerm.FusedSymbols[TargetSubTerm.Symbol] += TargetSubTerm.SymbolPower;
                        }

                        // however primary symbol in source still the same so we need to add it to the value in target
                        //    (if exist in fused variables in target)

                        // also

                        // there are still some fused variables in source that weren't altered by the target fused symbols
                        // go through every symbol in fused symbols and add it to the source fused symbols
                        foreach (var tfs in TargetSubTerm.FusedSymbols)
                        {
                            if (SourceTerm.FusedSymbols.ContainsKey(tfs.Key))
                            {
                                // symbol exist so accumulate it
                                SourceTerm._FusedSymbols[tfs.Key] += tfs.Value;
                            }
                            else
                            {
                                // two cases here
                                // 1 the fused key equal the primary symbol in source
                                if (SourceTerm.Symbol.Equals(tfs.Key, StringComparison.OrdinalIgnoreCase))
                                {
                                    if (tfs.Value.SymbolicVariable != null)
                                    {
                                        if (SourceTerm._SymbolPowerTerm != null)
                                        {
                                            SourceTerm._SymbolPowerTerm += tfs.Value.SymbolicVariable;
                                        }
                                        else
                                        {
                                            // sum the value in the numerical part to the value in symbolic part
                                            SourceTerm._SymbolPowerTerm = new SymbolicVariable(SourceTerm._SymbolPower.ToString(CultureInfo.InvariantCulture)) + tfs.Value.SymbolicVariable;
                                            // reset the value in numerical part
                                            SourceTerm._SymbolPower = 1;
                                        }
                                    }
                                    else
                                    {
                                        SourceTerm._SymbolPower += tfs.Value.NumericalVariable;
                                    }
                                }
                                else
                                {
                                    // 2 no matching at all which needs to add the symbol from target into the fused symbols in source.
                                    SourceTerm.FusedSymbols.Add(tfs.Key, tfs.Value);
                                }
                            }
                        }
                        #endregion
                    }
                    else
                    {
                        #region Fourth Case: Target primary symbol doesn't exist in Source Primary Symbol nor Source Fused symbols
                        // Add Target primary symbol to the fused symbols in source
                        SourceTerm.FusedSymbols.Add(
                            TargetSubTerm.Symbol,
                            new HybridVariable
                        {
                            NumericalVariable = TargetSubTerm.SymbolPower,
                            SymbolicVariable  = TargetSubTerm.SymbolPowerTerm == null ? null : TargetSubTerm.SymbolPowerTerm.Clone()
                        });


                        // But the primary symbol of source may exist in the target fused variables.

                        foreach (var fsv in TargetSubTerm.FusedSymbols)
                        {
                            if (SourceTerm.FusedSymbols.ContainsKey(fsv.Key))
                            {
                                SourceTerm.FusedSymbols[fsv.Key] += fsv.Value;
                            }
                            else
                            {
                                // 1- if symbol is the same as priamry source
                                if (SourceTerm.Symbol.Equals(fsv.Key, StringComparison.OrdinalIgnoreCase))
                                {
                                    if (fsv.Value.SymbolicVariable != null)
                                    {
                                        if (SourceTerm._SymbolPowerTerm != null)
                                        {
                                            SourceTerm._SymbolPowerTerm += fsv.Value.SymbolicVariable;
                                        }
                                        else
                                        {
                                            // sum the value in the numerical part to the value in symbolic part
                                            SourceTerm._SymbolPowerTerm = new SymbolicVariable(SourceTerm._SymbolPower.ToString(CultureInfo.InvariantCulture)) + fsv.Value.SymbolicVariable;
                                            // reset the value in numerical part
                                            SourceTerm._SymbolPower = 1;
                                        }
                                    }
                                    else
                                    {
                                        if (SourceTerm.SymbolPowerTerm != null)
                                        {
                                            SourceTerm._SymbolPowerTerm += new SymbolicVariable(fsv.Value.ToString());
                                        }
                                        else
                                        {
                                            SourceTerm._SymbolPower += fsv.Value.NumericalVariable;
                                        }
                                    }
                                }
                                else
                                {
                                    SourceTerm.FusedSymbols.Add(fsv.Key, fsv.Value);
                                }
                            }
                        }
                        #endregion
                    }

                    #endregion
                }

                MultiplyCoeffecients(ref SourceTerm, TargetSubTerm);

                #endregion
            }

            if (SourceTerm.DividedTerm.IsOne)
            {
                SourceTerm.DividedTerm = TargetSubTerm.DividedTerm;
            }
            else
            {
                SourceTerm.DividedTerm = Multiply(SourceTerm.DividedTerm, TargetSubTerm.DividedTerm);
            }

            //here is a code to continue with other parts of a when multiplying them
            if (SourceTerm.AddedTerms.Count > 0)
            {
                Dictionary <string, SymbolicVariable> newAddedVariables = new Dictionary <string, SymbolicVariable>(StringComparer.OrdinalIgnoreCase);
                foreach (var vv in SourceTerm.AddedTerms)
                {
                    // get rid of divided term here because I already include it for the source term above
                    var TSubTerm = TargetSubTerm.Numerator;

                    var newv = Multiply(vv.Value, TSubTerm);

                    newAddedVariables.Add(newv.WholeValueBaseKey, newv);
                }
                SourceTerm._AddedTerms = newAddedVariables;
            }

            // Extra Terms of a
            if (SourceTerm.ExtraTerms.Count > 0)
            {
                List <ExtraTerm> newExtraTerms = new List <ExtraTerm>();
                foreach (var et in SourceTerm.ExtraTerms)
                {
                    var eterm = et.Term;
                    if (et.Negative)
                    {
                        eterm = Multiply(NegativeOne, eterm);
                    }

                    var newe = Multiply(eterm, TargetSubTerm);
                    newExtraTerms.Add(new ExtraTerm {
                        Term = newe
                    });
                }
                SourceTerm._ExtraTerms = newExtraTerms;
            }

            // now source term which is the first parameter cloned, have the new calculated value.
            int subIndex           = 0;
            SymbolicVariable total = SourceTerm;

            while (subIndex < b.AddedTerms.Count)
            {
                // we should multiply other parts also
                // then add it to the current instance

                // there are still terms to be consumed
                //   this new term is a sub term in b and will be added to all terms of a.
                TargetSubTerm = b.AddedTerms.ElementAt(subIndex).Value.Clone();


                TargetSubTerm.DividedTerm = b.DividedTerm;   // this line is important because I extracted this added term from a bigger term with the same divided term
                                                             // and when I did this the extracted term lost its divided term


                var TargetTermSubTotal = Multiply(a, TargetSubTerm);
                total = Add(total, TargetTermSubTotal);

                subIndex = subIndex + 1;  //increase
            }

            // for extra terms  {terms that has different divided term}
            int extraIndex = 0;
            while (extraIndex < b.ExtraTerms.Count)
            {
                var eTerm = b.ExtraTerms[extraIndex];
                TargetSubTerm = eTerm.Term;
                if (eTerm.Negative)
                {
                    TargetSubTerm = Multiply(NegativeOne, TargetSubTerm);
                }
                var TargetTermSubTotal = Multiply(a, TargetSubTerm);
                total = Add(total, TargetTermSubTotal);
                extraIndex++;
            }


            AdjustSpecialFunctions(ref total);
            AdjustZeroPowerTerms(total);

            AdjustZeroCoeffecientTerms(ref total);


            return(total);
        }
Esempio n. 10
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);
        }