Esempio n. 1
0
        internal static bool TrySolve(Entity expr, Variable x, out Set dst)
        {
            dst = Set.Empty;
            var children = TreeAnalyzer.GatherLinearChildrenOverSumAndExpand(
                expr, entity => entity.ContainsNode(x)
                );

            if (children is null)
            {
                return(false);
            }

            Entity normalPolynom = 0;
            var    fractioned    = new List <(Entity multiplier, List <(Entity main, Integer pow)> fracs)>();

            // Use PowerRules to replace sqrt(f(x))^2 => f(x)
            foreach (var child in children.Select(c => c.InnerSimplified.Replace(Patterns.PowerRules)))
            {
                (Entity multiplier, List <(Entity main, Integer pow)> fracs)potentialFraction;
                potentialFraction.multiplier = 1;
                potentialFraction.fracs      = new List <(Entity main, Integer pow)>();
                foreach (var mpChild in Mulf.LinearChildren(child))
                {
                    if (!(mpChild is Powf(var @base, Number num and not Integer))) // (x + 3) ^ 3
                    {
                        potentialFraction.multiplier *= mpChild;
                        continue;
                    }
                    if (num is not Rational fracNum)
                    {
                        return(false); // (x + 1)^0.2348728
                    }
                    var newChild = MathS.Pow(@base, fracNum.ERational.Numerator).InnerSimplified;
                    var den      = fracNum.ERational.Denominator;
                    potentialFraction.fracs.Add((newChild, den));

                    MultithreadingFunctional.ExitIfCancelled();
                }

                if (potentialFraction.fracs.Count > 0)
                {
                    fractioned.Add(potentialFraction);
                }
                else
                {
                    normalPolynom += child;
                }
            }

            if (fractioned.Count == 0)
            {
                return(false); // means that one can either be solved polynomially or unsolvable at all
            }
Esempio n. 2
0
        internal override void Check()
        {
            // Can't have other name
            TreeAnalyzer.AssertTree(Name == "tensort", "Tensors must have Name=tensort");
            // Tensor can't be scalar
            TreeAnalyzer.AssertTree(Dimensions > 0, "Dimensions can't be equal to 0");

            // All elements are not null
            for (int i = 0; i < Data.Length; i++)
            {
                TreeAnalyzer.AssertTree(Data[i] != null, "One tensor's element is null");
            }
        }
        internal static Entity?SolveBySplittingSum(Entity expr, Entity.Variable x)
        {
            var splitted = TreeAnalyzer.GatherLinearChildrenOverSumAndExpand(expr, e => e.ContainsNode(x));

            if (splitted is null || splitted.Count < 2)
            {
                return(null);                                                    // nothing to do, let other solvers do the work
            }
            splitted[0] = Integration.ComputeIndefiniteIntegral(splitted[0], x); // base case for aggregate
            var result = splitted.Aggregate((e1, e2) => e1 + Integration.ComputeIndefiniteIntegral(e2, x));

            return(result);
        }
Esempio n. 4
0
        public void TestEnumerator3()
        {
            Entity expr    = "2 + 3 + x";
            var    pattern = Powf.PHang(Patterns.any1, Patterns.any2);

            var matches = new Set();

            foreach (var match in TreeAnalyzer.GetPatternEnumerator(expr, pattern))
            {
                matches.Add(match);
            }
            Assert.IsTrue(matches.Count == 0, "match is NOT empty, but should");
        }
Esempio n. 5
0
        public void AssertExpander(Entity expr, params ComplexNumber[] toSubs)
        {
            MathS.Settings.MaxExpansionTermCount.Set(3000);
            var expanded =
                TreeAnalyzer.MultiHangBinary(
                    TreeAnalyzer.SmartExpandOver(expr, entity => entity.FindSubtree("x") != null), "sumf", Const.PRIOR_SUM);

            MathS.Settings.MaxExpansionTermCount.Unset();
            foreach (var toSub in toSubs)
            {
                var comparisonResult = AreEqual(expr, expanded, toSub);
                Assert.IsTrue(comparisonResult.equal, "E: " + comparisonResult.err + "  toSub: " + toSub + "  expanded: " + expanded.ToString());
            }
        }
Esempio n. 6
0
        /// <summary>
        /// solves ax3 + bx2 + cx + d
        /// </summary>
        /// <param name="a">
        /// Coefficient of x^3
        /// </param>
        /// <param name="b">
        /// Coefficient of x^2
        /// </param>
        /// <param name="c">
        /// Coefficient of x
        /// </param>
        /// <param name="d">
        /// Free coefficient
        /// </param>
        /// <returns>
        /// Set of roots
        /// </returns>
        internal static Set SolveCubic(Entity a, Entity b, Entity c, Entity d)
        {
            // en: https://en.wikipedia.org/wiki/Cubic_equation
            // ru: https://ru.wikipedia.org/wiki/%D0%A4%D0%BE%D1%80%D0%BC%D1%83%D0%BB%D0%B0_%D0%9A%D0%B0%D1%80%D0%B4%D0%B0%D0%BD%D0%BE

            // TODO (to remove sympy code!)

            Set res;

            if (TreeAnalyzer.IsZero(d))
            {
                res = SolveQuadratic(a, b, c);
                res.Add(0);
                return(res);
            }

            if (TreeAnalyzer.IsZero(a))
            {
                return(SolveQuadratic(b, c, d));
            }

            res = new Set();

            var coeff = MathS.i * MathS.Sqrt(3) / 2;

            var u1 = new NumberEntity(1);
            var u2 = SySyn.Rational(-1, 2) + coeff;
            var u3 = SySyn.Rational(-1, 2) - coeff;
            var D0 = MathS.Sqr(b) - 3 * a * c;
            var D1 = (2 * MathS.Pow(b, 3) - 9 * a * b * c + 27 * MathS.Sqr(a) * d).InnerSimplify();
            var C  = MathS.Pow((D1 + MathS.Sqrt(MathS.Sqr(D1) - 4 * MathS.Pow(D0, 3))) / 2, Number.CreateRational(1, 3));

            foreach (var uk in new List <Entity> {
                u1, u2, u3
            })
            {
                Entity r;
                if (Const.EvalIfCan(C) == 0 && Const.EvalIfCan(D0) == 0)
                {
                    r = -(b + uk * C) / 3 / a;
                }
                else
                {
                    r = -(b + uk * C + D0 / C / uk) / 3 / a;
                }
                res.Add(r);
            }
            return(res);
        }
Esempio n. 7
0
        /// <summary>Solves ax^2 + bx + c</summary>
        /// <param name="a">Coefficient of x^2</param>
        /// <param name="b">Coefficient of x</param>
        /// <param name="c">Free coefficient</param>
        /// <returns>Set of roots</returns>
        internal static IEnumerable <Entity> SolveQuadratic(Entity a, Entity b, Entity c)
        {
            if (TreeAnalyzer.IsZero(c))
            {
                return(SolveLinear(a, b).Append(0));
            }
            if (TreeAnalyzer.IsZero(a))
            {
                return(SolveLinear(b, c));
            }
            var D = MathS.Sqr(b) - 4 * a * c;

            return(new[] { ((-b - MathS.Sqrt(D)) / (2 * a)).InnerSimplified,
                           ((-b + MathS.Sqrt(D)) / (2 * a)).InnerSimplified });
        }
        /// <summary>
        /// Solves one equation
        /// </summary>
        /// <param name="equation"></param>
        /// <param name="x"></param>
        /// <returns></returns>
        internal static Set Solve(Entity equation, VariableEntity x)
        {
            var res = new Set();

            equation = equation.DeepCopy();

            MathS.Settings.PrecisionErrorZeroRange.Set(1e-12m);
            MathS.Settings.FloatToRationalIterCount.Set(0);
            AnalyticalSolver.Solve(equation, x, res);
            MathS.Settings.FloatToRationalIterCount.Unset();
            MathS.Settings.PrecisionErrorZeroRange.Unset();

            if (res.Power == Set.PowerLevel.FINITE)
            {
                res.FiniteApply(entity => entity.InnerSimplify());
                Func <Entity, Entity> simplifier = entity => entity.InnerSimplify();
                Func <Entity, Entity> evaluator  = entity => entity.InnerEval();

                Entity collapser(Entity expr)
                {
                    if (MathS.Utils.GetUniqueVariables(equation).Count == 1)
                    {
                        return(expr.InnerEval());
                    }
                    else
                    {
                        return(expr.InnerSimplify());
                    }
                }

                var finalSet = new Set();
                finalSet.FastAddingMode = true;
                foreach (var elem in res.FiniteSet())
                {
                    if (TreeAnalyzer.IsDefinite(elem) &&
                        TreeAnalyzer.IsDefinite(collapser(equation.Substitute(x, elem)))
                        )
                    {
                        finalSet.Add(elem);
                    }
                }
                finalSet.FastAddingMode = false;
                res = finalSet;
            }

            return(res);
        }
Esempio n. 9
0
        public void TestEnumerator2()
        {
            Entity expr    = "a^x + ((b^y + c^z)^2)^x";
            var    pattern = Powf.PHang(Patterns.any1, Patterns.any2);

            var matches = new Set();

            foreach (var match in TreeAnalyzer.GetPatternEnumerator(expr, pattern))
            {
                matches.Add(match);
            }
            Assert.IsTrue(matches.Count == 5, "not all matched were found");
            foreach (var match in matches.FiniteSet())
            {
                Assert.IsNotNull(expr.FindSubtree(match), "match is not in expression");
            }
        }
Esempio n. 10
0
        /// <summary>Solves ax^4 + bx^3 + cx^2 + dx + e</summary>
        /// <param name="a">Coefficient of x^4</param>
        /// <param name="b">Coefficient of x^3</param>
        /// <param name="c">Coefficient of x^2</param>
        /// <param name="d">Coefficient of x</param>
        /// <param name="e">Free coefficient</param>
        /// <returns>Set of roots</returns>
        internal static IEnumerable <Entity> SolveQuartic(Entity a, Entity b, Entity c, Entity d, Entity e)
        {
            // en: https://en.wikipedia.org/wiki/Quartic_function
            // ru: https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%A4%D0%B5%D1%80%D1%80%D0%B0%D1%80%D0%B8

            if (TreeAnalyzer.IsZero(e))
            {
                return(SolveCubic(a, b, c, d).Append(0));
            }
            if (TreeAnalyzer.IsZero(a))
            {
                return(SolveCubic(b, c, d, e));
            }

            var alpha = (-3 * MathS.Sqr(b) / (8 * MathS.Sqr(a)) + c / a)
                        .InnerSimplified;
            var beta = (MathS.Pow(b, 3) / (8 * MathS.Pow(a, 3)) - (b * c) / (2 * MathS.Sqr(a)) + d / a)
                       .InnerSimplified;
            var gamma = (-3 * MathS.Pow(b, 4) / (256 * MathS.Pow(a, 4)) + MathS.Sqr(b) * c / (16 * MathS.Pow(a, 3)) - (b * d) / (4 * MathS.Sqr(a)) + e / a)
                        .InnerSimplified;

            if (beta.Evaled == 0)
            {
                return(sqrtsOf1.SelectMany(_ => sqrtsOf1,
                                           (s, t) => - b / 4 * a + s * MathS.Sqrt((-alpha + t * MathS.Sqrt(MathS.Sqr(alpha) - 4 * gamma)) / 2)));
            }

            var oneThird = Rational.Create(1, 3);
            var P        = (-MathS.Sqr(alpha) / 12 - gamma)
                           .InnerSimplified;
            var Q = (-MathS.Pow(alpha, 3) / 108 + alpha * gamma / 3 - MathS.Sqr(beta) / 8)
                    .InnerSimplified;
            var R = -Q / 2 + MathS.Sqrt(MathS.Sqr(Q) / 4 + MathS.Pow(P, 3) / 27);
            var U = MathS.Pow(R, oneThird)
                    .InnerSimplified;
            var y = (Rational.Create(-5, 6) * alpha + U + (U.Evaled == 0 ? -MathS.Pow(Q, oneThird) : -P / (3 * U)))
                    .InnerSimplified;
            var W = MathS.Sqrt(alpha + 2 * y)
                    .InnerSimplified;

            // Now we need to permutate all four combinations
            return(sqrtsOf1.SelectMany(_ => sqrtsOf1,
                                       (s, t) => - b / (4 * a) + (s * W + t * MathS.Sqrt(-(3 * alpha + 2 * y + s * 2 * beta / W))) / 2));
        }
Esempio n. 11
0
        /// <summary>
        /// Performs scalar product operation on two vectors
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        internal static Entity ScalarProduct(Tensor a, Tensor b)
        {
            // TODO: Extend to tensors
            if (!a.IsVector() || !b.IsVector())
            {
                throw new MathSException("Scalar product of non-vectors is not supported yet");
            }
            // TODO: allow different shapes
            if (a.Shape[0] != b.Shape[0])
            {
                throw new MathSException("Vectors should be the same size");
            }
            var operands = new List <Entity>();

            for (int i = 0; i < a.Shape[0]; i++)
            {
                operands.Add(a[i] * b[i]);
            }
            return(TreeAnalyzer.MultiHangBinary(operands, "sumf", Const.PRIOR_SUM));
        }
Esempio n. 12
0
        /// <summary>
        /// solves ax2 + bx + c
        /// </summary>
        /// <param name="a">
        /// Coefficient of x^2
        /// </param>
        /// <param name="b">
        /// Coefficient of x
        /// </param>
        /// <param name="c">
        /// Free coefficient
        /// </param>
        /// <returns>
        /// Set of roots
        /// </returns>
        internal static Set SolveQuadratic(Entity a, Entity b, Entity c)
        {
            Set res;

            if (TreeAnalyzer.IsZero(c))
            {
                res = SolveLinear(a, b);
                res.Add(0);
                return(res);
            }

            if (TreeAnalyzer.IsZero(a))
            {
                return(SolveLinear(b, c));
            }

            res = new Set();
            var D = MathS.Sqr(b) - 4 * a * c;

            res.Add(((-b - MathS.Sqrt(D)) / (2 * a)).InnerSimplify());
            res.Add(((-b + MathS.Sqrt(D)) / (2 * a)).InnerSimplify());
            return(res);
        }
Esempio n. 13
0
 /// <summary>
 /// Finds the first occurance of a subtree that fits a pattern
 /// </summary>
 /// <param name="pattern"></param>
 /// <returns>
 /// Entity: first found subtree
 /// </returns>
 internal Entity FindPatternSubtree(Pattern pattern)
 {
     return(TreeAnalyzer.GetPatternEnumerator(this, pattern).FirstOrDefault());
 }
Esempio n. 14
0
 private Entity Expand_(int level)
 => level <= 1
         ? TreeAnalyzer.Replace(Patterns.ExpandRules, this)
         : TreeAnalyzer.Replace(Patterns.ExpandRules, this).Expand_(level - 1);
Esempio n. 15
0
        /// <summary>
        /// Finds all alternative forms of an expression
        /// </summary>
        /// <param name="src"></param>
        /// <param name="level"></param>
        /// <returns></returns>
        internal static Set Alternate(Entity src, int level)
        {
            if (src.entType == Entity.EntType.NUMBER || src.entType == Entity.EntType.VARIABLE)
            {
                return(new Set(src.Copy()));
            }
            var stage1 = src.InnerSimplify();

            if (stage1.entType == Entity.EntType.NUMBER)
            {
                return(new Set(stage1));
            }

            var history = new SortedDictionary <int, Entity>();

            void TryInnerSimplify(ref Entity expr)
            {
                TreeAnalyzer.Sort(ref expr, TreeAnalyzer.SortLevel.HIGH_LEVEL);
                expr = expr.InnerSimplify();
            }

            void __IterAddHistory(Entity expr)
            {
                Entity refexpr = expr.DeepCopy();

                TryInnerSimplify(ref refexpr);
                var n = refexpr.Complexity() > expr.Complexity() ? expr : refexpr;

                history[n.Complexity()] = n;
            }

            void AddHistory(Entity expr)
            {
                __IterAddHistory(expr);
                Entity _res = expr;

                TreeAnalyzer.InvertNegativePowers(ref _res);
                __IterAddHistory(_res);
            }

            AddHistory(stage1);
            var res = stage1.DeepCopy();

            for (int i = 0; i < Math.Abs(level); i++)
            {
                if (i == 0 || i > 2)
                {
                    TreeAnalyzer.Sort(ref res, TreeAnalyzer.SortLevel.HIGH_LEVEL);
                }
                else if (i == 1)
                {
                    TreeAnalyzer.Sort(ref res, TreeAnalyzer.SortLevel.MIDDLE_LEVEL);
                }
                else if (i == 2)
                {
                    TreeAnalyzer.Sort(ref res, TreeAnalyzer.SortLevel.LOW_LEVEL);
                }
                res = res.InnerSimplify();
                if (TreeAnalyzer.Optimization.ContainsPower(res))
                {
                    TreeAnalyzer.ReplaceInPlace(Patterns.PowerRules, ref res);
                    AddHistory(res);
                }

                {
                    TreeAnalyzer.InvertNegativePowers(ref res);
                    TreeAnalyzer.InvertNegativeMultipliers(ref res);
                    TreeAnalyzer.Sort(ref res, TreeAnalyzer.SortLevel.HIGH_LEVEL);
                    AddHistory(res);
                    TreeAnalyzer.ReplaceInPlace(Patterns.CommonRules, ref res);
                    AddHistory(res);
                    TreeAnalyzer.InvertNegativePowers(ref res);
                }

                {
                    TreeAnalyzer.InvertNegativePowers(ref res);
                    TreeAnalyzer.ReplaceInPlace(Patterns.DivisionPreparingRules, ref res);
                    res = res.InnerSimplify();
                    TreeAnalyzer.FindDivisors(ref res, (num, denom) => !MathS.CanBeEvaluated(num) && !MathS.CanBeEvaluated(denom));
                }

                res = res.InnerSimplify();
                if (TreeAnalyzer.Optimization.ContainsTrigonometric(res))
                {
                    var res1 = res.DeepCopy();
                    TreeAnalyzer.ReplaceInPlace(Patterns.TrigonometricRules, ref res);
                    AddHistory(res);
                    TreeAnalyzer.ReplaceInPlace(Patterns.ExpandTrigonometricRules, ref res1);
                    AddHistory(res1);
                    res = res.Complexity() > res1.Complexity() ? res1 : res;
                }
                if (TreeAnalyzer.Optimization.ContainsPower(res))
                {
                    TreeAnalyzer.ReplaceInPlace(Patterns.PowerRules, ref res);
                    AddHistory(res);
                }
                AddHistory(res);
                res = history[history.Keys.Min()].DeepCopy();
            }
            if (level > 0) // if level < 0 we don't check whether expanded version is better
            {
                var expanded = res.Expand().Simplify(-level);
                AddHistory(expanded);
                var collapsed = res.Collapse().Simplify(-level);
                AddHistory(collapsed);
            }
            return(new Set(history.Values.Select(p => (Piece)p).ToArray()));
        }
Esempio n. 16
0
        internal Node Sort(SortLevel level)
        {
            if (Left != null)
            {
                Left = Left.Sort(level);
            }
            if (Right != null)
            {
                Right = Right.Sort(level);
            }
            if (!(this is BinaryOperatorNode))
            {
                return(Clone() as Node);
            }
            BinaryOperatorNode binOp = this as BinaryOperatorNode;

            if (binOp.Operator != BinaryOperator.Add && binOp.Operator != BinaryOperator.Subtract && binOp.Operator != BinaryOperator.Multiply && binOp.Operator != BinaryOperator.Divide)
            {
                return(Clone() as Node);
            }
            bool isSum = binOp.Operator == BinaryOperator.Add || binOp.Operator == BinaryOperator.Subtract;
            List <Tuple <Node, TreeAnalyzer.LinearChildTag> >         children        = TreeAnalyzer.LinearChildren(this, isSum ? BinaryOperator.Add : BinaryOperator.Multiply, isSum ? BinaryOperator.Subtract : BinaryOperator.Divide);
            List <List <Tuple <Node, TreeAnalyzer.LinearChildTag> > > groups          = TreeAnalyzer.groupByHash(children, level);
            List <Tuple <Node, TreeAnalyzer.LinearChildTag> >         groupedChildren = new List <Tuple <Node, TreeAnalyzer.LinearChildTag> >();

            foreach (List <Tuple <Node, TreeAnalyzer.LinearChildTag> > group in groups)
            {
                groupedChildren.Add(TreeAnalyzer.internalMultihang(group, isSum ? BinaryOperator.Add : BinaryOperator.Multiply, isSum ? BinaryOperator.Subtract : BinaryOperator.Divide));
            }
            return(TreeAnalyzer.MultiHang(groupedChildren, isSum ? BinaryOperator.Add : BinaryOperator.Multiply, isSum ? BinaryOperator.Subtract : BinaryOperator.Divide));
        }
Esempio n. 17
0
 /// <summary>
 /// Collapses an equation trying to eliminate as many power-uses as possible ( e. g. x * 3 + x * y = x * (3 + y) )
 /// </summary>
 /// <param name="level">
 /// The number of iterations (increase this argument if some collapse operations are still available)
 /// </param>
 /// <returns></returns>
 public Entity Collapse(int level) => level <= 1
     ? TreeAnalyzer.Replace(Patterns.CollapseRules, this)
     : TreeAnalyzer.Replace(Patterns.CollapseRules, this).Collapse(level - 1);
        /// <summary>
        /// Finds all alternative forms of an expression
        /// </summary>
        /// <param name="src"></param>
        /// <param name="level"></param>
        /// <returns></returns>
        internal static Set Alternate(Entity src, int level)
        {
            if (src.entType == Entity.EntType.NUMBER || src.entType == Entity.EntType.VARIABLE)
            {
                return(new Set(src.Copy()));
            }
            var stage1 = src.InnerSimplify();

            if (stage1.entType == Entity.EntType.NUMBER)
            {
                return(new Set(stage1));
            }

            var history = new SortedDictionary <int, List <Entity> >();

            void TryInnerSimplify(ref Entity expr)
            {
                TreeAnalyzer.Sort(ref expr, TreeAnalyzer.SortLevel.HIGH_LEVEL);
                expr = expr.InnerSimplify();
            }

            // List of criterians of expr's complexity
            int CountExpressionComplexity(Entity expr)
            => MathS.Settings.ComplexityCriteria.Value(expr);

            void __IterAddHistory(Entity expr)
            {
                Entity refexpr = expr.DeepCopy();

                TryInnerSimplify(ref refexpr);
                var compl1 = CountExpressionComplexity(refexpr);
                var compl2 = CountExpressionComplexity(expr);
                var n      = compl1 > compl2 ? expr : refexpr;
                var ncompl = Math.Min(compl2, compl1);

                if (!history.ContainsKey(ncompl))
                {
                    history[ncompl] = new List <Entity>();
                }
                history[ncompl].Add(n);
            }

            void AddHistory(Entity expr)
            {
                __IterAddHistory(expr);
                Entity _res = expr;

                TreeAnalyzer.InvertNegativePowers(ref _res);
                __IterAddHistory(_res);
            }

            AddHistory(stage1);
            var res = stage1.DeepCopy();

            for (int i = 0; i < Math.Abs(level); i++)
            {
                if (i == 0 || i > 2)
                {
                    TreeAnalyzer.Sort(ref res, TreeAnalyzer.SortLevel.HIGH_LEVEL);
                }
                else if (i == 1)
                {
                    TreeAnalyzer.Sort(ref res, TreeAnalyzer.SortLevel.MIDDLE_LEVEL);
                }
                else if (i == 2)
                {
                    TreeAnalyzer.Sort(ref res, TreeAnalyzer.SortLevel.LOW_LEVEL);
                }
                res = res.InnerSimplify();
                if (TreeAnalyzer.Optimization.ContainsPower(res))
                {
                    TreeAnalyzer.ReplaceInPlace(Patterns.PowerRules, ref res);
                    AddHistory(res);
                }

                {
                    TreeAnalyzer.InvertNegativePowers(ref res);
                    TreeAnalyzer.InvertNegativeMultipliers(ref res);
                    TreeAnalyzer.Sort(ref res, TreeAnalyzer.SortLevel.HIGH_LEVEL);
                    AddHistory(res);
#if DEBUG
                    var pre = res.Substitute("x", 3).InnerEval();
#endif
                    res = res.InnerSimplify();
#if DEBUG
                    var post = res.Substitute("x", 3).InnerEval();
                    if (post != pre && MathS.CanBeEvaluated(res))
                    {
                        throw new SysException("Wrong inner simplification");
                    }
#endif
                    TreeAnalyzer.ReplaceInPlace(Patterns.CommonRules, ref res);
                    AddHistory(res);
                    TreeAnalyzer.InvertNegativePowers(ref res);
                }

                {
                    TreeAnalyzer.InvertNegativePowers(ref res);
                    TreeAnalyzer.ReplaceInPlace(Patterns.DivisionPreparingRules, ref res);
                    res = res.InnerSimplify();
                    TreeAnalyzer.FindDivisors(ref res, (num, denom) => !MathS.CanBeEvaluated(num) && !MathS.CanBeEvaluated(denom));
                }

                res = res.InnerSimplify();
                if (TreeAnalyzer.Optimization.ContainsTrigonometric(res))
                {
                    var res1 = res.DeepCopy();
                    TreeAnalyzer.ReplaceInPlace(Patterns.TrigonometricRules, ref res);
                    AddHistory(res);
                    TreeAnalyzer.ReplaceInPlace(Patterns.ExpandTrigonometricRules, ref res1);
                    AddHistory(res1);
                    res = res.Complexity() > res1.Complexity() ? res1 : res;
                }
                if (TreeAnalyzer.Optimization.ContainsPower(res))
                {
                    TreeAnalyzer.ReplaceInPlace(Patterns.PowerRules, ref res);
                    AddHistory(res);
                }
                AddHistory(res);
                res = history[history.Keys.Min()][0].DeepCopy();
            }
            if (level > 0) // if level < 0 we don't check whether expanded version is better
            {
                var expanded = res.Expand().Simplify(-level);
                AddHistory(expanded);
                var collapsed = res.Collapse().Simplify(-level);
                AddHistory(collapsed);
            }

            var result = new Set();

            foreach (var pair in history)
            {
                foreach (var el in pair.Value)
                {
                    result.Add(el);
                }
            }

            return(result);
        }
Esempio n. 19
0
        internal static void ParseMonomial <T>(Entity aVar, Entity expr, out Entity freeMono, ref TreeAnalyzer.IPrimitive <T> power)
        {
            if (expr.FindSubtree(aVar) == null)
            {
                freeMono = expr;
                return;
            }

            freeMono = 1; // a * b

            bool allowFloat = typeof(T) == typeof(decimal);

            foreach (var mp in TreeAnalyzer.LinearChildren(expr, "mulf", "divf", Const.FuncIfMul))
            {
                if (mp.FindSubtree(aVar) == null)
                {
                    freeMono *= mp;
                }
                else if (mp.entType == Entity.EntType.OPERATOR &&
                         mp.Name == "powf")
                {
                    var pow_num = MathS.CanBeEvaluated(mp.Children[1]) ? mp.Children[1].Eval() : mp.Children[1];

                    // x ^ a is bad
                    if (pow_num.entType != Entity.EntType.NUMBER)
                    {
                        freeMono = null;
                        return;
                    }

                    // x ^ 0.3 is bad
                    if (!allowFloat && !pow_num.Eval().IsInteger())
                    {
                        freeMono = null;
                        return;
                    }

                    if (mp == aVar)
                    {
                        if (allowFloat)
                        {
                            (power as TreeAnalyzer.PrimitiveDouble).Add(pow_num.GetValue().Real);
                        }
                        else
                        {
                            (power as TreeAnalyzer.PrimitiveInt).Add(pow_num.GetValue().Real.AsInt());
                        }
                    }
                    else
                    {
                        if (!MathS.CanBeEvaluated(mp.Children[1]))
                        {
                            freeMono = null;
                            return;
                        }
                        Entity tmpFree;
                        // TODO
                        object pow;
                        if (typeof(T) == typeof(decimal))
                        {
                            pow = new TreeAnalyzer.PrimitiveDouble();
                        }
                        else
                        {
                            pow = new TreeAnalyzer.PrimitiveInt();
                        }
                        TreeAnalyzer.IPrimitive <T> q = pow as TreeAnalyzer.IPrimitive <T>;
                        ParseMonomial <T>(aVar, mp.Children[0], out tmpFree, ref q);
                        if (tmpFree == null)
                        {
                            freeMono = null;
                            return;
                        }
                        else
                        {
                            // Can we eval it right here?
                            mp.Children[1] = mp.Children[1].Eval();
                            freeMono      *= MathS.Pow(tmpFree, mp.Children[1]);
                            power.AddMp(q.GetValue(), mp.Children[1].GetValue());
                        }
                    }
                }
                else if (mp == aVar)
                {
                    if (allowFloat)
                    {
                        (power as TreeAnalyzer.PrimitiveDouble).Add(1);
                    }
                    else
                    {
                        (power as TreeAnalyzer.PrimitiveInt).Add(1);
                    }
                }
                else
                {
                    // a ^ x, (a + x) etc. are bad
                    if (mp.FindSubtree(aVar) != null)
                    {
                        freeMono = null;
                        return;
                    }
                    freeMono *= mp;
                }
            }
            // TODO: do we need to simplify freeMono?
        }
Esempio n. 20
0
        internal static Set Solve(Entity expr, VariableEntity x)
        {
            var childrenRaw = TreeAnalyzer.GatherLinearChildrenOverAndExpand(
                expr, entity => entity.FindSubtree(x) != null
                );

            if (childrenRaw is null)
            {
                return(null);
            }

            childrenRaw = childrenRaw.Select(c => c.InnerSimplify()).ToList();
            var children = new List <Entity>();

            foreach (var child in childrenRaw)
            {
                var ch = child;
                // sqrt(f(x))^2 => f(x)
                TreeAnalyzer.ReplaceInPlace(Patterns.PowerRules, ref ch);
                children.Add(ch);
            }

            Entity normalPolynom = 0;
            var    fractioned    = new List <(Entity multiplier, List <(Entity main, IntegerNumber pow)> fracs)>();

            foreach (var child in children)
            {
                (Entity multiplier, List <(Entity main, IntegerNumber pow)> fracs)potentialFraction;
                potentialFraction.multiplier = 1;
                potentialFraction.fracs      = new List <(Entity main, IntegerNumber pow)>();
                foreach (var mpChild in TreeAnalyzer.LinearChildrenOverProduct(child))
                {
                    if (mpChild.entType != Entity.EntType.OPERATOR)
                    {
                        potentialFraction.multiplier *= mpChild;
                        continue;
                    }
                    if (mpChild.Name != "powf")
                    {
                        potentialFraction.multiplier *= mpChild;
                        continue;
                    }
                    if (mpChild.Children[1].entType != Entity.EntType.NUMBER)
                    {
                        potentialFraction.multiplier *= mpChild;
                        continue;
                    }
                    if (mpChild.Children[0].FindSubtree(x) == null)
                    {
                        potentialFraction.multiplier *= mpChild;
                        continue;
                    }
                    var num = (mpChild.Children[1] as NumberEntity).Value;
                    if (!num.IsRational())
                    {
                        return(null);      // (x + 1)^0.2348728
                    }
                    if (!num.IsFraction()) // (x + 3) ^ 3
                    {
                        potentialFraction.multiplier *= mpChild;
                        continue;
                    }
                    var fracNum  = num as RationalNumber;
                    var newChild = MathS.Pow(mpChild.Children[0], fracNum.Numerator).InnerSimplify();
                    var den      = fracNum.Denominator;
                    potentialFraction.fracs.Add((newChild, den));
                }

                if (potentialFraction.fracs.Count > 0)
                {
                    fractioned.Add(potentialFraction);
                }
                else
                {
                    normalPolynom += child;
                }
            }

            if (fractioned.Count == 0)
            {
                return(null); // means that one can either be solved polynomially or unsolvable at all
            }
            // starting from i = 1 check if all are equal to [0]
            bool BasesAreEqual(List <(Entity main, IntegerNumber pow)> f1,
                               List <(Entity main, IntegerNumber pow)> f2)
            {
                if (f1.Count != f2.Count)
                {
                    return(false);
                }
                for (int i = 0; i < f1.Count; i++)
                {
                    if (f1[i].main != f2[i].main || f1[i].pow != f2[i].pow)
                    {
                        return(false);
                    }
                }
                return(true);
            }

            for (int i = 1; i < fractioned.Count; i++)
            {
                if (BasesAreEqual(fractioned[i].fracs, fractioned[0].fracs))
                {
                    var were = fractioned[0];
                    fractioned[0] = (were.multiplier + fractioned[i].multiplier, were.fracs);
                }
                else
                {
                    return(null);
                }
            }

            var fractionedProduct = fractioned[0];

            var lcm = Utils.LCM(fractionedProduct.fracs.Select(
                                    c => c.pow.Value
                                    ).ToArray());
            var intLcm = Number.Create(lcm);

            //                        "-" to compensate sum: x + sqrt(x + 1) = 0 => x = -sqrt(x+1)
            Entity mp = MathS.Pow(-fractionedProduct.multiplier, intLcm).InnerSimplify();

            foreach (var mainPowPair in fractionedProduct.fracs)
            {
                mp *= MathS.Pow(mainPowPair.main, Number.Create(lcm.Divide(mainPowPair.pow.Value)));
            }

            var finalExpr = MathS.Pow(normalPolynom, intLcm) - mp;

            return(finalExpr.SolveEquation(x));
        }
Esempio n. 21
0
        internal static void Solve(Entity expr, VariableEntity x, Set dst, bool compensateSolving)
        {
            if (expr == x)
            {
                dst.Add(0);
                return;
            }

            // Applies an attempt to downcast roots
            void DestinationAddRange(Set toAdd)
            {
                toAdd.FiniteApply(ent => TryDowncast(expr, x, ent));
                dst.AddRange(toAdd);
            }

            var polyexpr = expr.DeepCopy();
            Set res      = PolynomialSolver.SolveAsPolynomial(polyexpr, x);

            if (res != null)
            {
                res.FiniteApply(e => e.InnerSimplify());
                DestinationAddRange(res);
                return;
            }

            if (expr.entType == Entity.EntType.OPERATOR)
            {
                switch (expr.Name)
                {
                case "mulf":
                    Solve(expr.Children[0], x, dst);
                    Solve(expr.Children[1], x, dst);
                    return;

                case "divf":

                    bool IsSetNumeric(Set a)
                    => a.Select(piece => piece.LowerBound().Item1).All(MathS.CanBeEvaluated);

                    var zeroNumerators = new Set();
                    Solve(expr.Children[0], x, zeroNumerators);
                    if (!IsSetNumeric(zeroNumerators))
                    {
                        dst.AddRange(zeroNumerators);
                        return;
                    }
                    var zeroDenominators = new Set();
                    Solve(expr.Children[1], x, zeroDenominators);
                    if (!IsSetNumeric(zeroDenominators))
                    {
                        dst.AddRange(zeroNumerators);
                        return;
                    }
                    dst.AddRange((zeroNumerators & !zeroDenominators) as Set);
                    return;

                case "powf":
                    Solve(expr.Children[0], x, dst);
                    return;

                case "minusf":
                    if (expr.Children[1].FindSubtree(x) == null && compensateSolving)
                    {
                        if (expr.Children[0] == x)
                        {
                            dst.Add(expr.Children[1]);
                            return;
                        }
                        var    subs      = 0;
                        Entity lastChild = null;
                        foreach (var child in expr.Children[0].Children)
                        {
                            if (child.FindSubtree(x) != null)
                            {
                                subs     += 1;
                                lastChild = child;
                            }
                        }
                        if (subs != 1)
                        {
                            break;
                        }
                        var resInverted = TreeAnalyzer.FindInvertExpression(expr.Children[0], expr.Children[1], lastChild);
                        foreach (var result in resInverted.FiniteSet())
                        {
                            Solve(lastChild - result, x, dst, compensateSolving: true);
                        }
                        return;
                    }
                    break;
                }
            }
            else if (expr.entType == Entity.EntType.FUNCTION)
            {
                DestinationAddRange(TreeAnalyzer.InvertFunctionEntity(expr as FunctionEntity, 0, x));
                return;
            }


            // Here we generate a unique variable name
            var uniqVars = MathS.Utils.GetUniqueVariables(expr);

            uniqVars.Pieces.Sort((a, b) => ((Entity)b).Name.Length.CompareTo(((Entity)a).Name.Length));
            VariableEntity newVar = ((Entity)uniqVars.Pieces[0]).Name + "quack";
            // // //


            // Here we find all possible replacements
            var replacements = new List <Tuple <Entity, Entity> >();

            replacements.Add(new Tuple <Entity, Entity>(TreeAnalyzer.GetMinimumSubtree(expr, x), expr));
            foreach (var alt in expr.Alternate(4).FiniteSet())
            {
                if ((alt).FindSubtree(x) == null)
                {
                    return; // in this case there is either 0 or +oo solutions
                }
                replacements.Add(new Tuple <Entity, Entity>(TreeAnalyzer.GetMinimumSubtree(alt, x), alt));
            }
            // // //

            // Here we find one that has at least one solution

            foreach (var replacement in replacements)
            {
                Set solutions = null;
                if (replacement.Item1 == x)
                {
                    continue;
                }
                var newExpr = replacement.Item2.DeepCopy();
                TreeAnalyzer.FindAndReplace(ref newExpr, replacement.Item1, newVar);
                solutions = newExpr.SolveEquation(newVar);
                if (!solutions.IsEmpty())
                {
                    var bestReplacement = replacement.Item1;

                    // Here we are trying to solve for this replacement
                    Set newDst = new Set();
                    foreach (var solution in solutions.FiniteSet())
                    {
                        var str = bestReplacement.ToString();
                        // TODO: make a smarter comparison than just comparison of complexities of two expressions
                        // The idea is
                        // similarToPrevious = ((bestReplacement - solution) - expr).Simplify() == 0
                        // But Simplify costs us too much time
                        var similarToPrevious = (bestReplacement - solution).Complexity() >= expr.Complexity();
                        if (!compensateSolving || !similarToPrevious)
                        {
                            Solve(bestReplacement - solution, x, newDst, compensateSolving: true);
                        }
                    }
                    DestinationAddRange(newDst);
                    if (!dst.IsEmpty())
                    {
                        break;
                    }
                    // // //
                }
            }
            // // //

            // if no replacement worked, try trigonometry solver
            if (dst.IsEmpty())
            {
                var trigexpr = expr.DeepCopy();
                res = TrigonometricSolver.SolveLinear(trigexpr, x);
                if (res != null)
                {
                    DestinationAddRange(res);
                    return;
                }
            }
            // // //


            // if nothing has been found so far
            if (dst.IsEmpty() && MathS.Settings.AllowNewton)
            {
                Set allVars = new Set();
                TreeAnalyzer._GetUniqueVariables(expr, allVars);
                if (allVars.Count == 1)
                {
                    DestinationAddRange(expr.SolveNt(x));
                }
            }
        }
Esempio n. 22
0
 /// <summary>
 /// Multiplies all the given terms and returns the resulting expression
 /// new Entity[]{ 1, 2, 3 }.MultiplyAll() -> "1 * 2 * 3"
 /// </summary>
 public static Entity MultiplyAll(this IEnumerable <Entity> terms)
 => TreeAnalyzer.MultiHangBinary(terms.ToArray(), (a, b) => a * b);
Esempio n. 23
0
 /// <summary>
 /// Returns list of unique variables, for example
 /// it extracts `x`, `goose` from (x + 2 * goose) - pi * x
 /// </summary>
 /// <param name="expr"></param>
 /// <returns></returns>
 public static Set GetUniqueVariables(Entity expr)
 => TreeAnalyzer.GetUniqueVariables(expr);
Esempio n. 24
0
 /// <summary>
 /// Checks tree for some unexpected bad occasions
 /// Throws SysException's children
 /// If you need a message, it's better to write
 /// try
 /// {
 ///     MathS.CheckTree(a);
 /// }
 /// catch (SysException e)
 /// {
 ///     Console.WriteLine(e.Message);
 /// }
 /// </summary>
 /// <param name="expr"></param>
 /// <returns></returns>
 public static void CheckTree(Entity expr)
 => TreeAnalyzer.CheckTree(expr);
Esempio n. 25
0
        /// <summary>
        /// solves ax4 + bx3 + cx2 + dx + e
        /// </summary>
        /// <param name="a">
        /// Coefficient of x^4
        /// </param>
        /// <param name="b">
        /// Coefficient of x^3
        /// </param>
        /// <param name="c">
        /// Coefficient of x^2
        /// </param>
        /// <param name="d">
        /// Coefficient of x
        /// </param>
        /// <param name="e">
        /// Free coefficient
        /// </param>
        /// <returns>
        /// Set of roots
        /// </returns>
        internal static Set SolveQuartic(Entity a, Entity b, Entity c, Entity d, Entity e)
        {
            // en: https://en.wikipedia.org/wiki/Quartic_function
            // ru: https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%A4%D0%B5%D1%80%D1%80%D0%B0%D1%80%D0%B8

            Set res;

            if (TreeAnalyzer.IsZero(e))
            {
                res = SolveCubic(a, b, c, d);
                res.Add(0);
                return(res);
            }

            if (TreeAnalyzer.IsZero(a))
            {
                return(SolveCubic(b, c, d, e));
            }


            res = new Set();

            var alpha = (-3 * MathS.Sqr(b) / (8 * MathS.Sqr(a)) + c / a)
                        .InnerSimplify();
            var beta = (MathS.Pow(b, 3) / (8 * MathS.Pow(a, 3)) - (b * c) / (2 * MathS.Sqr(a)) + d / a)
                       .InnerSimplify();
            var gamma = (-3 * MathS.Pow(b, 4) / (256 * MathS.Pow(a, 4)) + MathS.Sqr(b) * c / (16 * MathS.Pow(a, 3)) - (b * d) / (4 * MathS.Sqr(a)) + e / a)
                        .InnerSimplify();

            if (Const.EvalIfCan(beta) == 0)
            {
                res.FastAddingMode = true;
                for (int s = -1; s <= 1; s += 2)
                {
                    for (int t = -1; t <= 1; t += 2)
                    {
                        var x = -b / 4 * a + s * MathS.Sqrt((-alpha + t * MathS.Sqrt(MathS.Sqr(alpha) - 4 * gamma)) / 2);
                        res.Add(x);
                    }
                }
                res.FastAddingMode = false;
                return(res);
            }


            var oneThird = Number.CreateRational(1, 3);
            var P        = (-MathS.Sqr(alpha) / 12 - gamma)
                           .InnerSimplify();
            var Q = (-MathS.Pow(alpha, 3) / 108 + alpha * gamma / 3 - MathS.Sqr(beta) / 8)
                    .InnerSimplify();
            var R = -Q / 2 + MathS.Sqrt(MathS.Sqr(Q) / 4 + MathS.Pow(P, 3) / 27);
            var U = MathS.Pow(R, oneThird)
                    .InnerSimplify();
            var y = (Number.CreateRational(-5, 6) * alpha + U + (Const.EvalIfCan(U) == 0 ? -MathS.Pow(Q, oneThird) : -P / (3 * U)))
                    .InnerSimplify();
            var W = MathS.Sqrt(alpha + 2 * y)
                    .InnerSimplify();

            // Now we need to permutate all four combinations
            res.FastAddingMode = true;  /* we are sure that there's no such root yet */
            for (int s = -1; s <= 1; s += 2)
            {
                for (int t = -1; t <= 1; t += 2)
                {
                    var x = -b / (4 * a) + (s * W + t * MathS.Sqrt(-(3 * alpha + 2 * y + s * 2 * beta / W))) / 2;
                    res.Add(x);
                }
            }
            res.FastAddingMode = false;
            return(res);
        }
Esempio n. 26
0
 internal override void Check()
 {
     // Number has no children
     TreeAnalyzer.AssertTree(Children.Count == 0, "A number cannot have children");
 }
Esempio n. 27
0
        /// <summary>
        /// Tries to solve as polynomial
        /// </summary>
        /// <param name="expr">
        /// Polynomial of an expression
        /// </param>
        /// <param name="subtree">
        /// The expression the polynomial of (e. g. cos(x)^2 + cos(x) + 1 is a polynomial of cos(x))
        /// </param>
        /// <returns>
        /// a finite Set if successful,
        /// null otherwise
        /// </returns>
        internal static Set SolveAsPolynomial(Entity expr, Entity subtree)
        {
            // Here we find all terms
            expr = expr.Expand(); // (x + 1) * x => x^2 + x
            List <Entity> children;
            Set           res = new Set();

            if (expr.entType == Entity.EntType.OPERATOR && expr.Name == "sumf" || expr.Name == "minusf")
            {
                children = TreeAnalyzer.LinearChildren(expr, "sumf", "minusf", Const.FuncIfSum);
            }
            else
            {
                children = new List <Entity> {
                    expr
                }
            };
            // Check if all are like {1} * x^n & gather information about them
            var monomialsByPower = GatherMonomialInformation <long>(children, subtree);

            if (monomialsByPower == null)
            {
                return(null); // meaning that the given equation is not polynomial
            }
            Entity GetMonomialByPower(long power)
            {
                return(monomialsByPower.ContainsKey(power) ? monomialsByPower[power].InnerSimplify() : 0);
            }

            if (ReduceCommonPower(ref monomialsByPower)) // x5 + x3 + x2 - common power is 2, one root is 0, then x3 + x + 1
            {
                res.Add(0);
            }
            var powers   = new List <long>(monomialsByPower.Keys);
            var gcdPower = Utils.GCD(powers.ToArray());

            // // //



            // Change all replacements, x6 + x3 + 1 => x2 + x + 1
            if (gcdPower != 1)
            {
                for (int i = 0; i < powers.Count; i++)
                {
                    powers[i] /= gcdPower;
                }

                var newMonom = new Dictionary <long, Entity>();
                foreach (var pair in monomialsByPower)
                {
                    newMonom[pair.Key / gcdPower] = pair.Value;
                }
                monomialsByPower = newMonom;
            }
            // // //



            // if we had x^6 + x^3 + 1, we replace it with x^2 + x + 1 and find all cubic roots of the final answer
            Set FinalPostProcess(Set set)
            {
                if (gcdPower != 1)
                {
                    var newSet = new Set();
                    foreach (var root in set.FiniteSet())
                    {
                        foreach (var coef in Number.GetAllRoots(1, gcdPower).FiniteSet())
                        {
                            newSet.Add(coef * MathS.Pow(root, Number.Create(1.0) / gcdPower));
                        }
                    }
                    set = newSet;
                }
                return(set);
            }

            if (powers.Count == 0)
            {
                return(null);
            }
            powers.Sort();
            if (powers.Last() == 0)
            {
                return(FinalPostProcess(res));
            }
            if (powers.Last() > 4 && powers.Count > 2)
            {
                return(null); // So far, we can't solve equations of powers more than 4
            }
            if (powers.Count == 1)
            {
                res.Add(0);
                return(FinalPostProcess(res));
            }
            else if (powers.Count == 2)
            {
                // Provided a x ^ n + b = 0
                // a = -b x ^ n
                // (- a / b) ^ (1 / n) = x
                // x ^ n = (-a / b)
                var value = (-1 * monomialsByPower[powers[0]] / monomialsByPower[powers[1]]).Simplify();
                res.AddRange(TreeAnalyzer.FindInvertExpression(MathS.Pow(subtree, powers[1]), value, subtree));
                return(FinalPostProcess(res));
            }
            // By this moment we know for sure that expr's power is <= 4, that expr is not a monomial,
            // and that it consists of more than 2 monomials
            else if (powers.Last() == 2)
            {
                var a = GetMonomialByPower(2);
                var b = GetMonomialByPower(1);
                var c = GetMonomialByPower(0);

                res.AddRange(SolveQuadratic(a, b, c));
                return(FinalPostProcess(res));
            }
            else if (powers.Last() == 3)
            {
                var a = GetMonomialByPower(3);
                var b = GetMonomialByPower(2);
                var c = GetMonomialByPower(1);
                var d = GetMonomialByPower(0);

                res.AddRange(SolveCubic(a, b, c, d));
                return(FinalPostProcess(res));
            }
            else if (powers.Last() == 4)
            {
                var a = GetMonomialByPower(4);
                var b = GetMonomialByPower(3);
                var c = GetMonomialByPower(2);
                var d = GetMonomialByPower(1);
                var e = GetMonomialByPower(0);

                res.AddRange(SolveQuartic(a, b, c, d, e));
                return(FinalPostProcess(res));
            }
            return(null);
        }
Esempio n. 28
0
 /// <summary>
 /// Expands an equation trying to eliminate all the parentheses ( e. g. 2 * (x + 3) = 2 * x + 2 * 3 )
 /// </summary>
 /// <param name="level">
 /// The number of iterations (increase this argument in case if some parentheses remain)
 /// </param>
 /// <returns>
 /// An expanded Entity
 /// </returns>
 public Entity Expand(int level) => level <= 1
     ? TreeAnalyzer.Replace(Patterns.ExpandRules, this)
     : TreeAnalyzer.Replace(Patterns.ExpandRules, this).Expand(level - 1);
Esempio n. 29
0
 /// <summary>
 /// Finds out whether "name" is mentioned at least once
 /// </summary>
 /// <param name="name"></param>
 /// <returns></returns>
 internal bool ContainsName(string name) => TreeAnalyzer.ContainsName(this, name);
Esempio n. 30
0
        /// <summary>
        /// Tries to solve as polynomial
        /// </summary>
        /// <param name="expr">
        /// Polynomial of an expression
        /// </param>
        /// <param name="subtree">
        /// The expression the polynomial of (e. g. cos(x)^2 + cos(x) + 1 is a polynomial of cos(x))
        /// </param>
        /// <returns>
        /// a finite Set if successful,
        /// null otherwise
        /// </returns>
        internal static Set SolveAsPolynomial(Entity expr, VariableEntity subtree)
        {
            // Safely expand the expression
            // Here we find all terms

            /*
             * var children = new List<Entity>();
             * var subNodes = TreeAnalyzer.LinearChildrenOverSum(expr);
             * foreach (var child in subNodes)
             *  if (child.FindSubtree(subtree) is null)
             *      children.Add(child); // We don't need to expand constants
             *  else
             *  {
             *
             *      var expanded = TreeAnalyzer.SmartExpandOver(child, entity => entity.FindSubtree(subtree) != null);
             *      if (expanded is null) // Expanded expression is predicted to be too big
             *          return null;
             *      children.AddRange(expanded);
             *  }
             */
            var children = TreeAnalyzer.GatherLinearChildrenOverAndExpand(
                expr, entity => entity.FindSubtree(subtree) != null
                );

            if (children is null)
            {
                return(null);
            }

            // // //

            var res = new Set();

            // Check if all are like {1} * x^n & gather information about them
            var monomialsByPower = GatherMonomialInformation <long>(children, subtree);

            if (monomialsByPower == null)
            {
                return(null); // meaning that the given equation is not polynomial
            }
            Entity GetMonomialByPower(long power)
            {
                return(monomialsByPower.ContainsKey(power) ? monomialsByPower[power].InnerSimplify() : 0);
            }

            if (ReduceCommonPower(ref monomialsByPower)) // x5 + x3 + x2 - common power is 2, one root is 0, then x3 + x + 1
            {
                res.Add(0);
            }
            var powers   = new List <long>(monomialsByPower.Keys);
            var gcdPower = Utils.GCD(powers.ToArray());

            // // //



            // Change all replacements, x6 + x3 + 1 => x2 + x + 1
            if (gcdPower != 1)
            {
                for (int i = 0; i < powers.Count; i++)
                {
                    powers[i] /= gcdPower;
                }

                var newMonom = new Dictionary <long, Entity>();
                foreach (var pair in monomialsByPower)
                {
                    newMonom[pair.Key / gcdPower] = pair.Value;
                }
                monomialsByPower = newMonom;
            }
            // // //



            // if we had x^6 + x^3 + 1, we replace it with x^2 + x + 1 and find all cubic roots of the final answer
            Set FinalPostProcess(Set set)
            {
                if (gcdPower != 1)
                {
                    var newSet = new Set();
                    foreach (var root in set.FiniteSet())
                    {
                        foreach (var coef in Number.GetAllRootsOf1(gcdPower).FiniteSet())
                        {
                            newSet.Add(coef * MathS.Pow(root, Number.CreateRational(1, gcdPower)));
                        }
                    }
                    set = newSet;
                }
                return(set);
            }

            if (powers.Count == 0)
            {
                return(null);
            }
            powers.Sort();
            if (powers.Last() == 0)
            {
                return(FinalPostProcess(res));
            }
            if (powers.Last() > 4 && powers.Count > 2)
            {
                return(null); // So far, we can't solve equations of powers more than 4
            }
            if (powers.Count == 1)
            {
                res.Add(0);
                return(FinalPostProcess(res));
            }
            else if (powers.Count == 2)
            {
                // Provided a x ^ n + b = 0
                // a = -b x ^ n
                // (- a / b) ^ (1 / n) = x
                // x ^ n = (-a / b)
                var value = (-1 * monomialsByPower[powers[0]] / monomialsByPower[powers[1]]).InnerSimplify();
                res.AddRange(TreeAnalyzer.FindInvertExpression(MathS.Pow(subtree, powers[1]), value, subtree));
                return(FinalPostProcess(res));
            }
            // By this moment we know for sure that expr's power is <= 4, that expr is not a monomial,
            // and that it consists of more than 2 monomials
            else if (powers.Last() == 2)
            {
                var a = GetMonomialByPower(2);
                var b = GetMonomialByPower(1);
                var c = GetMonomialByPower(0);

                res.AddRange(SolveQuadratic(a, b, c));
                return(FinalPostProcess(res));
            }
            else if (powers.Last() == 3)
            {
                var a = GetMonomialByPower(3);
                var b = GetMonomialByPower(2);
                var c = GetMonomialByPower(1);
                var d = GetMonomialByPower(0);

                res.AddRange(SolveCubic(a, b, c, d));
                return(FinalPostProcess(res));
            }
            else if (powers.Last() == 4)
            {
                var a = GetMonomialByPower(4);
                var b = GetMonomialByPower(3);
                var c = GetMonomialByPower(2);
                var d = GetMonomialByPower(1);
                var e = GetMonomialByPower(0);

                res.AddRange(SolveQuartic(a, b, c, d, e));
                return(FinalPostProcess(res));
            }
            return(null);
        }