Skip to content

Commit

Permalink
CSharpMath.Evaluation.Interpret tests (#151)
Browse files Browse the repository at this point in the history
* Added Interpret Tests + Deterministic Builds

* Fix build

* Fix build 2

* Simplify stuff

* Make Extensions.cs the top-level source file of CSharpMath

* ?? Windows?

* Update Build.yml

* E

* Update Build.yml

* Try fix?

* Update Build.yml

* Detect dotnet msbuild

* Update Directory.Build.props

* Update Test.yml

* Update Test.yml

* Sleeping does nothing

* Simplify

* Update Test.yml

* Update local build version

* Update Test.yml
  • Loading branch information
Happypig375 committed Aug 2, 2020
1 parent cecc4b0 commit 0f81662
Show file tree
Hide file tree
Showing 20 changed files with 279 additions and 320 deletions.
9 changes: 4 additions & 5 deletions .github/release-drafter.yml
Expand Up @@ -39,12 +39,11 @@ categories:
label: 'Type/Housekeeping'
# Extra line before $BODY or markdown on the first line of $BODY will be interpreted as plain text
change-template: |
<details><summary>$TITLE (#$NUMBER) @$AUTHOR</summary>
<details><summary>`$TITLE` (#$NUMBER) @$AUTHOR</summary><table><td>
$BODY
</details>
</td></table></details>
no-changes-template: '* (No changes)'
replacers:
# We don't support nested <summary> and <details> so we add a (?!<details>|<summary>)
- search: '/<details><summary>((?:(?!<details>|<summary>).)+?)<\/summary>\s*<\/details>/g'
- search: '/<details><summary>(.+?)<\/summary><table><td>\s*<\/td><\/table><\/details>/g'
replace: '- $1'
2 changes: 1 addition & 1 deletion .github/workflows/Build.yml
Expand Up @@ -18,5 +18,5 @@ jobs:
uses: warrenbuckley/Setup-MSBuild@v1
- name: Restore NuGet Packages
run: nuget restore CSharpMath.sln
- name: Build CI artifacts
- name: Build Everything
run: msbuild CSharpMath.sln /p:Configuration=Release
17 changes: 6 additions & 11 deletions .github/workflows/Test.yml
Expand Up @@ -10,12 +10,6 @@ jobs:
uses: release-drafter/release-drafter@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: cardinalby/git-get-release-action@v1
id: release_info
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
releaseId: ${{ steps.release_drafter.outputs.id }}
- uses: actions/checkout@v2
with:
submodules: 'recursive'
Expand All @@ -35,9 +29,9 @@ jobs:
- name: Build and Test
env:
RELEASE_NOTES: |
# ${{ steps.release_info.outputs.name }}
# ${{ steps.release_drafter.outputs.name }}
${{ steps.release_info.outputs.body }}
${{ steps.release_drafter.outputs.body }}
# run: dotnet test CSharpMath.CrossPlatform.slnf
run: | # https://github.com/dotnet/sdk/issues/10409, https://github.com/dotnet/sdk/issues/11417
# .NET Core MSBuild cannot parse , and ; correctly so we replace them with substitutions: https://github.com/dotnet/msbuild/issues/471#issuecomment-366268743
Expand All @@ -60,16 +54,17 @@ jobs:
dotnet add "$p" package Microsoft.NET.Test.Sdk # Update is required for GitHubActionsTestLogger to print anything
dotnet add "$p" package GitHubActionsTestLogger
# -r for restore
dotnet msbuild -r -p:Configuration=Release -p:PackageVersion=${{ steps.release_drafter.outputs.tag_name }}-ci-${{ github.sha }} -p:PackageReleaseNotes="$RELEASE_NOTES" "$p"
dotnet msbuild -r -p:Configuration=Release -p:PackageVersion=${{ steps.release_drafter.outputs.tag_name || format('{0}-pr', github.event.number) }}-ci-${{ github.sha }} -p:PackageReleaseNotes="$RELEASE_NOTES" "$p"
# --no-build because building again will produce additional NuGet packages without the PackageVersion setting above
dotnet test "$p" --no-build -c Release -l GitHubActions --blame
done
- uses: actions/upload-artifact@v2
- name: Upload CSharpMath.Rendering.Tests results as CI artifacts
uses: actions/upload-artifact@v2
if: always() # Run even when a previous step failed: https://stackoverflow.com/a/58859404/5429648
with:
name: CSharpMath.Rendering.Tests results
path: CSharpMath.Rendering.Tests/*/*.png
- name: Upload CI artifacts
- name: Upload NuGet packages as CI artifacts
uses: actions/upload-artifact@v2
if: always()
with:
Expand Down
26 changes: 15 additions & 11 deletions CSharpMath.Evaluation.Tests/EvaluationTests.cs
Expand Up @@ -3,12 +3,12 @@
using Xunit;
using AngouriMath;

namespace CSharpMath {
namespace CSharpMath.EvaluationTests {
using Atom;
public partial class EvluationTests {
MathList ParseLaTeX(string latex) =>
public class EvaluationTests {
internal static MathList ParseLaTeX(string latex) =>
LaTeXParser.MathListFromLaTeX(latex).Match(list => list, e => throw new Xunit.Sdk.XunitException(e));
Evaluation.MathItem ParseMath(string latex) =>
static Evaluation.MathItem ParseMath(string latex) =>
Evaluation.Evaluate(ParseLaTeX(latex)).Match(entity => entity, e => throw new Xunit.Sdk.XunitException(e));
void Test(string input, string converted, string? result) {
void Test(string input) {
Expand Down Expand Up @@ -424,7 +424,10 @@ public partial class EvluationTests {
[InlineData(@"\sin^a\ \; (x)^2(x)", @"\sin \left( x\right) ^{a\times 2}\times x", @"\sin \left( x\right) ^{2\times a}\times x")]
[InlineData(@"\sin (\frac\pi2)", @"\sin \left( \frac{\pi }{2}\right) ", @"1")]
[InlineData(@"\sin (\frac\pi2)+1", @"\sin \left( \frac{\pi }{2}\right) +1", @"2")]
public void Parentheses(string latex, string converted, string result) => Test(latex, converted, result);
public void Parentheses(string latex, string converted, string result) {
Test(latex, converted, result);
Test(latex.Replace('(', '[').Replace(')', ']'), converted, result);
}
[Theory]
[InlineData(@"\begin{matrix}1\end{matrix}", @"\left( \begin{matrix}1\end{matrix}\right) ", @"\left( \begin{matrix}1\end{matrix}\right) ")]
[InlineData(@"\begin{pmatrix}1\end{pmatrix}", @"\left( \begin{matrix}1\end{matrix}\right) ", @"\left( \begin{matrix}1\end{matrix}\right) ")]
Expand Down Expand Up @@ -580,11 +583,12 @@ public partial class EvluationTests {
[InlineData(@"\left(1+\right]", "Missing right operand for +")]
[InlineData(@"\left(2,3\right]^\square", "Placeholders should be filled")]
[InlineData(@"(2,3]^\square", "Placeholders should be filled")]
[InlineData(@"[]", "Unrecognized bracket pair [ ]")]
[InlineData(@"[x]", "Unrecognized bracket pair [ ]")]
[InlineData(@"[[x]", "Unrecognized bracket pair [ ]")]
[InlineData(@"[x]]", "Unrecognized bracket pair [ ]")]
[InlineData(@"\left[\right]", "Unrecognized bracket pair [ ]")]
[InlineData(@"[]", "Missing math inside [ ]")]
[InlineData(@"[[x]", "Missing ]")]
[InlineData(@"[x]]", "Missing [")]
[InlineData(@"[_\square x]", "Subscripts are unsupported for Open [")]
[InlineData(@"[x]_\square", "Subscripts are unsupported for Close ]")]
[InlineData(@"\left[\right]", "Missing math inside [ ]")]
[InlineData(@"\left[1+\right]", "Missing right operand for +")]
[InlineData(@"\left[2,3\right]^\square", "Placeholders should be filled")]
[InlineData(@"[2,3]^\square", "Placeholders should be filled")]
Expand Down Expand Up @@ -633,7 +637,7 @@ public partial class EvluationTests {
[InlineData(@"+(3,4]", "Set cannot be right operand for +")]
[InlineData(@"[5,6)\times", "Set cannot be left operand for ×")]
[InlineData(@"\frac{[7,8]}{9}", "Set cannot be numerator")]
[InlineData(@"\sqrt[{[]}]{}", "Unrecognized bracket pair [ ]")]
[InlineData(@"\sqrt[{[)}]{}", "Unrecognized bracket pair [ )")]
[InlineData(@"\sqrt[{[a,b]}]{}", "Set cannot be degree")]
[InlineData(@"\{\{\}\}", "Set cannot be set element")]
[InlineData(@"\cap", "Unsupported Unary Operator ∩")]
Expand Down
26 changes: 26 additions & 0 deletions CSharpMath.Evaluation.Tests/InterpretTests.cs
@@ -0,0 +1,26 @@
using System;
using System.Linq;
using Xunit;
namespace CSharpMath.EvaluationTests {
public class InterpretTests {
[Theory]
[InlineData(@"", @"\color{red}\text{There is nothing to evaluate}")]
[InlineData(@"1", @"\underline\mathrm{Input}\\1\\\\\underline\mathrm{Simplified}\\1\\\\\underline\mathrm{Value\ (100\ digits)}\\1")]
[InlineData(@"1+", @"\color{red}\text{Missing right operand for +}")]
[InlineData(@"1+2", @"\underline\mathrm{Input}\\1+2\\\\\underline\mathrm{Simplified}\\3\\\\\underline\mathrm{Value\ (100\ digits)}\\3")]
[InlineData(@"1+\sqrt", @"\color{red}\text{Missing radicand}")]
[InlineData(@"1+\sqrt2", @"\underline\mathrm{Input}\\1+\sqrt{2}\\\\\underline\mathrm{Simplified}\\1+\sqrt{2}\\\\\underline\mathrm{Value\ (100\ digits)}\\2.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573")]
[InlineData(@"1+\sqrt{2x}", @"\underline\mathrm{Input}\\1+\sqrt{2\times x_{}}\\\\\underline\mathrm{Simplified}\\1+\sqrt{2\times x_{}}\\\\\underline\mathrm{Expanded}\\1+\sqrt{2\times x_{}}\\\\\underline\mathrm{Factorized}\\1+\sqrt{2\times x_{}}")]
[InlineData(@"1+\sqrt{2xy}", @"\underline\mathrm{Input}\\1+\sqrt{2\times x_{}\times y_{}}\\\\\underline\mathrm{Simplified}\\1+\sqrt{2\times x_{}\times y_{}}\\\\\underline\mathrm{Expanded}\\1+\sqrt{2\times x_{}\times y_{}}\\\\\underline\mathrm{Factorized}\\1+\sqrt{2\times x_{}\times y_{}}")]
[InlineData(@"=1+\sqrt{2xy}", @"\color{red}\text{Missing left side of equation}")]
[InlineData(@"1+\sqrt{2xy}=", @"\color{red}\text{Missing right side of equation}")]
[InlineData(@"1+\sqrt{2xy}=3", @"\underline\mathrm{Input}\\1+\sqrt{2\times x_{}\times y_{}}=3\\\\\underline\mathrm{Solutions}\\x_{}\in \left\{\frac{--\frac{4}{y_{}}}{2}\right\}\\y_{}\in \left\{\frac{4}{2\times x_{}}\right\}\\")]
[InlineData(@"1=3", @"\underline\mathrm{Input}\\1=3\\\\\underline\mathrm{Result}\\\text{False}")]
[InlineData(@"1=1", @"\underline\mathrm{Input}\\1=1\\\\\underline\mathrm{Result}\\\text{True}")]
public void Interpret(string input, string expected) {
var actual = Evaluation.Interpret(EvaluationTests.ParseLaTeX(input));
Assert.Equal(expected, actual);
Assert.NotEmpty(EvaluationTests.ParseLaTeX(actual));
}
}
}
110 changes: 54 additions & 56 deletions CSharpMath.Evaluation.Tests/PredictTests.cs
@@ -1,62 +1,60 @@
using System;
using System.Linq;
using Xunit;
namespace CSharpMath {
public partial class EvaluationTests {
public class PredictTests {
[Theory]
[InlineData(1, 1, 1)]
[InlineData(2, 2, 2)]
[InlineData(1, 2, 3, 4)]
[InlineData(3, 4, 5, 6)]
[InlineData(1, 2, 3, 4, 5)]
[InlineData(3, 4, 5, 6, 7)]
[InlineData(1, 3, 5, 7)]
[InlineData(8, 10, 12, 14)]
[InlineData(1, 3, 5, 7, 9)]
[InlineData(8, 10, 12, 14, 16)]
[InlineData(1, 4, 7, 10)]
[InlineData(1, 4, 7, 10, 13)]
[InlineData(24, 31, 38, 45)]
[InlineData(24, 31, 38, 45, 52)]
[InlineData(17, 21, 25, 29)]
[InlineData(17, 21, 25, 29, 33)]
[InlineData(1, 1, 1, 1)]
[InlineData(1, 1, 1, 1, 1)]
[InlineData(1, 3, 1, 3, 1)]
[InlineData(1, 3, 1, 3, 1, 3)]
[InlineData(1, 2, 4, 8)]
[InlineData(1, 2, 4, 8, 16)]
[InlineData(1, 3, 9, 27)]
[InlineData(1, 3, 9, 27, 81)]
[InlineData(1, -2, 4, -8)]
[InlineData(-1, 2, -4, 8)]
[InlineData(30, 31, 40, 41, 50, 51)]
[InlineData(61, 62, 63, 71, 72, 73, 81, 82)]
[InlineData(2, 4, 8, 24, 48, 96, 288, 576, 1152)]
[InlineData(0, 0, 0, 1, 0, 0, 0, 1, 0)]
[InlineData(39, 34, 27, 22, 15, 10)]
[InlineData(39, 34, 27, 22, 15, 10, 3)]
[InlineData(31, 30, 22, 21, 13, 12)]
[InlineData(31, 30, 22, 21, 13, 12, 4)]
// Use int instead of double because https://github.com/xunit/xunit/issues/1670#issuecomment-373566797
public void Integer(params int[] input) {
static void Test(System.Collections.Generic.IEnumerable<int> seq) =>
Assert.Equal(seq.Last(), Assert.IsType<double>(Evaluation.Predict(seq.Select(x => (double)x).SkipLast(1).ToArray())), 12);
Test(input);
Test(input.Reverse());
}
[Theory]
[InlineData(new int[0])]
[InlineData(1)]
[InlineData(1, 2)]
[InlineData(2, 1)]
[InlineData(1, 2, 1)]
[InlineData(1, 2, 1, 3)]
[InlineData(39, 34, 27, 22)]
[InlineData(31, 30, 22, 21)]
public void IntegerFail(params int[] input) =>
Assert.Null(Evaluation.Predict(input.Select(x => (double)x).ToArray()));
namespace CSharpMath.EvaluationTests {
public class PredictTests {
[Theory]
[InlineData(1, 1, 1)]
[InlineData(2, 2, 2)]
[InlineData(1, 2, 3, 4)]
[InlineData(3, 4, 5, 6)]
[InlineData(1, 2, 3, 4, 5)]
[InlineData(3, 4, 5, 6, 7)]
[InlineData(1, 3, 5, 7)]
[InlineData(8, 10, 12, 14)]
[InlineData(1, 3, 5, 7, 9)]
[InlineData(8, 10, 12, 14, 16)]
[InlineData(1, 4, 7, 10)]
[InlineData(1, 4, 7, 10, 13)]
[InlineData(24, 31, 38, 45)]
[InlineData(24, 31, 38, 45, 52)]
[InlineData(17, 21, 25, 29)]
[InlineData(17, 21, 25, 29, 33)]
[InlineData(1, 1, 1, 1)]
[InlineData(1, 1, 1, 1, 1)]
[InlineData(1, 3, 1, 3, 1)]
[InlineData(1, 3, 1, 3, 1, 3)]
[InlineData(1, 2, 4, 8)]
[InlineData(1, 2, 4, 8, 16)]
[InlineData(1, 3, 9, 27)]
[InlineData(1, 3, 9, 27, 81)]
[InlineData(1, -2, 4, -8)]
[InlineData(-1, 2, -4, 8)]
[InlineData(30, 31, 40, 41, 50, 51)]
[InlineData(61, 62, 63, 71, 72, 73, 81, 82)]
[InlineData(2, 4, 8, 24, 48, 96, 288, 576, 1152)]
[InlineData(0, 0, 0, 1, 0, 0, 0, 1, 0)]
[InlineData(39, 34, 27, 22, 15, 10)]
[InlineData(39, 34, 27, 22, 15, 10, 3)]
[InlineData(31, 30, 22, 21, 13, 12)]
[InlineData(31, 30, 22, 21, 13, 12, 4)]
// Use int instead of double because https://github.com/xunit/xunit/issues/1670#issuecomment-373566797
public void Integer(params int[] input) {
static void Test(System.Collections.Generic.IEnumerable<int> seq) =>
Assert.Equal(seq.Last(), Assert.IsType<double>(Evaluation.Predict(seq.Select(x => (double)x).SkipLast(1).ToArray())), 12);
Test(input);
Test(input.Reverse());
}
[Theory]
[InlineData(new int[0])]
[InlineData(1)]
[InlineData(1, 2)]
[InlineData(2, 1)]
[InlineData(1, 2, 1)]
[InlineData(1, 2, 1, 3)]
[InlineData(39, 34, 27, 22)]
[InlineData(31, 30, 22, 21)]
public void IntegerFail(params int[] input) =>
Assert.Null(Evaluation.Predict(input.Select(x => (double)x).ToArray()));
}
}
36 changes: 14 additions & 22 deletions CSharpMath.Evaluation/Evaluation.cs
Expand Up @@ -167,8 +167,9 @@ public sealed class Set : MathItem {
_ => "Unrecognized bracket pair ( ]"
} },
{ ("[", "]"), item => item switch {
null => "Missing math inside [ ]",
MathItem.Comma c => TryMakeSet(c, true, true),
_ => "Unrecognized bracket pair [ ]"
_ => item
} },
{ ("{", "}"), item => item.AsEntities("set element").Bind(entities => (MathItem)MathS.Sets.Finite(entities)) }
};
Expand Down Expand Up @@ -392,14 +393,18 @@ public sealed class Set : MathItem {
handlePrecendence = Precedence.SetOperation;
handleBinarySet = (l, r) => l - r;
goto handleBinarySet;
// Until C# allows declaring variables under "or pattern"s...
case Atoms.Inner { LeftBoundary:{ Nucleus:"[" }, InnerList:{ Count:1 } inner, RightBoundary:{ Nucleus:"]" } }
when inner[0] is Atoms.Table { Environment: "matrix" } table:
var matrix = table;
goto handleMatrix;
case Atoms.Table { Environment: "matrix" } table:
matrix = table;
goto handleMatrix;
case Atoms.Table { Environment: "matrix" } matrix:
var (rows, cols, cells) = (matrix.NRows, matrix.NColumns, matrix.Cells);
var matrixElements = new Entity[rows * cols];
for (var row = 0; row < rows; row++)
for (var col = 0; col < cols; col++) {
if (cells[row].Count <= col)
return $"There are empty slots in the {rows}×{cols} matrix";
(matrixElements[row * cols + col], error) = Transform(cells[row][col]).ExpectEntity("matrix element");
if (error != null) return error;
}
@this = MathS.Matrices.Matrix(rows, cols, matrixElements);
goto handleThis;
case Atoms.Open { Nucleus: var opening }:
if (!OpenBracketInfo.TryGetValue(opening, out var bracketInfo))
return "Unsupported opening bracket " + opening;
Expand Down Expand Up @@ -463,19 +468,6 @@ public sealed class Set : MathItem {
return $"Unsupported table environment {table.Environment}";
default:
return $"Unsupported {atom.TypeName} {atom.Nucleus}";

handleMatrix:
var (rows, cols, cells) = (matrix.NRows, matrix.NColumns, matrix.Cells);
var matrixElements = new Entity[rows * cols];
for (var row = 0; row < rows; row++)
for (var col = 0; col < cols; col++) {
if (cells[row].Count <= col)
return $"There are empty slots in the {rows}×{cols} matrix";
(matrixElements[row * cols + col], error) = Transform(cells[row][col]).ExpectEntity("matrix element");
if (error != null) return error;
}
@this = MathS.Matrices.Matrix(rows, cols, matrixElements);
goto handleThis;
#pragma warning disable CS0162 // Unreachable code detected
#pragma warning disable CS0164 // This label has not been referenced
handleFunction:
Expand Down
4 changes: 0 additions & 4 deletions CSharpMath.Evaluation/Interpret.cs
Expand Up @@ -53,10 +53,6 @@ static partial class Evaluation {
latex.AppendLaTeXHeader("Expanded").AppendLaTeX(entity.Expand());
latex.AppendLaTeXHeader("Factorized").AppendLaTeX(entity.Collapse());
}
foreach (AngouriMath.VariableEntity variable in AngouriMath.MathS.Utils.GetUniqueVariables(entity).FiniteSet())
latex.AppendLaTeXHeader(@"\mathnormal\frac\partial{\partial " + variable.Latexise() + @"}")
.AppendLaTeX(entity.Derive(variable).Simplify());
// TryOutput("Alternate forms", () => entity.Alternate(5));
break;
case MathItem.Set _:
case MathItem.Comma _:
Expand Down

0 comments on commit 0f81662

Please sign in to comment.