| 1 | //===- MatrixTest.cpp - Tests for Matrix ----------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "mlir/Analysis/Presburger/Matrix.h" |
| 10 | #include "./Utils.h" |
| 11 | #include "mlir/Analysis/Presburger/Fraction.h" |
| 12 | #include <gmock/gmock.h> |
| 13 | #include <gtest/gtest.h> |
| 14 | |
| 15 | using namespace mlir; |
| 16 | using namespace presburger; |
| 17 | |
| 18 | TEST(MatrixTest, ReadWrite) { |
| 19 | IntMatrix mat(5, 5); |
| 20 | for (unsigned row = 0; row < 5; ++row) |
| 21 | for (unsigned col = 0; col < 5; ++col) |
| 22 | mat(row, col) = 10 * row + col; |
| 23 | for (unsigned row = 0; row < 5; ++row) |
| 24 | for (unsigned col = 0; col < 5; ++col) |
| 25 | EXPECT_EQ(mat(row, col), int(10 * row + col)); |
| 26 | } |
| 27 | |
| 28 | TEST(MatrixTest, SwapColumns) { |
| 29 | IntMatrix mat(5, 5); |
| 30 | for (unsigned row = 0; row < 5; ++row) |
| 31 | for (unsigned col = 0; col < 5; ++col) |
| 32 | mat(row, col) = col == 3 ? 1 : 0; |
| 33 | mat.swapColumns(column: 3, otherColumn: 1); |
| 34 | for (unsigned row = 0; row < 5; ++row) |
| 35 | for (unsigned col = 0; col < 5; ++col) |
| 36 | EXPECT_EQ(mat(row, col), col == 1 ? 1 : 0); |
| 37 | |
| 38 | // swap around all the other columns, swap (1, 3) twice for no effect. |
| 39 | mat.swapColumns(column: 3, otherColumn: 1); |
| 40 | mat.swapColumns(column: 2, otherColumn: 4); |
| 41 | mat.swapColumns(column: 1, otherColumn: 3); |
| 42 | mat.swapColumns(column: 0, otherColumn: 4); |
| 43 | mat.swapColumns(column: 2, otherColumn: 2); |
| 44 | |
| 45 | for (unsigned row = 0; row < 5; ++row) |
| 46 | for (unsigned col = 0; col < 5; ++col) |
| 47 | EXPECT_EQ(mat(row, col), col == 1 ? 1 : 0); |
| 48 | } |
| 49 | |
| 50 | TEST(MatrixTest, SwapRows) { |
| 51 | IntMatrix mat(5, 5); |
| 52 | for (unsigned row = 0; row < 5; ++row) |
| 53 | for (unsigned col = 0; col < 5; ++col) |
| 54 | mat(row, col) = row == 2 ? 1 : 0; |
| 55 | mat.swapRows(row: 2, otherRow: 0); |
| 56 | for (unsigned row = 0; row < 5; ++row) |
| 57 | for (unsigned col = 0; col < 5; ++col) |
| 58 | EXPECT_EQ(mat(row, col), row == 0 ? 1 : 0); |
| 59 | |
| 60 | // swap around all the other rows, swap (2, 0) twice for no effect. |
| 61 | mat.swapRows(row: 3, otherRow: 4); |
| 62 | mat.swapRows(row: 1, otherRow: 4); |
| 63 | mat.swapRows(row: 2, otherRow: 0); |
| 64 | mat.swapRows(row: 1, otherRow: 1); |
| 65 | mat.swapRows(row: 0, otherRow: 2); |
| 66 | |
| 67 | for (unsigned row = 0; row < 5; ++row) |
| 68 | for (unsigned col = 0; col < 5; ++col) |
| 69 | EXPECT_EQ(mat(row, col), row == 0 ? 1 : 0); |
| 70 | } |
| 71 | |
| 72 | TEST(MatrixTest, resizeVertically) { |
| 73 | IntMatrix mat(5, 5); |
| 74 | EXPECT_EQ(mat.getNumRows(), 5u); |
| 75 | EXPECT_EQ(mat.getNumColumns(), 5u); |
| 76 | for (unsigned row = 0; row < 5; ++row) |
| 77 | for (unsigned col = 0; col < 5; ++col) |
| 78 | mat(row, col) = 10 * row + col; |
| 79 | |
| 80 | mat.resizeVertically(newNRows: 3); |
| 81 | ASSERT_TRUE(mat.hasConsistentState()); |
| 82 | EXPECT_EQ(mat.getNumRows(), 3u); |
| 83 | EXPECT_EQ(mat.getNumColumns(), 5u); |
| 84 | for (unsigned row = 0; row < 3; ++row) |
| 85 | for (unsigned col = 0; col < 5; ++col) |
| 86 | EXPECT_EQ(mat(row, col), int(10 * row + col)); |
| 87 | |
| 88 | mat.resizeVertically(newNRows: 5); |
| 89 | ASSERT_TRUE(mat.hasConsistentState()); |
| 90 | EXPECT_EQ(mat.getNumRows(), 5u); |
| 91 | EXPECT_EQ(mat.getNumColumns(), 5u); |
| 92 | for (unsigned row = 0; row < 5; ++row) |
| 93 | for (unsigned col = 0; col < 5; ++col) |
| 94 | EXPECT_EQ(mat(row, col), row >= 3 ? 0 : int(10 * row + col)); |
| 95 | } |
| 96 | |
| 97 | TEST(MatrixTest, insertColumns) { |
| 98 | IntMatrix mat(5, 5, 5, 10); |
| 99 | EXPECT_EQ(mat.getNumRows(), 5u); |
| 100 | EXPECT_EQ(mat.getNumColumns(), 5u); |
| 101 | for (unsigned row = 0; row < 5; ++row) |
| 102 | for (unsigned col = 0; col < 5; ++col) |
| 103 | mat(row, col) = 10 * row + col; |
| 104 | |
| 105 | mat.insertColumns(pos: 3, count: 100); |
| 106 | ASSERT_TRUE(mat.hasConsistentState()); |
| 107 | EXPECT_EQ(mat.getNumRows(), 5u); |
| 108 | EXPECT_EQ(mat.getNumColumns(), 105u); |
| 109 | for (unsigned row = 0; row < 5; ++row) { |
| 110 | for (unsigned col = 0; col < 105; ++col) { |
| 111 | if (col < 3) |
| 112 | EXPECT_EQ(mat(row, col), int(10 * row + col)); |
| 113 | else if (3 <= col && col <= 102) |
| 114 | EXPECT_EQ(mat(row, col), 0); |
| 115 | else |
| 116 | EXPECT_EQ(mat(row, col), int(10 * row + col - 100)); |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | mat.removeColumns(pos: 3, count: 100); |
| 121 | ASSERT_TRUE(mat.hasConsistentState()); |
| 122 | mat.insertColumns(pos: 0, count: 0); |
| 123 | ASSERT_TRUE(mat.hasConsistentState()); |
| 124 | mat.insertColumn(pos: 5); |
| 125 | ASSERT_TRUE(mat.hasConsistentState()); |
| 126 | |
| 127 | EXPECT_EQ(mat.getNumRows(), 5u); |
| 128 | EXPECT_EQ(mat.getNumColumns(), 6u); |
| 129 | for (unsigned row = 0; row < 5; ++row) |
| 130 | for (unsigned col = 0; col < 6; ++col) |
| 131 | EXPECT_EQ(mat(row, col), col == 5 ? 0 : 10 * row + col); |
| 132 | } |
| 133 | |
| 134 | TEST(MatrixTest, insertRows) { |
| 135 | IntMatrix mat(5, 5, 5, 10); |
| 136 | ASSERT_TRUE(mat.hasConsistentState()); |
| 137 | EXPECT_EQ(mat.getNumRows(), 5u); |
| 138 | EXPECT_EQ(mat.getNumColumns(), 5u); |
| 139 | for (unsigned row = 0; row < 5; ++row) |
| 140 | for (unsigned col = 0; col < 5; ++col) |
| 141 | mat(row, col) = 10 * row + col; |
| 142 | |
| 143 | mat.insertRows(pos: 3, count: 100); |
| 144 | ASSERT_TRUE(mat.hasConsistentState()); |
| 145 | EXPECT_EQ(mat.getNumRows(), 105u); |
| 146 | EXPECT_EQ(mat.getNumColumns(), 5u); |
| 147 | for (unsigned row = 0; row < 105; ++row) { |
| 148 | for (unsigned col = 0; col < 5; ++col) { |
| 149 | if (row < 3) |
| 150 | EXPECT_EQ(mat(row, col), int(10 * row + col)); |
| 151 | else if (3 <= row && row <= 102) |
| 152 | EXPECT_EQ(mat(row, col), 0); |
| 153 | else |
| 154 | EXPECT_EQ(mat(row, col), int(10 * (row - 100) + col)); |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | mat.removeRows(pos: 3, count: 100); |
| 159 | ASSERT_TRUE(mat.hasConsistentState()); |
| 160 | mat.insertRows(pos: 0, count: 0); |
| 161 | ASSERT_TRUE(mat.hasConsistentState()); |
| 162 | mat.insertRow(pos: 5); |
| 163 | ASSERT_TRUE(mat.hasConsistentState()); |
| 164 | |
| 165 | EXPECT_EQ(mat.getNumRows(), 6u); |
| 166 | EXPECT_EQ(mat.getNumColumns(), 5u); |
| 167 | for (unsigned row = 0; row < 6; ++row) |
| 168 | for (unsigned col = 0; col < 5; ++col) |
| 169 | EXPECT_EQ(mat(row, col), row == 5 ? 0 : 10 * row + col); |
| 170 | } |
| 171 | |
| 172 | TEST(MatrixTest, resize) { |
| 173 | IntMatrix mat(5, 5); |
| 174 | EXPECT_EQ(mat.getNumRows(), 5u); |
| 175 | EXPECT_EQ(mat.getNumColumns(), 5u); |
| 176 | for (unsigned row = 0; row < 5; ++row) |
| 177 | for (unsigned col = 0; col < 5; ++col) |
| 178 | mat(row, col) = 10 * row + col; |
| 179 | |
| 180 | mat.resize(newNRows: 3, newNColumns: 3); |
| 181 | ASSERT_TRUE(mat.hasConsistentState()); |
| 182 | EXPECT_EQ(mat.getNumRows(), 3u); |
| 183 | EXPECT_EQ(mat.getNumColumns(), 3u); |
| 184 | for (unsigned row = 0; row < 3; ++row) |
| 185 | for (unsigned col = 0; col < 3; ++col) |
| 186 | EXPECT_EQ(mat(row, col), int(10 * row + col)); |
| 187 | |
| 188 | mat.resize(newNRows: 7, newNColumns: 7); |
| 189 | ASSERT_TRUE(mat.hasConsistentState()); |
| 190 | EXPECT_EQ(mat.getNumRows(), 7u); |
| 191 | EXPECT_EQ(mat.getNumColumns(), 7u); |
| 192 | for (unsigned row = 0; row < 7; ++row) |
| 193 | for (unsigned col = 0; col < 7; ++col) |
| 194 | EXPECT_EQ(mat(row, col), row >= 3 || col >= 3 ? 0 : int(10 * row + col)); |
| 195 | } |
| 196 | |
| 197 | template <typename T> |
| 198 | static void checkMatEqual(const Matrix<T> m1, const Matrix<T> m2) { |
| 199 | EXPECT_EQ(m1.getNumRows(), m2.getNumRows()); |
| 200 | EXPECT_EQ(m1.getNumColumns(), m2.getNumColumns()); |
| 201 | |
| 202 | for (unsigned row = 0, rows = m1.getNumRows(); row < rows; ++row) |
| 203 | for (unsigned col = 0, cols = m1.getNumColumns(); col < cols; ++col) |
| 204 | EXPECT_EQ(m1(row, col), m2(row, col)); |
| 205 | } |
| 206 | |
| 207 | static void checkHermiteNormalForm(const IntMatrix &mat, |
| 208 | const IntMatrix &hermiteForm) { |
| 209 | auto [h, u] = mat.computeHermiteNormalForm(); |
| 210 | |
| 211 | checkMatEqual(m1: h, m2: hermiteForm); |
| 212 | } |
| 213 | |
| 214 | TEST(MatrixTest, computeHermiteNormalForm) { |
| 215 | // TODO: Add a check to test the original statement of hermite normal form |
| 216 | // instead of using a precomputed result. |
| 217 | |
| 218 | { |
| 219 | // Hermite form of a unimodular matrix is the identity matrix. |
| 220 | IntMatrix mat = makeIntMatrix(numRow: 3, numColumns: 3, matrix: {{2, 3, 6}, {3, 2, 3}, {17, 11, 16}}); |
| 221 | IntMatrix hermiteForm = |
| 222 | makeIntMatrix(numRow: 3, numColumns: 3, matrix: {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}); |
| 223 | checkHermiteNormalForm(mat, hermiteForm); |
| 224 | } |
| 225 | |
| 226 | { |
| 227 | // Hermite form of a unimodular is the identity matrix. |
| 228 | IntMatrix mat = makeIntMatrix( |
| 229 | numRow: 4, numColumns: 4, |
| 230 | matrix: {{-6, -1, -19, -20}, {0, 1, 0, 0}, {-5, 0, -15, -16}, {6, 0, 18, 19}}); |
| 231 | IntMatrix hermiteForm = makeIntMatrix( |
| 232 | numRow: 4, numColumns: 4, matrix: {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}); |
| 233 | checkHermiteNormalForm(mat, hermiteForm); |
| 234 | } |
| 235 | |
| 236 | { |
| 237 | IntMatrix mat = makeIntMatrix( |
| 238 | numRow: 4, numColumns: 4, matrix: {{3, 3, 1, 4}, {0, 1, 0, 0}, {0, 0, 19, 16}, {0, 0, 0, 3}}); |
| 239 | IntMatrix hermiteForm = makeIntMatrix( |
| 240 | numRow: 4, numColumns: 4, matrix: {{1, 0, 0, 0}, {0, 1, 0, 0}, {1, 0, 3, 0}, {18, 0, 54, 57}}); |
| 241 | checkHermiteNormalForm(mat, hermiteForm); |
| 242 | } |
| 243 | |
| 244 | { |
| 245 | IntMatrix mat = makeIntMatrix( |
| 246 | numRow: 4, numColumns: 4, matrix: {{3, 3, 1, 4}, {0, 1, 0, 0}, {0, 0, 19, 16}, {0, 0, 0, 3}}); |
| 247 | IntMatrix hermiteForm = makeIntMatrix( |
| 248 | numRow: 4, numColumns: 4, matrix: {{1, 0, 0, 0}, {0, 1, 0, 0}, {1, 0, 3, 0}, {18, 0, 54, 57}}); |
| 249 | checkHermiteNormalForm(mat, hermiteForm); |
| 250 | } |
| 251 | |
| 252 | { |
| 253 | IntMatrix mat = makeIntMatrix( |
| 254 | numRow: 3, numColumns: 5, matrix: {{0, 2, 0, 7, 1}, {-1, 0, 0, -3, 0}, {0, 4, 1, 0, 8}}); |
| 255 | IntMatrix hermiteForm = makeIntMatrix( |
| 256 | numRow: 3, numColumns: 5, matrix: {{1, 0, 0, 0, 0}, {0, 1, 0, 0, 0}, {0, 0, 1, 0, 0}}); |
| 257 | checkHermiteNormalForm(mat, hermiteForm); |
| 258 | } |
| 259 | } |
| 260 | |
| 261 | TEST(MatrixTest, inverse) { |
| 262 | IntMatrix mat1 = makeIntMatrix(numRow: 2, numColumns: 2, matrix: {{2, 1}, {7, 0}}); |
| 263 | EXPECT_EQ(mat1.determinant(), -7); |
| 264 | |
| 265 | FracMatrix mat = makeFracMatrix( |
| 266 | numRow: 2, numColumns: 2, matrix: {{Fraction(2), Fraction(1)}, {Fraction(7), Fraction(0)}}); |
| 267 | FracMatrix inverse = makeFracMatrix( |
| 268 | numRow: 2, numColumns: 2, matrix: {{Fraction(0), Fraction(1, 7)}, {Fraction(1), Fraction(-2, 7)}}); |
| 269 | |
| 270 | FracMatrix inv(2, 2); |
| 271 | mat.determinant(inverse: &inv); |
| 272 | |
| 273 | EXPECT_EQ_FRAC_MATRIX(a: inv, b: inverse); |
| 274 | |
| 275 | mat = makeFracMatrix( |
| 276 | numRow: 2, numColumns: 2, matrix: {{Fraction(0), Fraction(1)}, {Fraction(0), Fraction(2)}}); |
| 277 | Fraction det = mat.determinant(inverse: nullptr); |
| 278 | |
| 279 | EXPECT_EQ(det, Fraction(0)); |
| 280 | |
| 281 | mat = makeFracMatrix(numRow: 3, numColumns: 3, |
| 282 | matrix: {{Fraction(1), Fraction(2), Fraction(3)}, |
| 283 | {Fraction(4), Fraction(8), Fraction(6)}, |
| 284 | {Fraction(7), Fraction(8), Fraction(6)}}); |
| 285 | inverse = makeFracMatrix(numRow: 3, numColumns: 3, |
| 286 | matrix: {{Fraction(0), Fraction(-1, 3), Fraction(1, 3)}, |
| 287 | {Fraction(-1, 2), Fraction(5, 12), Fraction(-1, 6)}, |
| 288 | {Fraction(2, 3), Fraction(-1, 6), Fraction(0)}}); |
| 289 | |
| 290 | mat.determinant(inverse: &inv); |
| 291 | EXPECT_EQ_FRAC_MATRIX(a: inv, b: inverse); |
| 292 | |
| 293 | mat = makeFracMatrix(numRow: 0, numColumns: 0, matrix: {}); |
| 294 | mat.determinant(inverse: &inv); |
| 295 | } |
| 296 | |
| 297 | TEST(MatrixTest, intInverse) { |
| 298 | IntMatrix mat = makeIntMatrix(numRow: 2, numColumns: 2, matrix: {{2, 1}, {7, 0}}); |
| 299 | IntMatrix inverse = makeIntMatrix(numRow: 2, numColumns: 2, matrix: {{0, -1}, {-7, 2}}); |
| 300 | |
| 301 | IntMatrix inv(2, 2); |
| 302 | mat.determinant(inverse: &inv); |
| 303 | |
| 304 | EXPECT_EQ_INT_MATRIX(a: inv, b: inverse); |
| 305 | |
| 306 | mat = makeIntMatrix( |
| 307 | numRow: 4, numColumns: 4, matrix: {{4, 14, 11, 3}, {13, 5, 14, 12}, {13, 9, 7, 14}, {2, 3, 12, 7}}); |
| 308 | inverse = makeIntMatrix(numRow: 4, numColumns: 4, |
| 309 | matrix: {{155, 1636, -579, -1713}, |
| 310 | {725, -743, 537, -111}, |
| 311 | {210, 735, -855, 360}, |
| 312 | {-715, -1409, 1401, 1482}}); |
| 313 | |
| 314 | mat.determinant(inverse: &inv); |
| 315 | |
| 316 | EXPECT_EQ_INT_MATRIX(a: inv, b: inverse); |
| 317 | |
| 318 | mat = makeIntMatrix(numRow: 2, numColumns: 2, matrix: {{0, 0}, {1, 2}}); |
| 319 | |
| 320 | DynamicAPInt det = mat.determinant(inverse: &inv); |
| 321 | |
| 322 | EXPECT_EQ(det, 0); |
| 323 | } |
| 324 | |
| 325 | TEST(MatrixTest, gramSchmidt) { |
| 326 | FracMatrix mat = |
| 327 | makeFracMatrix(numRow: 3, numColumns: 5, |
| 328 | matrix: {{Fraction(3, 1), Fraction(4, 1), Fraction(5, 1), |
| 329 | Fraction(12, 1), Fraction(19, 1)}, |
| 330 | {Fraction(4, 1), Fraction(5, 1), Fraction(6, 1), |
| 331 | Fraction(13, 1), Fraction(20, 1)}, |
| 332 | {Fraction(7, 1), Fraction(8, 1), Fraction(9, 1), |
| 333 | Fraction(16, 1), Fraction(24, 1)}}); |
| 334 | |
| 335 | FracMatrix gramSchmidt = makeFracMatrix( |
| 336 | numRow: 3, numColumns: 5, |
| 337 | matrix: {{Fraction(3, 1), Fraction(4, 1), Fraction(5, 1), Fraction(12, 1), |
| 338 | Fraction(19, 1)}, |
| 339 | {Fraction(142, 185), Fraction(383, 555), Fraction(68, 111), |
| 340 | Fraction(13, 185), Fraction(-262, 555)}, |
| 341 | {Fraction(53, 463), Fraction(27, 463), Fraction(1, 463), |
| 342 | Fraction(-181, 463), Fraction(100, 463)}}); |
| 343 | |
| 344 | FracMatrix gs = mat.gramSchmidt(); |
| 345 | |
| 346 | EXPECT_EQ_FRAC_MATRIX(a: gs, b: gramSchmidt); |
| 347 | for (unsigned i = 0; i < 3u; i++) |
| 348 | for (unsigned j = i + 1; j < 3u; j++) |
| 349 | EXPECT_EQ(dotProduct(gs.getRow(i), gs.getRow(j)), 0); |
| 350 | |
| 351 | mat = makeFracMatrix(numRow: 3, numColumns: 3, |
| 352 | matrix: {{Fraction(20, 1), Fraction(17, 1), Fraction(10, 1)}, |
| 353 | {Fraction(20, 1), Fraction(18, 1), Fraction(6, 1)}, |
| 354 | {Fraction(15, 1), Fraction(14, 1), Fraction(10, 1)}}); |
| 355 | |
| 356 | gramSchmidt = makeFracMatrix( |
| 357 | numRow: 3, numColumns: 3, |
| 358 | matrix: {{Fraction(20, 1), Fraction(17, 1), Fraction(10, 1)}, |
| 359 | {Fraction(460, 789), Fraction(1180, 789), Fraction(-2926, 789)}, |
| 360 | {Fraction(-2925, 3221), Fraction(3000, 3221), Fraction(750, 3221)}}); |
| 361 | |
| 362 | gs = mat.gramSchmidt(); |
| 363 | |
| 364 | EXPECT_EQ_FRAC_MATRIX(a: gs, b: gramSchmidt); |
| 365 | for (unsigned i = 0; i < 3u; i++) |
| 366 | for (unsigned j = i + 1; j < 3u; j++) |
| 367 | EXPECT_EQ(dotProduct(gs.getRow(i), gs.getRow(j)), 0); |
| 368 | |
| 369 | mat = makeFracMatrix( |
| 370 | numRow: 4, numColumns: 4, |
| 371 | matrix: {{Fraction(1, 26), Fraction(13, 12), Fraction(34, 13), Fraction(7, 10)}, |
| 372 | {Fraction(40, 23), Fraction(34, 1), Fraction(11, 19), Fraction(15, 1)}, |
| 373 | {Fraction(21, 22), Fraction(10, 9), Fraction(4, 11), Fraction(14, 11)}, |
| 374 | {Fraction(35, 22), Fraction(1, 15), Fraction(5, 8), Fraction(30, 1)}}); |
| 375 | |
| 376 | gs = mat.gramSchmidt(); |
| 377 | |
| 378 | // The integers involved are too big to construct the actual matrix. |
| 379 | // but we can check that the result is linearly independent. |
| 380 | ASSERT_FALSE(mat.determinant(nullptr) == 0); |
| 381 | |
| 382 | for (unsigned i = 0; i < 4u; i++) |
| 383 | for (unsigned j = i + 1; j < 4u; j++) |
| 384 | EXPECT_EQ(dotProduct(gs.getRow(i), gs.getRow(j)), 0); |
| 385 | |
| 386 | mat = FracMatrix::identity(/*dim=*/dimension: 10); |
| 387 | |
| 388 | gs = mat.gramSchmidt(); |
| 389 | |
| 390 | EXPECT_EQ_FRAC_MATRIX(a: gs, b: FracMatrix::identity(dimension: 10)); |
| 391 | } |
| 392 | |
| 393 | void checkReducedBasis(FracMatrix mat, Fraction delta) { |
| 394 | FracMatrix gsOrth = mat.gramSchmidt(); |
| 395 | |
| 396 | // Size-reduced check. |
| 397 | for (unsigned i = 0, e = mat.getNumRows(); i < e; i++) { |
| 398 | for (unsigned j = 0; j < i; j++) { |
| 399 | Fraction mu = dotProduct(a: mat.getRow(row: i), b: gsOrth.getRow(row: j)) / |
| 400 | dotProduct(a: gsOrth.getRow(row: j), b: gsOrth.getRow(row: j)); |
| 401 | EXPECT_TRUE(abs(mu) <= Fraction(1, 2)); |
| 402 | } |
| 403 | } |
| 404 | |
| 405 | // Lovasz condition check. |
| 406 | for (unsigned i = 1, e = mat.getNumRows(); i < e; i++) { |
| 407 | Fraction mu = dotProduct(a: mat.getRow(row: i), b: gsOrth.getRow(row: i - 1)) / |
| 408 | dotProduct(a: gsOrth.getRow(row: i - 1), b: gsOrth.getRow(row: i - 1)); |
| 409 | EXPECT_TRUE(dotProduct(mat.getRow(i), mat.getRow(i)) > |
| 410 | (delta - mu * mu) * |
| 411 | dotProduct(gsOrth.getRow(i - 1), gsOrth.getRow(i - 1))); |
| 412 | } |
| 413 | } |
| 414 | |
| 415 | TEST(MatrixTest, LLL) { |
| 416 | FracMatrix mat = |
| 417 | makeFracMatrix(numRow: 3, numColumns: 3, |
| 418 | matrix: {{Fraction(1, 1), Fraction(1, 1), Fraction(1, 1)}, |
| 419 | {Fraction(-1, 1), Fraction(0, 1), Fraction(2, 1)}, |
| 420 | {Fraction(3, 1), Fraction(5, 1), Fraction(6, 1)}}); |
| 421 | mat.LLL(delta: Fraction(3, 4)); |
| 422 | |
| 423 | checkReducedBasis(mat, delta: Fraction(3, 4)); |
| 424 | |
| 425 | mat = makeFracMatrix( |
| 426 | numRow: 2, numColumns: 2, |
| 427 | matrix: {{Fraction(12, 1), Fraction(2, 1)}, {Fraction(13, 1), Fraction(4, 1)}}); |
| 428 | mat.LLL(delta: Fraction(3, 4)); |
| 429 | |
| 430 | checkReducedBasis(mat, delta: Fraction(3, 4)); |
| 431 | |
| 432 | mat = makeFracMatrix(numRow: 3, numColumns: 3, |
| 433 | matrix: {{Fraction(1, 1), Fraction(0, 1), Fraction(2, 1)}, |
| 434 | {Fraction(0, 1), Fraction(1, 3), -Fraction(5, 3)}, |
| 435 | {Fraction(0, 1), Fraction(0, 1), Fraction(1, 1)}}); |
| 436 | mat.LLL(delta: Fraction(3, 4)); |
| 437 | |
| 438 | checkReducedBasis(mat, delta: Fraction(3, 4)); |
| 439 | } |
| 440 | |
| 441 | TEST(MatrixTest, moveColumns) { |
| 442 | IntMatrix mat = |
| 443 | makeIntMatrix(numRow: 3, numColumns: 4, matrix: {{0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 4, 2}}); |
| 444 | |
| 445 | { |
| 446 | IntMatrix movedMat = |
| 447 | makeIntMatrix(numRow: 3, numColumns: 4, matrix: {{0, 3, 1, 2}, {4, 7, 5, 6}, {8, 2, 9, 4}}); |
| 448 | |
| 449 | movedMat.moveColumns(srcPos: 2, num: 2, dstPos: 1); |
| 450 | checkMatEqual(m1: mat, m2: movedMat); |
| 451 | } |
| 452 | |
| 453 | { |
| 454 | IntMatrix movedMat = |
| 455 | makeIntMatrix(numRow: 3, numColumns: 4, matrix: {{0, 3, 1, 2}, {4, 7, 5, 6}, {8, 2, 9, 4}}); |
| 456 | |
| 457 | movedMat.moveColumns(srcPos: 1, num: 1, dstPos: 3); |
| 458 | checkMatEqual(m1: mat, m2: movedMat); |
| 459 | } |
| 460 | |
| 461 | { |
| 462 | IntMatrix movedMat = |
| 463 | makeIntMatrix(numRow: 3, numColumns: 4, matrix: {{1, 2, 0, 3}, {5, 6, 4, 7}, {9, 4, 8, 2}}); |
| 464 | |
| 465 | movedMat.moveColumns(srcPos: 0, num: 2, dstPos: 1); |
| 466 | checkMatEqual(m1: mat, m2: movedMat); |
| 467 | } |
| 468 | |
| 469 | { |
| 470 | IntMatrix movedMat = |
| 471 | makeIntMatrix(numRow: 3, numColumns: 4, matrix: {{1, 0, 2, 3}, {5, 4, 6, 7}, {9, 8, 4, 2}}); |
| 472 | |
| 473 | movedMat.moveColumns(srcPos: 0, num: 1, dstPos: 1); |
| 474 | checkMatEqual(m1: mat, m2: movedMat); |
| 475 | } |
| 476 | } |
| 477 | |