[clang-tools-extra] [MLIR][Presburger] Define matrix inverse for rational matrices (PR #67382)

via cfe-commits cfe-commits at lists.llvm.org
Mon Sep 25 22:55:26 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir-presburger

<details>
<summary>Changes</summary>

A new class, FracMatrix, has been created for rational matrices.
It inherits from Matrix<Fraction> with no new data attributes and one new method, `inverse()`.
Gaussian elimination is used in the inverse implementation.
A basic test for inverses has also been added.

---
Full diff: https://github.com/llvm/llvm-project/pull/67382.diff


5 Files Affected:

- (modified) mlir/include/mlir/Analysis/Presburger/Fraction.h (+1-1) 
- (modified) mlir/include/mlir/Analysis/Presburger/Matrix.h (+26) 
- (modified) mlir/lib/Analysis/Presburger/Matrix.cpp (+66) 
- (modified) mlir/unittests/Analysis/Presburger/MatrixTest.cpp (+11) 
- (modified) mlir/unittests/Analysis/Presburger/Utils.h (+2-2) 


``````````diff
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 &&

``````````

</details>


https://github.com/llvm/llvm-project/pull/67382


More information about the cfe-commits mailing list