/// <summary> /// Converts the symbolic variable into a state of separate simle terms with different denominators /// </summary> /// <param name="sv"></param> /// <returns></returns> public static SymbolicVariable[] SeparateWithDifferentDenominators(SymbolicVariable sv) { List <SymbolicVariable> SeparatedVariabls = new List <SymbolicVariable>(); for (int i = 0; i < sv.TermsCount; i++) { SymbolicVariable ordered; SymbolicVariable.ReOrderNegativeSymbols(sv[i], out ordered); SeparatedVariabls.Add(ordered); } foreach (var eTerm in sv.ExtraTerms) { for (int i = 0; i < eTerm.Term.TermsCount; i++) { SymbolicVariable ordered; SymbolicVariable.ReOrderNegativeSymbols(eTerm.Term[i], out ordered); if (eTerm.Negative) { ordered = SymbolicVariable.Multiply(SymbolicVariable.NegativeOne, ordered); } SeparatedVariabls.Add(ordered); } } return(SeparatedVariabls.ToArray()); }
/// <summary> /// Raise to specified power. /// </summary> /// <param name="power"></param> /// <returns></returns> public SymbolicVariable Power(int power) { if (power == 0) { return(SymbolicVariable._One); } SymbolicVariable total = this.Clone(); int pw = Math.Abs(power); while (pw > 1) { if (this.IsFunction && this.FunctionName.Equals("Sqrt", StringComparison.OrdinalIgnoreCase)) { // var parameterpower = power * 0.5; total = this.FunctionParameters[0].Power(parameterpower); pw = 0; // to end the loop } else { total = SymbolicVariable.Multiply(total, this); pw--; } } if (power < 0) { total = SymbolicVariable.Divide(SymbolicVariable._One, total); } return(total); }
/// <summary> /// Substitute variable with another variable /// </summary> /// <param name="variable"></param> /// <param name="value"></param> /// <returns></returns> public SymbolicVariable Substitute(string variable, SymbolicVariable value) { var s = this.ToString(); var ss = s.Replace(variable, "(" + value.ToString() + ")"); return(Parse(ss)); }
/// <summary> /// Solve for the variable and gets the whole expression for that variable /// </summary> /// <param name="variable"></param> /// <returns></returns> public SymbolicVariable Solve(string variable) { // "5*t1+3/t2" ==> 5*t1 = -3/t2 ==> t1 = (-3/t2)*5 if (_ExtraTerms != null && _ExtraTerms.Count > 0) { throw new SymbolicException("can't solve expression with extra terms that hold terms with different denominator"); } // Algorithm: // search for the term with variable in it // don't accept more than one term // don't accept terms with power other than 1 // solve SymbolicVariable ExtractedTerm = null; SymbolicVariable RestTerm = this.Clone(); // extract the needed term if (this.Symbol.Equals(variable, StringComparison.OrdinalIgnoreCase)) { ExtractedTerm = this.Clone(); ExtractedTerm._AddedTerms = null; RestTerm.Coeffecient = 0; AdjustZeroCoeffecientTerms(ref RestTerm); // this will adjust the internal structure of symbolic variabl } else { foreach (var t in RestTerm.AddedTerms) { if (t.Value.Symbol.Equals(variable, StringComparison.OrdinalIgnoreCase)) { ExtractedTerm = t.Value.Clone(); t.Value.Coeffecient = 0; break; } } AdjustZeroCoeffecientTerms(ref RestTerm); } if (ExtractedTerm == null) { throw new SymbolicException("the variable (" + variable + ") of solving not found"); } if (ExtractedTerm.SymbolPower != 1) { throw new SymbolicException("Variables with higher powers is not solvable for now"); } RestTerm = RestTerm * SymbolicVariable.NegativeOne; // this will transfer the rest value from left to right // now we have extracted term as 3*x [Extracted Term] = 5*y [Rest Term] SymbolicVariable result = RestTerm / ExtractedTerm.Coeffecient; return(result); }
public static SymbolicVariable Abs(this SymbolicVariable sv) { if (sv.IsNegative) { return(sv * SymbolicVariable.NegativeOne); } else { return(sv.Clone()); } }
/// <summary> /// Multiply hybrid variable by symbolic variable, and returns the value into symbolic variable. /// because hybrid variable is either number of symbolic. /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns><see cref="SymbolicVariable"/></returns> internal static SymbolicVariable Multiply(HybridVariable a, SymbolicVariable b) { if (a.SymbolicVariable != null) { return(Multiply(a.SymbolicVariable, b)); } else { return(Multiply(new SymbolicVariable(a.NumericalVariable.ToString(CultureInfo.InvariantCulture)), b)); } }
/// <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); }
/// <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> /// 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()); }
public SymbolicVariable Power(double power) { if (Math.Floor(power) == power) { return(Power((int)power)); } SymbolicVariable p = this.Clone(); if (p.IsOneTerm) { // raise the coeffecient and symbol if (!string.IsNullOrEmpty(p.Symbol)) { p.SymbolPower = power; } p.Coeffecient = Math.Pow(p.Coeffecient, power); } else { if (power == 0.5) { // return sqrt function of the multi term return(new SymbolicVariable("Sqrt(" + p.ToString() + ")")); } else if (power > 0 && power < 1) { // I don't have solution for this now throw new SymbolicException("I don't have solution for this type of power " + p.ToString() + "^ (" + power.ToString() + ")"); } else { // multi term that we can't raise it to the double return(p.RaiseToSymbolicPower(new SymbolicVariable(power.ToString()))); } } return(p); }
/// <summary> /// Works on expressions of extra terms to get an expression unified in denominator /// </summary> /// <param name="sv"></param> /// <returns></returns> public static SymbolicVariable UnifyDenominators(SymbolicVariable sv) { var terms = SeparateWithDifferentDenominators(sv); SymbolicVariable OrderedVariable = SymbolicVariable.Zero; foreach (var exTerm in terms) { var proTerm = exTerm.Clone(); if (exTerm._DividedTerm.ExtraTerms.Count > 0) { // the denominator needs to be unified also var unif = UnifyDenominators(exTerm._DividedTerm); proTerm._DividedTerm = unif.Numerator; proTerm = SymbolicVariable.Multiply(proTerm, unif.Denominator); } // multipy the OrderedVariable divided term in the target extra term var exNumerator = SymbolicVariable.Multiply(OrderedVariable.DividedTerm, proTerm.Numerator); var exDenominator = SymbolicVariable.Multiply(OrderedVariable.DividedTerm, proTerm.Denominator); var OrdNumerator = SymbolicVariable.Multiply(proTerm.Denominator, OrderedVariable.Numerator); OrderedVariable = SymbolicVariable.Add(OrdNumerator, exNumerator); OrderedVariable._DividedTerm = exDenominator; } return(OrderedVariable); }
/// <summary> /// Works on expressions of extra terms to get an expression unified in denominator /// </summary> /// <param name="sv"></param> /// <returns></returns> public static SymbolicVariable UnifyDenominators(SymbolicVariable sv) { var terms = SeparateWithDifferentDenominators(sv); SymbolicVariable OrderedVariable = SymbolicVariable.Zero; foreach (var exTerm in terms) { // multipy the OrderedVariable divided term in the target extra term var exNumerator = SymbolicVariable.Multiply(OrderedVariable.DividedTerm, exTerm.Numerator); var exDenominator = SymbolicVariable.Multiply(OrderedVariable.DividedTerm, exTerm.Denominator); var OrdNumerator = SymbolicVariable.Multiply(exTerm.Denominator, OrderedVariable.Numerator); OrderedVariable = SymbolicVariable.Add(OrdNumerator, exNumerator); OrderedVariable._DividedTerm = exDenominator; } return(OrderedVariable); }
public static SymbolicVariable Simplify(SymbolicVariable sv) { return(UnifyDenominators(sv)); }
/// <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); }
private static SymbolicVariable ArithExpression(SymbolicExpressionOperator eop, out short skip) { SymbolicVariable left = eop.SymbolicExpression; string op = eop.Operation; SymbolicVariable right = eop.Next.SymbolicExpression; skip = 1; if (op == "|") { int p = (int)right.SymbolPower; string rp = right.Symbol; SymbolicVariable v = left; while (p > 0) { v = v.Differentiate(rp); p--; } return(v); } if (op == "^") { // This will be right associative operator // which means if more than one power appeared like this 3^2^4 then it will be processed like this 3^(2^4) if (eop.Next.Next != null) { if (eop.Next.Operation == "^") { short iskip; var powerResult = SymbolicVariable.SymbolicPower( left , ArithExpression(eop.Next, out iskip) ); skip += iskip; return(powerResult); } else { return(SymbolicVariable.SymbolicPower(left, right)); } } else { return(SymbolicVariable.SymbolicPower(left, right)); } } if (op == "*") { return(SymbolicVariable.Multiply(left, right)); } if (op == "/") { return(SymbolicVariable.Divide(left, right)); } if (op == "+") { return(SymbolicVariable.Add(left, right)); } if (op == "-") { return(SymbolicVariable.Subtract(left, right)); } throw new NotSupportedException("Not Supported Operator '" + op + "'"); }
public static SymbolicVariable operator -(SymbolicVariable a, SymbolicVariable b) { return(SymbolicVariable.Subtract(a, b)); }
/// <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> /// Parse expression of variables and make SymbolicVariable /// </summary> /// <param name="expr"></param> /// <returns></returns> public static SymbolicVariable Parse(string expression) { var r = from zr in expression.Split(new string[] { ":=" }, StringSplitOptions.RemoveEmptyEntries) where string.IsNullOrWhiteSpace(zr) == false select zr.Trim(); string[] rr = r.ToArray(); string expr = string.Empty; if (rr.Length == 0) { return(null); } if (rr.Length > 1) { //function expr = rr[1]; } else { expr = rr[0]; } char[] separators = { '^', '*', '/', '+', '-', '(', '|' }; char[] seps = { '^', '*', '/', '+', '-', '|' }; expr = expr.Replace(" ", ""); //if (expression.StartsWith("-") ||expression.StartsWith("+")) expression = expression.Insert(1,"1*"); // simple parsing // obeys the rules of priorities // Priorities // ^ Power // * multiplication // / division // + Addition // - Subtraction bool NextGroupIsNegativeSign = false; // Tokenization is done by separating with operators SymbolicExpressionOperator Root = new SymbolicExpressionOperator(); SymbolicExpressionOperator ep = Root; StringBuilder TokenBuilder = new StringBuilder(); Stack <int> PLevels = new Stack <int>(); bool Inner = false; bool FunctionContext = false; for (int ix = 0; ix < expr.Length; ix++) { if (PLevels.Count == 0) { // include the normal parsing when we are not in parenthesis group if (separators.Contains(expr[ix])) { if ((expr[ix] == '-' || expr[ix] == '+') && ix == 0) { if (expr[ix] == '-') { // in case of -x for example ..this will converted into operations // of -1 * x ep.SymbolicExpression = SymbolicVariable.NegativeOne; ep.Operation = "*"; ep.Next = new SymbolicExpressionOperator(); ep = ep.Next; // advance the reference to the next node to make the linked list. TokenBuilder = new StringBuilder(); } else { // append the normal token TokenBuilder.Append(expr[ix]); } } else if (ix > 1 && char.ToUpper(expr[ix - 1]) == 'E' && char.IsDigit(expr[ix - 2]) && (expr[ix] == '-' || expr[ix] == '+')) { // case of 3e+2 4e-2 all cases with e in it. TokenBuilder.Append(expr[ix]); } else if (expr[ix] == '(') { PLevels.Push(1); var bb = ix > 0 ? separators.Contains(expr[ix - 1]) : true; if (!bb) { //the previous charachter is normal word which indicates we reached a function FunctionContext = true; TokenBuilder.Append(expr[ix]); } } else if ( seps.Contains(expr[ix - 1]) && (expr[ix] == '-' || expr[ix] == '+') ) { if (expr[ix + 1] == '(') { // so this sign is glued to the next parentheisis group TokenBuilder.Append(expr[ix]); // now TokenBuilder contains all signs before this // and we need to preserve the information about next group // that it has a sign. string signs = TokenBuilder.ToString(); int nve = signs.ToCharArray().Count(sign => sign == '-'); if ((nve % 2.0) != 0) { // negative sign NextGroupIsNegativeSign = true; } TokenBuilder.Clear(); } else { TokenBuilder.Append(expr[ix]); } } else { // tokenize when we reach any operator or open '(' parenthesis if (Inner) { ep.SymbolicExpression = Parse(TokenBuilder.ToString()); if (NextGroupIsNegativeSign) { ep.SymbolicExpression = SymbolicVariable.Multiply(SymbolicVariable.NegativeOne, ep.SymbolicExpression); NextGroupIsNegativeSign = false; } Inner = false; } else { ep.SymbolicExpression = new SymbolicVariable(TokenBuilder.ToString()); } TokenBuilder = new StringBuilder(); ep.Operation = expr[ix].ToString(); ep.Next = new SymbolicExpressionOperator(); ep = ep.Next; // advance the reference to the next node to make the linked list. } } else { TokenBuilder.Append(expr[ix]); } } else { // we are in group if (expr[ix] == '(') { PLevels.Push(1); } if (expr[ix] == ')') { PLevels.Pop(); if (PLevels.Count == 0) { Inner = true; if (FunctionContext) { TokenBuilder.Append(expr[ix]); FunctionContext = false; Inner = false; // because i am taking the function body as a whole in this parse pass. // then inner parameters of the function will be parsed again } } else { TokenBuilder.Append(expr[ix]); } } else { TokenBuilder.Append(expr[ix]); } } } // Last pass that escaped from the loop. if (Inner) { ep.SymbolicExpression = Parse(TokenBuilder.ToString()); if (NextGroupIsNegativeSign) { ep.SymbolicExpression = SymbolicVariable.Multiply(SymbolicVariable.NegativeOne, ep.SymbolicExpression); NextGroupIsNegativeSign = false; } Inner = false; } else { ep.SymbolicExpression = new SymbolicVariable(TokenBuilder.ToString()); } TokenBuilder = null; string[] Group = { "^" /* Power for normal product '*' */ }; string[] SymGroup = { "|" /* Derivation operator */ }; string[] Group1 = { "*" /* normal multiplication */, "/" /* normal division */, "%" /* modulus */ }; string[] Group2 = { "+", "-" }; /// Operator Groups Ordered by Priorities. string[][] OperatorGroups = { Group, SymGroup, Group1, Group2 }; foreach (var opg in OperatorGroups) { SymbolicExpressionOperator eop = Root; //Pass for '[op]' and merge it but from top to child :) {forward) while (eop.Next != null) { //if the operator in node found in the opg (current operator group) then execute the logic if (opg.Count(c => c.Equals(eop.Operation, StringComparison.OrdinalIgnoreCase)) > 0) { short skip; eop.SymbolicExpression = ArithExpression(eop, out skip); //drop eop.Next if (eop.Next.Next != null) { while (skip > 0) { eop.Operation = eop.Next.Operation; eop.Next = eop.Next.Next; skip--; } } else { //no more nodes exit the loop eop.Next = null; //last item were processed. eop.Operation = string.Empty; } } else { eop = eop.Next; } } } if (rr.Length > 1) { // there was a function defintion var fname = rr[0]; Functions[fname] = Root.SymbolicExpression; } return(Root.SymbolicExpression); }
public static SymbolicVariable operator /(int a, SymbolicVariable b) { var sv = new SymbolicVariable(a.ToString(CultureInfo.InvariantCulture)) / b; return(sv); }
public static SymbolicVariable operator +(SymbolicVariable a, SymbolicVariable b) { return(SymbolicVariable.Add(a, b)); }
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); }
public static SymbolicVariable operator /(SymbolicVariable a, SymbolicVariable b) { return(SymbolicVariable.Divide(a, b)); }
public static SymbolicVariable operator *(SymbolicVariable a, SymbolicVariable b) { return(SymbolicVariable.Multiply(a, b)); }
public static SymbolicVariable DiffBFunction(SymbolicVariable fv, string parameter) { var pa = fv.GetFunctionParameters()[0]; var ps = SymbolicVariable.Multiply(pa, pa); var func = fv.FunctionName; var dpa = pa.Differentiate(parameter); if (string.Equals(func, "asin", StringComparison.OrdinalIgnoreCase)) { //asin(x) → 1 / sqrt(1-x^2) return(SymbolicVariable.Parse(dpa.ToString() + "/sqrt(1-(" + ps.ToString() + "))")); } if (string.Equals(func, "acos", StringComparison.OrdinalIgnoreCase)) { return(SymbolicVariable.Parse("-" + dpa.ToString() + "/sqrt(1-(" + ps.ToString() + "))")); } if (string.Equals(func, "atan", StringComparison.OrdinalIgnoreCase)) { return(SymbolicVariable.Parse(dpa.ToString() + "/(" + ps.ToString() + "+1)")); } if (string.Equals(func, "acot", StringComparison.OrdinalIgnoreCase)) { return(SymbolicVariable.Parse("-" + dpa.ToString() + "/(" + ps.ToString() + "+1)")); } if (string.Equals(func, "asec", StringComparison.OrdinalIgnoreCase)) { return(SymbolicVariable.Parse(dpa.ToString() + "/(sqrt(1-1/(" + ps.ToString() + "))*" + ps.ToString() + ")")); } if (string.Equals(func, "acsc", StringComparison.OrdinalIgnoreCase)) { return(SymbolicVariable.Parse("-" + dpa.ToString() + "/(sqrt(1-1/(" + ps.ToString() + "))*" + ps.ToString() + ")")); } #region hyperbolic functions if (string.Equals(func, "asinh", StringComparison.OrdinalIgnoreCase)) { //asin(x) → 1 / sqrt(x^2+1) return(SymbolicVariable.Parse(dpa.ToString() + "/sqrt(" + ps.ToString() + "+1)")); } if (string.Equals(func, "acosh", StringComparison.OrdinalIgnoreCase)) { return(SymbolicVariable.Parse("-" + dpa.ToString() + "/sqrt(" + ps.ToString() + "-1)")); } if (string.Equals(func, "atanh", StringComparison.OrdinalIgnoreCase)) { return(SymbolicVariable.Parse(dpa.ToString() + "/(1-(" + ps.ToString() + "))")); } if (string.Equals(func, "acoth", StringComparison.OrdinalIgnoreCase)) { return(SymbolicVariable.Parse("-" + dpa.ToString() + "/(" + ps.ToString() + "-1)")); } if (string.Equals(func, "asech", StringComparison.OrdinalIgnoreCase)) { return(SymbolicVariable.Parse("-" + dpa.ToString() + "/(sqrt(1/" + ps.ToString() + "-1)*" + ps.ToString() + ")")); } if (string.Equals(func, "acsch", StringComparison.OrdinalIgnoreCase)) { return(SymbolicVariable.Parse("-" + dpa.ToString() + "/(sqrt(1/" + ps.ToString() + "+1)*" + ps.ToString() + ")")); } #endregion throw new SymbolicException(fv.FunctionName + " differentiation not implemented yet"); }
/* * * 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); }
/// <summary> /// get the function derivation like sin => cos /// </summary> /// <param name="function"></param> /// <param name="negative">indicates if the function returned should have negative value or not</param> /// <returns>string of the differentiated function</returns> public static string[] DiffFFunction(SymbolicVariable function, out bool negative) { string func = function.FunctionName; if (string.Equals(func, "exp", StringComparison.OrdinalIgnoreCase)) { negative = false; return(new string[] { "exp" }); } if (string.Equals(func, "sin", StringComparison.OrdinalIgnoreCase)) { negative = false; return(new string[] { "cos" }); } if (string.Equals(func, "sinh", StringComparison.OrdinalIgnoreCase)) { negative = false; return(new string[] { "cosh" }); } if (string.Equals(func, "cos", StringComparison.OrdinalIgnoreCase)) { negative = true; return(new string[] { "sin" }); } if (string.Equals(func, "cosh", StringComparison.OrdinalIgnoreCase)) { negative = false; return(new string[] { "sinh" }); } if (string.Equals(func, "tan", StringComparison.OrdinalIgnoreCase)) { negative = false; return(new string[] { "sec", "sec" }); } if (string.Equals(func, "tanh", StringComparison.OrdinalIgnoreCase)) { negative = false; return(new string[] { "sech", "sech" }); } if (string.Equals(func, "sec", StringComparison.OrdinalIgnoreCase)) { negative = false; return(new string[] { "sec", "tan" }); } if (string.Equals(func, "sech", StringComparison.OrdinalIgnoreCase)) { negative = true; return(new string[] { "sech", "tanh" }); } if (string.Equals(func, "csc", StringComparison.OrdinalIgnoreCase)) { negative = true; return(new string[] { "csc", "cot" }); } if (string.Equals(func, "csch", StringComparison.OrdinalIgnoreCase)) { negative = true; return(new string[] { "csch", "coth" }); } if (string.Equals(func, "cot", StringComparison.OrdinalIgnoreCase)) { negative = true; return(new string[] { "csc", "csc" }); } if (string.Equals(func, "coth", StringComparison.OrdinalIgnoreCase)) { negative = true; return(new string[] { "csch", "csch" }); } negative = false; return(null); }
/// <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); }
/// <summary> /// Multiply Coeffecients of second argument into first argument. /// </summary> /// <param name="SourceTerm"></param> /// <param name="TargetSubTerm"></param> private static void DivideCoeffecients(ref SymbolicVariable SourceTerm, SymbolicVariable TargetSubTerm) { // Note: I will try to avoid the primary coeffecient so it doesn't hold power // and only hold coeffecient itself. foreach (var cst in TargetSubTerm.Constants) { if (SourceTerm._CoeffecientPowerTerm == null && cst.ConstantPower == null) { SourceTerm.Coeffecient /= cst.ConstantValue; } // there is a coeffecient power term needs to be injected into the source else { // no the coeffecient part is not empty so we will test if bases are equal // then make use of the fusedsymbols to add our constant double sbase = Math.Log(SourceTerm.Coeffecient, cst.ConstantValue); if (SourceTerm.Coeffecient == cst.ConstantValue) { // sample: 2^x/2^y = 2^(x-y) var cpower = cst.ConstantPower; if (cpower == null) { cpower = One; } if (SourceTerm._CoeffecientPowerTerm == null) { SourceTerm._CoeffecientPowerTerm = One; } SourceTerm._CoeffecientPowerTerm -= cpower; } else if ((sbase - Math.Floor(sbase)) == 0.0 && sbase > 0) // make sure there are no { // then we can use the target base // 27/3^x = 3^3/3^x = 3^(3-x) var cpower = cst.ConstantPower; if (cpower == null) { cpower = new SymbolicVariable("1"); } SourceTerm._CoeffecientPowerTerm = SymbolicVariable.Subtract(new SymbolicVariable(sbase.ToString(CultureInfo.InvariantCulture)), cpower); SourceTerm.Coeffecient = cst.ConstantValue; } else { // sample: 2^(x+y)*log(2)*3^y * 3^z can't be summed. HybridVariable SameCoeffecient; if (SourceTerm.FusedConstants.TryGetValue(cst.ConstantValue, out SameCoeffecient)) { SameCoeffecient.SymbolicVariable -= cst.ConstantPower; SourceTerm.FusedConstants[cst.ConstantValue] = SameCoeffecient; } else { // Add Target coefficient symbol to the fused symbols in source, with key as the coefficient number itself. if (cst.ConstantPower != null) { SourceTerm.FusedConstants.Add( cst.ConstantValue, new HybridVariable { NumericalVariable = -1, // power SymbolicVariable = Subtract(Zero, cst.ConstantPower) }); } else { // coeffecient we working with is number only // First Attempt: to try to get the power of this number with base of available coeffecients // if no base produced an integer power value then we add it into fused constants as it is. if (cst.ConstantValue == 1.0) { continue; // ONE doesn't change anything so we bypass it } double?SucceededConstant = null; double ower = 0; foreach (var p in SourceTerm.Constants) { ower = Math.Log(cst.ConstantValue, p.ConstantValue); if (ower == Math.Floor(ower)) { SucceededConstant = p.ConstantValue; break; } } if (SucceededConstant.HasValue) { if (SourceTerm.Coeffecient == SucceededConstant.Value) { SourceTerm._CoeffecientPowerTerm -= new SymbolicVariable(ower.ToString(CultureInfo.InvariantCulture)); } else { var rr = SourceTerm.FusedConstants[SucceededConstant.Value]; rr.SymbolicVariable -= new SymbolicVariable(ower.ToString(CultureInfo.InvariantCulture)); SourceTerm.FusedConstants[SucceededConstant.Value] = rr; } } else { SourceTerm.FusedConstants.Add( cst.ConstantValue, new HybridVariable { NumericalVariable = -1, // power }); } } } } } } }
public static SymbolicVariable Pow(SymbolicVariable a, double power) { return(a.RaiseToSymbolicPower(new SymbolicVariable(power.ToString()))); }