Skip to content

Commit ce56555

Browse files
Merge pull request #398 from asc-community/matrix-operators
Matrix operators for F#. Bugs fixed. Adjugate and Inverse don't throw exceptions anymore (null returned instead).
2 parents 49b95c2 + 78fd180 commit ce56555

File tree

13 files changed

+196
-154
lines changed

13 files changed

+196
-154
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,4 @@ out/
5858
/Sources/Utils/Utils/Properties/launchSettings.json
5959
out/
6060
TestResults
61+
/Sources/Wrappers/AngouriMath.CPP.Importing/AngouriMath.CPP.Importing.rar

Sources/AngouriMath/AngouriMath.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@
4343
</None>
4444
<PackageReference Include="Antlr4.Runtime.Standard" Version="4.9.2" />
4545
<PackageReference Include="FieldCache" Version="1.0.0-alpha.3" />
46-
<PackageReference Include="GenericTensor" Version="1.0.0" />
47-
<PackageReference Include="PeterO.Numbers" Version="1.7.4" />
46+
<PackageReference Include="GenericTensor" Version="1.0.3" />
47+
<PackageReference Include="PeterO.Numbers" Version="1.8.0" />
4848
<PackageReference Include="System.Memory" Version="4.5.4" />
4949
<PackageReference Include="Nullable" Version="1.3.0" PrivateAssets="all" />
5050
<ProjectReference Include="../Analyzers/Analyzers/Analyzers.csproj" PrivateAssets="all" ReferenceOutputAssembly="false" OutputItemType="Analyzer" />

Sources/AngouriMath/Convenience/MathS.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -688,9 +688,10 @@ public static Rational CreateRational(EInteger numerator, EInteger denominator)
688688
}
689689

690690
/// <summary>
691-
/// Finds the determinant of the given matrix
691+
/// Finds the determinant of the given matrix. If
692+
/// the matrix is non-square, returns null
692693
/// </summary>
693-
public static Entity Det(Matrix m)
694+
public static Entity? Det(Matrix m)
694695
=> m.Determinant;
695696

696697
/// <summary>Creates an instance of <see cref="Entity.Matrix"/>.</summary>

Sources/AngouriMath/Core/Entity/Omni/Entity.Matrix.cs

+28-42
Original file line numberDiff line numberDiff line change
@@ -194,35 +194,32 @@ public Entity AsScalar()
194194
/// <summary>
195195
/// Finds the symbolical determinant via Laplace's method
196196
/// </summary>
197-
public Entity Determinant => determinant.GetValue(
198-
static @this => @this.InnerMatrix.DeterminantGaussianSafeDivision().InnerSimplified,
197+
public Entity? Determinant => determinant.GetValue(
198+
static @this =>
199+
{
200+
if (!@this.IsSquare)
201+
return null;
202+
return @this.InnerMatrix.DeterminantGaussianSafeDivision().InnerSimplified;
203+
},
199204
this
200205
);
201-
private FieldCache<Entity> determinant;
206+
private FieldCache<Entity?> determinant;
202207

203-
// The reason it's not cached is because it throws exceptions.
204-
/// <summary>Inverts the matrix</summary>
205-
public Matrix ComputeInverse()
208+
/// <summary>Returns an inverse matrix if it exists</summary>
209+
public Matrix? Inverse => inverse.GetValue(static @this =>
206210
{
207-
var cp = InnerMatrix.Copy(false);
208-
try
209-
{
210-
cp.InvertMatrix();
211-
}
212-
catch (InvalidShapeException)
213-
{
214-
throw new InvalidMatrixOperationException("Cannot inverse a non-square matrix!");
215-
}
216-
catch (InvalidDeterminantException)
217-
{
218-
throw new InvalidMatrixOperationException("Cannot inverse a singular matrix!");
219-
}
211+
var cp = @this.InnerMatrix.Copy(false);
212+
if (!@this.IsSquare)
213+
return null;
214+
if (@this.Determinant is null)
215+
return null;
216+
if (@this.Determinant == 0)
217+
return null;
218+
cp.InvertMatrix();
220219
return ToMatrix(new Matrix(cp).InnerSimplified);
221-
}
220+
}, this);
221+
private FieldCache<Matrix?> inverse;
222222

223-
/// <summary>Inverts the matrix</summary>
224-
[Obsolete("Use ComputeInverse() instead")]
225-
public Matrix Inverse() => ComputeInverse();
226223

227224
/// <summary>
228225
/// The Add operator. Performs an active operation
@@ -270,22 +267,6 @@ public Matrix ComputeInverse()
270267
}
271268
}
272269

273-
/// <summary>
274-
/// The Multiply operator. Performs an active operation.
275-
/// 1. Finds the inverse of the divisor
276-
/// 2. Multiplies the dividend by the inverse of the divisor
277-
/// and then applies inner simplification.
278-
/// The operator only works with square matrices of the same size
279-
/// </summary>
280-
/// <exception cref="InvalidMatrixOperationException">
281-
/// May be thrown if no inverse was found.
282-
/// </exception>
283-
public static Matrix operator /(Matrix m1, Matrix m2)
284-
{
285-
var inv = m2.ComputeInverse();
286-
return m1 * inv;
287-
}
288-
289270
/// <summary>
290271
/// Performs a binary power of the matrix.
291272
/// The matrix must be a square matrix.
@@ -369,11 +350,16 @@ public IEnumerator<Entity> GetEnumerator()
369350
/// <summary>
370351
/// Adjugate form of a matrix
371352
/// </summary>
372-
public Matrix Adjugate =>
353+
public Matrix? Adjugate =>
373354
adjugate.GetValue(static @this =>
374-
(Matrix)new Matrix(@this.InnerMatrix.Adjoint()).InnerSimplified,
355+
{
356+
if (!@this.IsSquare)
357+
return null;
358+
var innerSimplified = new Matrix(@this.InnerMatrix.Adjoint()).InnerSimplified;
359+
return ToMatrix(innerSimplified);
360+
},
375361
this);
376-
private FieldCache<Matrix> adjugate;
362+
private FieldCache<Matrix?> adjugate;
377363

378364
/// <summary>
379365
/// Returns a vector, where the i-th element

Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs

-22
Original file line numberDiff line numberDiff line change
@@ -121,31 +121,11 @@ protected override Entity InnerSimplify() =>
121121
}
122122
public partial record Divf
123123
{
124-
private static bool TryDivide(Matrix m1, Matrix m2, out Entity res)
125-
{
126-
res = 0;
127-
if (!m1.IsSquare)
128-
return false;
129-
if (m1.InnerMatrix.Shape != m2.InnerMatrix.Shape)
130-
return false;
131-
try
132-
{
133-
res = m1 / m2;
134-
return true;
135-
}
136-
catch (InvalidMatrixOperationException)
137-
{
138-
return false;
139-
}
140-
}
141-
142124
/// <inheritdoc/>
143125
protected override Entity InnerEval() =>
144126
ExpandOnTwoArguments(Dividend.Evaled, Divisor.Evaled,
145127
(a, b) => (a, b) switch
146128
{
147-
(Matrix m1, Matrix m2) when TryDivide(m1, m2, out var res) => res.Evaled,
148-
(var any, Matrix m) => (any / m),
149129
(Complex n1, Complex n2) => n1 / n2,
150130
(Integer(0), _) => 0,
151131
(_, Integer(0)) => Real.NaN,
@@ -158,8 +138,6 @@ protected override Entity InnerSimplify() =>
158138
ExpandOnTwoArguments(Dividend.InnerSimplified, Divisor.InnerSimplified,
159139
(a, b) => (a, b) switch
160140
{
161-
(Matrix m1, Matrix m2) when TryDivide(m1, m2, out var res) => res,
162-
(var any, Matrix m) => (any / m),
163141
(Integer(0), _) => 0,
164142
(_, Integer(0)) => Real.NaN,
165143
(var n1, Integer(1)) => n1,

Sources/Samples/Samples/Program.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
using System.Runtime.InteropServices;
88
using System.Runtime.CompilerServices;
99

10-
11-
Console.WriteLine("Ducks.");
10+
Matrix m = "[5]";
11+
Console.WriteLine(m.Determinant);
12+
Console.WriteLine(5);

Sources/Tests/FSharpWrapperUnitTests/FSharpWrapperUnitTests.fsproj

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11+
<Compile Include="MatrixOperatorsTest.fs" />
1112
<None Include="coverlet.runsettings" />
1213
<Compile Include="Functions.Sets.fs" />
1314
<Compile Include="CoreTest.fs" />
@@ -21,8 +22,6 @@
2122
<Compile Include="Program.fs" />
2223
</ItemGroup>
2324

24-
<ItemGroup />
25-
2625
<ItemGroup>
2726
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0-preview-20210219-03" />
2827
<PackageReference Include="xunit" Version="2.4.1" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
module MatrixOperatorsTest
2+
3+
open AngouriMath
4+
open AngouriMath.FSharp.Functions
5+
open AngouriMath.FSharp.MatrixOperators
6+
open Xunit
7+
8+
(*
9+
10+
Matrix and matrix operators
11+
M = matrix
12+
13+
*)
14+
15+
[<Fact>]
16+
let ``M+M`` () =
17+
Assert.Equal<Entity.Matrix>(vector [11; 32], vector [10; 30] |+ vector [1; 2])
18+
19+
[<Fact>]
20+
let ``M-M`` () =
21+
Assert.Equal<Entity.Matrix>(vector [9; 28], vector [10; 30] |- vector [1; 2])
22+
23+
[<Fact>]
24+
let ``M*M`` () =
25+
Assert.Equal<Entity.Matrix>(vector [2; 4], "[[2, 0], [0, 2]]" |* "[1, 2]")
26+
27+
(*
28+
29+
Matrix and scalar operators
30+
Scalar and matrix operators
31+
M = matrix
32+
S = scalar
33+
34+
*)
35+
36+
[<Fact>]
37+
let ``M+S`` () =
38+
Assert.Equal<Entity.Matrix>(vector [11; 31], vector [10; 30] |+ 1)
39+
40+
[<Fact>]
41+
let ``S+M`` () =
42+
Assert.Equal<Entity.Matrix>(vector [11; 31], 1 |+ vector [10; 30])
43+
44+
[<Fact>]
45+
let ``M-S`` () =
46+
Assert.Equal<Entity.Matrix>(vector [9; 29], vector [10; 30] |- 1)
47+
48+
[<Fact>]
49+
let ``S-M`` () =
50+
Assert.Equal<Entity.Matrix>(vector [90; 70], 100 |- vector [10; 30])
51+
52+
[<Fact>]
53+
let ``M*S`` () =
54+
Assert.Equal<Entity.Matrix>(vector [3; 6], vector [1; 2] |* 3)
55+
56+
[<Fact>]
57+
let ``S*M`` () =
58+
Assert.Equal<Entity.Matrix>(vector [3; 6], 3 |* vector [1; 2])
59+
60+
[<Fact>]
61+
let ``M/S`` () =
62+
Assert.Equal<Entity.Matrix>(vector [5; 15], vector [10; 30] |/ 2)
63+
64+
[<Fact>]
65+
let ``M**S`` () =
66+
Assert.Equal<Entity.Matrix>(matrix [[37; 54]; [81; 118]], matrix [[1; 2]; [3; 4]] |** 3)

0 commit comments

Comments
 (0)