[memprof] Move YAML traits to MemProf.h (NFC) (#118668)
[llvm-project.git] / mlir / unittests / Analysis / Presburger / MatrixTest.cpp
blobcb8df8b346011a006b7be40c0f4ddcd9119eca8c
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 //===----------------------------------------------------------------------===//
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>
15 using namespace mlir;
16 using namespace presburger;
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));
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(3, 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);
38 // swap around all the other columns, swap (1, 3) twice for no effect.
39 mat.swapColumns(3, 1);
40 mat.swapColumns(2, 4);
41 mat.swapColumns(1, 3);
42 mat.swapColumns(0, 4);
43 mat.swapColumns(2, 2);
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);
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(2, 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);
60 // swap around all the other rows, swap (2, 0) twice for no effect.
61 mat.swapRows(3, 4);
62 mat.swapRows(1, 4);
63 mat.swapRows(2, 0);
64 mat.swapRows(1, 1);
65 mat.swapRows(0, 2);
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);
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;
80 mat.resizeVertically(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));
88 mat.resizeVertically(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));
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;
105 mat.insertColumns(3, 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));
120 mat.removeColumns(3, 100);
121 ASSERT_TRUE(mat.hasConsistentState());
122 mat.insertColumns(0, 0);
123 ASSERT_TRUE(mat.hasConsistentState());
124 mat.insertColumn(5);
125 ASSERT_TRUE(mat.hasConsistentState());
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);
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;
143 mat.insertRows(3, 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));
158 mat.removeRows(3, 100);
159 ASSERT_TRUE(mat.hasConsistentState());
160 mat.insertRows(0, 0);
161 ASSERT_TRUE(mat.hasConsistentState());
162 mat.insertRow(5);
163 ASSERT_TRUE(mat.hasConsistentState());
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);
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;
180 mat.resize(3, 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));
188 mat.resize(7, 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));
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());
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));
207 static void checkHermiteNormalForm(const IntMatrix &mat,
208 const IntMatrix &hermiteForm) {
209 auto [h, u] = mat.computeHermiteNormalForm();
211 checkMatEqual(h, hermiteForm);
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.
219 // Hermite form of a unimodular matrix is the identity matrix.
220 IntMatrix mat = makeIntMatrix(3, 3, {{2, 3, 6}, {3, 2, 3}, {17, 11, 16}});
221 IntMatrix hermiteForm =
222 makeIntMatrix(3, 3, {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}});
223 checkHermiteNormalForm(mat, hermiteForm);
227 // Hermite form of a unimodular is the identity matrix.
228 IntMatrix mat = makeIntMatrix(
229 4, 4,
230 {{-6, -1, -19, -20}, {0, 1, 0, 0}, {-5, 0, -15, -16}, {6, 0, 18, 19}});
231 IntMatrix hermiteForm = makeIntMatrix(
232 4, 4, {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}});
233 checkHermiteNormalForm(mat, hermiteForm);
237 IntMatrix mat = makeIntMatrix(
238 4, 4, {{3, 3, 1, 4}, {0, 1, 0, 0}, {0, 0, 19, 16}, {0, 0, 0, 3}});
239 IntMatrix hermiteForm = makeIntMatrix(
240 4, 4, {{1, 0, 0, 0}, {0, 1, 0, 0}, {1, 0, 3, 0}, {18, 0, 54, 57}});
241 checkHermiteNormalForm(mat, hermiteForm);
245 IntMatrix mat = makeIntMatrix(
246 4, 4, {{3, 3, 1, 4}, {0, 1, 0, 0}, {0, 0, 19, 16}, {0, 0, 0, 3}});
247 IntMatrix hermiteForm = makeIntMatrix(
248 4, 4, {{1, 0, 0, 0}, {0, 1, 0, 0}, {1, 0, 3, 0}, {18, 0, 54, 57}});
249 checkHermiteNormalForm(mat, hermiteForm);
253 IntMatrix mat = makeIntMatrix(
254 3, 5, {{0, 2, 0, 7, 1}, {-1, 0, 0, -3, 0}, {0, 4, 1, 0, 8}});
255 IntMatrix hermiteForm = makeIntMatrix(
256 3, 5, {{1, 0, 0, 0, 0}, {0, 1, 0, 0, 0}, {0, 0, 1, 0, 0}});
257 checkHermiteNormalForm(mat, hermiteForm);
261 TEST(MatrixTest, inverse) {
262 IntMatrix mat1 = makeIntMatrix(2, 2, {{2, 1}, {7, 0}});
263 EXPECT_EQ(mat1.determinant(), -7);
265 FracMatrix mat = makeFracMatrix(
266 2, 2, {{Fraction(2), Fraction(1)}, {Fraction(7), Fraction(0)}});
267 FracMatrix inverse = makeFracMatrix(
268 2, 2, {{Fraction(0), Fraction(1, 7)}, {Fraction(1), Fraction(-2, 7)}});
270 FracMatrix inv(2, 2);
271 mat.determinant(&inv);
273 EXPECT_EQ_FRAC_MATRIX(inv, inverse);
275 mat = makeFracMatrix(
276 2, 2, {{Fraction(0), Fraction(1)}, {Fraction(0), Fraction(2)}});
277 Fraction det = mat.determinant(nullptr);
279 EXPECT_EQ(det, Fraction(0));
281 mat = makeFracMatrix(3, 3,
282 {{Fraction(1), Fraction(2), Fraction(3)},
283 {Fraction(4), Fraction(8), Fraction(6)},
284 {Fraction(7), Fraction(8), Fraction(6)}});
285 inverse = makeFracMatrix(3, 3,
286 {{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)}});
290 mat.determinant(&inv);
291 EXPECT_EQ_FRAC_MATRIX(inv, inverse);
293 mat = makeFracMatrix(0, 0, {});
294 mat.determinant(&inv);
297 TEST(MatrixTest, intInverse) {
298 IntMatrix mat = makeIntMatrix(2, 2, {{2, 1}, {7, 0}});
299 IntMatrix inverse = makeIntMatrix(2, 2, {{0, -1}, {-7, 2}});
301 IntMatrix inv(2, 2);
302 mat.determinant(&inv);
304 EXPECT_EQ_INT_MATRIX(inv, inverse);
306 mat = makeIntMatrix(
307 4, 4, {{4, 14, 11, 3}, {13, 5, 14, 12}, {13, 9, 7, 14}, {2, 3, 12, 7}});
308 inverse = makeIntMatrix(4, 4,
309 {{155, 1636, -579, -1713},
310 {725, -743, 537, -111},
311 {210, 735, -855, 360},
312 {-715, -1409, 1401, 1482}});
314 mat.determinant(&inv);
316 EXPECT_EQ_INT_MATRIX(inv, inverse);
318 mat = makeIntMatrix(2, 2, {{0, 0}, {1, 2}});
320 DynamicAPInt det = mat.determinant(&inv);
322 EXPECT_EQ(det, 0);
325 TEST(MatrixTest, gramSchmidt) {
326 FracMatrix mat =
327 makeFracMatrix(3, 5,
328 {{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)}});
335 FracMatrix gramSchmidt = makeFracMatrix(
336 3, 5,
337 {{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)}});
344 FracMatrix gs = mat.gramSchmidt();
346 EXPECT_EQ_FRAC_MATRIX(gs, 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);
351 mat = makeFracMatrix(3, 3,
352 {{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)}});
356 gramSchmidt = makeFracMatrix(
357 3, 3,
358 {{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)}});
362 gs = mat.gramSchmidt();
364 EXPECT_EQ_FRAC_MATRIX(gs, 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);
369 mat = makeFracMatrix(
370 4, 4,
371 {{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)}});
376 gs = mat.gramSchmidt();
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);
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);
386 mat = FracMatrix::identity(/*dim=*/10);
388 gs = mat.gramSchmidt();
390 EXPECT_EQ_FRAC_MATRIX(gs, FracMatrix::identity(10));
393 void checkReducedBasis(FracMatrix mat, Fraction delta) {
394 FracMatrix gsOrth = mat.gramSchmidt();
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(mat.getRow(i), gsOrth.getRow(j)) /
400 dotProduct(gsOrth.getRow(j), gsOrth.getRow(j));
401 EXPECT_TRUE(abs(mu) <= Fraction(1, 2));
405 // Lovasz condition check.
406 for (unsigned i = 1, e = mat.getNumRows(); i < e; i++) {
407 Fraction mu = dotProduct(mat.getRow(i), gsOrth.getRow(i - 1)) /
408 dotProduct(gsOrth.getRow(i - 1), gsOrth.getRow(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)));
415 TEST(MatrixTest, LLL) {
416 FracMatrix mat =
417 makeFracMatrix(3, 3,
418 {{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(Fraction(3, 4));
423 checkReducedBasis(mat, Fraction(3, 4));
425 mat = makeFracMatrix(
426 2, 2,
427 {{Fraction(12, 1), Fraction(2, 1)}, {Fraction(13, 1), Fraction(4, 1)}});
428 mat.LLL(Fraction(3, 4));
430 checkReducedBasis(mat, Fraction(3, 4));
432 mat = makeFracMatrix(3, 3,
433 {{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(Fraction(3, 4));
438 checkReducedBasis(mat, Fraction(3, 4));
441 TEST(MatrixTest, moveColumns) {
442 IntMatrix mat =
443 makeIntMatrix(3, 4, {{0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 4, 2}});
446 IntMatrix movedMat =
447 makeIntMatrix(3, 4, {{0, 3, 1, 2}, {4, 7, 5, 6}, {8, 2, 9, 4}});
449 movedMat.moveColumns(2, 2, 1);
450 checkMatEqual(mat, movedMat);
454 IntMatrix movedMat =
455 makeIntMatrix(3, 4, {{0, 3, 1, 2}, {4, 7, 5, 6}, {8, 2, 9, 4}});
457 movedMat.moveColumns(1, 1, 3);
458 checkMatEqual(mat, movedMat);
462 IntMatrix movedMat =
463 makeIntMatrix(3, 4, {{1, 2, 0, 3}, {5, 6, 4, 7}, {9, 4, 8, 2}});
465 movedMat.moveColumns(0, 2, 1);
466 checkMatEqual(mat, movedMat);
470 IntMatrix movedMat =
471 makeIntMatrix(3, 4, {{1, 0, 2, 3}, {5, 4, 6, 7}, {9, 8, 4, 2}});
473 movedMat.moveColumns(0, 1, 1);
474 checkMatEqual(mat, movedMat);