[Mlir-commits] [mlir] [MLIR][Presburger] Add support for Smith normal form (PR #185328)

Arjun Pitchanathan llvmlistbot at llvm.org
Sun Mar 15 16:53:50 PDT 2026


================
@@ -535,6 +553,120 @@ std::pair<IntMatrix, IntMatrix> IntMatrix::computeHermiteNormalForm() const {
   return {h, u};
 }
 
+std::tuple<IntMatrix, IntMatrix, IntMatrix>
+IntMatrix::computeSmithNormalForm() const {
+  IntMatrix d = *this;
+  // The matrix U records row operations, while V records column operations.
+  // When we operate on the matrix D in the following code, we record the same
+  // operations on U and V respectively.
+  IntMatrix u = IntMatrix::identity(d.getNumRows());
+  IntMatrix v = IntMatrix::identity(d.getNumColumns());
+
+  unsigned numRows = d.getNumRows();
+  unsigned numCols = d.getNumColumns();
+  for (unsigned i = 0, e = std::min(numRows, numCols); i < e; i++) {
+    bool changed;
+    do {
+      changed = false;
+
+      // Find the entry in the submatrix d(i:, i:) with the smallest non-zero
+      // absolute value.
+      // The element is denoted d(p, q), and is the pivot.
+      unsigned p = i, q = i;
+      DynamicAPInt minVal(0);
+      for (unsigned r = i; r < numRows; r++)
+        for (unsigned c = i; c < numCols; c++) {
+          DynamicAPInt val = llvm::abs(d(r, c));
+          if (val != 0 && (minVal == 0 || val < minVal)) {
+            minVal = val;
+            p = r;
+            q = c;
+          }
+        }
+
+      // The remaining submatrix is zero.
+      if (minVal == 0)
+        break;
+
+      // Bring pivot to d(i, i). Record the operation in u, v respectively.
+      if (p != i) {
+        d.swapRows(p, i);
+        u.swapRows(p, i);
+      }
+      if (q != i) {
+        d.swapColumns(q, i);
+        v.swapColumns(q, i);
+      }
+
+      // The pivot should be positive.
+      if (d(i, i) < 0) {
+        d.negateRow(i);
+        u.negateRow(i);
+      }
+
+      DynamicAPInt pivot = d(i, i);
+
+      // Clear other entries in row i and column i with Euclid's algorithm.
+      for (unsigned r = 0; r < numRows; ++r) {
+        if (r == i)
+          continue;
+        while (d(r, i) != 0) {
+          auto quotient = d(r, i) / d(i, i);
+          d.addToRow(i, r, -quotient);
+          u.addToRow(i, r, -quotient);
+
+          if (llvm::abs(d(r, i)) < llvm::abs(d(i, i)) && d(r, i) != 0) {
+            d.swapRows(r, i);
+            u.swapRows(r, i);
+            changed = true;
+          }
+        }
+      }
+      // Similar to the rows operations, this time it works on columns.
+      for (unsigned c = 0; c < numCols; ++c) {
+        if (c == i)
+          continue;
+        while (d(i, c) != 0) {
+          DynamicAPInt quotient = d(i, c) / d(i, i);
+
+          d.addToColumn(i, c, -quotient);
+          v.addToColumn(i, c, -quotient);
+
+          if (llvm::abs(d(i, c)) < llvm::abs(d(i, i)) && d(i, c) != 0) {
+            d.swapColumns(c, i);
+            v.swapColumns(c, i);
+            changed = true;
+          }
+          assert(d(i, i) != 0);
+        }
+      }
+
+      for (unsigned r = i + 1; r < numRows; ++r) {
+        bool breakFlag = false;
+        for (unsigned c = i + 1; c < numCols; ++c) {
+          if (d(r, c) % pivot != 0) {
+            // Add row r to row i. This brings d(r, c) into the i-th row,
+            // creating a new value at d(i, c) that will be used to reduce the
+            // pivot size.
+            d.addToRow(r, i, 1);
+            u.addToRow(r, i, 1);
+            changed = true;
+
+            // We must break and restart the inner process to find the new,
+            // smaller pivot in the submatrix d(i:, i:).
+            breakFlag = true;
+            break;
+          }
+        }
+        if (breakFlag)
+          break;
+      }
+    } while (changed);
----------------
superty wrote:

sorry I meanta that the lambda should return min row s.t. exists col s.t. d(row, col) % pivot != 0. (or empty optoinal if there is none.)

then you can do

```
if (auto maybeRow = findFirstNonMultipleRow(...)) {
          d.addToRow(*maybeRow, i, 1);
          u.addToRow(*maybeRow, i, 1);
          changed = true;
}
```

where findFirstNonMultipleRow is your lambda

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


More information about the Mlir-commits mailing list