Esempio n. 1
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);
        }
        /*
         *
         * Expression like   a*sin(x)+a*cos(x)  can be written as follow a*(sin(x)+cos(x))
         * i want to know the common factor that can be multiplied in these terms
         *
         * so the common factor in my case is a variable key in fused terms or whatever
         *
         * the result should be factor and its existence in indices in the symblic variable added terms
         *
         * in case of previous example          [a..>0,1]
         *
         * and the result should be the common factor as symbolic variable
         * multiplied term
         * terms that cannot be factorized .. to be added later
         *
         */

        /// <summary>
        /// Returns a map of occurence of variable name in the terms of the symbolic variable expression
        /// </summary>
        /// <returns></returns>
        public Dictionary <SymbolicVariable, List <int> > GetCommonFactorsMap()
        {
            // a*sin(x)+a*cos(x) + c
            // loop through all terms
            //   begin with primary term
            //     see if it exists in added terms in primary or fusedsymbols
            // build a dictionary with the existence of this variable
            // repeat this for each fused variable
            // the dictionary will increase in its data
            //  once we are done       check the dictionary lenghs for each variable .. the one with more existence of 2 or more is what we need
            // begin an analysis for the existence indices
            //   a =>  2,5,9
            //   b =>  2,3,4
            // then a*b => 2   and etc.

            List <SymbolicVariable[]> bo2bo2 = new List <SymbolicVariable[]>();

            bo2bo2.Add(this.GetMultipliedTerms());

            if (_AddedTerms != null)
            {
                foreach (var aterm in _AddedTerms)
                {
                    bo2bo2.Add(aterm.Value.GetMultipliedTerms());
                }
            }

            // now i have the matrix of multiplied terms.

            /*
             * a*sin(x)+a*cos(x) + c
             *
             * 0           1          2
             * -------------------------
             * a           a          c
             * sin(x)     cos(x)
             *
             *
             * a in columns 0, 1
             *
             */

            // take each column components and compare to next columns components
            Dictionary <SymbolicVariable, List <int> > CommonFactorsMap = new Dictionary <SymbolicVariable, List <int> >();

            for (int column = 0; column < bo2bo2.Count; column++)
            {
                var components = bo2bo2[column];


                for (int ix = 0; ix < components.Length; ix++)
                {
                    // get the component.
                    SymbolicVariable src_component = components[ix];

                    // once we this component we should write its existence in the list
                    List <int> indices;
                    if (!CommonFactorsMap.TryGetValue(src_component, out indices))
                    {
                        // new creation of the list
                        indices = new List <int>();
                        indices.Add(column);
                        CommonFactorsMap.Add(src_component, indices);
                    }


                    for (int nxc = column + 1; nxc < bo2bo2.Count; nxc++)
                    {
                        var targetColumn = bo2bo2[nxc];

                        // compare it to the next column components

                        for (int nx_i = 0; nx_i < targetColumn.Length; nx_i++)
                        {
                            var trg_nx_compnent = targetColumn[nx_i];
                            if (src_component.Equals(trg_nx_compnent))
                            {
                                // bingo we found a match   .. write this information
                                if (!indices.Contains(nxc))
                                {
                                    indices.Add(nxc);
                                }
                            }
                        }
                    }
                }
            }


            return(CommonFactorsMap);
        }