Skip to content

Commit 8b33aad

Browse files
Compile expressions whose matrices cancel out, and name what cannot be (#425, #526) (#673)
1 parent e7cab69 commit 8b33aad

3 files changed

Lines changed: 73 additions & 2 deletions

File tree

‎Sources/AngouriMath/Functions/Compilation/IntoLinq/CompilationProtocol.cs‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,8 @@ Logf when
215215

216216
Providedf => HandleProvidedf(left, right),
217217

218-
_ => throw new AngouriBugException("A binary node seems to be not added")
218+
_ => throw new UncompilableNodeException(
219+
$"The node of type {typeHolder.GetType()} does not support compilation.")
219220
};
220221

221222
Expression HandleProvidedf(Expression expr, Expression cond)
@@ -238,7 +239,8 @@ public virtual Expression ConvertOtherNode(IEnumerable<Expression> en, Entity ty
238239
{
239240
Piecewise => HandlePiecewise(en),
240241
// TODO: finite set -> hash set
241-
_ => throw new AngouriBugException("A node seems to be not added")
242+
_ => throw new UncompilableNodeException(
243+
$"The node of type {typeHolder.GetType()} does not support compilation.")
242244
//FiniteSet => Expression.
243245
};
244246
}

‎Sources/AngouriMath/Functions/Compilation/IntoLinq/IntoLinqCompiler.cs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ internal static TDelegate Compile<TDelegate>(
2020
IEnumerable<(Type type, Variable variable)> typesAndNames
2121
) where TDelegate : Delegate
2222
{
23+
// A matrix has no compiled form, but an expression built out of matrices often
24+
// has a value that is an ordinary number -- [0, 1]T * [[a, b], [c, d]] * [1, 0]
25+
// is c -- and there is nothing to stop that being compiled. Nothing simplified
26+
// before compiling, so those failed along with the ones that genuinely cannot
27+
// be compiled (https://github.com/asc-community/AngouriMath/issues/425).
28+
// Only expressions that mention a matrix pay for this.
29+
if (expr.Nodes.Any(node => node is Entity.Matrix))
30+
expr = expr.InnerSimplified;
31+
2332
var subexpressionsCache = typesAndNames.ToDictionary(c => (Entity)c.variable, c => Expression.Parameter(c.type));
2433
var functionArguments = subexpressionsCache.Select(c => c.Value).ToArray(); // copying
2534
var localVars = new List<ParameterExpression>();
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//
2+
// Copyright (c) 2019-2022 Angouri.
3+
// AngouriMath is licensed under MIT.
4+
// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
5+
// Website: https://am.angouri.org.
6+
//
7+
8+
using AngouriMath;
9+
using AngouriMath.Core.Exceptions;
10+
using AngouriMath.Extensions;
11+
using Xunit;
12+
13+
namespace AngouriMath.Tests.Common
14+
{
15+
/// <summary>
16+
/// Compiling expressions that mention matrices. A matrix has no compiled form, but an
17+
/// expression built out of matrices often has a value that is an ordinary number.
18+
/// </summary>
19+
public sealed class MatrixCompilationTest
20+
{
21+
// https://github.com/asc-community/AngouriMath/issues/425
22+
// This is the issue's own example of what ought to work, and did not: it is the
23+
// scalar c, but nothing simplified before compiling, so it reached the matrix node
24+
// and threw.
25+
[Fact]
26+
public void ScalarBuiltFromMatricesCompiles()
27+
{
28+
var compiled = "[0, 1]T * [[a, b], [c, d]] * [1, 0]".ToEntity()
29+
.Compile<double, double, double, double, double>("a", "b", "c", "d");
30+
Assert.Equal(3, compiled(1, 2, 3, 4), 9);
31+
}
32+
33+
[Fact]
34+
public void ScalarProductOfVectorsCompiles()
35+
{
36+
var compiled = "[1, 2]T * [a, b]".ToEntity().Compile<double, double, double>("a", "b");
37+
Assert.Equal(1 * 3 + 2 * 4, compiled(3, 4), 9);
38+
}
39+
40+
[Theory]
41+
[InlineData("[[a, b], [c, d]]")]
42+
[InlineData("[[a, b], [c, d]] * [1, 0]")]
43+
[InlineData("[a, b]")]
44+
public void MatrixValuedExpressionsSayTheyCannotBeCompiled(string expression)
45+
{
46+
var thrown = Assert.Throws<UncompilableNodeException>(
47+
() => expression.ToEntity().Compile<double, double>("a"));
48+
Assert.Contains("Matrix", thrown.Message);
49+
}
50+
51+
// Expressions with no matrix in them must be unaffected -- they do not go anywhere
52+
// near the extra simplification.
53+
[Theory]
54+
[InlineData("x + 1", 2.0, 3.0)]
55+
[InlineData("x ^ 2", 3.0, 9.0)]
56+
[InlineData("sin(x)", 0.0, 0.0)]
57+
public void OrdinaryExpressionsAreUnaffected(string expression, double argument, double expected) =>
58+
Assert.Equal(expected, expression.ToEntity().Compile<double, double>("x")(argument), 9);
59+
}
60+
}

0 commit comments

Comments
 (0)