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); }