예제 #1
0
 public static Entity ParseExpression(string latexIn)
 {
     return(MathS.FromString(ConvertToMathString(latexIn)).Simplify());
 }
 public void Test2() => Assert.IsTrue(Measure(() => MathS.FromString("x + log(2, 4)^2 * sin(cos(sin(cos(5)))) + x^3")) < 10);
 public void Test4() => MathS.FromString((MathS.Sin(x) / MathS.Cos(x)).Differentiate(x).Stringize() ?? "");
예제 #4
0
 public void TestMi()
 {
     Assert.IsTrue(MathS.FromString("-i^2").Eval() == 1);
 }
 public void TestString(string expr)
 => Assert.Equal(True, MathS.FromString(expr).EvalBoolean());
예제 #6
0
        public CalcResult Compute()
        {
            CalcResult res = new CalcResult();

            try
            {
                // INITIALIZATION OF STUFF
                Lexer         lexer         = new Lexer(rawExpression);
                TokenList     tokenList     = lexer.GenerateTokens();
                Parser        parser        = new Parser(tokenList);
                PostTokenList postTokenList = parser.Parse();
                postTokenList.Freeze();
                MathPreprocessor mathPreprocessor = new MathPreprocessor(postTokenList);
                mathPreprocessor.Process();
                MajorSegmentList         majorSegmentList   = mathPreprocessor.GetSegments();
                List <ExpressionSegment> expressionSegments = new List <ExpressionSegment>();
                expressionSegments.Add(
                    (ExpressionSegment)majorSegmentList.Select("expression").Item()
                    );

                // PROCESSING SOME `WHERE` AND `FOR` TOKENS
                for (int i = majorSegmentList.Count - 1; i >= 0; i--)
                {
                    if (majorSegmentList[i] is ExpressionSegment)
                    {
                        break;
                    }
                    if (majorSegmentList[i] is EqKeyword
                        &&
                        (((EqKeyword)majorSegmentList[i]).Type == Keyword.Type.WHERE ||
                         ((EqKeyword)majorSegmentList[i]).Type == Keyword.Type.FOR)
                        &&
                        FixedKeyword.IsVariable(((EqKeyword)majorSegmentList[i]).GetBeforeEq())
                        &&
                        (CustomData.GetType(((EqKeyword)majorSegmentList[i]).GetAfterEq()) == CustomData.Type.FIXED))
                    {
                        string v    = ((EqKeyword)majorSegmentList[i]).GetBeforeEq();
                        string expr = ((EqKeyword)majorSegmentList[i]).GetAfterEq();
                        expressionSegments[0].Substitute(v, expr);
                    }
                    else
                    {
                        majorSegmentList[i].Ignored = true;
                    }
                }

                MajorSegmentList newExpression = majorSegmentList.CutTill(expressionSegments[0]);
                res.InterpretedAs.Add(expressionSegments[0].Build());
                List <MajorSegmentList> list = DivideByField(newExpression);
                var simplOpt = new MajorSegmentList();
                simplOpt.Add(new FieldSegment("simplify", "", Field.Type.SIMPLIFICATION));
                list.Insert(0, simplOpt);

                // SEQUENTIAL PROCESSING
                list.Reverse();
                foreach (var fieldOpts in list)
                {
                    bool isLast = fieldOpts == list[list.Count - 1];

                    // PROCESSING SOME `WHERE` AND `FOR` TOKENS
                    foreach (var expressionSegment in expressionSegments)
                    {
                        for (int i = 1; i < fieldOpts.Count; i++)
                        {
                            if (fieldOpts[i] is EqKeyword &&
                                ((fieldOpts[i] as EqKeyword).Type == Keyword.Type.WHERE ||
                                 (fieldOpts[i] as EqKeyword).Type == Keyword.Type.FOR) &&
                                CustomData.GetType((fieldOpts[i] as EqKeyword).GetAfterEq()) == CustomData.Type.FIXED &&
                                CustomData.GetType((fieldOpts[i] as EqKeyword).GetBeforeEq()) == CustomData.Type.FIXED &&
                                FixedKeyword.IsVariable((fieldOpts[i] as EqKeyword).GetBeforeEq()))
                            {
                                expressionSegment.Substitute((fieldOpts[i] as EqKeyword).GetBeforeEq(), (fieldOpts[i] as EqKeyword).GetAfterEq());
                            }
                        }
                        res.InterpretedAs.Add(fieldOpts.Build() + " " + expressionSegment.Build());
                    }

                    var fieldType = FindField(fieldOpts[0].Keyname);

                    List <string> newExprs      = new List <string>();
                    List <string> newLatexExprs = new List <string>();
                    bool          quickExit     = false;
                    foreach (var expressionSegment in expressionSegments)
                    {
                        if (fieldType == FieldType.BOOL)
                        {
                            var vars = expressionSegment.tokens.ExtractVariables();
                            vars = Functions.MakeUnique(vars);
                            foreach (var v in vars)
                            {
                                if (v.Length > 1)
                                {
                                    throw new ParsingException("Multi-symbol vars are forbidden in boolean mode");
                                }
                            }
                            var    be = new BoolEng(expressionSegment.Build());
                            string newExpr;
                            newExpr = be.CompileTable();
                            string line = "{";
                            foreach (var onevar in vars)
                            {
                                line += ": " + onevar + " %";
                            }
                            line   += ": F %}\n";
                            newExpr = line + newExpr;
                            newExprs.Add(newExpr);
                            {
                                newExpr = newExpr.Replace(":", "<th>");
                                newExpr = newExpr.Replace("%", "</th>");
                                newExpr = newExpr.Replace("{", "<tr>");
                                newExpr = newExpr.Replace("}", "</tr>");
                                newExpr = newExpr.Replace("[", "<td class=\"cellbool-res\">");
                                newExpr = newExpr.Replace("]", "</td>");
                                newExpr = newExpr.Replace("\n", "");
                                newExpr = "<table id=\"bool-res\">" + newExpr + "</table>";
                            }
                            newLatexExprs.Add(newExpr);
                            quickExit = true;
                            break;
                        }
                        else if (AscCalc.MathAnalysis.Contains(fieldType))
                        {
                            expressionSegment.tokens.AddOmittedOps();
                            var    vars = expressionSegment.tokens.ExtractVariables();
                            string diffVar;
                            vars = Functions.MakeUnique(vars);
                            if (fieldOpts.Select(Names.FOR).Count == 0)
                            {
                                if (vars.Contains("x") || vars.Count == 0)
                                {
                                    diffVar = "x";
                                }
                                else if (vars.Contains("y"))
                                {
                                    diffVar = "y";
                                }
                                else
                                {
                                    diffVar = vars[0];
                                }
                                res.InterpretedAs.Add("Interpreted as `" + Names.FOR + " " + diffVar + "`");
                            }
                            else if (fieldOpts.Select(Names.FOR).Count == 1)
                            {
                                diffVar = (fieldOpts.Select(Names.FOR).Item() as FixedKeyword).GetVariable();
                            }
                            else
                            {
                                diffVar = (fieldOpts.Select(Names.FOR)[0] as FixedKeyword).GetVariable();
                            }
                            vars.Add(diffVar);
                            vars = Functions.MakeUnique(vars);
                            string req = expressionSegment.Build();
                            if (fieldType == FieldType.DERIVATIVE)
                            {
                                newExprs.Add(MathS.FromString(req).Derive(MathS.Var(diffVar)).ToString());
                                if (isLast && latex)
                                {
                                    newLatexExprs.Add("$$" + MathS.FromString(req).Derive(MathS.Var(diffVar)).Latexise().ToString() + "$$");
                                }
                            }
                            else if (fieldType == FieldType.SOLVE)
                            {
                                expressionSegment.tokens.AddOmittedOps();
                                if (vars.Count > 1)
                                {
                                    throw new InvalidRequestException();
                                }
                                var roots = MathS.FromString(req).SolveNt(MathS.Var(diffVar), precision: 400);
                                foreach (var root in roots)
                                {
                                    newExprs.Add(root.ToString());
                                }
                                if (isLast && latex)
                                {
                                    foreach (var root in roots)
                                    {
                                        newExprs.Add("$$" + root.ToString() + "$$");
                                    }
                                }
                            }
                        }

                        else if (fieldType == FieldType.SIMPLIFICATION)
                        {
                            expressionSegment.tokens.AddOmittedOps();
                            var vars = expressionSegment.tokens.ExtractVariables();
                            vars = Functions.MakeUnique(vars);
                            string req = expressionSegment.Build();
                            string newExpr;
                            newExpr = MathS.FromString(req).SimplifyIntelli().ToString();
                            newExprs.Add(newExpr);
                            if (isLast && latex)
                            {
                                newExpr = MathS.FromString(req).SimplifyIntelli().Latexise();
                                newLatexExprs.Add("$$" + newExpr + "$$");
                            }
                        }
                    }
                    if (newExprs.Count == 0)
                    {
                        res.Result = "No answer";
                        break;
                    }
                    if (!isLast && !quickExit)
                    {
                        expressionSegments = new List <ExpressionSegment>();
                        foreach (var nexp in newExprs)
                        {
                            expressionSegments.Add(new ExpressionSegment("expression", nexp));
                        }
                    }
                    else
                    {
                        res.Result = "";
                        foreach (var segm in newExprs)
                        {
                            res.Result += segm + " ";
                        }
                        res.LatexResult = "";
                        foreach (var segm in newLatexExprs)
                        {
                            res.LatexResult += segm + " ";
                        }
                        break; // For quickExit case
                    }
                }
            }
            catch (Exception e)
            {
                throw e;
            }
            return(res);
        }
예제 #7
0
 public void TestDM()
 {
     Assert.IsTrue(MathS.FromString("1 + -1").Eval() == 0);
 }
        public void TestSqrt()
        {
            var expr = MathS.FromString("sqrt(x)");

            Assert.IsTrue(expr == MathS.Sqrt(x));
        }
예제 #9
0
 public void AssertErrorWhenMultiplyingNumberAccordingToSetting(string expr)
 {
     using var _ = ExplicitParsingOnly.Set(true);
     Assert.Throws <InvalidArgumentParseException>(() => MathS.FromString(expr));
 }
예제 #10
0
        public void Test2()
        {
            const string expr = "2 ^ 3 + sin(3)";

            Assert.AreEqual(expr, MathS.FromString(expr).ToString());
        }
예제 #11
0
 public void Test4()
 {
     MathS.FromString((MathS.Sin(x) / MathS.Cos(x)).Derive(x).ToString());
 }
예제 #12
0
        public void Test1()
        {
            const string expr = "1 + 2 * log(2, 3)";

            Assert.AreEqual(expr, MathS.FromString(expr).ToString());
        }
예제 #13
0
        /// <summary>
        /// A dirty way to convert to an AngouriMath string without actually parsing LaTeX.
        /// </summary>
        /// <remarks>
        /// This converter is much more picky than <see cref="ConvertToMathString(string)"/>,
        /// but in most cases it will be faster.
        /// </remarks>
        public static string DirtyConvertToMathString(string latexIn)
        {
            string output  = "";
            var    matches = Regex.Matches(latexIn.Replace(@"\ ", " "), @"\\?(\{.*\}|[^\\\s])*");

            foreach (Match m in matches)
            {
                string lPart = m.Value;
                if (lPart.Length == 0)
                {
                    continue;
                }

                if (Char.IsDigit(lPart[0]) && Char.IsLetter(lPart.Last()) && lPart.All(c => Char.IsLetterOrDigit(c)))
                {
                    int startOfVar = 1;
                    while (Char.IsDigit(lPart[startOfVar]))
                    {
                        if (startOfVar + 1 < lPart.Length)
                        {
                            startOfVar++;
                        }
                    }
                    lPart = lPart.Insert(startOfVar, "*");
                }
                else if (Char.IsLetter(lPart[0]) && Char.IsDigit(lPart.Last()) && lPart.All(c => Char.IsLetterOrDigit(c)))
                {
                    int startOfNum = 1;
                    while (Char.IsLetter(lPart[startOfNum]))
                    {
                        if (startOfNum + 1 < lPart.Length)
                        {
                            startOfNum++;
                        }
                    }
                    lPart = lPart.Insert(startOfNum, "*");
                }

                else if (!lPart.StartsWith("\\"))
                {
                    // Do nothing, but skip the branches that check for LaTeX commands
                }
                else if (lPart.StartsWith(@"\,") || lPart.StartsWith(@"\:") || lPart.StartsWith(@"\;") ||
                         lPart.StartsWith(@"\,") || lPart.StartsWith(@"\ "))
                {
                    // Replace the LaTeX command with a space
                    lPart = " " + lPart.Remove(0, 2);
                }
                else if (lPart.StartsWith(@"\quad"))
                {
                    lPart = "  " + lPart.Remove(0, @"\quad".Length);
                }
                else if (lPart.StartsWith(@"\qquad"))
                {
                    lPart = "   " + lPart.Remove(0, @"\qquad".Length);
                }
                else if (lPart.StartsWith(@"\cdot"))
                {
                    lPart = lPart.Replace(@"\cdot", "*");
                }
                else if (lPart.StartsWith(@"\sin") || lPart.StartsWith(@"\cos") || lPart.StartsWith(@"\tan") ||
                         lPart.StartsWith(@"\arcsin") || lPart.StartsWith(@"\arccos") || lPart.StartsWith(@"\arctan") ||
                         lPart.StartsWith(@"\csc") || lPart.StartsWith(@"\sec") || lPart.StartsWith(@"\cot"))
                {
                    lPart = lPart.Remove(0, 1); // Just remove the slash
                }
                else if (lPart.StartsWith(@"\left"))
                {
                    lPart = lPart.Remove(0, @"\left".Length);
                }
                else if (lPart.StartsWith(@"\right"))
                {
                    lPart = lPart.Remove(0, @"\right".Length);
                }
                else if (lPart.StartsWith(@"\over"))
                {
                    lPart = lPart.Replace(@"\over", "/");
                }
                else if (lPart.StartsWith(@"\frac"))
                {
                    var parameters = ParseParameters(lPart);

                    // Handle derivatives
                    if (parameters.Count >= 3 && parameters[0].StartsWith("d") && parameters[1].StartsWith("d"))
                    {
                        // Get the variable to derive with respect to
                        string varName = Regex.Match(parameters[1], @"d(\S)$").Value.Substring(1);
                        var    varWRT  = MathS.Var(varName);

                        // Derive the function with respect to varWRT
                        var derFunc = MathS.FromString(parameters[2], true).Differentiate(varWRT);
                        lPart = derFunc.Simplify().ToString();
                    }
                    else
                    {
                        lPart = $"({parameters[0]})/({parameters[1]})";
                    }
                }
                else if (lPart.StartsWith(@"\sqrt"))
                {
                    var parameters = ParseParameters(lPart);
                    lPart = $"sqrt({parameters[0]})";
                }
                else if (lPart.StartsWith(@"\int"))
                {
                    // User must put paratheses around the expression to integrate
                    var parameters = ParseParameters(lPart);
                    if (parameters.Count == 3)
                    {
                        string expression = parameters[2];

                        // Get the variable to integrate with respect to
                        string varName = Regex.Match(expression, @"d(\S)$").Value;
                        if (!String.IsNullOrEmpty(varName))
                        {
                            expression = expression.Replace(varName, String.Empty);
                            varName    = varName.Substring(1);
                        }
                        else
                        {
                            varName = "x";
                        }
                        var varWRT = MathS.Var(varName);

                        // TODO: Support expressions for start and end
                        // Get start and end of interval
                        double start = Double.Parse(parameters[0]);
                        double end   = Double.Parse(parameters[1]);

                        var intFunc = MathS.FromString(expression).Integrate(varWRT);
                        lPart = (intFunc.Substitute(varWRT, end) - intFunc.Substitute(varWRT, start)).Simplify().ToString();
                    }
                    else if (parameters.Count == 1)
                    {
                        string expression = parameters[0];

                        // Get the variable to integrate with respect to
                        string varName = Regex.Match(expression, @"d(\S)$").Value;
                        if (!String.IsNullOrEmpty(varName))
                        {
                            expression = expression.Replace(varName, String.Empty);
                            varName    = varName.Substring(1);
                        }
                        else
                        {
                            varName = "x";
                        }
                        var varWRT = MathS.Var(varName);

                        lPart = MathS.FromString(expression).Integrate(varWRT).Simplify().ToString();
                    }
                }

                output += lPart;
            }
            return(output);
        }
예제 #14
0
        public static string ConvertToMathString(IList <MathAtom> atoms)
        {
            string output = "";

            for (int i = 0; i < atoms.Count; i++)
            {
                var atom = atoms[i];
                if (atom is Variable variable)
                {
                    output += atom.Nucleus;
                    if (i + 1 < atoms.Count && atoms[i + 1] is Variable)
                    {
                        output += "*";
                    }
                }
                else if (atom is Fraction fraction)
                {
                    output += $"({ConvertToMathString(fraction.Numerator)})/({ConvertToMathString(fraction.Denominator)})";
                }
                else if (atom is Inner inner)
                {
                    output += $"({ConvertToMathString(inner.InnerList)})";
                }
                else if (atom is BinaryOperator binaryOperator)
                {
                    if (binaryOperator.Nucleus == "·")
                    {
                        output += "*";
                    }
                }
                else if (atom is LargeOperator largeOperator)
                {
                    if (largeOperator.Nucleus == "∫")
                    {
                        // Figure out which kind of intergral we're dealing with
                        if (largeOperator.Subscript.Count > 0 || largeOperator.Superscript.Count > 0)
                        {
                            // Definite integral

                            // Find the variable to integrate with respect to
                            bool foundWRT = false;
                            int  idxOfWRT = i + 1;
                            while (!foundWRT && idxOfWRT + 1 < atoms.Count)
                            {
                                foundWRT = atoms[idxOfWRT] is Variable intWRTMarker && intWRTMarker.Nucleus == "d" &&
                                           atoms[idxOfWRT + 1] is Variable;
                                idxOfWRT++;
                            }

                            // Get the bounds of integration
                            LaTeXParser.MathListFromLaTeX(@"\infty").Deconstruct(out MathList defaultUpperBound, out _);
                            LaTeXParser.MathListFromLaTeX(@"-\infty").Deconstruct(out MathList defaultLowerBound, out _);
                            var upperBound = MathS.FromString(
                                ConvertToMathString(largeOperator.Superscript.Count == 0 ? defaultUpperBound : largeOperator.Superscript)
                                );
                            var lowerBound = MathS.FromString(
                                ConvertToMathString(largeOperator.Subscript.Count == 0 ? defaultLowerBound : largeOperator.Subscript)
                                );

                            // Get the list of atoms that we need to integrate
                            // i+1 to skip the integral symbol, and idxOfWRT-i-2 to remove the dx
                            var intAtoms = atoms.Skip(i + 1).Take(idxOfWRT - i - 2).ToList();

                            // Calculate the integral of the expression
                            var varWRT         = MathS.Var(foundWRT ? atoms[idxOfWRT].Nucleus : "x");
                            var antiderivative = MathS.FromString(ConvertToMathString(intAtoms)).Integrate(varWRT).Simplify();
                            output += (antiderivative.Substitute(varWRT, upperBound) - antiderivative.Substitute(varWRT, lowerBound)).Simplify().ToString();

                            // Make sure the atoms involved in the integration aren't parsed again
                            i = idxOfWRT;
                            continue;
                        }
                        else
                        {
                            // Indefinite integral

                            // Find the variable to integrate with respect to
                            bool foundWRT = false;
                            int  idxOfWRT = i + 1;
                            while (!foundWRT && idxOfWRT + 1 < atoms.Count)
                            {
                                foundWRT = atoms[idxOfWRT] is Variable intWRTMarker && intWRTMarker.Nucleus == "d" &&
                                           atoms[idxOfWRT + 1] is Variable;
                                idxOfWRT++;
                            }

                            // Get the list of atoms that we need to integrate
                            // i+1 to skip the integral symbol, and idxOfWRT-i-2 to remove the dx
                            var intAtoms = atoms.Skip(i + 1).Take(idxOfWRT - i - 2).ToList();

                            // Calculate the integral of the expression
                            var varWRT = MathS.Var(foundWRT ? atoms[idxOfWRT].Nucleus : "x");
                            output += MathS.FromString(ConvertToMathString(intAtoms)).Integrate(varWRT).Simplify().ToString();

                            // Make sure the atoms involved in the integration aren't parsed again
                            i = idxOfWRT;
                            continue;
                        }
                    }
                    else
                    {
                        output += atom.Nucleus;
                    }
                }
                else
                {
                    output += atom.Nucleus;
                }

                if (atom.Superscript.Count > 0)
                {
                    output += $"^({ConvertToMathString(atom.Superscript)})";
                }
            }
            return(output);
        }
예제 #15
0
        public void VarsExpanded(string expr, int rootCount)
        {
            var eq = MathS.FromString(expr);

            TestSolver(eq.Expand(), rootCount);
        }
 // Testing parsing
 [Benchmark] public void ParseEasy() => MathS.FromString("1 + 2 / x + 2 / (y + x)", useCache: false);
예제 #17
0
        public void Vars(string expr, int rootCount)
        {
            var eq = MathS.FromString(expr);

            TestSolver(eq, rootCount);
        }
 [Benchmark] public void ParseHard() => MathS.FromString("x ^ (x + y ^ 2 ^ sin(3 / z + i)) - log(-i, 3) ^ (x + x * y) - sqrt(y) / (i + sqrt(-1))", useCache: false);
예제 #19
0
 public void TestDP()
 {
     Assert.IsTrue(MathS.FromString("-23").Eval() == -23);
 }
 [Fact] public void TestDP() => Assert.Equal(-23, MathS.FromString("-23").EvalNumerical());
예제 #21
0
 public void TestB()
 {
     Assert.IsTrue(MathS.FromString("1 + (-1)").Eval() == 0);
 }
 [Fact] public void TestB() => Assert.Equal(0, MathS.FromString("1 + (-1)").EvalNumerical());
예제 #23
0
 public void TestMm()
 {
     Assert.IsTrue(MathS.FromString("-1 * -1 * -1").Eval() == -1);
 }
 [Fact] public void TestMi() => Assert.Equal(1, MathS.FromString("-i^2").EvalNumerical());
 public void Test1() => Assert.IsTrue(Measure(() => MathS.FromString("x + x^2 + x^3")) < 4);
 [Fact] public void TestMm() => Assert.Equal(-1, MathS.FromString("-1 * -1 * -1").EvalNumerical());
 public void Circle(string inputIsOutput) =>
 Assert.Equal(inputIsOutput, MathS.FromString(inputIsOutput).Stringize());
예제 #28
0
 public static Entity ToEntity(this String expr)
 => MathS.FromString(expr);
 public void TestDiscrete(string inputIsOutput) =>
 Assert.Equal(inputIsOutput, MathS.FromString(inputIsOutput).Stringize());
예제 #30
0
 public void Test15()
 {
     Assert.IsTrue(MathS.FromString("x(2 + 3)").Simplify() == 5 * x);
 }