/// <summary> /// Distribute products across sums. /// </summary> /// <param name="f"></param> /// <param name="x"></param> /// <returns></returns> public static Expression Factor(this Expression f, Expression x) { // If f is a product, just factor its terms. if (f is Product) { return(Product.New(((Product)f).Terms.Select(i => i.Factor(x)))); } // If if is l^r, factor l and distribute r. if (f is Power) { Expression l = ((Power)f).Left.Factor(x); Expression r = ((Power)f).Right; return(Product.New(Product.TermsOf(l).Select(i => Power.New(i, r)))); } // If f is a polynomial of x, use polynomial factoring methods. if (f is Polynomial && (((Polynomial)f).Variable.Equals(x) || ReferenceEquals(x, null))) { return(((Polynomial)f).Factor()); } // Try interpreting f as a polynomial of x. if (!ReferenceEquals(x, null)) { // If f is a polynomial of x, factor it. try { return(Polynomial.New(f, x).Factor()); } catch (Exception) { } } // Just factor out common sub-expressions. if (f is Sum) { Sum s = (Sum)f; IEnumerable <Expression> terms = s.Terms.Select(i => i.Factor()).Buffer(); // All of the distinct factors. IEnumerable <Expression> factors = terms.SelectMany(i => FactorsOf(i).Except(1, -1)).Distinct(); // Choose the most common factor to use. Expression factor = factors.ArgMax(i => terms.Count(j => FactorsOf(j).Contains(i))); // Find the terms that contain the factor. IEnumerable <Expression> contains = terms.Where(i => FactorsOf(i).Contains(factor)).Buffer(); // If more than one term contains the factor, pull it out and factor the resulting expression (again). if (contains.Count() > 1) { return(Sum.New( Product.New(factor, Sum.New(contains.Select(i => Binary.Divide(i, factor))).Evaluate()), Sum.New(terms.Except(contains, Expression.RefComparer))).Factor(null)); } } return(f); }
public static Expression operator /(Polynomial N, Polynomial D) { if (Equals(N.Variable, D.Variable)) { Polynomial R; Polynomial Q = Divide(N, D, out R); return(Sum.New(Q, Binary.Divide(R, D))); } else { return((Expression)N / (Expression)D); } }
public override bool Matches(Expression E, MatchContext Matched) { Expression matched; if (Matched.TryGetValue(Right, out matched)) { if (Left.Matches(E ^ Binary.Divide(1, matched), Matched)) { return(true); } } // x^0 = 1. if (E.EqualsOne() && Right.Matches(0, Matched)) { return(true); } // 0^x = 0. if (E.EqualsZero() && Left.Matches(0, Matched)) { return(true); } Binary PE = E as Power; if (!ReferenceEquals(PE, null) && Matched.TryMatch(() => Left.Matches(PE.Left, Matched) && Right.Matches(PE.Right, Matched))) { return(true); } // If the exponent matches 1, E can match left. if (Matched.TryMatch(() => Right.Matches(1, Matched) && Left.Matches(E, Matched))) { return(true); } if (Right.IsInteger() && Left.Matches(ComputerAlgebra.Power.New(E, Binary.Divide(1, Right)).Evaluate(), Matched)) { return(true); } return(false); }
protected override Expression VisitPower(Power P) { Expression f = P.Left; Expression g = P.Right; if (g.DependsOn(x)) { // f(x)^g(x) return(Product.New(P, Sum.New( Product.New(Visit(f), Binary.Divide(g, f)), Product.New(Visit(g), Call.Ln(f)))).Evaluate()); } else { // f(x)^g return(Product.New( g, Power.New(f, Binary.Subtract(g, 1)), Visit(f)).Evaluate()); } }
public override bool Matches(Expression E, MatchContext Matched) { // if E is zero, any term can match to zero to succeed. if (E.EqualsZero()) { return(Terms.Any(i => i.Matches(0, Matched))); } // Move the constants in this pattern to E. IEnumerable <Expression> PTerms = Terms; IEnumerable <Expression> Constants = PTerms.OfType <Constant>(); if (Constants.Any()) { E = Binary.Divide(E, New(Constants)).Evaluate(); PTerms = PTerms.Except(Constants, RefComparer); } IEnumerable <Expression> ETerms = TermsOf(E); // Try starting the match at each term of the pattern. foreach (Expression p in PTerms) { // Remaining terms of the pattern. Expression P = New(PTerms.ExceptUnique(p, RefComparer)); // If p is a variable, we have to handle the possibility that more than one term of E might match this term. if (p is Variable) { // Check if p has already been matched. If it has, treat it as a constant and match the rest of the terms. Expression matched; if (Matched.TryGetValue(p, out matched)) { // p has already been matched. Remove it out of E and match the remainder of the pattern. if (P.Matches(E / matched, Matched)) { return(true); } } else { // Try matching p to the various combinations of the terms of E. for (int i = 1; i <= ETerms.Count(); ++i) { foreach (IEnumerable <Expression> e in ETerms.Combinations(i)) { if (Matched.TryMatch(() => p.Matches(New(e), Matched) && P.Matches(New(ETerms.ExceptUnique(e, RefComparer)), Matched))) { return(true); } } } // Try matching p to identity. if (Matched.TryMatch(() => p.Matches(1, Matched) && P.Matches(E, Matched))) { return(true); } } } else { // If p is not a variable, try matching it to any of the terms of E. foreach (Expression e in ETerms) { if (Matched.TryMatch(() => p.Matches(e, Matched) && P.Matches(New(ETerms.ExceptUnique(e, RefComparer)), Matched))) { return(true); } } } } return(false); }