Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,20 @@ now, which is the one silent change: a variable spelled `forall` or `exists` no
| `forall + 1` | `forall + 1`, a variable named `forall` | `UnhandledParseException` |
| `exists(x)` | `exists * x` | `UnhandledParseException` |

### A matrix compiles

**Addition, not silent.** Under the LINQ compiler a `Matrix` node compiles to a
`GenTensor<T, TWrapper>` over its elements' type, with the wrappers `DoubleOperations`,
`SingleOperations`, `ComplexOperations`, `Int32Operations`, `Int64Operations` and
`BigIntegerOperations` in `AngouriMath.Core.Compilation.IntoLinq`, and a sum, difference, product,
quotient or whole power with a matrix in it to GenericTensor's operation of that name
([#526](https://github.com/asc-community/AngouriMath/issues/526)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"[[x, 2 x], [x + 1, x^2]]".ToEntity().Compile<double, GenTensor<double, DoubleOperations>>("x")` | `UncompilableNodeException` | a delegate; at `3` the matrix `[[3, 6], [4, 9]]` |
| `"A * B".ToEntity().Compile<GenTensor<…>, GenTensor<…>, GenTensor<…>>("A", "B")` | `UncompilableNodeException` | the matrix product |
| `"[[1, 0]] * [[a, b], [c, d]] * [[0], [1]]".ToEntity().Compile<double, double, double, double, double>("a", "b", "c", "d")` | `2` at `(1, 2, 3, 4)` — simplified to the scalar first | unchanged |
### `lcm` is a function, and a congruence is solved to a residue class

`lcm(a, b, ...)` is a node, `Entity.Lcmf`, by the conventions of `gcd`: non-negative, `0` where
Expand Down
6 changes: 6 additions & 0 deletions Sources/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,12 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed
[AngouriMath/Functions/Continuous/ExtremumOverSet.cs]
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n

[AngouriMath/Functions/Compilation/IntoLinq/TensorCompilation.cs]
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n

[Tests/UnitTests/Common/CompileMatrixTest.cs]
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n

[AngouriMath/Functions/IntervalArithmetic.cs]
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n

Expand Down
12 changes: 11 additions & 1 deletion Sources/AngouriMath/Docs/Usage/Exceptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,24 @@ take.

`Compile` was asked for a function it cannot build. Two distinct causes, and the message says which:

- a node with no compiled form — a matrix, a derivative, an integral, a limit;
- a node with no compiled form — a derivative, an integral, a limit, a function of a matrix;
- a variable the expression mentions that the compilation was not given. The message names the
variable and lists the ones it *was* given, since `Compile("x")` on `a * x` failing used to
surface as a bare `KeyNotFoundException` about some dictionary.

Both compilers raise it: the stack-machine one (`Compile`) and the LINQ one
(`Compile<TIn, TOut>`).

A matrix is not on the first list any more: under the LINQ compiler it compiles to a
`GenTensor<T, TWrapper>` over its elements' type — `GenTensor<double, DoubleOperations>`,
`GenTensor<Complex, ComplexOperations>`, and the same for `float`, `int`, `long`, `BigInteger`,
the wrappers living in `AngouriMath.Core.Compilation.IntoLinq` — and that is the type to compile
to and to pass a matrix in as: `"A * B".ToEntity().Compile<GenTensor<double, DoubleOperations>,
GenTensor<double, DoubleOperations>, GenTensor<double, DoubleOperations>>("A", "B")` is the matrix
product, `2 A + B - 1` scales, adds and shifts element by element, `A ^ 3` is the matrix power
([#526](https://github.com/asc-community/AngouriMath/issues/526)). Compiling a matrix as a
number, or a number as a matrix, or `sin(A)`, is still this exception.

### `CannotEvalException`

Something did not collapse to a single number or boolean. Overwhelmingly this is
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ public virtual Expression ConvertType(Expression expr, Type type)

if (expr.Type == type)
return expr;
// A tensor converts to nothing but itself: a matrix over one element type is not
// a matrix over another, and it is not a number.
if (TensorCompilation.IsTensor(expr.Type) || TensorCompilation.IsTensor(type))
throw new UncompilableNodeException($"A value of type {expr.Type} cannot be compiled as {type}");

bool exprNullable = (Nullable.GetUnderlyingType(expr.Type) is not null) || (expr.Type == typeof(object));
bool typeNullable = (Nullable.GetUnderlyingType(type) is not null) || (type == typeof(object));
Expand Down Expand Up @@ -107,7 +111,11 @@ public virtual Expression ConvertType(Expression expr, Type type)
/// </summary>
public virtual Expression ConvertUnaryNode(Expression e, Entity typeHolder)
{

// A function of a matrix has no compiled form here: the tensor operations are the
// arithmetic ones, and sin(A) is not an element-by-element sine of a matrix.
if (TensorCompilation.IsTensor(e.Type))
throw new UncompilableNodeException(
$"There is no compiled form for {typeHolder.GetType().Name} of a matrix.");
return typeHolder switch
{
Sinf when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("Sin", 1, newE.Type), newE),
Expand Down Expand Up @@ -155,7 +163,13 @@ private Expression ShouldBeAtLeastDouble(Expression expr)
/// </summary>
public virtual Expression ConvertBinaryNode(Expression left, Expression right, Entity typeHolder)
{

// A matrix in either place: the tensor operation of the same name, the scalar side
// converted to the element type. https://github.com/asc-community/AngouriMath/issues/526
if (TensorCompilation.IsTensor(left.Type) || TensorCompilation.IsTensor(right.Type))
return TensorCompilation.Binary(typeHolder, left, right, ConvertType)
?? throw new UncompilableNodeException(
$"The node of type {typeHolder.GetType()} has no compiled form over a matrix.");

(left, right) = EqualizeTypesIfAble(left, right);
return typeHolder switch
{
Expand Down Expand Up @@ -214,13 +228,30 @@ public virtual Expression ConvertOtherNode(IEnumerable<Expression> en, Entity ty
return typeHolder switch
{
Piecewise => HandlePiecewise(en),
// A matrix is a tensor over its elements' common type, built from the compiled
// elements in row-major order, which is the order DirectChildren gives them.
// https://github.com/asc-community/AngouriMath/issues/526
Entity.Matrix matrix => HandleMatrix(matrix, en),
// TODO: finite set -> hash set
_ => throw new UncompilableNodeException(
$"The node of type {typeHolder.GetType()} does not support compilation.")
//FiniteSet => Expression.
};
}

private Expression HandleMatrix(Entity.Matrix matrix, IEnumerable<Expression> en)
{
var elements = en.ToArray();
if (elements.Length == 0)
throw new UncompilableNodeException("An empty matrix has no compiled form");
var common = elements[0].Type;
foreach (var element in elements)
common = MaxType(Nullable.GetUnderlyingType(common) ?? common, Nullable.GetUnderlyingType(element.Type) ?? element.Type);
for (var i = 0; i < elements.Length; i++)
elements[i] = ConvertType(elements[i], common);
return TensorCompilation.Build(matrix, elements);
}

private Expression HandlePiecewise(IEnumerable<Expression> en)
{
Expression[] children = en.ToArray();
Expand Down
Loading
Loading