-
Notifications
You must be signed in to change notification settings - Fork 11.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[MLIR][Presburger] Implement matrix inverse #67382
Conversation
…nstantiation Duplicate makeMatrix to makeIntMatrix and makeFracMatrix Implement arithmetic operations for Fraction for compatibility
…nstantiation Duplicate makeMatrix to makeIntMatrix and makeFracMatrix Implement arithmetic operations for Fraction for compatibility
This reverts commit 2871b0127a3cbc8d2a4cf294e731aade1ed56424.
…nstantiation Duplicate makeMatrix to makeIntMatrix and makeFracMatrix Implement arithmetic operations for Fraction for compatibility
…nstantiation Duplicate makeMatrix to makeIntMatrix and makeFracMatrix Implement arithmetic operations for Fraction for compatibility
Fix reduce() method in Fraction
✅ With the latest revision this PR passed the C/C++ code formatter. |
@llvm/pr-subscribers-mlir-presburger ChangesA new class, FracMatrix, has been created for rational matrices. Full diff: https://github.com/llvm/llvm-project/pull/67382.diff 5 Files Affected:
diff --git a/mlir/include/mlir/Analysis/Presburger/Fraction.h b/mlir/include/mlir/Analysis/Presburger/Fraction.h
index 74127a900d53ed2..f633192a870c8d4 100644
--- a/mlir/include/mlir/Analysis/Presburger/Fraction.h
+++ b/mlir/include/mlir/Analysis/Presburger/Fraction.h
@@ -102,7 +102,7 @@ inline bool operator>=(const Fraction &x, const Fraction &y) {
inline Fraction reduce(const Fraction &f) {
if (f == Fraction(0))
return Fraction(0, 1);
- MPInt g = gcd(f.num, f.den);
+ MPInt g = gcd(abs(f.num), abs(f.den));
return Fraction(f.num / g, f.den / g);
}
diff --git a/mlir/include/mlir/Analysis/Presburger/Matrix.h b/mlir/include/mlir/Analysis/Presburger/Matrix.h
index f05a4fb2ffbb70d..b9048334c39f1f3 100644
--- a/mlir/include/mlir/Analysis/Presburger/Matrix.h
+++ b/mlir/include/mlir/Analysis/Presburger/Matrix.h
@@ -244,6 +244,32 @@ class IntMatrix : public Matrix<MPInt>
};
+// An inherited class for rational matrices, with no new data attributes.
+// This is only used for the matrix-related method which apply only
+// to fractions (inverse).
+class FracMatrix : public Matrix<Fraction>
+{
+public:
+ FracMatrix(unsigned rows, unsigned columns, unsigned reservedRows = 0,
+ unsigned reservedColumns = 0) :
+ Matrix<Fraction>(rows, columns, reservedRows, reservedColumns) {};
+
+ FracMatrix(Matrix<Fraction> m) :
+ Matrix<Fraction>(m.getNumRows(), m.getNumColumns(), m.getNumReservedRows(), m.getNumReservedColumns())
+ {
+ for (unsigned i = 0; i < m.getNumRows(); i++)
+ for (unsigned j = 0; j < m.getNumColumns(); j++)
+ at(i, j) = m(i, j);
+ };
+
+ /// Return the identity matrix of the specified dimension.
+ static FracMatrix identity(unsigned dimension);
+
+ // Return the inverse of the matrix, leaving the calling object unmodified.
+ FracMatrix inverse();
+
+};
+
} // namespace presburger
} // namespace mlir
diff --git a/mlir/lib/Analysis/Presburger/Matrix.cpp b/mlir/lib/Analysis/Presburger/Matrix.cpp
index f0bcb09fb28f7b1..c0fbc688be2e1b2 100644
--- a/mlir/lib/Analysis/Presburger/Matrix.cpp
+++ b/mlir/lib/Analysis/Presburger/Matrix.cpp
@@ -390,4 +390,70 @@ MPInt IntMatrix::normalizeRow(unsigned row, unsigned cols) {
MPInt IntMatrix::normalizeRow(unsigned row) {
return normalizeRow(row, getNumColumns());
+}
+
+
+FracMatrix FracMatrix::identity(unsigned dimension) {
+ FracMatrix matrix(dimension, dimension);
+ for (unsigned i = 0; i < dimension; ++i)
+ matrix(i, i) = 1;
+ return matrix;
+}
+
+FracMatrix FracMatrix::inverse()
+{
+ // We use Gaussian elimination on the rows of [M | I]
+ // to find the integer inverse. We proceed left-to-right,
+ // top-to-bottom. M is assumed to be a dim x dim matrix.
+
+ unsigned dim = getNumRows();
+
+ // Construct the augmented matrix [M | I]
+ FracMatrix augmented(dim, dim + dim);
+ for (unsigned i = 0; i < dim; i++)
+ {
+ augmented.fillRow(i, 0);
+ for (unsigned j = 0; j < dim; j++)
+ augmented(i, j) = at(i, j);
+ augmented(i, dim+i).num = 1;
+ augmented(i, dim+i).den = 1;
+ }
+ Fraction a, b;
+ for (unsigned i = 0; i < dim; i++)
+ {
+ if (augmented(i, i) == Fraction(0, 1))
+ for (unsigned j = i+1; j < dim; j++)
+ if (augmented(j, i) != Fraction(0, 1))
+ {
+ augmented.addToRow(i, augmented.getRow(j), Fraction(1, 1));
+ break;
+ }
+
+ b = augmented(i, i);
+ for (unsigned j = 0; j < dim; j++)
+ {
+ if (i == j || augmented(j, i) == 0) continue;
+ a = augmented(j, i);
+ // Rj -> Rj - (b/a)Ri
+ augmented.addToRow(j, augmented.getRow(i), - a / b);
+ // Now (Rj)i = 0
+ }
+ }
+
+ // Now only diagonal elements are nonzero, but they are
+ // not necessarily 1.
+ for (unsigned i = 0; i < dim; i++)
+ {
+ a = augmented(i, i);
+ for (unsigned j = dim; j < dim + dim; j++)
+ augmented(i, j) = augmented(i, j) / a;
+ }
+
+ // Copy the right half of the augmented matrix.
+ FracMatrix inverse(dim, dim);
+ for (unsigned i = 0; i < dim; i++)
+ for (unsigned j = 0; j < dim; j++)
+ inverse(i, j) = augmented(i, j+dim);
+
+ return inverse;
}
\ No newline at end of file
diff --git a/mlir/unittests/Analysis/Presburger/MatrixTest.cpp b/mlir/unittests/Analysis/Presburger/MatrixTest.cpp
index 6b23cedabf624ec..d07318617e1a249 100644
--- a/mlir/unittests/Analysis/Presburger/MatrixTest.cpp
+++ b/mlir/unittests/Analysis/Presburger/MatrixTest.cpp
@@ -248,3 +248,14 @@ TEST(MatrixTest, computeHermiteNormalForm) {
checkHermiteNormalForm(mat, hermiteForm);
}
}
+
+TEST(MatrixTest, inverse) {
+ FracMatrix mat = makeFracMatrix(2, 2, {{Fraction(2, 1), Fraction(1, 1)}, {Fraction(7, 1), Fraction(0, 1)}});
+ FracMatrix inverse = makeFracMatrix(2, 2, {{Fraction(0, 1), Fraction(1, 7)}, {Fraction(1, 1), Fraction(-2, 7)}});
+
+ FracMatrix inv = mat.inverse();
+
+ for (unsigned row = 0; row < 2; row++)
+ for (unsigned col = 0; col < 2; col++)
+ EXPECT_EQ(inv(row, col), inverse(row, col));
+}
diff --git a/mlir/unittests/Analysis/Presburger/Utils.h b/mlir/unittests/Analysis/Presburger/Utils.h
index ef4a67d0b8c004f..c652daa583a882c 100644
--- a/mlir/unittests/Analysis/Presburger/Utils.h
+++ b/mlir/unittests/Analysis/Presburger/Utils.h
@@ -40,9 +40,9 @@ inline IntMatrix makeIntMatrix(unsigned numRow, unsigned numColumns,
return results;
}
-inline Matrix<Fraction> makeFracMatrix(unsigned numRow, unsigned numColumns,
+inline FracMatrix makeFracMatrix(unsigned numRow, unsigned numColumns,
ArrayRef<SmallVector<Fraction, 8>> matrix) {
- Matrix<Fraction> results(numRow, numColumns);
+ FracMatrix results(numRow, numColumns);
assert(matrix.size() == numRow);
for (unsigned i = 0; i < numRow; ++i) {
assert(matrix[i].size() == numColumns &&
|
Formatting
Shift the
determinant()
function from LinearTransform to Matrix.Implement a FracMatrix class, inheriting from Matrix, for inverses.
Implement inverse for FracMatrix and intInverse for IntMatrix.