mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-10 21:47:21 +00:00
123 lines
6.3 KiB
C#
123 lines
6.3 KiB
C#
using AIStudio.Tools.Mathematics;
|
|
|
|
using AngouriMath;
|
|
|
|
namespace AIStudio.Tests.Tools.Mathematics;
|
|
|
|
[TestFixture]
|
|
public sealed class NumericCheckTests
|
|
{
|
|
private static NumericCheckOutcome Check(string left, string right) => NumericCheck.AreEqual(MathExpressionReader.Read(left, "left"), MathExpressionReader.Read(right, "right"));
|
|
|
|
[Test]
|
|
public void PassesWhatIsEqual()
|
|
{
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(Check("sin(x)^2 + cos(x)^2", "1"), Is.EqualTo(NumericCheckOutcome.PASSED));
|
|
Assert.That(Check("(x + y)^2", "x^2 + 2*x*y + y^2"), Is.EqualTo(NumericCheckOutcome.PASSED));
|
|
Assert.That(Check("x^4 - 1", "(x + 1)*(x - 1)*(x^2 + 1)"), Is.EqualTo(NumericCheckOutcome.PASSED));
|
|
Assert.That(Check("547 / 57576", "1094 / 115152"), Is.EqualTo(NumericCheckOutcome.PASSED));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PassesAnExpansionWhoseTermsCancel()
|
|
{
|
|
// At the sample point x = 1.47, the terms of the expanded form reach about 10^92 and add up to
|
|
// about 10^-66; in doubles, or at 50 digits, nothing of the value would be left:
|
|
var power = MathExpressionReader.Read("(x - 1)^200", "expression");
|
|
Assert.That(NumericCheck.AreEqual(power, power.Expand()), Is.EqualTo(NumericCheckOutcome.PASSED));
|
|
}
|
|
|
|
[Test]
|
|
public void FailsWhatDiffers()
|
|
{
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(Check("x^2", "x^3"), Is.EqualTo(NumericCheckOutcome.FAILED));
|
|
Assert.That(Check("(x + y)^2", "x^2 + y^2"), Is.EqualTo(NumericCheckOutcome.FAILED));
|
|
Assert.That(Check("pi^4/15", "6.4939394022668"), Is.EqualTo(NumericCheckOutcome.FAILED), "Fourteen digits are not equality.");
|
|
Assert.That(Check("sin(x)", "sin(x + 2*pi)"), Is.EqualTo(NumericCheckOutcome.PASSED), "pi is a constant, not a variable which takes the values of the sample points.");
|
|
Assert.That(Check("e^x", "x + 1"), Is.EqualTo(NumericCheckOutcome.FAILED));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void TellsTinyValuesApart()
|
|
{
|
|
// With an absolute tolerance of 1e-30, any two values below it would pass for equal:
|
|
var x = MathS.Var("x");
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(Check("6.62607015e-34 * x", "6.62607015e-35 * x"), Is.EqualTo(NumericCheckOutcome.FAILED));
|
|
Assert.That(Check("6.62607015e-34 * sin(x)", "6.62607015e-34 * sin(x) * (1 + 1e-20)"), Is.EqualTo(NumericCheckOutcome.FAILED));
|
|
Assert.That(Check("6.62607015e-34 * x^2", "x * 6.62607015e-34 * x"), Is.EqualTo(NumericCheckOutcome.PASSED));
|
|
Assert.That(Check("sin(2*x) - 2*sin(x)*cos(x)", "0"), Is.EqualTo(NumericCheckOutcome.PASSED), "Against 0, the tolerance stays absolute, since terms which cancel leave their rounding noise.");
|
|
Assert.That(NumericCheck.IsDerivativeOf(MathExpressionReader.Read("1.32521403e-33 * x", "derivative"), MathExpressionReader.Read("6.62607015e-34 * x^2", "function"), x), Is.EqualTo(NumericCheckOutcome.PASSED));
|
|
Assert.That(NumericCheck.IsDerivativeOf(MathExpressionReader.Read("6.62607015e-34 * x", "derivative"), MathExpressionReader.Read("6.62607015e-34 * x^2", "function"), x), Is.EqualTo(NumericCheckOutcome.FAILED));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void ComparesWhereAConditionHolds()
|
|
{
|
|
var simplified = MathExpressionReader.Read("(x^2 - 1)/(x - 1)", "expression").Simplify();
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(simplified, Is.TypeOf<Entity.Providedf>());
|
|
Assert.That(NumericCheck.AreEqual(simplified, MathExpressionReader.Read("x + 1", "expression")), Is.EqualTo(NumericCheckOutcome.PASSED));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void IsNotPossibleWithoutValues()
|
|
{
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(Check("integral(sin(sin(x)), x)", "x"), Is.EqualTo(NumericCheckOutcome.NOT_POSSIBLE), "An integral without a closed form has no value.");
|
|
Assert.That(Check("1/(x - x)", "1/(y - y)"), Is.EqualTo(NumericCheckOutcome.NOT_POSSIBLE), "No sample point has a value.");
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void ChecksADerivativeByItsCentralDifference()
|
|
{
|
|
var x = MathS.Var("x");
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(NumericCheck.IsDerivativeOf(MathExpressionReader.Read("2*x*sin(x) + x^2*cos(x)", "derivative"), MathExpressionReader.Read("x^2*sin(x)", "function"), x), Is.EqualTo(NumericCheckOutcome.PASSED));
|
|
Assert.That(NumericCheck.IsDerivativeOf(MathExpressionReader.Read("2*x + 1", "derivative"), MathExpressionReader.Read("x^2", "function"), x), Is.EqualTo(NumericCheckOutcome.FAILED));
|
|
Assert.That(NumericCheck.IsDerivativeOf(MathExpressionReader.Read("a", "derivative"), MathExpressionReader.Read("a*x + C", "function"), x), Is.EqualTo(NumericCheckOutcome.PASSED), "Other variables, the constant of integration among them, take sample values.");
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GivesAnIntegerParameterIntegerValues()
|
|
{
|
|
var parameter = MathS.Var("n_1");
|
|
var values = Enumerable.Range(0, 6).Select(point => NumericCheck.SampleAssignment(point, [parameter])[parameter]).Distinct().ToList();
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(values, Is.EquivalentTo(new Entity[] { -1, 0, 1 }));
|
|
Assert.That(NumericCheck.IsIntegerParameter(MathS.Var("n_12")), Is.True);
|
|
Assert.That(NumericCheck.IsIntegerParameter(MathS.Var("n")), Is.False);
|
|
Assert.That(NumericCheck.IsIntegerParameter(MathS.Var("n_x")), Is.False);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void TheSamplePointsAreFixedAndDifferForEachVariable()
|
|
{
|
|
var variables = new[] { MathS.Var("x"), MathS.Var("y"), MathS.Var("z") };
|
|
var first = NumericCheck.SampleAssignment(0, variables);
|
|
var again = NumericCheck.SampleAssignment(0, variables);
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(again, Is.EqualTo(first));
|
|
Assert.That(first.Values.Distinct().Count(), Is.EqualTo(3));
|
|
Assert.That(first[variables[0]], Is.EqualTo(Entity.Number.Rational.Create(61, 100)));
|
|
Assert.That(NumericCheck.SampleAssignment(1, variables)[variables[0]], Is.Not.EqualTo(first[variables[0]]));
|
|
}
|
|
}
|
|
} |