Example #1
0
        internal static Entity?SolveBySubstitution(Entity expr, Variable x)
        {
            // For now we remove all provideds from an expression
            // Is it a correct thing to do?
            var res = expr.Replace(e => e is Providedf(var expr, _) ? expr : e).Substitute(x, Infinity);

            if (res.Evaled is Complex limit)
            {
                MultithreadingFunctional.ExitIfCancelled();
                if (limit == Real.NaN)
                {
                    return(null);
                }
                if (!limit.RealPart.IsFinite)
                {
                    return(limit.RealPart); // TODO: sometimes we get { oo + value * i } so we assume it is just infinity
                }
                if (limit == Integer.Zero)
                {
                    return(limit);
                }

                return(res);
            }
            return(null);
        }
Example #2
0
        // solves equation f(sin(x), cos(x), tan(x), cot(x)) for x
        internal static bool TrySolveLinear(Entity expr, Variable variable, out Set res)
        {
            res = Empty;
            var replacement = Variable.CreateTemp(expr.Vars);

            expr = expr.Replace(Patterns.NormalTrigonometricForm);
            expr = expr.Replace(Patterns.TrigonometricToExponentialRules(variable, replacement));
            MultithreadingFunctional.ExitIfCancelled();
            // if there is still original variable after replacements,
            // equation is not in a form f(sin(x), cos(x), tan(x), cot(x))
            if (expr.ContainsNode(variable))
            {
                return(false);
            }

            if (AnalyticalEquationSolver.Solve(expr, replacement) is FiniteSet els)
            {
                MultithreadingFunctional.ExitIfCancelled();
                res = (Set)els.Select(sol => MathS.Pow(MathS.e, MathS.i * variable).Invert(sol, variable).ToSet()).Unite().InnerSimplified;
                return(true);
            }
            else
            {
                return(false);
            }
        }
Example #3
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
            }
Example #4
0
 internal static Entity?SolveAsPolynomial(Entity expr, Variable x)
 {
     if (ParseAsPolynomial(expr, x) is { } mono)
     {
         MultithreadingFunctional.ExitIfCancelled();
         var maxPower = mono.Keys.Max();
         return
             (maxPower.IsZero
             ? mono[maxPower]
             : maxPower.IsNegative
             ? 0
             : mono[maxPower].Evaled is Complex power
             ? Infinity * power
             : Infinity * mono[maxPower]);
     }
Example #5
0
        /// <summary>Finds all alternative forms of an expression</summary>
        internal static IEnumerable <Entity> Alternate(Entity src, int level)
        {
            if (src is FiniteSet ss)
            {
                return new[] { ss.Apply(ent => ent.Simplify()).InnerSimplified }
            }
            ;
            if (src is Number or Variable or Entity.Boolean)
            {
                return new[] { src }
            }
            ;
            var stage1 = src.InnerSimplified;

            if (stage1 is Number or Variable or Entity.Boolean)
            {
                return new[] { stage1 }
            }
            ;

            // List of criteria for expr's complexity
            var history = new SortedDictionary <double, HashSet <Entity> >();

            void AddHistory(Entity expr)
            {
                void __IterAddHistory(Entity expr)
                {
                    var refexpr = expr.Replace(Patterns.SortRules(TreeAnalyzer.SortLevel.HIGH_LEVEL)).InnerSimplified;
                    var compl1  = refexpr.SimplifiedRate;
                    var compl2  = expr.SimplifiedRate;
                    var n       = compl1 > compl2 ? expr : refexpr;
                    var ncompl  = Math.Min(compl2, compl1);

                    if (history.TryGetValue(ncompl, out var ncomplList))
                    {
                        ncomplList.Add(n);
                    }
                    else
                    {
                        history[ncompl] = new HashSet <Entity> {
                            n
                        }
                    };
                }

                __IterAddHistory(expr);

                __IterAddHistory(expr.Replace(Patterns.InvertNegativePowers));

                MultithreadingFunctional.ExitIfCancelled();
            }

            AddHistory(stage1);
            var res = stage1;

            for (int i = 0; i < Math.Abs(level); i++)
            {
                res = res.Replace(Patterns.SortRules(i switch
                {
                    1 => TreeAnalyzer.SortLevel.MIDDLE_LEVEL,
                    2 => TreeAnalyzer.SortLevel.LOW_LEVEL,
                    _ => TreeAnalyzer.SortLevel.HIGH_LEVEL
                })).InnerSimplified;
                if (res.Nodes.Any(child => child is Powf))
                {
                    AddHistory(res = res.Replace(Patterns.PowerRules).InnerSimplified);
                }

                AddHistory(res = SimplifyChildren(res));

                AddHistory(res = res.Replace(Patterns.InvertNegativePowers).Replace(Patterns.DivisionPreparingRules).InnerSimplified);
                AddHistory(res = res.Replace(Patterns.PolynomialLongDivision).InnerSimplified);

                if (res.Nodes.Any(child => child is TrigonometricFunction))
                {
                    var res1 = res.Replace(Patterns.ExpandTrigonometricRules).InnerSimplified;
                    AddHistory(res = res.Replace(Patterns.TrigonometricRules).Replace(Patterns.CommonRules).InnerSimplified);
                    AddHistory(res1);
                    res            = PickSimplest(res, res1);
                    AddHistory(res = res.Replace(Patterns.CollapseTrigonometricFunctions).Replace(Patterns.TrigonometricRules));
                }

                if (res.Nodes.Any(child => child is Statement))
                {
                    AddHistory(res = res.Replace(Patterns.BooleanRules).InnerSimplified);
                }

                if (res.Nodes.Any(child => child is ComparisonSign))
                {
                    AddHistory(res = res.Replace(Patterns.InequalityEqualityRules).InnerSimplified);
                }

                if (res.Nodes.Any(child => child is Factorialf))
                {
                    AddHistory(res = res.Replace(Patterns.ExpandFactorialDivisions).InnerSimplified);
                    AddHistory(res = res.Replace(Patterns.FactorizeFactorialMultiplications).InnerSimplified);
                }
                if (res.Nodes.Any(child => child is Powf or Logf))
                {
                    AddHistory(res = res.Replace(Patterns.PowerRules).InnerSimplified);
                }

                if (res.Nodes.Any(child => child is Set))
                {
                    AddHistory(res = res.Replace(Patterns.SetOperatorRules).InnerSimplified);
                }

                if (res.Nodes.Any(child => child is Phif))
                {
                    AddHistory(res = res.Replace(Patterns.PhiFunctionRules).InnerSimplified);
                }

                Entity?possiblePoly = null;
                foreach (var var in res.Vars)
                {
                    if (TryPolynomial(res, var, out var resPoly) &&
                        (possiblePoly is null || resPoly.Complexity < possiblePoly.Complexity))
                    {
                        AddHistory(possiblePoly = resPoly);
                    }
                }
                if (possiblePoly is { } && possiblePoly.Complexity < res.Complexity)
Example #6
0
        /// <summary>Finds all alternative forms of an expression</summary>
        internal static IEnumerable <Entity> Alternate(Entity src, int level)
        {
            if (src is FiniteSet ss)
            {
                return new[] { ss.Apply(ent => ent.Simplify()).InnerSimplified }
            }
            ;
            if (src is Number or Variable or Entity.Boolean)
            {
                return new[] { src }
            }
            ;
            var stage1 = src.InnerSimplified;

#if DEBUG
            if (MathS.Diagnostic.CatchOnSimplify.Value(stage1))
            {
                throw new MathS.Diagnostic.DiagnosticCatchException();
            }
#endif

            if (stage1 is Number or Variable or Entity.Boolean)
            {
                return new[] { stage1 }
            }
            ;

            // List of criteria for expr's complexity
            var history = new SortedDictionary <double, HashSet <Entity> >();
            void AddHistory(Entity expr)
            {
#if DEBUG
                if (MathS.Diagnostic.CatchOnSimplify.Value(expr))
                {
                    throw new MathS.Diagnostic.DiagnosticCatchException();
                }
#endif
                void __IterAddHistory(Entity expr)
                {
                    var refexpr = expr.Replace(Patterns.SortRules(TreeAnalyzer.SortLevel.HIGH_LEVEL)).InnerSimplified;
                    var compl1  = refexpr.SimplifiedRate;
                    var compl2  = expr.SimplifiedRate;
                    var n       = compl1 > compl2 ? expr : refexpr;
                    var ncompl  = Math.Min(compl2, compl1);

                    if (history.TryGetValue(ncompl, out var ncomplList))
                    {
                        ncomplList.Add(n);
                    }
                    else
                    {
                        history[ncompl] = new HashSet <Entity> {
                            n
                        }
                    };
                }

                __IterAddHistory(expr);

                __IterAddHistory(expr.Replace(Patterns.InvertNegativePowers));

                MultithreadingFunctional.ExitIfCancelled();
            }

            AddHistory(stage1);
            var res = stage1;

            for (int i = 0; i < Math.Abs(level); i++)
            {
                var sortLevel = i switch
                {
                    1 => TreeAnalyzer.SortLevel.MIDDLE_LEVEL,
                    2 => TreeAnalyzer.SortLevel.LOW_LEVEL,
                    _ => TreeAnalyzer.SortLevel.HIGH_LEVEL
                };
                res = res.Replace(Patterns.SortRules(sortLevel)).InnerSimplified;
                if (res.Nodes.Any(child => child is Powf))
                {
                    AddHistory(res = res.Replace(Patterns.PowerRules).InnerSimplified);
                }

                AddHistory(res = SimplifyChildren(res));

                AddHistory(res = res.Replace(Patterns.InvertNegativePowers).Replace(Patterns.DivisionPreparingRules).InnerSimplified);

                AddHistory(res = res.Replace(Patterns.PolynomialLongDivision).InnerSimplified);

                AddHistory(res = res.Replace(Patterns.NormalTrigonometricForm).InnerSimplified);
                AddHistory(res = res.Replace(Patterns.CollapseMultipleFractions).InnerSimplified);
                AddHistory(res = res.Replace(e => Patterns.FractionCommonDenominatorRules(e, sortLevel)).InnerSimplified);
                AddHistory(res = res.Replace(Patterns.InvertNegativePowers).Replace(Patterns.DivisionPreparingRules).InnerSimplified);
                AddHistory(res = res.Replace(Patterns.PowerRules).InnerSimplified);
                AddHistory(res = res.Replace(Patterns.TrigonometricRules).InnerSimplified);
                AddHistory(res = res.Replace(Patterns.CollapseTrigonometricFunctions).InnerSimplified);

                if (res.Nodes.Any(child => child is TrigonometricFunction))
                {
                    var res1 = res.Replace(Patterns.ExpandTrigonometricRules).InnerSimplified;
                    AddHistory(res = res.Replace(Patterns.TrigonometricRules).Replace(Patterns.CommonRules).InnerSimplified);
                    AddHistory(res1);
                    res            = PickSimplest(res, res1);
                    AddHistory(res = res.Replace(Patterns.CollapseTrigonometricFunctions).Replace(Patterns.TrigonometricRules));
                }


                if (res.Nodes.Any(child => child is Statement))
                {
                    AddHistory(res = res.Replace(Patterns.BooleanRules).InnerSimplified);
                }


                if (res.Nodes.Any(child => child is ComparisonSign))
                {
                    AddHistory(res = res.Replace(Patterns.InequalityEqualityRules).InnerSimplified);
                }

                if (res.Nodes.Any(child => child is Factorialf))
                {
                    AddHistory(res = res.Replace(Patterns.ExpandFactorialDivisions).InnerSimplified);
                    AddHistory(res = res.Replace(Patterns.FactorizeFactorialMultiplications).InnerSimplified);
                }


                if (res.Nodes.Any(child => child is Powf or Logf))
                {
                    AddHistory(res = res.Replace(Patterns.PowerRules).InnerSimplified);
                }

                if (res.Nodes.Any(child => child is Set))
                {
                    var replaced = res.Replace(Patterns.SetOperatorRules);

                    AddHistory(res = replaced.InnerSimplified);
                }


                if (res.Nodes.Any(child => child is Phif))
                {
                    AddHistory(res = res.Replace(Patterns.PhiFunctionRules).InnerSimplified);
                }

                Entity?possiblePoly = null;
                foreach (var var in res.Vars)
                {
                    if (TryPolynomial(res, var, out var resPoly) &&
                        (possiblePoly is null || resPoly.Complexity < possiblePoly.Complexity))
                    {
                        AddHistory(possiblePoly = resPoly);
                    }
                }
                if (possiblePoly is { } && possiblePoly.Complexity < res.Complexity)
                {
                    res = possiblePoly;
                }


                AddHistory(res = res.Replace(Patterns.CommonRules));


                AddHistory(res = res.Replace(Patterns.NumericNeatRules));

                /*
                 * This was intended to simplify expressions as polynomials over nodes, some kind of
                 * greatest common node and simplifying over it. However, the current algorithm does
                 * not solve this issue completely and yet too slow to be accepted.
                 *
                 * AddHistory(res = TreeAnalyzer.Factorize(res));
                 */

                res = history[history.Keys.Min()].First();
            }
            if (level > 0) // if level < 0 we don't check whether expanded version is better
            {
                AddHistory(res.Expand().Simplify(-level));
                AddHistory(res.Factorize().Simplify(-level));
            }

            return(history.Values.SelectMany(x => x));
        }
Example #7
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 <see cref="Set"/> if successful, <see langword="null"/> otherwise</returns>
        internal static IEnumerable <Entity>?SolveAsPolynomial(Entity expr, Variable subtree)
        {
            // Safely expand the expression
            // Here we find all terms
            var children = TreeAnalyzer.GatherLinearChildrenOverSumAndExpand(expr, entity => entity.ContainsNode(subtree));

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

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

            if (monomialsByPower == null)
            {
                return(null); // meaning that the given equation is not polynomial
            }
            var res = ReduceCommonPower(ref monomialsByPower)
                ? new Entity[] { 0 } // x5 + x3 + x2 - common power is 2, one root is 0, then x3 + x + 1
                : Enumerable.Empty <Entity>();
            var powers   = monomialsByPower.Keys.ToList();
            var gcdPower = powers.Aggregate((accumulate, current) => accumulate.Gcd(current));

            // // //

            if (gcdPower.IsZero)
            {
                gcdPower = EInteger.One;
            }
            // Change all replacements, x6 + x3 + 1 => x2 + x + 1
            if (!gcdPower.Equals(EInteger.One))
            {
                for (int i = 0; i < powers.Count; i++)
                {
                    powers[i] /= gcdPower;
                }
                monomialsByPower = monomialsByPower.ToDictionary(pair => pair.Key / gcdPower, pair => pair.Value);
            }
            // // //

            MultithreadingFunctional.ExitIfCancelled();

            var gcdPowerRoots = GetAllRootsOf1(gcdPower);

            Entity GetMonomialByPower(EInteger power) =>
            monomialsByPower.TryGetValue(power, out var monomial) ? monomial.InnerSimplified : 0;

            powers.Sort();
            if (!powers.Last().CanFitInInt32())
            {
                return(null);
            }
            return((powers.Count, powers.Last().ToInt32Unchecked()) switch
            {
                (0, _) => null,
                (_, 0) => Enumerable.Empty <Entity>(),
                (> 2, > 4) => null, // So far, we can't solve equations of powers more than 4
                // 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
                (1, _) => new Entity[] { 0 },
                (2, _) =>
                // Solve a x ^ n + b = 0 for x ^ n -> x ^ n = -b / a
                MathS.Pow(subtree, Integer.Create(powers[1]))
                .Invert((-1 * monomialsByPower[powers[0]] / monomialsByPower[powers[1]]).InnerSimplified, subtree),
                (_, 2) => SolveQuadratic(GetMonomialByPower(2), GetMonomialByPower(1), GetMonomialByPower(0)),
                (_, 3) => SolveCubic(GetMonomialByPower(3), GetMonomialByPower(2), GetMonomialByPower(1), GetMonomialByPower(0)),
                (_, 4) => SolveQuartic(GetMonomialByPower(4), GetMonomialByPower(3),
                                       GetMonomialByPower(2), GetMonomialByPower(1), GetMonomialByPower(0)),
                _ => null
            } is { } resConcat