diff --git a/src/FSharpUnitTests/FsUnit.fs b/src/FSharpUnitTests/FsUnit.fs index 09778d30..84d2eeb2 100644 --- a/src/FSharpUnitTests/FsUnit.fs +++ b/src/FSharpUnitTests/FsUnit.fs @@ -146,6 +146,27 @@ module SpecOps = else Fail (sprintf "Expected actual to be same reference as expected %A" other)) (sprintf "Expected %A to have different reference than %A" x other) + let array_equal (expected: float []) (actual: float []) = + make (fun () -> + let mutable f = true + for i=0 to expected.Length-1 do + f <- f && (expected.[i] = actual.[i]) + if f + then Pass + else Fail (sprintf "Expected: %A\nActual: %A" expected actual)) + (sprintf "NOT Expected: %A\nActual: %A" expected actual) + + let array2_equal (expected: float [,]) (actual: float [,]) = + make (fun () -> + let mutable f = true + for i=0 to expected.GetLength(0)-1 do + for j=0 to expected.GetLength(1)-1 do + f <- f && (expected.[i,j] = actual.[i,j]) + if f + then Pass + else Fail (sprintf "Expected: %A\nActual: %A" expected actual)) + (sprintf "NOT Expected: %A\nActual: %A" expected actual) + let approximately_equal (places : int) (expected: float) (actual: float) = make (fun () -> if Precision.AlmostEqualInDecimalPlaces(actual, expected, places) @@ -157,7 +178,7 @@ module SpecOps = make (fun () -> let mutable f = true for i=0 to expected.Count-1 do - f <- f && Precision.AlmostEqualInDecimalPlaces(expected.[i], actual.[i], places) + f <- f && Precision.AlmostEqualInDecimalPlaces(expected.[i], actual.[i], places) if f then Pass else Fail (sprintf "Expected: %A\nActual: %A" expected actual)) diff --git a/src/FSharpUnitTests/Program.fs b/src/FSharpUnitTests/Program.fs index 884475dd..85dc1b6c 100644 --- a/src/FSharpUnitTests/Program.fs +++ b/src/FSharpUnitTests/Program.fs @@ -36,7 +36,7 @@ let VectorTests = specs "Vector" [ spec "Vector.to_array" - (Vector.to_array smallv |> should equal [|0.3;0.3;0.3;0.3;0.3|]) + (Vector.to_array smallv |> should array_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" @@ -97,7 +97,7 @@ let MatrixTests = 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)) + (Matrix.toArray2 smallM |> should array2_equal (Array2D.create 2 2 0.3)) spec "Matrix.forall" (Matrix.forall (fun x -> x = 0.3) smallM |> should equal true) spec "Matrix.exists" diff --git a/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs b/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs index c0ef53e4..1ee92e67 100644 --- a/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs @@ -47,7 +47,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// /// the size of the square matrix. /// - /// If is less than one. + /// If is less than one. /// public DenseMatrix(int order) : base(order) @@ -91,13 +91,21 @@ namespace MathNet.Numerics.LinearAlgebra.Double } /// - /// Initializes a new instance of the class from a 2D array. + /// Initializes a new instance of the class from a 2D array. This constructor + /// will allocate a completely new memory block for storing the dense matrix. /// /// The 2D array to create this matrix from. public DenseMatrix(double[,] array) : base(array.GetLength(0), array.GetLength(1)) { - throw new NotImplementedException(); + Data = new double[array.GetLength(0) * array.GetLength(1)]; + for (int i = 0; i < array.GetLength(0); i++) + { + for (int j = 0; j < array.GetLength(1); j++) + { + At(i, j, array[i,j]); + } + } } /// diff --git a/src/Numerics/LinearAlgebra/Double/Matrix.cs b/src/Numerics/LinearAlgebra/Double/Matrix.cs index 7bb13c27..1ba95145 100644 --- a/src/Numerics/LinearAlgebra/Double/Matrix.cs +++ b/src/Numerics/LinearAlgebra/Double/Matrix.cs @@ -50,6 +50,16 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// protected Matrix(int rows, int columns) { + if (rows <= 0) + { + throw new ArgumentOutOfRangeException(Resources.MatrixRowsMustBePositive); + } + + if (columns <= 0) + { + throw new ArgumentOutOfRangeException(Resources.MatrixColumnsMustBePositive); + } + RowCount = rows; ColumnCount = columns; } @@ -62,6 +72,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// protected Matrix(int order) { + if (order <= 0) + { + throw new ArgumentOutOfRangeException(Resources.MatrixRowsOrColumnsMustBePositive); + } + RowCount = order; ColumnCount = order; } @@ -175,16 +190,21 @@ namespace MathNet.Numerics.LinearAlgebra.Double throw new ArgumentException("target", Resources.ArgumentMatrixSameDimensions); } - throw new NotImplementedException(); - - /* - foreach (KeyValuePair column in GetColumnEnumerator()) + var denseMatrix = target as DenseMatrix; + if (denseMatrix != null) { - foreach (KeyValuePair element in column.Value.GetIndexedEnumerator()) + // TODO this assumes that all entries matter; if "this" is a sparse matrix, + // we might be able to optimize the copying a bit. + for (int i = 0; i < RowCount; i++) { - target.ValueAt(element.Key, column.Key, element.Value); + for (int j = 0; j < ColumnCount; j++) + { + denseMatrix.At(i, j, this.At(i, j)); + } } - }*/ + + return; + } } /// diff --git a/src/Numerics/Properties/Resources.Designer.cs b/src/Numerics/Properties/Resources.Designer.cs index 7fd45cfe..c1690ed7 100644 --- a/src/Numerics/Properties/Resources.Designer.cs +++ b/src/Numerics/Properties/Resources.Designer.cs @@ -501,6 +501,33 @@ namespace MathNet.Numerics.Properties { } } + /// + /// Looks up a localized string similar to The number of columns of a matrix must be positive.. + /// + internal static string MatrixColumnsMustBePositive { + get { + return ResourceManager.GetString("MatrixColumnsMustBePositive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The number of rows of a matrix must be positive.. + /// + internal static string MatrixRowsMustBePositive { + get { + return ResourceManager.GetString("MatrixRowsMustBePositive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The number of rows or columns of a matrix must be positive.. + /// + internal static string MatrixRowsOrColumnsMustBePositive { + get { + return ResourceManager.GetString("MatrixRowsOrColumnsMustBePositive", resourceCulture); + } + } + /// /// Looks up a localized string similar to The two arguments can't be compared (maybe they are part of a partial ordering?). /// diff --git a/src/Numerics/Properties/Resources.resx b/src/Numerics/Properties/Resources.resx index 4c0de2d2..6ce30845 100644 --- a/src/Numerics/Properties/Resources.resx +++ b/src/Numerics/Properties/Resources.resx @@ -273,4 +273,13 @@ The two arguments can't be compared (maybe they are part of a partial ordering?) + + The number of columns of a matrix must be positive. + + + The number of rows of a matrix must be positive. + + + The number of rows or columns of a matrix must be positive. + \ No newline at end of file diff --git a/src/UnitTests/LinearAlgebraTests/Double/DenseMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Double/DenseMatrixTests.cs index 306108d8..f4b9afb8 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/DenseMatrixTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/DenseMatrixTests.cs @@ -29,7 +29,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double 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++) + for (var j = 0; j < testData[name].GetLength(1); j++) { Assert.AreEqual(testData[name][i,j], matrix[i,j]); } diff --git a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs index 656c634e..c3014dfb 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs @@ -17,12 +17,14 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [SetUp] public void SetupDistributions() { + testData = new Dictionary(); 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 } }); + testMatrices = new Dictionary(); foreach(var name in testData.Keys) { testMatrices.Add(name, CreateMatrix(testData[name])); @@ -46,7 +48,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double Assert.AreEqual(matrix.ColumnCount, clone.ColumnCount); for (var i = 0; i < matrix.RowCount; i++) { - for (var j = 0; j < matrix.RowCount; j++) + for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(matrix[i,j], clone[i,j]); } @@ -70,7 +72,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double Assert.AreEqual(matrix.ColumnCount, clone.ColumnCount); for (var i = 0; i < matrix.RowCount; i++) { - for (var j = 0; j < matrix.RowCount; j++) + for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(matrix[i, j], clone[i, j]); } @@ -112,7 +114,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Test] [Row(0, 2)] [Row(-1, 1)] - [ExpectedArgumentException] + [ExpectedArgumentOutOfRangeException] public void ThrowsArgumentExceptionIfSizeIsNotPositive(int rows, int columns) { var A = CreateMatrix(rows, columns);