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() ?? "");
public void TestMi() { Assert.IsTrue(MathS.FromString("-i^2").Eval() == 1); }
public void TestString(string expr) => Assert.Equal(True, MathS.FromString(expr).EvalBoolean());
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); }
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)); }
public void AssertErrorWhenMultiplyingNumberAccordingToSetting(string expr) { using var _ = ExplicitParsingOnly.Set(true); Assert.Throws <InvalidArgumentParseException>(() => MathS.FromString(expr)); }
public void Test2() { const string expr = "2 ^ 3 + sin(3)"; Assert.AreEqual(expr, MathS.FromString(expr).ToString()); }
public void Test4() { MathS.FromString((MathS.Sin(x) / MathS.Cos(x)).Derive(x).ToString()); }
public void Test1() { const string expr = "1 + 2 * log(2, 3)"; Assert.AreEqual(expr, MathS.FromString(expr).ToString()); }
/// <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); }
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); }
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);
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);
public void TestDP() { Assert.IsTrue(MathS.FromString("-23").Eval() == -23); }
[Fact] public void TestDP() => Assert.Equal(-23, MathS.FromString("-23").EvalNumerical());
public void TestB() { Assert.IsTrue(MathS.FromString("1 + (-1)").Eval() == 0); }
[Fact] public void TestB() => Assert.Equal(0, MathS.FromString("1 + (-1)").EvalNumerical());
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());
public static Entity ToEntity(this String expr) => MathS.FromString(expr);
public void TestDiscrete(string inputIsOutput) => Assert.Equal(inputIsOutput, MathS.FromString(inputIsOutput).Stringize());
public void Test15() { Assert.IsTrue(MathS.FromString("x(2 + 3)").Simplify() == 5 * x); }