/// <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); }
/// <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); }
public static SymbolicVariable operator +(SymbolicVariable a, SymbolicVariable b) { return(SymbolicVariable.Add(a, b)); }
/// <summary> /// Multiply Coeffecients of second argument into first argument. /// </summary> /// <param name="SourceTerm"></param> /// <param name="TargetSubTerm"></param> private static void MultiplyCoeffecients(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.Add(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) { if (SourceTerm.IsNegativeOne) { SourceTerm.Coeffecient = -1 * cst.ConstantValue; SourceTerm._CoeffecientPowerTerm = cst.ConstantPower; } else { SourceTerm.FusedConstants.Add( cst.ConstantValue, new HybridVariable { NumericalVariable = 1, // power SymbolicVariable = cst.ConstantPower.Clone() }); } } 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 }); } } } } } } }
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 + "'"); }
private static SymbolicVariable DiffBigTerm(SymbolicVariable sv, string parameter) { // now result contains only one term // ----------------------------------- // we need to differentiate multiplied terms in this ONE TERM // every term is differentiated and multiplied by other terms if x*y*z then == dx*y*z+x*dy+z+x*y*dz int MultipliedTermsCount = sv.FusedSymbols.Count + sv.FusedConstants.Count + 1; // last one is the basic symbol and coeffecient in the instant SymbolicVariable SvDividedTerm = sv.DividedTerm; // here we isolate the divided term for later calculations sv.DividedTerm = One; // separate all terms into array by flatting them List <MultipliedTerm> MultipliedTerms = new List <MultipliedTerm>(MultipliedTermsCount); Action <SymbolicVariable> SpliBaseTerm = (rr) => { var basicterm = rr.Clone(); basicterm._FusedConstants = null; basicterm._FusedSymbols = null; // split coeffecient and its associated symbol if (basicterm.CoeffecientPowerTerm != null) { // coefficient SymbolicVariable CoeffecientOnly = new SymbolicVariable(""); CoeffecientOnly._CoeffecientPowerTerm = basicterm.CoeffecientPowerTerm; CoeffecientOnly.Coeffecient = basicterm.Coeffecient; MultipliedTerms.Add(new MultipliedTerm(CoeffecientOnly)); // multiplied symbol if (!string.IsNullOrEmpty(basicterm.SymbolBaseKey)) { MultipliedTerms.Add(new MultipliedTerm(SymbolicVariable.Parse(basicterm.WholeValueBaseKey))); } } else { MultipliedTerms.Add(new MultipliedTerm(basicterm)); } }; Action <SymbolicVariable> SpliFusedConstants = (rr) => { var basicterm = rr.Clone(); var FCConstants = basicterm._FusedConstants; // Key is the coefficient // value contains the power which always will be symbolic power or null foreach (var FC in FCConstants) { SymbolicVariable CoeffecientOnly = new SymbolicVariable(""); CoeffecientOnly._CoeffecientPowerTerm = FC.Value.SymbolicVariable.Clone(); CoeffecientOnly.Coeffecient = FC.Key; MultipliedTerms.Add(new MultipliedTerm(CoeffecientOnly)); } }; Action <SymbolicVariable> SplitFusedSymbols = (rr) => { var basicterm = rr.Clone(); var FSymbols = basicterm._FusedSymbols; // Key is the coefficient // value contains the power which always will be symbolic power or null foreach (var FS in FSymbols) { var ss = new SymbolicVariable(FS.Key); ss.SymbolPower = FS.Value.NumericalVariable; if (FS.Value.SymbolicVariable != null) { ss._SymbolPowerTerm = FS.Value.SymbolicVariable.Clone(); } MultipliedTerms.Add(new MultipliedTerm(ss)); } }; SpliBaseTerm(sv); if (sv.FusedConstants.Count > 0) { SpliFusedConstants(sv); } if (sv.FusedSymbols.Count > 0) { SplitFusedSymbols(sv); } List <SymbolicVariable> CalculatedDiffs = new List <SymbolicVariable>(MultipliedTermsCount); // get all differentials of all terms // x*y*z ==> dx dy dz for (int ix = 0; ix < MultipliedTerms.Count; ix++) { CalculatedDiffs.Add(DiffTerm(MultipliedTerms[ix].Term, parameter)); } // what about divided term ?? if (!SvDividedTerm.IsOne) { /* * diff(f(x)*g(x)/h(x),x); * -(f(x)*g(x)*('diff(h(x),x,1)))/h(x)^2 <== notice the negative sign here and the squared denominator * +(f(x)*('diff(g(x),x,1)))/h(x) * +(g(x)*('diff(f(x),x,1)))/h(x) */ var dvr = Subtract(Zero, SvDividedTerm.Differentiate(parameter)); //differential of divided takes minus sign because it wil CalculatedDiffs.Add(dvr); // add the divided term but in negative value because it is divided and in differentiation it will have -ve power MultipliedTerms.Add(new MultipliedTerm(SvDividedTerm, true)); } // every result of calculated differentials should be multiplied by the other terms. for (int ix = 0; ix < CalculatedDiffs.Count; ix++) { var term = CalculatedDiffs[ix]; if (term.IsZero) { continue; } var mt = One; int mltc = MultipliedTerms.Count; //if (!SvDividedTerm.IsOne) mltc++; for (int iy = 0; iy < mltc; iy++) { if (iy == ix) { continue; } if (MultipliedTerms[iy].Divided) { mt = SymbolicVariable.Divide(mt, MultipliedTerms[iy].Term); } else { mt = SymbolicVariable.Multiply(mt, MultipliedTerms[iy].Term); } } // term *mt CalculatedDiffs[ix] = SymbolicVariable.Multiply(mt, term); } // dx*y*z dy*x*z dz*x*y var total = Zero; foreach (var cc in CalculatedDiffs) { if (cc.IsZero) { continue; } total = SymbolicVariable.Add(total, cc); } if (!SvDividedTerm.IsOne) { total.DividedTerm = Multiply(SvDividedTerm, SvDividedTerm); } return(total); }