protected override PrettyString VisitProduct(Product M) { Expression N = Product.Numerator(M); Expression D = Product.Denominator(M); bool negative = false; if (N is Product && IsNegative(N)) { negative = !negative; N = -N; } if (D is Product && IsNegative(D)) { negative = !negative; D = -D; } if (!D.Equals(1)) { return(PrettyString.ConcatColumns(negative ? "- " : "", VisitDivide(N, D))); } else if (N is Product) { return(PrettyString.ConcatColumns(negative ? "-" : "", UnSplit(Product.TermsOf(N), "*"))); } else { return(PrettyString.ConcatColumns(negative ? "-" : "", Visit(N))); } }
/// <summary> /// Expand a multiplication expression. /// </summary> /// <param name="f"></param> /// <param name="x"></param> /// <returns></returns> private static Expression ExpandMultiply(Expression f, Expression x) { // If the denominator is multiplication, expand partial fractions. if (!ReferenceEquals(x, null)) { Expression d = Product.Denominator(f).Factor(x); if (d is Product) { return(ExpandPartialFractions(Product.Numerator(f), (Product)d, x)); } } // If f contains an add expression, distribute it. if (Product.TermsOf(f).Any(i => i is Sum)) { Expression e = 1; foreach (Expression i in Product.TermsOf(f)) { e = Distribute(i.Expand(x), e); } return(e); } return(f); }
protected override string VisitProduct(Product M) { int pr = Parser.Precedence(Operator.Multiply); Expression N = Product.Numerator(M); string minus = ""; if (IsNegative(N)) { minus = "-"; N = -N; } string n = String.Join(" ", Product.TermsOf(N).Select(i => Visit(i, pr))); string d = String.Join(" ", Product.TermsOf(Product.Denominator(M)).Select(i => Visit(i, pr))); if (d != "1") { return(minus + Frac(n, d)); } else { return(minus + n); } }
/// <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); }
private static bool IsNegative(Expression x) { Constant C = Product.TermsOf(x).First() as Constant; if (C != null) { return((Real)C < 0); } return(false); }
protected static bool IsNegative(Expression x) { Constant C = Product.TermsOf(x).FirstOrDefault(i => i is Constant) as Constant; if (C != null) { return((Real)C < 0); } return(false); }
/// <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 product) { return(Product.New(product.Terms.Select(i => i.Factor(x)))); } // If if is l^r, factor l and distribute r. if (f is Power power) { Expression l = power.Left.Factor(x); Expression r = power.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 p && (p.Variable.Equals(x) || (x is null))) { return(p.Factor()); } // Try interpreting f as a polynomial of x. if (!(x is 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 s) { // Make a list of each terms' products. List <List <Expression> > terms = s.Terms.Select(i => FactorsOf(i).ToList()).ToList(); // All of the distinct factors. IEnumerable <Expression> factors = terms.SelectMany(i => i.Except(1, -1)).Distinct(); // Choose the most common factor to factor. Expression factor = factors.ArgMax(i => terms.Count(j => j.Contains(i))); // Find the terms that contain the factor. List <List <Expression> > contains = terms.Where(i => i.Contains(factor)).ToList(); // If more than one term contains the factor, pull it out and factor the resulting expressions (again). if (contains.Count() > 1) { Expression factored = Sum.New(contains.Select(i => Product.New(i.Except(factor)))); Expression not_factored = Sum.New(terms.Except(contains).Select(i => Product.New(i))); return(Sum.New(Product.New(factor, factored), not_factored).Factor(null)); } } return(f); }
// Expand N(x)/D(x) using partial fractions. private static Expression ExpandPartialFractions(Expression N, Expression D, Expression x) { List <Expression> terms = new List <Expression>(); List <Variable> unknowns = new List <Variable>(); List <Expression> basis = new List <Expression>(); foreach (Expression i in Product.TermsOf(D)) { // Get the multiplicity of this basis term. Expression e = i; int n = Power.IntegralExponentOf(e); if (n != 1) { e = ((Power)i).Left; } // Convert to a polynomial. Polynomial Pi = Polynomial.New(e, x); // Add new terms for each multiplicity n. for (int j = 1; j <= n; ++j) { // Expression for the unknown numerator of this term. Expression unknown = 0; for (int k = 0; k < Pi.Degree; ++k) { Variable Ai = Variable.New("_A" + unknowns.Count.ToString()); unknown += Ai * (x ^ k); unknowns.Add(Ai); } terms.Add(Product.New(unknown, Power.New(e, -j))); } basis.Add(i); } // Equate the original expression with the decomposed expressions. D = Sum.New(terms.Select(j => (Expression)(D * j))).Expand(); Polynomial l = Polynomial.New(N, x); Polynomial r = Polynomial.New(D, x); // Equate terms of equal degree and solve for the unknowns. int degree = Math.Max(l.Degree, r.Degree); List <Equal> eqs = new List <Equal>(degree + 1); for (int i = 0; i <= degree; ++i) { eqs.Add(Equal.New(l[i], r[i])); } List <Arrow> A = eqs.Solve(unknowns); // Substitute the now knowns. return(Sum.New(terms.Select(i => i.Evaluate(A)))); }
private void AddTerm(IEnumerable <Expression> B, Expression t) { foreach (Expression b in B) { if (Product.TermsOf(t).Count(i => i.Equals(b)) == 1) { terms[b] += Product.New(Product.TermsOf(t).Except(b)); return; } } terms[1] += t; }
// Combine like terms and multiply constants. protected override Expression VisitProduct(Product M) { // Map terms to exponents. DefaultDictionary <Expression, Real> terms = new DefaultDictionary <Expression, Real>(0); // Accumulate constants and sum exponent of each term. Real C = 1; foreach (Expression i in M.Terms.SelectMany(i => Product.TermsOf(Visit(i)))) { if (i is Constant) { Real Ci = (Real)i; // Early exit if 0. if (Ci.EqualsZero()) { return(0); } C *= Ci; } else { Power Pi = i as Power; if (!ReferenceEquals(Pi, null) && Pi.Right is Constant) { terms[Pi.Left] += (Real)Pi.Right; } else { terms[i] += 1; } } } // Build a new expression with the accumulated terms. if (!C.EqualsOne()) { // Find a sum term that has a constant term to distribute into. KeyValuePair <Expression, Real> A = terms.FirstOrDefault(i => Real.Abs(i.Value).EqualsOne() && i.Key is Sum); if (!ReferenceEquals(A.Key, null)) { terms.Remove(A.Key); terms[ExpandExtension.Distribute(C ^ A.Value, A.Key)] += A.Value; } else { terms.Add(C, 1); } } return(Product.New(terms .Where(i => !i.Value.EqualsZero()) .Select(i => !i.Value.EqualsOne() ? Power.New(i.Key, Constant.New(i.Value)) : i.Key))); }
// V((A*x)^n) = A^(1/n)*V(x^n) protected override Expression VisitPower(Power P) { if (!IsConstant(P.Right)) { return(base.VisitPower(P)); } Expression L = P.Left.Factor(); IEnumerable <Expression> A = Product.TermsOf(L).Where(i => IsConstant(i)); if (A.Any()) { return(Product.New(Power.New(Product.New(A), 1 / P.Right), Visit(Product.New(Product.TermsOf(L).Where(i => !IsConstant(i)))))); } return(base.VisitPower(P)); }
// Enumerates x, splitting negative constants into a positive constant and -1. private static IEnumerable <Expression> FactorsOf(Expression x) { foreach (Expression i in Product.TermsOf(x)) { if (i is Constant && (Real)i < 0) { yield return(-1); yield return(Real.Abs((Real)i)); } else if (i is Power power) { yield return(i); yield return(power.Left); } else { yield return(i); } } }
public static Expression EvaluateSum(IEnumerable <Expression> Terms) { // Map terms to their coefficients. DefaultDictionary <Expression, Real> terms = new DefaultDictionary <Expression, Real>(0); // Accumulate constants and sum coefficient of each term. Real C = 0; foreach (Expression i in Terms) { if (i is Constant) { C += (Real)i; } else { // Find constant term. Constant coeff = Product.TermsOf(i).OfType <Constant>().FirstOrDefault(); if (!(coeff is null)) { terms[Product.New(Product.TermsOf(i).ExceptUnique(coeff, Expression.RefComparer))] += (Real)coeff; }
public static Expression EvaluateSum(IEnumerable <Expression> Terms) { // Map terms to their coefficients. DefaultDictionary <Expression, Real> terms = new DefaultDictionary <Expression, Real>(0); // Accumulate constants and sum coefficient of each term. Real C = 0; foreach (Expression i in Terms) { if (i is Constant) { C += (Real)i; } else { // Find constant term. Constant coeff = Product.TermsOf(i).OfType <Constant>().FirstOrDefault(); if (!ReferenceEquals(coeff, null)) { terms[Product.New(Product.TermsOf(i).ExceptUnique(coeff, Expression.RefComparer))] += (Real)coeff; } else { terms[i] += 1; } } } // Build a new expression with the accumulated terms. if (!C.EqualsZero()) { terms.Add(Constant.New(C), (Real)1); } return(Sum.New(terms .Where(i => !i.Value.EqualsZero()) .Select(i => !i.Value.EqualsOne() ? Product.New(i.Key, Constant.New(i.Value)) : i.Key))); }
public static Expression Denominator(Expression x) { return(Product.New(Product.TermsOf(x).Where(i => IsInDenominator(i)).Select(i => (Expression)(i ^ -1)))); }
public static Expression Numerator(Expression x) { return(Product.New(Product.TermsOf(x).Where(i => !IsInDenominator(i)))); }