diff --git a/src/FSharp/DenseMatrix.fs b/src/FSharp/DenseMatrix.fs new file mode 100644 index 00000000..7678caa7 --- /dev/null +++ b/src/FSharp/DenseMatrix.fs @@ -0,0 +1,127 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// +// Copyright (c) 2009 Math.NET +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Double + +open MathNet.Numerics.LinearAlgebra + +/// A module which implements functional dense vector operations. +module DenseMatrix = + + /// Initialize a matrix by calling a construction function for every element. + let inline init (n: int) (m: int) f = + let A = new DenseMatrix(n,m) + for i=0 to n-1 do + for j=0 to m-1 do + A.[i,j] <- f i j + A + + /// Create the identity matrix. + let inline identity (n:int) = + let A = new DenseMatrix(n, n, 0.0) + for i=0 to n-1 do + A.[i,i] <- 1.0 + A + + /// Create a matrix from a list of float lists. Every list in the master list specifies a row. + let inline of_list (fll: float list list) = + let n = List.length fll + let m = List.length (List.hd fll) + let A = DenseMatrix(n,m) + fll |> List.iteri (fun i fl -> + if (List.length fl) <> m then failwith "Each subrow must be of the same length." else + List.iteri (fun j f -> A.[i,j] <- f) fl) + A + + /// Create a matrix from a list of sequences. Every sequence in the master sequence specifies a row. + let inline of_seq (fss: #seq<#seq>) = + let n = Seq.length fss + let m = Seq.length (Seq.hd fss) + let A = DenseMatrix(n,m) + fss |> Seq.iteri (fun i fs -> + if (Seq.length fs) <> m then failwith "Each subrow must be of the same length." else + Seq.iteri (fun j f -> A.[i,j] <- f) fs) + A + + /// Create a matrix from a 2D array of floating point numbers. + let inline of_array2 (arr: float[,]) = new DenseMatrix(arr) + + /// Create a matrix with the given entries. + let inline init_dense (n: int) (m: int) (es: #seq) = + let A = new DenseMatrix(n,m) + Seq.iter (fun (i,j,f) -> A.[i,j] <- f) es + A + + /// Create a square matrix with constant diagonal entries. + let inline constDiag (n: int) (f: float) = + let A = new DenseMatrix(n,n) + for i=0 to n-1 do + A.[i,i] <- f + A + + /// Create a square matrix with the vector elements on the diagonal. + let inline diag (v: #Vector) = + let n = v.Count + let A = new DenseMatrix(n,n) + for i=0 to n-1 do + A.[i,i] <- v.Item(i) + A + + (* + + /// Initialize a matrix by calling a construction function for every row. + let inline init_row (n: int) (m: int) (f: int -> #Vector) = + let A = new DenseMatrix(n,m) + for i=0 to n-1 do + let row = f i + if row.Count <> m then failwith "Row generator does not create rows of the appropriate size." + A.SetRow(i, row) + A + + /// Initialize a matrix by calling a construction function for every column. + let inline init_col (n: int) (m: int) (f: int -> #Vector) = + let A = new DenseMatrix(n,m) + for i=0 to m-1 do + let col = f i + if col.Count <> n then failwith "Column generator does not create columns of the appropriate size." + A.SetColumn(i, col) + A + + /// Create a 1xn dimensional matrix from a row vector. + let inline of_rowvector (v: #Vector) = + let n = v.Count + let A = new DenseMatrix(1, n) + A.SetRow(0, v) + A + + /// Create an nx1 dimensional matrix from a column vector. + let inline of_vector (v: #Vector) = + let n = v.Count + let A = new DenseMatrix(n, 1) + A.SetColumn(0, v) + A*) \ No newline at end of file diff --git a/src/FSharp/FSharp.fsproj b/src/FSharp/FSharp.fsproj index 61279acb..43d622bd 100644 --- a/src/FSharp/FSharp.fsproj +++ b/src/FSharp/FSharp.fsproj @@ -46,6 +46,7 @@ + diff --git a/src/FSharp/Main.fs b/src/FSharp/Main.fs index 55e2ac23..0afbd4b8 100644 --- a/src/FSharp/Main.fs +++ b/src/FSharp/Main.fs @@ -34,7 +34,7 @@ open MathNet.Numerics.LinearAlgebra.Double module FSharp = /// Construct a dense matrix from a list of floating point numbers. - //let inline matrix (lst: list>) = DenseMatrix.of_list lst :> Matrix + let inline matrix (lst: list>) = DenseMatrix.of_list lst :> Matrix /// Construct a dense vector from a list of floating point numbers. let inline vector (lst: list) = DenseVector.of_list lst :> Vector \ No newline at end of file diff --git a/src/FSharpUnitTests/Program.fs b/src/FSharpUnitTests/Program.fs index e73ad1aa..884475dd 100644 --- a/src/FSharpUnitTests/Program.fs +++ b/src/FSharpUnitTests/Program.fs @@ -23,6 +23,153 @@ let DenseVectorTests = spec "DenseVector.range" (DenseVector.range 0 99 |> should equal (new DenseVector( [| for i in 0 .. 99 -> float i |] ) )) ] + + +/// Unit tests for the vector type. +let VectorTests = + + /// A small uniform vector. + let smallv = new DenseVector( [|0.3;0.3;0.3;0.3;0.3|] ) :> Vector + + /// A large vector with increasingly large entries + let largev = new DenseVector( Array.init 100 (fun i -> float i / 100.0) ) :> Vector + + specs "Vector" [ + spec "Vector.to_array" + (Vector.to_array smallv |> should equal [|0.3;0.3;0.3;0.3;0.3|]) + spec "Vector.to_list" + (Vector.to_list smallv |> should equal [0.3;0.3;0.3;0.3;0.3]) + spec "Vector.mapInPlace" + ( let w = smallv.Clone() + Vector.mapInPlace (fun x -> 2.0 * x) w + w |> should equal (2.0 * smallv)) + spec "Vector.mapiInPlace" + ( let w = largev.Clone() + Vector.mapiInPlace (fun i x -> float i / 100.0) w + w |> should equal (largev)) + spec "Vector.addInPlace" + ( let w = largev.Clone() + Vector.addInPlace w largev + w |> should equal (2.0 * largev)) + spec "Vector.subInPlace" + ( let w = largev.Clone() + Vector.subInPlace w largev + w |> should equal (0.0 * largev)) + spec "Vector.map" + (Vector.map (fun x -> 2.0 * x) largev |> should equal (2.0 * largev)) + spec "Vector.mapi" + (Vector.mapi (fun i x -> float i / 100.0) largev |> should equal largev) + spec "Vector.fold" + (Vector.fold (fun a b -> a + b) 0.0 smallv |> should equal 1.5) + spec "Vector.foldi" + (Vector.foldi (fun i a b -> a + b) 0.0 smallv |> should equal 1.5) + spec "Vector.forall" + (Vector.forall (fun x -> x = 0.3) smallv |> should equal true) + spec "Vector.exists" + (Vector.exists (fun x -> x = 0.3) smallv |> should equal true) + spec "Vector.foralli" + (Vector.foralli (fun i x -> x = 0.3 && i < 5) smallv |> should equal true) + spec "Vector.existsi" + (Vector.existsi (fun i x -> x = 0.3 && i = 2) smallv |> should equal true) + spec "Vector.scan" + (Vector.scan (fun acc x -> acc + x) smallv |> should approximately_vector_equal 14 (new DenseVector( [|0.3;0.6;0.9;1.2;1.5|] ) :> Vector) ) + spec "Vector.scanBack" + (Vector.scanBack (fun x acc -> acc + x) smallv |> should approximately_vector_equal 14 (new DenseVector( [|1.5;1.2;0.9;0.6;0.3|] ) :> Vector) ) + spec "Vector.reduce_left" + (Vector.reduce (fun acc x -> acc ** x) smallv |> should approximately_equal 14 0.990295218585507) + spec "Vector.reduce_right" + (Vector.reduceBack (fun x acc -> x ** acc) smallv |> should approximately_equal 14 0.488911287726319) + ] + + +/// Unit tests for the matrix type. +let MatrixTests = + + /// A small uniform vector. + let smallM = new DenseMatrix( Array2D.create 2 2 0.3 ) + + /// A large vector with increasingly large entries + let largeM = new DenseMatrix( Array2D.init 100 100 (fun i j -> float i * 100.0 + float j) ) + + specs "Matrix" [ + spec "Matrix.fold" + (Matrix.fold (fun a b -> a + b) 0.0 smallM |> should equal 1.2) + spec "Matrix.foldi" + (Matrix.foldi (fun i j acc x -> acc + x + float (i+j)) 0.0 smallM |> should equal 5.2) + spec "Matrix.toArray2" + (Matrix.toArray2 smallM |> should equal (Array2D.create 2 2 0.3)) + spec "Matrix.forall" + (Matrix.forall (fun x -> x = 0.3) smallM |> should equal true) + spec "Matrix.exists" + (Matrix.exists (fun x -> x = 0.5) smallM |> should equal false) + spec "Matrix.foralli" + (Matrix.foralli (fun i j x -> x = float i * 100.0 + float j) largeM |> should equal true) + spec "Matrix.existsi" + (Matrix.existsi (fun i j x -> x = float i * 100.0 + float j) largeM |> should equal true) + (*spec "Matrix.map" + (Matrix.map (fun x -> 2.0 * x) smallM |> should equal (2.0 * smallM)) + spec "Matrix.mapi" + (Matrix.mapi (fun i j x -> float i * 100.0 + float j + x) largeM |> should equal (2.0 * largeM)) + spec "Matrix.inplaceAssign" + ( let N = smallM.Clone() + Matrix.inplaceAssign (fun i j -> 0.0) N + N |> should equal (0.0 * smallM)) + spec "Matrix.inplaceMapi" + ( let N = largeM.Clone() + Matrix.inplaceMapi (fun i j x -> 2.0 * (float i * 100.0 + float j) + x) N + N |> should equal (3.0 * largeM))*) + spec "Matrix.nonZeroEntries" + (Seq.length (Matrix.nonZeroEntries smallM) |> should equal 4) + spec "Matrix.sum" + (Matrix.sum smallM |> should equal 1.2) + spec "Matrix.foldCol" + (Matrix.foldCol (+) 0.0 largeM 0 |> should equal 495000.0) + spec "Matrix.foldRow" + (Matrix.foldRow (+) 0.0 largeM 0 |> should equal 4950.0) + spec "Matrix.foldByCol" + (Matrix.foldByCol (+) 0.0 smallM |> should equal (DenseVector.of_list [0.6;0.6] :> Vector)) + spec "Matrix.foldByRow" + (Matrix.foldByRow (+) 0.0 smallM |> should equal (DenseVector.of_list [0.6;0.6] :> Vector)) + ] + + +/// Unit tests for the dense matrix type. +let DenseMatrixTests = + + /// A small uniform vector. + let smallM = new DenseMatrix( Array2D.create 2 2 0.3 ) + + /// A large vector with increasingly large entries + let largeM = new DenseMatrix( Array2D.init 100 100 (fun i j -> float i * 100.0 + float j) ) + + specs "DenseMatrix" [ + spec "DenseMatrix.init" + (DenseMatrix.init 100 100 (fun i j -> float i * 100.0 + float j) |> should equal largeM) + spec "DenseMatrix.identity" + (DenseMatrix.identity 10 |> should equal (DenseMatrix.init 10 10 (fun i j -> if i = j then 1.0 else 0.0))) + spec "DenseMatrix.of_list" + (DenseMatrix.of_list [[0.3;0.3];[0.3;0.3]] |> should equal smallM) + spec "DenseMatrix.of_seq" + (DenseMatrix.of_seq (Seq.of_list [[0.3;0.3];[0.3;0.3]]) |> should equal smallM) + spec "DenseMatrix.of_array2" + (DenseMatrix.of_array2 (Array2D.create 2 2 0.3) |> should equal smallM) + spec "DenseMatrix.init_dense" + (DenseMatrix.init_dense 100 100 (seq { for i in 0 .. 99 do + for j in 0 .. 99 -> (i,j, float i * 100.0 + float j)}) |> should equal largeM) + (*spec "DenseMatrix.constDiag" + (DenseMatrix.constDiag 100 2.0 |> should equal (2.0 * (DenseMatrix.identity 100))) + spec "DenseMatrix.diag" + (DenseMatrix.diag (new DenseVector(100, 2.0)) |> should equal (2.0 * (DenseMatrix.identity 100))) + spec "DenseMatrix.init_row" + (DenseMatrix.init_row 100 100 (fun i -> (DenseVector.init 100 (fun j -> float i * 100.0 + float j))) |> should equal largeM) + spec "DenseMatrix.init_col" + (DenseMatrix.init_col 100 100 (fun j -> (DenseVector.init 100 (fun i -> float i * 100.0 + float j))) |> should equal largeM) + spec "DenseMatrix.of_rowvector" + (DenseMatrix.of_rowvector (new DenseVector(10,3.0)) |> should equal ((new DenseMatrix(1,10,3.0)))) + spec "DenseMatrix.of_vector" + (DenseMatrix.of_vector (new DenseVector(10,3.0)) |> should equal ((new DenseMatrix(10,1,3.0))))*) + ] + /// Report on errors and success and exit. printfn "F# Test Results:" diff --git a/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs b/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs new file mode 100644 index 00000000..c0ef53e4 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs @@ -0,0 +1,164 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// +// Copyright (c) 2009 Math.NET +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Double +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using Algorithms; + using Algorithms.LinearAlgebra; + using NumberTheory; + using Properties; + using Threading; + + /// + /// A Matrix class with dense storage. + /// + public class DenseMatrix : Matrix + { + /// + /// Initializes a new instance of the class. This matrix is square with a given size. + /// + /// the size of the square matrix. + /// + /// If is less than one. + /// + public DenseMatrix(int order) + : base(order) + { + Data = new double[order*order]; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The number of rows. + /// + /// + /// The number of columns. + /// + public DenseMatrix(int rows, int columns) + : base(rows, columns) + { + Data = new double[rows * columns]; + } + + /// + /// Initializes a new instance of the class with all entries set to a particular value. + /// + /// + /// The number of rows. + /// + /// + /// The number of columns. + /// The value which we assign to each element of the matrix. + public DenseMatrix(int rows, int columns, double value) + : base(rows, columns) + { + Data = new double[rows * columns]; + for (int i = 0; i < Data.Length; i++) + { + Data[i] = value; + } + } + + /// + /// Initializes a new instance of the class from a 2D array. + /// + /// The 2D array to create this matrix from. + public DenseMatrix(double[,] array) + : base(array.GetLength(0), array.GetLength(1)) + { + throw new NotImplementedException(); + } + + /// + /// Gets or sets the matrix's data. + /// + /// The matrix's data. + internal double[] Data + { + get; + private set; + } + + /// + /// Creates a DenseMatrix for the given number of rows and columns. + /// + /// + /// The number of rows. + /// + /// + /// The number of columns. + /// + /// + /// A DenseMatrix with the given dimensions. + /// + public override Matrix CreateMatrix(int numberOfRows, int numberOfColumns) + { + return new DenseMatrix(numberOfRows, numberOfColumns); + } + + /// + /// Retrieves the requested element without range checking. + /// + /// + /// The row of the element. + /// + /// + /// The column of the element. + /// + /// + /// The requested element. + /// + public override double At(int row, int column) + { + return Data[column * RowCount + row]; + } + + /// + /// Sets the value of the given element. + /// + /// + /// The row of the element. + /// + /// + /// The column of the element. + /// + /// + /// The value to set the element to. + /// + public override void At(int row, int column, double value) + { + Data[column * RowCount + row] = value; + } + } +} diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index c7103461..42efec89 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -92,6 +92,7 @@ + diff --git a/src/UnitTests/DistributionTests/CommonDistributionTests.cs b/src/UnitTests/DistributionTests/CommonDistributionTests.cs index 34cb6479..b6018479 100644 --- a/src/UnitTests/DistributionTests/CommonDistributionTests.cs +++ b/src/UnitTests/DistributionTests/CommonDistributionTests.cs @@ -41,7 +41,7 @@ namespace MathNet.Numerics.UnitTests.DistributionTests [SetUp] public void SetupDistributions() { - dists = new IDistribution[7]; + dists = new IDistribution[8]; dists[0] = new Beta(1.0, 1.0); dists[1] = new ContinuousUniform(0.0, 1.0); @@ -50,6 +50,7 @@ namespace MathNet.Numerics.UnitTests.DistributionTests dists[4] = new Bernoulli(0.6); dists[5] = new Weibull(1.0, 1.0); dists[6] = new DiscreteUniform(1, 10); + dists[7] = new LogNormal(1.0, 1.0); } [Test] diff --git a/src/UnitTests/LinearAlgebraTests/Double/DenseMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Double/DenseMatrixTests.cs new file mode 100644 index 00000000..306108d8 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Double/DenseMatrixTests.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using MbUnit.Framework; + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double +{ + using LinearAlgebra.Double; + + public class DenseMatrixTests : MatrixTests + { + protected override Matrix CreateMatrix(int rows, int columns) + { + return new DenseMatrix(rows, columns); + } + + protected override Matrix CreateMatrix(double[,] data) + { + return new DenseMatrix(data); + } + + [Test] + [Row("Singular3x3")] + [Row("Singular3x3")] + [Row("Square3x3")] + [Row("Square4x4")] + [Row("Tall3x2")] + [Row("Wide2x3")] + public void CanCreateMatrixFromArray(string name) + { + var matrix = new DenseMatrix(testData[name]); + for (var i = 0; i < testData[name].GetLength(0); i++) + { + for (var j = 0; j < testData[name].GetLength(0); j++) + { + Assert.AreEqual(testData[name][i,j], matrix[i,j]); + } + } + } + + [Test] + public void CanCreateMatrixWithUniformValues() + { + var matrix = new DenseMatrix(10, 10, 10.0); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], 10.0); + } + } + } + } +} diff --git a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs new file mode 100644 index 00000000..656c634e --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using MathNet.Numerics.LinearAlgebra.Double; +using MbUnit.Framework; + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double +{ + public abstract partial class MatrixTests + { + protected Dictionary testData; + protected Dictionary testMatrices; + + protected abstract Matrix CreateMatrix(int rows, int columns); + protected abstract Matrix CreateMatrix(double[,] data); + + [SetUp] + public void SetupDistributions() + { + testData.Add("Singular3x3", new double[,] { { 1, 1, 2 }, { 1, 1, 2 }, { 1, 1, 2 } }); + testData.Add("Square3x3", new double[,] { { -1.1, -2.2, -3.3 }, { 0, 1.1, 2.2 }, { -4.4, 5.5, 6.6 } }); + testData.Add("Square4x4", new double[,] { { -1.1, -2.2, -3.3, -4.4 }, { 0, 1.1, 2.2, 3.3 }, { -4.4, 5.5, 6.6, -7.7 } }); + testData.Add("Tall3x2", new double[,] { { -1.1, -2.2 }, { 0, 1.1 }, { -4.4, 5.5 } }); + testData.Add("Wide2x3", new double[,] { { -1.1, -2.2, -3.3 }, { 0, 1.1, 2.2 } }); + + foreach(var name in testData.Keys) + { + testMatrices.Add(name, CreateMatrix(testData[name])); + } + } + + [Test] + [Row("Singular3x3")] + [Row("Square3x3")] + [Row("Square4x4")] + [Row("Tall3x2")] + [Row("Wide2x3")] + [MultipleAsserts] + public void CanCloneMatrix(string name) + { + var matrix = CreateMatrix(testData[name]); + var clone = matrix.Clone(); + + Assert.AreNotSame(matrix, clone); + Assert.AreEqual(matrix.RowCount, clone.RowCount); + Assert.AreEqual(matrix.ColumnCount, clone.ColumnCount); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.RowCount; j++) + { + Assert.AreEqual(matrix[i,j], clone[i,j]); + } + } + } + + [Test] + [Row("Singular3x3")] + [Row("Square3x3")] + [Row("Square4x4")] + [Row("Tall3x2")] + [Row("Wide2x3")] + [MultipleAsserts] + public void CanCloneMatrixUsingICloneable(string name) + { + var matrix = CreateMatrix(testData[name]); + var clone = (Matrix)((ICloneable)matrix).Clone(); + + Assert.AreNotSame(matrix, clone); + Assert.AreEqual(matrix.RowCount, clone.RowCount); + Assert.AreEqual(matrix.ColumnCount, clone.ColumnCount); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.RowCount; j++) + { + Assert.AreEqual(matrix[i, j], clone[i, j]); + } + } + } + + [Test] + [Ignore] + public void CanConvertVectorToString() + { + } + + [Test] + public void CanCreateMatrix() + { + var expected = CreateMatrix(5, 6); + var actual = expected.CreateMatrix(5, 6); + Assert.AreEqual(expected.GetType(), actual.GetType(), "Matrices are same type."); + } + + [Test] + [Row("Singular3x3")] + [Row("Square3x3")] + [Row("Square4x4")] + [Row("Tall3x2")] + [Row("Wide2x3")] + [MultipleAsserts] + public void CanEquateMatrices(string name) + { + var matrix1 = CreateMatrix(testData[name]); + var matrix2 = CreateMatrix(testData[name]); + var matrix3 = CreateMatrix(testData[name].GetLength(0), testData[name].GetLength(1)); + Assert.IsTrue(matrix1.Equals(matrix1)); + Assert.IsTrue(matrix1.Equals(matrix2)); + Assert.IsFalse(matrix1.Equals(matrix3)); + Assert.IsFalse(matrix1.Equals(null)); + } + + [Test] + [Row(0, 2)] + [Row(-1, 1)] + [ExpectedArgumentException] + public void ThrowsArgumentExceptionIfSizeIsNotPositive(int rows, int columns) + { + var A = CreateMatrix(rows, columns); + } + + [Test] + [Row("Singular3x3")] + [Row("Square3x3")] + [Row("Square4x4")] + [Row("Tall3x2")] + [Row("Wide2x3")] + public void TestingForEqualityWithNonMatrixReturnsFalse(string name) + { + var matrix = CreateMatrix(testData[name]); + Assert.IsFalse(matrix.Equals(2)); + } + + [Test] + [Row("Singular3x3")] + [Row("Square3x3")] + [Row("Square4x4")] + [Row("Tall3x2")] + [Row("Wide2x3")] + public void CanTestForEqualityUsingObjectEquals(string name) + { + var matrix1 = CreateMatrix(testData[name]); + var matrix2 = CreateMatrix(testData[name]); + Assert.IsTrue(matrix1.Equals((object)matrix2)); + } + + [Test] + [Row(-1, 1, "Singular3x3")] + [Row(1, -1, "Singular3x3")] + [Row(4, 2, "Square3x3")] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void RangeCheckFails(int i, int j, string name) + { + var d = testMatrices[name][i, j]; + } + + [Test] + [Ignore] + public void MatrixGetHashCode() + { + } + } +} \ No newline at end of file diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj index 3799ad3a..45b72e39 100644 --- a/src/UnitTests/UnitTests.csproj +++ b/src/UnitTests/UnitTests.csproj @@ -86,6 +86,8 @@ + +