private static Entity TryDowncast(Entity equation, VariableEntity x, Entity root)
        {
            if (!MathS.CanBeEvaluated(root))
            {
                return(root);
            }
            var preciseValue = root.Eval();

            MathS.Settings.PrecisionErrorZeroRange.Set(1e-7m);
            MathS.Settings.FloatToRationalIterCount.Set(20);
            var downcasted = Number.Functional.Downcast(preciseValue) as ComplexNumber;

            MathS.Settings.FloatToRationalIterCount.Unset();
            MathS.Settings.PrecisionErrorZeroRange.Unset();
            var errorExpr = equation.Substitute(x, downcasted);

            if (!MathS.CanBeEvaluated(errorExpr))
            {
                return(root);
            }
            var error = errorExpr.Eval();

            bool ComplexRational(ComplexNumber a)
            => a.Real.IsRational() && a.Imaginary.IsRational();

            var innerSimplified = root.InnerSimplify();

            return(Number.IsZero(error) && ComplexRational(downcasted) ? downcasted : innerSimplified);
        }
        /// <summary>
        /// Returns true if a is inside a rect with corners from and to,
        /// OR a is an unevaluable expression
        /// </summary>
        /// <param name="a"></param>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <returns></returns>
        private static bool EntityInBounds(Entity a, ComplexNumber from, ComplexNumber to)
        {
            if (!MathS.CanBeEvaluated(a))
            {
                return(true);
            }
            var r = a.Eval();

            return(r.Real >= from.Real &&
                   r.Imaginary >= from.Imaginary &&
                   r.Real <= to.Real &&
                   r.Imaginary <= to.Imaginary);
        }
Example #3
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?
        }
Example #4
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()));
        }
        /// <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);
        }
Example #6
0
 /// <summary>
 /// So that any numberical operations could be performed
 /// </summary>
 /// <returns></returns>
 internal bool IsNumeric()
 => (MathS.CanBeEvaluated(LowerBound().Item1) && MathS.CanBeEvaluated(UpperBound().Item1));
        /// <summary>
        /// All constants, no matter multiplied or divided, are numerator's coefficients:
        /// 2 * x / 3 => num: 2 / 3
        ///
        /// All entities that contain x and have a real negative power are denominator's multipliers
        /// 2 / (x + 3) => den: [x + 3]
        /// 2 / ((x^(-1) + 3) * (x2 + 1)) => den: [x^(-1) + 3, x2 + 1]
        ///
        /// All entities that have complex power are considered as product of an entity with a real power
        /// and an entity whole power's real part is 0
        /// x ^ (-1 + 2i) => num: x ^ (2i), den: [x]
        /// x ^ (3 - 2i) => num: x ^ (3 - 2i), den: []
        ///
        /// </summary>
        /// <param name="term"></param>
        /// <returns></returns>
        internal static (Entity numerator, List <(Entity den, RealNumber pow)> denominatorMultipliers) FindFractions(Entity term, VariableEntity x)
        {
            // TODO: consider cases where we should NOT gather all powers in row
            Entity GetPower(Entity expr)
            {
                if (expr.entType != Entity.EntType.OPERATOR || expr.Name != "powf")
                {
                    return(1);
                }
                else
                {
                    return(expr.Children[1] * GetPower(expr.Children[0]));
                }
            }

            Entity GetBase(Entity expr)
            {
                if (expr.entType != Entity.EntType.OPERATOR || expr.Name != "powf")
                {
                    return(expr);
                }
                else
                {
                    return(GetBase(expr.Children[0]));
                }
            }

            (Entity numerator, List <(Entity den, RealNumber pow)> denominatorMultipliers)oneInfo;
            oneInfo.numerator = 1; // Once InnerSimplify is called, we get rid of 1 *
            oneInfo.denominatorMultipliers = new List <(Entity den, RealNumber pow)>();

            var multipliers = TreeAnalyzer.LinearChildren(term, "mulf", "divf", Const.FuncIfMul);
            var res         = new FractionInfoList();

            foreach (var multiplyer in multipliers)
            {
                if (multiplyer.FindSubtree(x) == null)
                {
                    oneInfo.numerator *= multiplyer;
                    continue;
                }
                var power = GetPower(multiplyer);
                if (!MathS.CanBeEvaluated(power))
                {
                    oneInfo.numerator *= multiplyer;
                    continue;
                }
                var preciseValue = power.Eval();
                if (preciseValue.IsImaginary())
                {
                    oneInfo.numerator *= multiplyer;
                    continue;
                }
                var realPart = preciseValue as RealNumber;
                if (realPart > 0)
                {
                    oneInfo.numerator *= multiplyer;
                    continue;
                }
                oneInfo.denominatorMultipliers.Add((GetBase(multiplyer), realPart));
            }

            return(oneInfo);
        }
 /// <summary>
 /// If an evaluable expression is equal to zero, true, otherwise, false
 /// For example, 1 - 1 is zero, but 1 + a is not
 /// </summary>
 /// <param name="e"></param>
 /// <returns></returns>
 internal static bool IsZero(Entity e) => MathS.CanBeEvaluated(e) && e.Eval() == 0;