예제 #1
0
        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)));
            }
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
        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);
            }
        }
예제 #4
0
        /// <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);
        }
예제 #5
0
        private static bool IsNegative(Expression x)
        {
            Constant C = Product.TermsOf(x).First() as Constant;

            if (C != null)
            {
                return((Real)C < 0);
            }
            return(false);
        }
예제 #6
0
        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);
        }
예제 #7
0
        /// <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);
        }
예제 #8
0
        // 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))));
        }
예제 #9
0
 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;
 }
예제 #10
0
        // 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)));
        }
예제 #11
0
        // 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));
        }
예제 #12
0
        // 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);
                }
            }
        }
예제 #13
0
        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;
                    }
예제 #14
0
        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)));
        }
예제 #15
0
 public static Expression Denominator(Expression x)
 {
     return(Product.New(Product.TermsOf(x).Where(i => IsInDenominator(i)).Select(i => (Expression)(i ^ -1))));
 }
예제 #16
0
 public static Expression Numerator(Expression x)
 {
     return(Product.New(Product.TermsOf(x).Where(i => !IsInDenominator(i))));
 }