|
| 1 | +namespace FsMath.Tests |
| 2 | + |
| 3 | +open Xunit |
| 4 | +open FsMath |
| 5 | + |
| 6 | +module MatrixEdgeCaseTests = |
| 7 | + |
| 8 | + // ============================================ |
| 9 | + // Tests for Matrix indexer setter (line 39) |
| 10 | + // ============================================ |
| 11 | + |
| 12 | + [<Fact>] |
| 13 | + let ``Matrix setter throws on negative row index`` () = |
| 14 | + let m = Matrix<float>.zeroCreate 3 3 |
| 15 | + Assert.Throws<System.ArgumentException>(fun () -> m.[-1, 0] <- 1.0) |> ignore |
| 16 | + |
| 17 | + [<Fact>] |
| 18 | + let ``Matrix setter throws on row index too large`` () = |
| 19 | + let m = Matrix<float>.zeroCreate 3 3 |
| 20 | + Assert.Throws<System.ArgumentException>(fun () -> m.[3, 0] <- 1.0) |> ignore |
| 21 | + |
| 22 | + [<Fact>] |
| 23 | + let ``Matrix setter throws on negative column index`` () = |
| 24 | + let m = Matrix<float>.zeroCreate 3 3 |
| 25 | + Assert.Throws<System.ArgumentException>(fun () -> m.[0, -1] <- 1.0) |> ignore |
| 26 | + |
| 27 | + [<Fact>] |
| 28 | + let ``Matrix setter throws on column index too large`` () = |
| 29 | + let m = Matrix<float>.zeroCreate 3 3 |
| 30 | + Assert.Throws<System.ArgumentException>(fun () -> m.[0, 3] <- 1.0) |> ignore |
| 31 | + |
| 32 | + |
| 33 | + // ============================================ |
| 34 | + // Tests for toFormattedString with custom floatFormat (line 272) |
| 35 | + // ============================================ |
| 36 | + |
| 37 | + [<Fact>] |
| 38 | + let ``toFormattedString with custom floatFormat`` () = |
| 39 | + let m = Matrix<float>.init 2 2 (fun i j -> float (i + j) + 0.123456) |
| 40 | + let formatted = m.toFormattedString(floatFormat = "0.0000") |
| 41 | + // Should contain the 4-decimal format |
| 42 | + Assert.Contains("0.1235", formatted) // 0.123456 rounded to 4 decimals |
| 43 | + |
| 44 | + [<Fact>] |
| 45 | + let ``toFormattedString with custom precision floatFormat`` () = |
| 46 | + let m = Matrix<float>.init 2 2 (fun i j -> float (i + j) * 1.5) |
| 47 | + let formatted = m.toFormattedString(floatFormat = "0.000") |
| 48 | + // Should use the custom format |
| 49 | + Assert.Contains("1.500", formatted) |
| 50 | + |
| 51 | + |
| 52 | + // ============================================ |
| 53 | + // Tests for toFormattedString truncation message (line 319) |
| 54 | + // ============================================ |
| 55 | + |
| 56 | + [<Fact>] |
| 57 | + let ``toFormattedString shows truncation message for large matrices`` () = |
| 58 | + let m = Matrix<float>.init 20 20 (fun i j -> float (i * 10 + j)) |
| 59 | + let formatted = m.toFormattedString(maxRows = 5, maxCols = 5) |
| 60 | + // Should contain truncation message |
| 61 | + Assert.Contains("truncated", formatted) |
| 62 | + Assert.Contains("(20x20)", formatted) |
| 63 | + |
| 64 | + [<Fact>] |
| 65 | + let ``toFormattedString shows truncation for rows exceeding maxRows`` () = |
| 66 | + let m = Matrix<int>.init 15 3 (fun i j -> i + j) |
| 67 | + let formatted = m.toFormattedString(maxRows = 5) |
| 68 | + Assert.Contains("truncated", formatted) |
| 69 | + |
| 70 | + [<Fact>] |
| 71 | + let ``toFormattedString shows truncation for cols exceeding maxCols`` () = |
| 72 | + let m = Matrix<int>.init 3 15 (fun i j -> i + j) |
| 73 | + let formatted = m.toFormattedString(maxCols = 5) |
| 74 | + Assert.Contains("truncated", formatted) |
| 75 | + |
| 76 | + |
| 77 | + // ============================================ |
| 78 | + // Tests for muliplyVector SIMD path (line 496) |
| 79 | + // This tests the accumulation line within the SIMD loop |
| 80 | + // ============================================ |
| 81 | + |
| 82 | + [<Fact>] |
| 83 | + let ``muliplyVector with large vectors exercises SIMD path`` () = |
| 84 | + // Create a matrix and vector large enough to use SIMD |
| 85 | + let size = 64 // Should be larger than SIMD vector size |
| 86 | + let m = Matrix<float>.init size size (fun i j -> if i = j then 1.0 else 0.0) // Identity |
| 87 | + let v = Array.init size (fun i -> float (i + 1)) |
| 88 | + |
| 89 | + let result = Matrix.muliplyVector m v |
| 90 | + |
| 91 | + // Identity matrix should return the same vector |
| 92 | + for i = 0 to size - 1 do |
| 93 | + Assert.Equal(float (i + 1), result.[i]) |
| 94 | + |
| 95 | + [<Fact>] |
| 96 | + let ``muliplyVector with non-trivial matrix exercises SIMD`` () = |
| 97 | + let rows = 32 |
| 98 | + let cols = 32 |
| 99 | + let m = Matrix<float>.init rows cols (fun i j -> float ((i + 1) * (j + 1))) |
| 100 | + let v = Array.init cols (fun i -> 1.0) |
| 101 | + |
| 102 | + let result = Matrix.muliplyVector m v |
| 103 | + |
| 104 | + // Each row sum should be sum of (i+1)*j for j=1 to cols |
| 105 | + for i = 0 to rows - 1 do |
| 106 | + let expected = float ((i + 1) * cols * (cols + 1) / 2) |
| 107 | + Assert.Equal(expected, result.[i]) |
| 108 | + |
| 109 | + |
| 110 | + // ============================================ |
| 111 | + // Tests for addRowVector SIMD path (line 534) |
| 112 | + // ============================================ |
| 113 | + |
| 114 | + [<Fact>] |
| 115 | + let ``addRowVector with large matrix exercises SIMD path`` () = |
| 116 | + let rows = 10 |
| 117 | + let cols = 64 // Large enough for SIMD |
| 118 | + let m = Matrix<float>.zeroCreate rows cols |
| 119 | + let v = Array.init cols (fun i -> float i) |
| 120 | + |
| 121 | + let result = Matrix.addRowVector m v |
| 122 | + |
| 123 | + // Every row should be equal to v |
| 124 | + for i = 0 to rows - 1 do |
| 125 | + for j = 0 to cols - 1 do |
| 126 | + Assert.Equal(float j, result.[i, j]) |
| 127 | + |
| 128 | + [<Fact>] |
| 129 | + let ``addRowVector with varying row data`` () = |
| 130 | + let rows = 5 |
| 131 | + let cols = 48 |
| 132 | + let m = Matrix<float>.init rows cols (fun i j -> float (i * 10)) |
| 133 | + let v = Array.init cols (fun i -> float (i + 1)) |
| 134 | + |
| 135 | + let result = Matrix.addRowVector m v |
| 136 | + |
| 137 | + // Each row should have base value + v |
| 138 | + for i = 0 to rows - 1 do |
| 139 | + for j = 0 to cols - 1 do |
| 140 | + Assert.Equal(float (i * 10 + j + 1), result.[i, j]) |
| 141 | + |
| 142 | + |
| 143 | + // ============================================ |
| 144 | + // Tests for addColVector SIMD path (line 572) |
| 145 | + // ============================================ |
| 146 | + |
| 147 | + [<Fact>] |
| 148 | + let ``addColVector with large matrix exercises SIMD path`` () = |
| 149 | + let rows = 16 |
| 150 | + let cols = 64 // Large enough for SIMD |
| 151 | + let m = Matrix<float>.zeroCreate rows cols |
| 152 | + let v = Array.init rows (fun i -> float i) |
| 153 | + |
| 154 | + let result = Matrix.addColVector m v |
| 155 | + |
| 156 | + // Every element in row i should be equal to v.[i] |
| 157 | + for i = 0 to rows - 1 do |
| 158 | + for j = 0 to cols - 1 do |
| 159 | + Assert.Equal(float i, result.[i, j]) |
| 160 | + |
| 161 | + [<Fact>] |
| 162 | + let ``addColVector with varying column data`` () = |
| 163 | + let rows = 8 |
| 164 | + let cols = 48 |
| 165 | + let m = Matrix<float>.init rows cols (fun i j -> float (j * 5)) |
| 166 | + let v = Array.init rows (fun i -> float (i + 1)) |
| 167 | + |
| 168 | + let result = Matrix.addColVector m v |
| 169 | + |
| 170 | + // Each element should have base value + v.[i] |
| 171 | + for i = 0 to rows - 1 do |
| 172 | + for j = 0 to cols - 1 do |
| 173 | + Assert.Equal(float (j * 5 + i + 1), result.[i, j]) |
| 174 | + |
| 175 | + [<Fact>] |
| 176 | + let ``addColVector with int32 type`` () = |
| 177 | + let rows = 6 |
| 178 | + let cols = 32 |
| 179 | + let m = Matrix<int>.zeroCreate rows cols |
| 180 | + let v = Array.init rows (fun i -> i + 10) |
| 181 | + |
| 182 | + let result = Matrix.addColVector m v |
| 183 | + |
| 184 | + for i = 0 to rows - 1 do |
| 185 | + for j = 0 to cols - 1 do |
| 186 | + Assert.Equal(i + 10, result.[i, j]) |
0 commit comments