[libcxx-commits] [libcxx] [MLIR][Presburger] Define matrix inverse for rational matrices (PR #67382)

via libcxx-commits libcxx-commits at lists.llvm.org
Mon Oct 2 05:41:19 PDT 2023


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

>From 8b09dcb29a66c3c88bdf1acac2df65091ab60183 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Wed, 6 Sep 2023 14:11:26 +0100
Subject: [PATCH 01/27] Update upstream branch

---
 libcxx/modules/std/mdspan.cppm | 33 +++++++++++++++++++++++++++++++++
 libcxx/modules/std/print.cppm  | 25 +++++++++++++++++++++++++
 2 files changed, 58 insertions(+)
 create mode 100644 libcxx/modules/std/mdspan.cppm
 create mode 100644 libcxx/modules/std/print.cppm

diff --git a/libcxx/modules/std/mdspan.cppm b/libcxx/modules/std/mdspan.cppm
new file mode 100644
index 000000000000000..40426cce3fce8c2
--- /dev/null
+++ b/libcxx/modules/std/mdspan.cppm
@@ -0,0 +1,33 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+module;
+#include <mdspan>
+
+export module std:mdspan;
+export namespace std {
+#if _LIBCPP_STD_VER >= 23
+  // [mdspan.extents], class template extents
+  using std::extents;
+
+  // [mdspan.extents.dextents], alias template dextents
+  using std::dextents;
+
+  // [mdspan.layout], layout mapping
+  using std::layout_left;
+  using std::layout_right;
+  // using std::layout_stride;
+
+  // [mdspan.accessor.default], class template default_accessor
+  using std::default_accessor;
+
+  // [mdspan.mdspan], class template mdspan
+  using std::mdspan;
+#endif // _LIBCPP_STD_VER >= 23
+} // namespace std
diff --git a/libcxx/modules/std/print.cppm b/libcxx/modules/std/print.cppm
new file mode 100644
index 000000000000000..02362633c6d9fbb
--- /dev/null
+++ b/libcxx/modules/std/print.cppm
@@ -0,0 +1,25 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+module;
+#include <print>
+
+export module std:print;
+export namespace std {
+#if _LIBCPP_STD_VER >= 23
+  // [print.fun], print functions
+  using std::print;
+  using std::println;
+
+  using std::vprint_nonunicode;
+#  ifndef _LIBCPP_HAS_NO_UNICODE
+  using std::vprint_unicode;
+#  endif // _LIBCPP_HAS_NO_UNICODE
+#endif   // _LIBCPP_STD_VER >= 23
+} // namespace std

>From 5733a7eee39a4c192271b18435e12737e2f6c73f Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Tue, 5 Sep 2023 10:42:03 +0100
Subject: [PATCH 02/27] Shift changes to Fraction

---
 .../mlir/Analysis/Presburger/Fraction.h        | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/mlir/include/mlir/Analysis/Presburger/Fraction.h b/mlir/include/mlir/Analysis/Presburger/Fraction.h
index 74127a900d53ed2..2c3e43021707e16 100644
--- a/mlir/include/mlir/Analysis/Presburger/Fraction.h
+++ b/mlir/include/mlir/Analysis/Presburger/Fraction.h
@@ -15,6 +15,7 @@
 #define MLIR_ANALYSIS_PRESBURGER_FRACTION_H
 
 #include "mlir/Analysis/Presburger/MPInt.h"
+#include "mlir/Analysis/Presburger/Utils.h"
 #include "mlir/Support/MathExtras.h"
 
 namespace mlir {
@@ -147,6 +148,23 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
   return os;
 }
 
+inline Fraction operator/(const Fraction &x, const Fraction &y) {
+  return Fraction(x.num * y.den, x.den * y.num);
+}
+
+inline Fraction operator+(const Fraction &x, const Fraction &y) {
+  return Fraction(x.num * y.den + x.den * y.num, x.den * y.den);
+}
+
+inline Fraction operator-(const Fraction &x, const Fraction &y) {
+  return Fraction(x.num * y.den - x.den * y.num, x.den * y.den);
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
+  x.print(os);
+  return os;
+}
+
 } // namespace presburger
 } // namespace mlir
 

>From 9b2a1713d0ac79a2e9683dc95294e1ce63f0196e Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Tue, 5 Sep 2023 11:15:05 +0100
Subject: [PATCH 03/27] Update documentation and remove extraneous include

---
 mlir/include/mlir/Analysis/Presburger/Fraction.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Fraction.h b/mlir/include/mlir/Analysis/Presburger/Fraction.h
index 2c3e43021707e16..3d0b8cde0b38d7c 100644
--- a/mlir/include/mlir/Analysis/Presburger/Fraction.h
+++ b/mlir/include/mlir/Analysis/Presburger/Fraction.h
@@ -15,7 +15,6 @@
 #define MLIR_ANALYSIS_PRESBURGER_FRACTION_H
 
 #include "mlir/Analysis/Presburger/MPInt.h"
-#include "mlir/Analysis/Presburger/Utils.h"
 #include "mlir/Support/MathExtras.h"
 
 namespace mlir {

>From 732aa3577193381a6a3e4456085b08051bf33af0 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Thu, 31 Aug 2023 17:30:17 +0100
Subject: [PATCH 04/27] Template Matrix to Matrix<T> (for MPInt and Fraction)
 with explicit instantiation Duplicate makeMatrix to makeIntMatrix and
 makeFracMatrix

Implement arithmetic operations for Fraction for compatibility
---
 .../mlir/Analysis/Presburger/Fraction.h       |   1 +
 .../Analysis/Presburger/IntegerRelation.h     |   6 +-
 .../Analysis/Presburger/LinearTransform.h     |  12 +-
 .../include/mlir/Analysis/Presburger/Matrix.h |  42 +++----
 .../mlir/Analysis/Presburger/PWMAFunction.h   |   8 +-
 .../mlir/Analysis/Presburger/Simplex.h        |   4 +-
 mlir/include/mlir/Analysis/Presburger/Utils.h |   2 +-
 .../Analysis/FlatLinearValueConstraints.cpp   |   2 +-
 .../Analysis/Presburger/IntegerRelation.cpp   |   6 +-
 .../Analysis/Presburger/LinearTransform.cpp   |   6 +-
 mlir/lib/Analysis/Presburger/Matrix.cpp       | 114 ++++++++++--------
 mlir/lib/Analysis/Presburger/Simplex.cpp      |   4 +-
 .../Presburger/LinearTransformTest.cpp        |  14 +--
 .../Analysis/Presburger/MatrixTest.cpp        |  43 +++----
 mlir/unittests/Analysis/Presburger/Parser.h   |   2 +-
 mlir/unittests/Analysis/Presburger/Utils.h    |  20 ++-
 16 files changed, 158 insertions(+), 128 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Fraction.h b/mlir/include/mlir/Analysis/Presburger/Fraction.h
index 3d0b8cde0b38d7c..2c3e43021707e16 100644
--- a/mlir/include/mlir/Analysis/Presburger/Fraction.h
+++ b/mlir/include/mlir/Analysis/Presburger/Fraction.h
@@ -15,6 +15,7 @@
 #define MLIR_ANALYSIS_PRESBURGER_FRACTION_H
 
 #include "mlir/Analysis/Presburger/MPInt.h"
+#include "mlir/Analysis/Presburger/Utils.h"
 #include "mlir/Support/MathExtras.h"
 
 namespace mlir {
diff --git a/mlir/include/mlir/Analysis/Presburger/IntegerRelation.h b/mlir/include/mlir/Analysis/Presburger/IntegerRelation.h
index eae866e63d8d128..d4e58ef0d04666c 100644
--- a/mlir/include/mlir/Analysis/Presburger/IntegerRelation.h
+++ b/mlir/include/mlir/Analysis/Presburger/IntegerRelation.h
@@ -366,7 +366,7 @@ class IntegerRelation {
   /// bounded. The span of the returned vectors is guaranteed to contain all
   /// such vectors. The returned vectors are NOT guaranteed to be linearly
   /// independent. This function should not be called on empty sets.
-  Matrix getBoundedDirections() const;
+  Matrix<MPInt> getBoundedDirections() const;
 
   /// Find an integer sample point satisfying the constraints using a
   /// branch and bound algorithm with generalized basis reduction, with some
@@ -792,10 +792,10 @@ class IntegerRelation {
   PresburgerSpace space;
 
   /// Coefficients of affine equalities (in == 0 form).
-  Matrix equalities;
+  Matrix<MPInt> equalities;
 
   /// Coefficients of affine inequalities (in >= 0 form).
-  Matrix inequalities;
+  Matrix<MPInt> inequalities;
 };
 
 /// An IntegerPolyhedron represents the set of points from a PresburgerSpace
diff --git a/mlir/include/mlir/Analysis/Presburger/LinearTransform.h b/mlir/include/mlir/Analysis/Presburger/LinearTransform.h
index cd56951fe773f8b..686e846a16c78a7 100644
--- a/mlir/include/mlir/Analysis/Presburger/LinearTransform.h
+++ b/mlir/include/mlir/Analysis/Presburger/LinearTransform.h
@@ -22,8 +22,8 @@ namespace presburger {
 
 class LinearTransform {
 public:
-  explicit LinearTransform(Matrix &&oMatrix);
-  explicit LinearTransform(const Matrix &oMatrix);
+  explicit LinearTransform(Matrix<MPInt> &&oMatrix);
+  explicit LinearTransform(const Matrix<MPInt> &oMatrix);
 
   // Returns a linear transform T such that MT is M in column echelon form.
   // Also returns the number of non-zero columns in MT.
@@ -32,7 +32,7 @@ class LinearTransform {
   // strictly below that of the previous column, and all columns which have only
   // zeros are at the end.
   static std::pair<unsigned, LinearTransform>
-  makeTransformToColumnEchelon(const Matrix &m);
+  makeTransformToColumnEchelon(const Matrix<MPInt> &m);
 
   // Returns an IntegerRelation having a constraint vector vT for every
   // constraint vector v in rel, where T is this transform.
@@ -50,8 +50,12 @@ class LinearTransform {
     return matrix.postMultiplyWithColumn(colVec);
   }
 
+  // Compute the determinant of the transform by converting it to row echelon
+  // form and then taking the product of the diagonal.
+  MPInt determinant();
+
 private:
-  Matrix matrix;
+  Matrix<MPInt> matrix;
 };
 
 } // namespace presburger
diff --git a/mlir/include/mlir/Analysis/Presburger/Matrix.h b/mlir/include/mlir/Analysis/Presburger/Matrix.h
index bae1661d9ce6c60..b03737ab2f70a4a 100644
--- a/mlir/include/mlir/Analysis/Presburger/Matrix.h
+++ b/mlir/include/mlir/Analysis/Presburger/Matrix.h
@@ -14,7 +14,6 @@
 #ifndef MLIR_ANALYSIS_PRESBURGER_MATRIX_H
 #define MLIR_ANALYSIS_PRESBURGER_MATRIX_H
 
-#include "mlir/Analysis/Presburger/MPInt.h"
 #include "mlir/Support/LLVM.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/raw_ostream.h"
@@ -32,6 +31,7 @@ namespace presburger {
 /// (i, j) is stored at data[i*nReservedColumns + j]. The reserved but unused
 /// columns always have all zero values. The reserved rows are just reserved
 /// space in the underlying SmallVector's capacity.
+template<typename T>
 class Matrix {
 public:
   Matrix() = delete;
@@ -49,21 +49,21 @@ class Matrix {
   static Matrix identity(unsigned dimension);
 
   /// Access the element at the specified row and column.
-  MPInt &at(unsigned row, unsigned column) {
+  T &at(unsigned row, unsigned column) {
     assert(row < nRows && "Row outside of range");
     assert(column < nColumns && "Column outside of range");
     return data[row * nReservedColumns + column];
   }
 
-  MPInt at(unsigned row, unsigned column) const {
+  T at(unsigned row, unsigned column) const {
     assert(row < nRows && "Row outside of range");
     assert(column < nColumns && "Column outside of range");
     return data[row * nReservedColumns + column];
   }
 
-  MPInt &operator()(unsigned row, unsigned column) { return at(row, column); }
+  T &operator()(unsigned row, unsigned column) { return at(row, column); }
 
-  MPInt operator()(unsigned row, unsigned column) const {
+  T operator()(unsigned row, unsigned column) const {
     return at(row, column);
   }
 
@@ -87,11 +87,11 @@ class Matrix {
   void reserveRows(unsigned rows);
 
   /// Get a [Mutable]ArrayRef corresponding to the specified row.
-  MutableArrayRef<MPInt> getRow(unsigned row);
-  ArrayRef<MPInt> getRow(unsigned row) const;
+  MutableArrayRef<T> getRow(unsigned row);
+  ArrayRef<T> getRow(unsigned row) const;
 
   /// Set the specified row to `elems`.
-  void setRow(unsigned row, ArrayRef<MPInt> elems);
+  void setRow(unsigned row, ArrayRef<T> elems);
 
   /// Insert columns having positions pos, pos + 1, ... pos + count - 1.
   /// Columns that were at positions 0 to pos - 1 will stay where they are;
@@ -125,23 +125,23 @@ class Matrix {
 
   void copyRow(unsigned sourceRow, unsigned targetRow);
 
-  void fillRow(unsigned row, const MPInt &value);
-  void fillRow(unsigned row, int64_t value) { fillRow(row, MPInt(value)); }
+  void fillRow(unsigned row, const T &value);
+  void fillRow(unsigned row, int64_t value) { fillRow(row, T(value)); }
 
   /// Add `scale` multiples of the source row to the target row.
-  void addToRow(unsigned sourceRow, unsigned targetRow, const MPInt &scale);
+  void addToRow(unsigned sourceRow, unsigned targetRow, const T &scale);
   void addToRow(unsigned sourceRow, unsigned targetRow, int64_t scale) {
-    addToRow(sourceRow, targetRow, MPInt(scale));
+    addToRow(sourceRow, targetRow, T(scale));
   }
   /// Add `scale` multiples of the rowVec row to the specified row.
-  void addToRow(unsigned row, ArrayRef<MPInt> rowVec, const MPInt &scale);
+  void addToRow(unsigned row, ArrayRef<T> rowVec, const T &scale);
 
   /// Add `scale` multiples of the source column to the target column.
   void addToColumn(unsigned sourceColumn, unsigned targetColumn,
-                   const MPInt &scale);
+                   const T &scale);
   void addToColumn(unsigned sourceColumn, unsigned targetColumn,
                    int64_t scale) {
-    addToColumn(sourceColumn, targetColumn, MPInt(scale));
+    addToColumn(sourceColumn, targetColumn, T(scale));
   }
 
   /// Negate the specified column.
@@ -152,18 +152,18 @@ class Matrix {
 
   /// Divide the first `nCols` of the specified row by their GCD.
   /// Returns the GCD of the first `nCols` of the specified row.
-  MPInt normalizeRow(unsigned row, unsigned nCols);
+  T normalizeRow(unsigned row, unsigned nCols);
   /// Divide the columns of the specified row by their GCD.
   /// Returns the GCD of the columns of the specified row.
-  MPInt normalizeRow(unsigned row);
+  T normalizeRow(unsigned row);
 
   /// The given vector is interpreted as a row vector v. Post-multiply v with
   /// this matrix, say M, and return vM.
-  SmallVector<MPInt, 8> preMultiplyWithRow(ArrayRef<MPInt> rowVec) const;
+  SmallVector<T, 8> preMultiplyWithRow(ArrayRef<T> rowVec) const;
 
   /// The given vector is interpreted as a column vector v. Pre-multiply v with
   /// this matrix, say M, and return Mv.
-  SmallVector<MPInt, 8> postMultiplyWithColumn(ArrayRef<MPInt> colVec) const;
+  SmallVector<T, 8> postMultiplyWithColumn(ArrayRef<T> colVec) const;
 
   /// Given the current matrix M, returns the matrices H, U such that H is the
   /// column hermite normal form of M, i.e. H = M * U, where U is unimodular and
@@ -192,7 +192,7 @@ class Matrix {
   unsigned appendExtraRow();
   /// Same as above, but copy the given elements into the row. The length of
   /// `elems` must be equal to the number of columns.
-  unsigned appendExtraRow(ArrayRef<MPInt> elems);
+  unsigned appendExtraRow(ArrayRef<T> elems);
 
   /// Print the matrix.
   void print(raw_ostream &os) const;
@@ -211,7 +211,7 @@ class Matrix {
 
   /// Stores the data. data.size() is equal to nRows * nReservedColumns.
   /// data.capacity() / nReservedColumns is the number of reserved rows.
-  SmallVector<MPInt, 16> data;
+  SmallVector<T, 16> data;
 };
 
 } // namespace presburger
diff --git a/mlir/include/mlir/Analysis/Presburger/PWMAFunction.h b/mlir/include/mlir/Analysis/Presburger/PWMAFunction.h
index ea3456624e72d4e..0b3804fc08a60e0 100644
--- a/mlir/include/mlir/Analysis/Presburger/PWMAFunction.h
+++ b/mlir/include/mlir/Analysis/Presburger/PWMAFunction.h
@@ -40,13 +40,13 @@ enum class OrderingKind { EQ, NE, LT, LE, GT, GE };
 /// value of the function at a specified point.
 class MultiAffineFunction {
 public:
-  MultiAffineFunction(const PresburgerSpace &space, const Matrix &output)
+  MultiAffineFunction(const PresburgerSpace &space, const Matrix<MPInt> &output)
       : space(space), output(output),
         divs(space.getNumVars() - space.getNumRangeVars()) {
     assertIsConsistent();
   }
 
-  MultiAffineFunction(const PresburgerSpace &space, const Matrix &output,
+  MultiAffineFunction(const PresburgerSpace &space, const Matrix<MPInt> &output,
                       const DivisionRepr &divs)
       : space(space), output(output), divs(divs) {
     assertIsConsistent();
@@ -65,7 +65,7 @@ class MultiAffineFunction {
   PresburgerSpace getOutputSpace() const { return space.getRangeSpace(); }
 
   /// Get a matrix with each row representing row^th output expression.
-  const Matrix &getOutputMatrix() const { return output; }
+  const Matrix<MPInt> &getOutputMatrix() const { return output; }
   /// Get the `i^th` output expression.
   ArrayRef<MPInt> getOutputExpr(unsigned i) const { return output.getRow(i); }
 
@@ -124,7 +124,7 @@ class MultiAffineFunction {
   /// The function's output is a tuple of integers, with the ith element of the
   /// tuple defined by the affine expression given by the ith row of this output
   /// matrix.
-  Matrix output;
+  Matrix<MPInt> output;
 
   /// Storage for division representation for each local variable in space.
   DivisionRepr divs;
diff --git a/mlir/include/mlir/Analysis/Presburger/Simplex.h b/mlir/include/mlir/Analysis/Presburger/Simplex.h
index 79a42d6c38d4113..922b0cb33168fb6 100644
--- a/mlir/include/mlir/Analysis/Presburger/Simplex.h
+++ b/mlir/include/mlir/Analysis/Presburger/Simplex.h
@@ -338,7 +338,7 @@ class SimplexBase {
   unsigned nSymbol;
 
   /// The matrix representing the tableau.
-  Matrix tableau;
+  Matrix<MPInt> tableau;
 
   /// This is true if the tableau has been detected to be empty, false
   /// otherwise.
@@ -861,7 +861,7 @@ class Simplex : public SimplexBase {
 
   /// Reduce the given basis, starting at the specified level, using general
   /// basis reduction.
-  void reduceBasis(Matrix &basis, unsigned level);
+  void reduceBasis(Matrix<MPInt> &basis, unsigned level);
 };
 
 /// Takes a snapshot of the simplex state on construction and rolls back to the
diff --git a/mlir/include/mlir/Analysis/Presburger/Utils.h b/mlir/include/mlir/Analysis/Presburger/Utils.h
index a3000a26c3f3d76..d3822ed572f8ee8 100644
--- a/mlir/include/mlir/Analysis/Presburger/Utils.h
+++ b/mlir/include/mlir/Analysis/Presburger/Utils.h
@@ -182,7 +182,7 @@ class DivisionRepr {
   /// Each row of the Matrix represents a single division dividend. The
   /// `i^th` row represents the dividend of the variable at `divOffset + i`
   /// in the constraint system (and the `i^th` local variable).
-  Matrix dividends;
+  Matrix<MPInt> dividends;
 
   /// Denominators of each division. If a denominator of a division is `0`, the
   /// division variable is considered to not have a division representation.
diff --git a/mlir/lib/Analysis/FlatLinearValueConstraints.cpp b/mlir/lib/Analysis/FlatLinearValueConstraints.cpp
index 3f000182250069d..31aff1a216bacc3 100644
--- a/mlir/lib/Analysis/FlatLinearValueConstraints.cpp
+++ b/mlir/lib/Analysis/FlatLinearValueConstraints.cpp
@@ -1292,7 +1292,7 @@ mlir::getMultiAffineFunctionFromMap(AffineMap map,
          "AffineMap cannot produce divs without local representation");
 
   // TODO: We shouldn't have to do this conversion.
-  Matrix mat(map.getNumResults(), map.getNumInputs() + divs.getNumDivs() + 1);
+  Matrix<MPInt> mat(map.getNumResults(), map.getNumInputs() + divs.getNumDivs() + 1);
   for (unsigned i = 0, e = flattenedExprs.size(); i < e; ++i)
     for (unsigned j = 0, f = flattenedExprs[i].size(); j < f; ++j)
       mat(i, j) = flattenedExprs[i][j];
diff --git a/mlir/lib/Analysis/Presburger/IntegerRelation.cpp b/mlir/lib/Analysis/Presburger/IntegerRelation.cpp
index 6f07c364d07653c..4672de03b40693d 100644
--- a/mlir/lib/Analysis/Presburger/IntegerRelation.cpp
+++ b/mlir/lib/Analysis/Presburger/IntegerRelation.cpp
@@ -738,7 +738,7 @@ bool IntegerRelation::isEmptyByGCDTest() const {
 //
 // It is sufficient to check the perpendiculars of the constraints, as the set
 // of perpendiculars which are bounded must span all bounded directions.
-Matrix IntegerRelation::getBoundedDirections() const {
+Matrix<MPInt> IntegerRelation::getBoundedDirections() const {
   // Note that it is necessary to add the equalities too (which the constructor
   // does) even though we don't need to check if they are bounded; whether an
   // inequality is bounded or not depends on what other constraints, including
@@ -759,7 +759,7 @@ Matrix IntegerRelation::getBoundedDirections() const {
   // The direction vector is given by the coefficients and does not include the
   // constant term, so the matrix has one fewer column.
   unsigned dirsNumCols = getNumCols() - 1;
-  Matrix dirs(boundedIneqs.size() + getNumEqualities(), dirsNumCols);
+  Matrix<MPInt> dirs(boundedIneqs.size() + getNumEqualities(), dirsNumCols);
 
   // Copy the bounded inequalities.
   unsigned row = 0;
@@ -845,7 +845,7 @@ IntegerRelation::findIntegerSample() const {
   // m is a matrix containing, in each row, a vector in which S is
   // bounded, such that the linear span of all these dimensions contains all
   // bounded dimensions in S.
-  Matrix m = getBoundedDirections();
+  Matrix<MPInt> m = getBoundedDirections();
   // In column echelon form, each row of m occupies only the first rank(m)
   // columns and has zeros on the other columns. The transform T that brings S
   // to column echelon form is unimodular as well, so this is a suitable
diff --git a/mlir/lib/Analysis/Presburger/LinearTransform.cpp b/mlir/lib/Analysis/Presburger/LinearTransform.cpp
index e7ad3ecf4306d38..d25e76d9229f605 100644
--- a/mlir/lib/Analysis/Presburger/LinearTransform.cpp
+++ b/mlir/lib/Analysis/Presburger/LinearTransform.cpp
@@ -12,11 +12,11 @@
 using namespace mlir;
 using namespace presburger;
 
-LinearTransform::LinearTransform(Matrix &&oMatrix) : matrix(oMatrix) {}
-LinearTransform::LinearTransform(const Matrix &oMatrix) : matrix(oMatrix) {}
+LinearTransform::LinearTransform(Matrix<MPInt> &&oMatrix) : matrix(oMatrix) {}
+LinearTransform::LinearTransform(const Matrix<MPInt> &oMatrix) : matrix(oMatrix) {}
 
 std::pair<unsigned, LinearTransform>
-LinearTransform::makeTransformToColumnEchelon(const Matrix &m) {
+LinearTransform::makeTransformToColumnEchelon(const Matrix<MPInt> &m) {
   // Compute the hermite normal form of m. This, is by definition, is in column
   // echelon form.
   auto [h, u] = m.computeHermiteNormalForm();
diff --git a/mlir/lib/Analysis/Presburger/Matrix.cpp b/mlir/lib/Analysis/Presburger/Matrix.cpp
index 4ee81c61a53a3b5..c19e5d8d49fec37 100644
--- a/mlir/lib/Analysis/Presburger/Matrix.cpp
+++ b/mlir/lib/Analysis/Presburger/Matrix.cpp
@@ -7,13 +7,14 @@
 //===----------------------------------------------------------------------===//
 
 #include "mlir/Analysis/Presburger/Matrix.h"
+#include "mlir/Analysis/Presburger/Fraction.h"
 #include "mlir/Analysis/Presburger/Utils.h"
 #include "llvm/Support/MathExtras.h"
 
 using namespace mlir;
 using namespace presburger;
 
-Matrix::Matrix(unsigned rows, unsigned columns, unsigned reservedRows,
+template <typename T> Matrix<T>::Matrix(unsigned rows, unsigned columns, unsigned reservedRows,
                unsigned reservedColumns)
     : nRows(rows), nColumns(columns),
       nReservedColumns(std::max(nColumns, reservedColumns)),
@@ -21,27 +22,27 @@ Matrix::Matrix(unsigned rows, unsigned columns, unsigned reservedRows,
   data.reserve(std::max(nRows, reservedRows) * nReservedColumns);
 }
 
-Matrix Matrix::identity(unsigned dimension) {
+template <typename T> Matrix<T> Matrix<T>::identity(unsigned dimension) {
   Matrix matrix(dimension, dimension);
   for (unsigned i = 0; i < dimension; ++i)
     matrix(i, i) = 1;
   return matrix;
 }
 
-unsigned Matrix::getNumReservedRows() const {
+template <typename T> unsigned Matrix<T>::getNumReservedRows() const {
   return data.capacity() / nReservedColumns;
 }
 
-void Matrix::reserveRows(unsigned rows) {
+template <typename T> void Matrix<T>::reserveRows(unsigned rows) {
   data.reserve(rows * nReservedColumns);
 }
 
-unsigned Matrix::appendExtraRow() {
+template <typename T> unsigned Matrix<T>::appendExtraRow() {
   resizeVertically(nRows + 1);
   return nRows - 1;
 }
 
-unsigned Matrix::appendExtraRow(ArrayRef<MPInt> elems) {
+template <typename T> unsigned Matrix<T>::appendExtraRow(ArrayRef<T> elems) {
   assert(elems.size() == nColumns && "elems must match row length!");
   unsigned row = appendExtraRow();
   for (unsigned col = 0; col < nColumns; ++col)
@@ -49,24 +50,24 @@ unsigned Matrix::appendExtraRow(ArrayRef<MPInt> elems) {
   return row;
 }
 
-void Matrix::resizeHorizontally(unsigned newNColumns) {
+template <typename T> void Matrix<T>::resizeHorizontally(unsigned newNColumns) {
   if (newNColumns < nColumns)
     removeColumns(newNColumns, nColumns - newNColumns);
   if (newNColumns > nColumns)
     insertColumns(nColumns, newNColumns - nColumns);
 }
 
-void Matrix::resize(unsigned newNRows, unsigned newNColumns) {
+template <typename T> void Matrix<T>::resize(unsigned newNRows, unsigned newNColumns) {
   resizeHorizontally(newNColumns);
   resizeVertically(newNRows);
 }
 
-void Matrix::resizeVertically(unsigned newNRows) {
+template <typename T> void Matrix<T>::resizeVertically(unsigned newNRows) {
   nRows = newNRows;
   data.resize(nRows * nReservedColumns);
 }
 
-void Matrix::swapRows(unsigned row, unsigned otherRow) {
+template <typename T> void Matrix<T>::swapRows(unsigned row, unsigned otherRow) {
   assert((row < getNumRows() && otherRow < getNumRows()) &&
          "Given row out of bounds");
   if (row == otherRow)
@@ -75,7 +76,7 @@ void Matrix::swapRows(unsigned row, unsigned otherRow) {
     std::swap(at(row, col), at(otherRow, col));
 }
 
-void Matrix::swapColumns(unsigned column, unsigned otherColumn) {
+template <typename T> void Matrix<T>::swapColumns(unsigned column, unsigned otherColumn) {
   assert((column < getNumColumns() && otherColumn < getNumColumns()) &&
          "Given column out of bounds");
   if (column == otherColumn)
@@ -84,23 +85,23 @@ void Matrix::swapColumns(unsigned column, unsigned otherColumn) {
     std::swap(at(row, column), at(row, otherColumn));
 }
 
-MutableArrayRef<MPInt> Matrix::getRow(unsigned row) {
+template <typename T> MutableArrayRef<T> Matrix<T>::getRow(unsigned row) {
   return {&data[row * nReservedColumns], nColumns};
 }
 
-ArrayRef<MPInt> Matrix::getRow(unsigned row) const {
+template <typename T> ArrayRef<T> Matrix<T>::getRow(unsigned row) const {
   return {&data[row * nReservedColumns], nColumns};
 }
 
-void Matrix::setRow(unsigned row, ArrayRef<MPInt> elems) {
+template <typename T> void Matrix<T>::setRow(unsigned row, ArrayRef<T> elems) {
   assert(elems.size() == getNumColumns() &&
          "elems size must match row length!");
   for (unsigned i = 0, e = getNumColumns(); i < e; ++i)
     at(row, i) = elems[i];
 }
 
-void Matrix::insertColumn(unsigned pos) { insertColumns(pos, 1); }
-void Matrix::insertColumns(unsigned pos, unsigned count) {
+template <typename T> void Matrix<T>::insertColumn(unsigned pos) { insertColumns(pos, 1); }
+template <typename T> void Matrix<T>::insertColumns(unsigned pos, unsigned count) {
   if (count == 0)
     return;
   assert(pos <= nColumns);
@@ -115,7 +116,7 @@ void Matrix::insertColumns(unsigned pos, unsigned count) {
     for (int ci = nReservedColumns - 1; ci >= 0; --ci) {
       unsigned r = ri;
       unsigned c = ci;
-      MPInt &dest = data[r * nReservedColumns + c];
+      T &dest = data[r * nReservedColumns + c];
       if (c >= nColumns) { // NOLINT
         // Out of bounds columns are zero-initialized. NOLINT because clang-tidy
         // complains about this branch being the same as the c >= pos one.
@@ -141,8 +142,8 @@ void Matrix::insertColumns(unsigned pos, unsigned count) {
   }
 }
 
-void Matrix::removeColumn(unsigned pos) { removeColumns(pos, 1); }
-void Matrix::removeColumns(unsigned pos, unsigned count) {
+template <typename T> void Matrix<T>::removeColumn(unsigned pos) { removeColumns(pos, 1); }
+template <typename T> void Matrix<T>::removeColumns(unsigned pos, unsigned count) {
   if (count == 0)
     return;
   assert(pos + count - 1 < nColumns);
@@ -155,8 +156,8 @@ void Matrix::removeColumns(unsigned pos, unsigned count) {
   nColumns -= count;
 }
 
-void Matrix::insertRow(unsigned pos) { insertRows(pos, 1); }
-void Matrix::insertRows(unsigned pos, unsigned count) {
+template <typename T> void Matrix<T>::insertRow(unsigned pos) { insertRows(pos, 1); }
+template <typename T> void Matrix<T>::insertRows(unsigned pos, unsigned count) {
   if (count == 0)
     return;
 
@@ -169,8 +170,8 @@ void Matrix::insertRows(unsigned pos, unsigned count) {
       at(r, c) = 0;
 }
 
-void Matrix::removeRow(unsigned pos) { removeRows(pos, 1); }
-void Matrix::removeRows(unsigned pos, unsigned count) {
+template <typename T> void Matrix<T>::removeRow(unsigned pos) { removeRows(pos, 1); }
+template <typename T> void Matrix<T>::removeRows(unsigned pos, unsigned count) {
   if (count == 0)
     return;
   assert(pos + count - 1 <= nRows);
@@ -179,76 +180,76 @@ void Matrix::removeRows(unsigned pos, unsigned count) {
   resizeVertically(nRows - count);
 }
 
-void Matrix::copyRow(unsigned sourceRow, unsigned targetRow) {
+template <typename T> void Matrix<T>::copyRow(unsigned sourceRow, unsigned targetRow) {
   if (sourceRow == targetRow)
     return;
   for (unsigned c = 0; c < nColumns; ++c)
     at(targetRow, c) = at(sourceRow, c);
 }
 
-void Matrix::fillRow(unsigned row, const MPInt &value) {
+template <typename T> void Matrix<T>::fillRow(unsigned row, const T &value) {
   for (unsigned col = 0; col < nColumns; ++col)
     at(row, col) = value;
 }
 
-void Matrix::addToRow(unsigned sourceRow, unsigned targetRow,
-                      const MPInt &scale) {
+template <typename T> void Matrix<T>::addToRow(unsigned sourceRow, unsigned targetRow,
+                      const T &scale) {
   addToRow(targetRow, getRow(sourceRow), scale);
 }
 
-void Matrix::addToRow(unsigned row, ArrayRef<MPInt> rowVec,
-                      const MPInt &scale) {
+template <typename T> void Matrix<T>::addToRow(unsigned row, ArrayRef<T> rowVec,
+                      const T &scale) {
   if (scale == 0)
     return;
   for (unsigned col = 0; col < nColumns; ++col)
-    at(row, col) += scale * rowVec[col];
+    at(row, col) = at(row, col) + scale * rowVec[col];
 }
 
-void Matrix::addToColumn(unsigned sourceColumn, unsigned targetColumn,
-                         const MPInt &scale) {
+template <typename T> void Matrix<T>::addToColumn(unsigned sourceColumn, unsigned targetColumn,
+                         const T &scale) {
   if (scale == 0)
     return;
   for (unsigned row = 0, e = getNumRows(); row < e; ++row)
-    at(row, targetColumn) += scale * at(row, sourceColumn);
+    at(row, targetColumn) = at(row, targetColumn) + scale * at(row, sourceColumn);
 }
 
-void Matrix::negateColumn(unsigned column) {
+template <typename T> void Matrix<T>::negateColumn(unsigned column) {
   for (unsigned row = 0, e = getNumRows(); row < e; ++row)
     at(row, column) = -at(row, column);
 }
 
-void Matrix::negateRow(unsigned row) {
+template <typename T> void Matrix<T>::negateRow(unsigned row) {
   for (unsigned column = 0, e = getNumColumns(); column < e; ++column)
     at(row, column) = -at(row, column);
 }
 
-MPInt Matrix::normalizeRow(unsigned row, unsigned cols) {
+template <> MPInt Matrix<MPInt>::normalizeRow(unsigned row, unsigned cols) {
   return normalizeRange(getRow(row).slice(0, cols));
 }
 
-MPInt Matrix::normalizeRow(unsigned row) {
+template <> MPInt Matrix<MPInt>::normalizeRow(unsigned row) {
   return normalizeRow(row, getNumColumns());
 }
 
-SmallVector<MPInt, 8> Matrix::preMultiplyWithRow(ArrayRef<MPInt> rowVec) const {
+template <typename T> SmallVector<T, 8> Matrix<T>::preMultiplyWithRow(ArrayRef<T> rowVec) const {
   assert(rowVec.size() == getNumRows() && "Invalid row vector dimension!");
 
-  SmallVector<MPInt, 8> result(getNumColumns(), MPInt(0));
+  SmallVector<T, 8> result(getNumColumns(), T(0));
   for (unsigned col = 0, e = getNumColumns(); col < e; ++col)
     for (unsigned i = 0, e = getNumRows(); i < e; ++i)
-      result[col] += rowVec[i] * at(i, col);
+      result[col] = result[col] + rowVec[i] * at(i, col);
   return result;
 }
 
-SmallVector<MPInt, 8>
-Matrix::postMultiplyWithColumn(ArrayRef<MPInt> colVec) const {
+template <typename T> SmallVector<T, 8>
+Matrix<T>::postMultiplyWithColumn(ArrayRef<T> colVec) const {
   assert(getNumColumns() == colVec.size() &&
          "Invalid column vector dimension!");
 
-  SmallVector<MPInt, 8> result(getNumRows(), MPInt(0));
+  SmallVector<T, 8> result(getNumRows(), T(0));
   for (unsigned row = 0, e = getNumRows(); row < e; row++)
     for (unsigned i = 0, e = getNumColumns(); i < e; i++)
-      result[row] += at(row, i) * colVec[i];
+      result[row] = result[row] + at(row, i) * colVec[i];
   return result;
 }
 
@@ -257,8 +258,8 @@ Matrix::postMultiplyWithColumn(ArrayRef<MPInt> colVec) const {
 /// sourceCol. This brings M(row, targetCol) to the range [0, M(row,
 /// sourceCol)). Apply the same column operation to otherMatrix, with the same
 /// integer multiple.
-static void modEntryColumnOperation(Matrix &m, unsigned row, unsigned sourceCol,
-                                    unsigned targetCol, Matrix &otherMatrix) {
+static void modEntryColumnOperation(Matrix<MPInt> &m, unsigned row, unsigned sourceCol,
+                                    unsigned targetCol, Matrix<MPInt> &otherMatrix) {
   assert(m(row, sourceCol) != 0 && "Cannot divide by zero!");
   assert(m(row, sourceCol) > 0 && "Source must be positive!");
   MPInt ratio = -floorDiv(m(row, targetCol), m(row, sourceCol));
@@ -266,12 +267,12 @@ static void modEntryColumnOperation(Matrix &m, unsigned row, unsigned sourceCol,
   otherMatrix.addToColumn(sourceCol, targetCol, ratio);
 }
 
-std::pair<Matrix, Matrix> Matrix::computeHermiteNormalForm() const {
+template <> std::pair<Matrix<MPInt>, Matrix<MPInt>> Matrix<MPInt>::computeHermiteNormalForm() const {
   // We start with u as an identity matrix and perform operations on h until h
   // is in hermite normal form. We apply the same sequence of operations on u to
   // obtain a transform that takes h to hermite normal form.
-  Matrix h = *this;
-  Matrix u = Matrix::identity(h.getNumColumns());
+  Matrix<MPInt> h = *this;
+  Matrix<MPInt> u = Matrix<MPInt>::identity(h.getNumColumns());
 
   unsigned echelonCol = 0;
   // Invariant: in all rows above row, all columns from echelonCol onwards
@@ -352,7 +353,7 @@ std::pair<Matrix, Matrix> Matrix::computeHermiteNormalForm() const {
   return {h, u};
 }
 
-void Matrix::print(raw_ostream &os) const {
+template <typename T> void Matrix<T>::print(raw_ostream &os) const {
   for (unsigned row = 0; row < nRows; ++row) {
     for (unsigned column = 0; column < nColumns; ++column)
       os << at(row, column) << ' ';
@@ -360,9 +361,9 @@ void Matrix::print(raw_ostream &os) const {
   }
 }
 
-void Matrix::dump() const { print(llvm::errs()); }
+template <typename T> void Matrix<T>::dump() const { print(llvm::errs()); }
 
-bool Matrix::hasConsistentState() const {
+template <typename T> bool Matrix<T>::hasConsistentState() const {
   if (data.size() != nRows * nReservedColumns)
     return false;
   if (nColumns > nReservedColumns)
@@ -375,3 +376,12 @@ bool Matrix::hasConsistentState() const {
 #endif
   return true;
 }
+
+namespace mlir
+{
+  namespace presburger
+  {
+    template class Matrix<MPInt>;
+    template class Matrix<Fraction>;
+  }
+}
\ No newline at end of file
diff --git a/mlir/lib/Analysis/Presburger/Simplex.cpp b/mlir/lib/Analysis/Presburger/Simplex.cpp
index 59447633e9fc8b8..75538da67ed9c50 100644
--- a/mlir/lib/Analysis/Presburger/Simplex.cpp
+++ b/mlir/lib/Analysis/Presburger/Simplex.cpp
@@ -1801,7 +1801,7 @@ class presburger::GBRSimplex {
 ///
 /// When incrementing i, no cached f values get invalidated. However, the cached
 /// duals do get invalidated as the duals for the higher levels are different.
-void Simplex::reduceBasis(Matrix &basis, unsigned level) {
+void Simplex::reduceBasis(Matrix<MPInt> &basis, unsigned level) {
   const Fraction epsilon(3, 4);
 
   if (level == basis.getNumRows() - 1)
@@ -1975,7 +1975,7 @@ std::optional<SmallVector<MPInt, 8>> Simplex::findIntegerSample() {
     return {};
 
   unsigned nDims = var.size();
-  Matrix basis = Matrix::identity(nDims);
+  Matrix<MPInt> basis = Matrix<MPInt>::identity(nDims);
 
   unsigned level = 0;
   // The snapshot just before constraining a direction to a value at each level.
diff --git a/mlir/unittests/Analysis/Presburger/LinearTransformTest.cpp b/mlir/unittests/Analysis/Presburger/LinearTransformTest.cpp
index 32d9e532e1f67dc..07c1f9069bca21c 100644
--- a/mlir/unittests/Analysis/Presburger/LinearTransformTest.cpp
+++ b/mlir/unittests/Analysis/Presburger/LinearTransformTest.cpp
@@ -13,7 +13,7 @@
 using namespace mlir;
 using namespace presburger;
 
-void testColumnEchelonForm(const Matrix &m, unsigned expectedRank) {
+void testColumnEchelonForm(const Matrix<MPInt> &m, unsigned expectedRank) {
   unsigned lastAllowedNonZeroCol = 0;
   std::pair<unsigned, LinearTransform> result =
       LinearTransform::makeTransformToColumnEchelon(m);
@@ -42,21 +42,21 @@ void testColumnEchelonForm(const Matrix &m, unsigned expectedRank) {
 
 TEST(LinearTransformTest, transformToColumnEchelonTest) {
   // m1, m2, m3 are rank 1 matrices -- the first and second rows are identical.
-  Matrix m1(2, 2);
+  Matrix<MPInt> m1(2, 2);
   m1(0, 0) = 4;
   m1(0, 1) = -7;
   m1(1, 0) = 4;
   m1(1, 1) = -7;
   testColumnEchelonForm(m1, 1u);
 
-  Matrix m2(2, 2);
+  Matrix<MPInt> m2(2, 2);
   m2(0, 0) = -4;
   m2(0, 1) = 7;
   m2(1, 0) = 4;
   m2(1, 1) = -7;
   testColumnEchelonForm(m2, 1u);
 
-  Matrix m3(2, 2);
+  Matrix<MPInt> m3(2, 2);
   m3(0, 0) = -4;
   m3(0, 1) = -7;
   m3(1, 0) = -4;
@@ -64,21 +64,21 @@ TEST(LinearTransformTest, transformToColumnEchelonTest) {
   testColumnEchelonForm(m3, 1u);
 
   // m4, m5, m6 are rank 2 matrices -- the first and second rows are different.
-  Matrix m4(2, 2);
+  Matrix<MPInt> m4(2, 2);
   m4(0, 0) = 4;
   m4(0, 1) = -7;
   m4(1, 0) = -4;
   m4(1, 1) = -7;
   testColumnEchelonForm(m4, 2u);
 
-  Matrix m5(2, 2);
+  Matrix<MPInt> m5(2, 2);
   m5(0, 0) = -4;
   m5(0, 1) = 7;
   m5(1, 0) = 4;
   m5(1, 1) = 7;
   testColumnEchelonForm(m5, 2u);
 
-  Matrix m6(2, 2);
+  Matrix<MPInt> m6(2, 2);
   m6(0, 0) = -4;
   m6(0, 1) = -7;
   m6(1, 0) = 4;
diff --git a/mlir/unittests/Analysis/Presburger/MatrixTest.cpp b/mlir/unittests/Analysis/Presburger/MatrixTest.cpp
index 5a1a827e6bb9a88..7a226936c5751eb 100644
--- a/mlir/unittests/Analysis/Presburger/MatrixTest.cpp
+++ b/mlir/unittests/Analysis/Presburger/MatrixTest.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "mlir/Analysis/Presburger/Matrix.h"
+#include "mlir/Analysis/Presburger/Fraction.h"
 #include "./Utils.h"
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -15,7 +16,7 @@ using namespace mlir;
 using namespace presburger;
 
 TEST(MatrixTest, ReadWrite) {
-  Matrix mat(5, 5);
+  Matrix<MPInt> mat(5, 5);
   for (unsigned row = 0; row < 5; ++row)
     for (unsigned col = 0; col < 5; ++col)
       mat(row, col) = 10 * row + col;
@@ -25,7 +26,7 @@ TEST(MatrixTest, ReadWrite) {
 }
 
 TEST(MatrixTest, SwapColumns) {
-  Matrix mat(5, 5);
+  Matrix<MPInt> mat(5, 5);
   for (unsigned row = 0; row < 5; ++row)
     for (unsigned col = 0; col < 5; ++col)
       mat(row, col) = col == 3 ? 1 : 0;
@@ -47,7 +48,7 @@ TEST(MatrixTest, SwapColumns) {
 }
 
 TEST(MatrixTest, SwapRows) {
-  Matrix mat(5, 5);
+  Matrix<MPInt> mat(5, 5);
   for (unsigned row = 0; row < 5; ++row)
     for (unsigned col = 0; col < 5; ++col)
       mat(row, col) = row == 2 ? 1 : 0;
@@ -69,7 +70,7 @@ TEST(MatrixTest, SwapRows) {
 }
 
 TEST(MatrixTest, resizeVertically) {
-  Matrix mat(5, 5);
+  Matrix<MPInt> mat(5, 5);
   EXPECT_EQ(mat.getNumRows(), 5u);
   EXPECT_EQ(mat.getNumColumns(), 5u);
   for (unsigned row = 0; row < 5; ++row)
@@ -94,7 +95,7 @@ TEST(MatrixTest, resizeVertically) {
 }
 
 TEST(MatrixTest, insertColumns) {
-  Matrix mat(5, 5, 5, 10);
+  Matrix<MPInt> mat(5, 5, 5, 10);
   EXPECT_EQ(mat.getNumRows(), 5u);
   EXPECT_EQ(mat.getNumColumns(), 5u);
   for (unsigned row = 0; row < 5; ++row)
@@ -131,7 +132,7 @@ TEST(MatrixTest, insertColumns) {
 }
 
 TEST(MatrixTest, insertRows) {
-  Matrix mat(5, 5, 5, 10);
+  Matrix<MPInt> mat(5, 5, 5, 10);
   ASSERT_TRUE(mat.hasConsistentState());
   EXPECT_EQ(mat.getNumRows(), 5u);
   EXPECT_EQ(mat.getNumColumns(), 5u);
@@ -169,7 +170,7 @@ TEST(MatrixTest, insertRows) {
 }
 
 TEST(MatrixTest, resize) {
-  Matrix mat(5, 5);
+  Matrix<MPInt> mat(5, 5);
   EXPECT_EQ(mat.getNumRows(), 5u);
   EXPECT_EQ(mat.getNumColumns(), 5u);
   for (unsigned row = 0; row < 5; ++row)
@@ -193,8 +194,8 @@ TEST(MatrixTest, resize) {
       EXPECT_EQ(mat(row, col), row >= 3 || col >= 3 ? 0 : int(10 * row + col));
 }
 
-static void checkHermiteNormalForm(const Matrix &mat,
-                                   const Matrix &hermiteForm) {
+static void checkHermiteNormalForm(const Matrix<MPInt> &mat,
+                                   const Matrix<MPInt> &hermiteForm) {
   auto [h, u] = mat.computeHermiteNormalForm();
 
   for (unsigned row = 0; row < mat.getNumRows(); row++)
@@ -208,42 +209,42 @@ TEST(MatrixTest, computeHermiteNormalForm) {
 
   {
     // Hermite form of a unimodular matrix is the identity matrix.
-    Matrix mat = makeMatrix(3, 3, {{2, 3, 6}, {3, 2, 3}, {17, 11, 16}});
-    Matrix hermiteForm = makeMatrix(3, 3, {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}});
+    Matrix<MPInt> mat = makeIntMatrix(3, 3, {{2, 3, 6}, {3, 2, 3}, {17, 11, 16}});
+    Matrix<MPInt> hermiteForm = makeIntMatrix(3, 3, {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}});
     checkHermiteNormalForm(mat, hermiteForm);
   }
 
   {
     // Hermite form of a unimodular is the identity matrix.
-    Matrix mat = makeMatrix(
+    Matrix<MPInt> mat = makeIntMatrix(
         4, 4,
         {{-6, -1, -19, -20}, {0, 1, 0, 0}, {-5, 0, -15, -16}, {6, 0, 18, 19}});
-    Matrix hermiteForm = makeMatrix(
+    Matrix<MPInt> hermiteForm = makeIntMatrix(
         4, 4, {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}});
     checkHermiteNormalForm(mat, hermiteForm);
   }
 
   {
-    Matrix mat = makeMatrix(
+    Matrix<MPInt> mat = makeIntMatrix(
         4, 4, {{3, 3, 1, 4}, {0, 1, 0, 0}, {0, 0, 19, 16}, {0, 0, 0, 3}});
-    Matrix hermiteForm = makeMatrix(
+    Matrix<MPInt> hermiteForm = makeIntMatrix(
         4, 4, {{1, 0, 0, 0}, {0, 1, 0, 0}, {1, 0, 3, 0}, {18, 0, 54, 57}});
     checkHermiteNormalForm(mat, hermiteForm);
   }
 
   {
-    Matrix mat = makeMatrix(
+    Matrix<MPInt> mat = makeIntMatrix(
         4, 4, {{3, 3, 1, 4}, {0, 1, 0, 0}, {0, 0, 19, 16}, {0, 0, 0, 3}});
-    Matrix hermiteForm = makeMatrix(
+    Matrix<MPInt> hermiteForm = makeIntMatrix(
         4, 4, {{1, 0, 0, 0}, {0, 1, 0, 0}, {1, 0, 3, 0}, {18, 0, 54, 57}});
     checkHermiteNormalForm(mat, hermiteForm);
   }
 
   {
-    Matrix mat =
-        makeMatrix(3, 5, {{0, 2, 0, 7, 1}, {-1, 0, 0, -3, 0}, {0, 4, 1, 0, 8}});
-    Matrix hermiteForm =
-        makeMatrix(3, 5, {{1, 0, 0, 0, 0}, {0, 1, 0, 0, 0}, {0, 0, 1, 0, 0}});
+    Matrix<MPInt> mat =
+        makeIntMatrix(3, 5, {{0, 2, 0, 7, 1}, {-1, 0, 0, -3, 0}, {0, 4, 1, 0, 8}});
+    Matrix<MPInt> hermiteForm =
+        makeIntMatrix(3, 5, {{1, 0, 0, 0, 0}, {0, 1, 0, 0, 0}, {0, 0, 1, 0, 0}});
     checkHermiteNormalForm(mat, hermiteForm);
   }
 }
diff --git a/mlir/unittests/Analysis/Presburger/Parser.h b/mlir/unittests/Analysis/Presburger/Parser.h
index c2c63730056e7fe..bd9b6f07664c7e7 100644
--- a/mlir/unittests/Analysis/Presburger/Parser.h
+++ b/mlir/unittests/Analysis/Presburger/Parser.h
@@ -52,7 +52,7 @@ inline MultiAffineFunction parseMultiAffineFunction(StringRef str) {
 
   // TODO: Add default constructor for MultiAffineFunction.
   MultiAffineFunction multiAff(PresburgerSpace::getRelationSpace(),
-                               Matrix(0, 1));
+                               Matrix<MPInt>(0, 1));
   if (getMultiAffineFunctionFromMap(parseAffineMap(str, &context), multiAff)
           .failed())
     llvm_unreachable(
diff --git a/mlir/unittests/Analysis/Presburger/Utils.h b/mlir/unittests/Analysis/Presburger/Utils.h
index c3246a09d5ae9be..8a7f86c866b7056 100644
--- a/mlir/unittests/Analysis/Presburger/Utils.h
+++ b/mlir/unittests/Analysis/Presburger/Utils.h
@@ -17,6 +17,7 @@
 #include "mlir/Analysis/Presburger/PWMAFunction.h"
 #include "mlir/Analysis/Presburger/PresburgerRelation.h"
 #include "mlir/Analysis/Presburger/Simplex.h"
+#include "mlir/Analysis/Presburger/Matrix.h"
 #include "mlir/IR/MLIRContext.h"
 #include "mlir/Support/LLVM.h"
 
@@ -26,9 +27,22 @@
 namespace mlir {
 namespace presburger {
 
-inline Matrix makeMatrix(unsigned numRow, unsigned numColumns,
-                         ArrayRef<SmallVector<int64_t, 8>> matrix) {
-  Matrix results(numRow, numColumns);
+inline Matrix<MPInt> makeIntMatrix(unsigned numRow, unsigned numColumns,
+                         ArrayRef<SmallVector<int, 8>> matrix) {
+  Matrix<MPInt> results(numRow, numColumns);
+  assert(matrix.size() == numRow);
+  for (unsigned i = 0; i < numRow; ++i) {
+    assert(matrix[i].size() == numColumns &&
+           "Output expression has incorrect dimensionality!");
+    for (unsigned j = 0; j < numColumns; ++j)
+      results(i, j) = MPInt(matrix[i][j]);
+  }
+  return results;
+}
+
+inline Matrix<Fraction> makeFracMatrix(unsigned numRow, unsigned numColumns,
+                         ArrayRef<SmallVector<Fraction, 8>> matrix) {
+  Matrix<Fraction> results(numRow, numColumns);
   assert(matrix.size() == numRow);
   for (unsigned i = 0; i < numRow; ++i) {
     assert(matrix[i].size() == numColumns &&

>From 7ef46f4f9a85f62813619db590b36b9f6ff41079 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Fri, 1 Sep 2023 15:54:28 +0100
Subject: [PATCH 05/27] Fix rebase conflict

---
 mlir/lib/Analysis/Presburger/Simplex.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mlir/lib/Analysis/Presburger/Simplex.cpp b/mlir/lib/Analysis/Presburger/Simplex.cpp
index 75538da67ed9c50..f8d274a7a4d17f3 100644
--- a/mlir/lib/Analysis/Presburger/Simplex.cpp
+++ b/mlir/lib/Analysis/Presburger/Simplex.cpp
@@ -436,7 +436,7 @@ LogicalResult SymbolicLexSimplex::addSymbolicCut(unsigned row) {
 }
 
 void SymbolicLexSimplex::recordOutput(SymbolicLexOpt &result) const {
-  Matrix output(0, domainPoly.getNumVars() + 1);
+  Matrix<MPInt> output(0, domainPoly.getNumVars() + 1);
   output.reserveRows(result.lexopt.getNumOutputs());
   for (const Unknown &u : var) {
     if (u.isSymbol)

>From 89ad6f957981b6a34b7bb7dfd875486e9157a983 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Thu, 31 Aug 2023 17:30:17 +0100
Subject: [PATCH 06/27] Template Matrix to Matrix<T> (for MPInt and Fraction)
 with explicit instantiation Duplicate makeMatrix to makeIntMatrix and
 makeFracMatrix

Implement arithmetic operations for Fraction for compatibility
---
 .../include/mlir/Analysis/Presburger/Fraction.h | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/mlir/include/mlir/Analysis/Presburger/Fraction.h b/mlir/include/mlir/Analysis/Presburger/Fraction.h
index 2c3e43021707e16..fdcd82a48729d0b 100644
--- a/mlir/include/mlir/Analysis/Presburger/Fraction.h
+++ b/mlir/include/mlir/Analysis/Presburger/Fraction.h
@@ -165,6 +165,23 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
   return os;
 }
 
+inline Fraction operator/(const Fraction &x, const Fraction &y) {
+  return Fraction(x.num * y.den, x.den * y.num);
+}
+
+inline Fraction operator+(const Fraction &x, const Fraction &y) {
+  return Fraction(x.num * y.den + x.den * y.num, x.den * y.den);
+}
+
+inline Fraction operator-(const Fraction &x, const Fraction &y) {
+  return Fraction(x.num * y.den - x.den * y.num, x.den * y.den);
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
+  x.print(os);
+  return os;
+}
+
 } // namespace presburger
 } // namespace mlir
 

>From b9586b112981b576cee69fb29a42b0e7443fb5f6 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Mon, 4 Sep 2023 13:36:14 +0100
Subject: [PATCH 07/27] Add static assert

---
 mlir/include/mlir/Analysis/Presburger/Fraction.h |  1 -
 mlir/include/mlir/Analysis/Presburger/Matrix.h   |  7 ++++++-
 mlir/lib/Analysis/Presburger/IntegerRelation.cpp |  2 +-
 mlir/lib/Analysis/Presburger/Matrix.cpp          | 10 +++++-----
 4 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Fraction.h b/mlir/include/mlir/Analysis/Presburger/Fraction.h
index fdcd82a48729d0b..ee3835d7e544617 100644
--- a/mlir/include/mlir/Analysis/Presburger/Fraction.h
+++ b/mlir/include/mlir/Analysis/Presburger/Fraction.h
@@ -15,7 +15,6 @@
 #define MLIR_ANALYSIS_PRESBURGER_FRACTION_H
 
 #include "mlir/Analysis/Presburger/MPInt.h"
-#include "mlir/Analysis/Presburger/Utils.h"
 #include "mlir/Support/MathExtras.h"
 
 namespace mlir {
diff --git a/mlir/include/mlir/Analysis/Presburger/Matrix.h b/mlir/include/mlir/Analysis/Presburger/Matrix.h
index b03737ab2f70a4a..d09981d79cac819 100644
--- a/mlir/include/mlir/Analysis/Presburger/Matrix.h
+++ b/mlir/include/mlir/Analysis/Presburger/Matrix.h
@@ -7,7 +7,8 @@
 //===----------------------------------------------------------------------===//
 //
 // This is a simple 2D matrix class that supports reading, writing, resizing,
-// swapping rows, and swapping columns.
+// swapping rows, and swapping columns. It can hold integers (MPInt) or rational
+// numbers (Fraction).
 //
 //===----------------------------------------------------------------------===//
 
@@ -15,6 +16,8 @@
 #define MLIR_ANALYSIS_PRESBURGER_MATRIX_H
 
 #include "mlir/Support/LLVM.h"
+#include "mlir/Analysis/Presburger/Fraction.h"
+#include "mlir/Analysis/Presburger/Matrix.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -33,6 +36,8 @@ namespace presburger {
 /// space in the underlying SmallVector's capacity.
 template<typename T>
 class Matrix {
+  // This class is not intended for general use: it supports only integers and rational numbers
+static_assert(std::is_same_v<T,MPInt> || std::is_same_v<T,Fraction>, "T must be MPInt or Fraction.");
 public:
   Matrix() = delete;
 
diff --git a/mlir/lib/Analysis/Presburger/IntegerRelation.cpp b/mlir/lib/Analysis/Presburger/IntegerRelation.cpp
index 4672de03b40693d..118ed1f19ce62a0 100644
--- a/mlir/lib/Analysis/Presburger/IntegerRelation.cpp
+++ b/mlir/lib/Analysis/Presburger/IntegerRelation.cpp
@@ -304,7 +304,7 @@ SymbolicLexOpt IntegerRelation::findSymbolicIntegerLexMax() const {
   // Get lexmax by flipping range sign in the PWMA constraints.
   for (auto &flippedPiece :
        flippedSymbolicIntegerLexMax.lexopt.getAllPieces()) {
-    Matrix mat = flippedPiece.output.getOutputMatrix();
+    Matrix<MPInt> mat = flippedPiece.output.getOutputMatrix();
     for (unsigned i = 0, e = mat.getNumRows(); i < e; i++)
       mat.negateRow(i);
     MultiAffineFunction maf(flippedPiece.output.getSpace(), mat);
diff --git a/mlir/lib/Analysis/Presburger/Matrix.cpp b/mlir/lib/Analysis/Presburger/Matrix.cpp
index c19e5d8d49fec37..e526af9809ee0e2 100644
--- a/mlir/lib/Analysis/Presburger/Matrix.cpp
+++ b/mlir/lib/Analysis/Presburger/Matrix.cpp
@@ -379,9 +379,9 @@ template <typename T> bool Matrix<T>::hasConsistentState() const {
 
 namespace mlir
 {
-  namespace presburger
-  {
-    template class Matrix<MPInt>;
-    template class Matrix<Fraction>;
-  }
+namespace presburger
+{
+template class Matrix<MPInt>;
+template class Matrix<Fraction>;
+}
 }
\ No newline at end of file

>From dfd4e7cce86f0a0a2d87526f8866bcbe6bb2e506 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Tue, 5 Sep 2023 10:35:33 +0100
Subject: [PATCH 08/27] Fix comment

---
 mlir/include/mlir/Analysis/Presburger/Matrix.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Matrix.h b/mlir/include/mlir/Analysis/Presburger/Matrix.h
index d09981d79cac819..79044e6fbb8a01a 100644
--- a/mlir/include/mlir/Analysis/Presburger/Matrix.h
+++ b/mlir/include/mlir/Analysis/Presburger/Matrix.h
@@ -36,7 +36,7 @@ namespace presburger {
 /// space in the underlying SmallVector's capacity.
 template<typename T>
 class Matrix {
-  // This class is not intended for general use: it supports only integers and rational numbers
+  // This class is not intended for general use: it supports only integers and rational numbers.
 static_assert(std::is_same_v<T,MPInt> || std::is_same_v<T,Fraction>, "T must be MPInt or Fraction.");
 public:
   Matrix() = delete;

>From ea5256e077cf5170d64bb3da0f02ea0ad3751c2d Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Tue, 5 Sep 2023 17:52:45 +0100
Subject: [PATCH 09/27] Make compatible with fraction patch

---
 .../mlir/Analysis/Presburger/Fraction.h       | 29 +++----------------
 mlir/lib/Analysis/Presburger/Matrix.cpp       |  8 ++---
 2 files changed, 8 insertions(+), 29 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Fraction.h b/mlir/include/mlir/Analysis/Presburger/Fraction.h
index ee3835d7e544617..732a378a77b32dd 100644
--- a/mlir/include/mlir/Analysis/Presburger/Fraction.h
+++ b/mlir/include/mlir/Analysis/Presburger/Fraction.h
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This is a simple class to represent fractions. It supports arithmetic,
+// This is a simple class to represent fractions. It supports multiplication,
 // comparison, floor, and ceiling operations.
 //
 //===----------------------------------------------------------------------===//
@@ -30,15 +30,15 @@ struct Fraction {
   Fraction() = default;
 
   /// Construct a Fraction from a numerator and denominator.
-  Fraction(const MPInt &oNum, const MPInt &oDen = MPInt(1)) : num(oNum), den(oDen) {
+  Fraction(const MPInt &oNum, const MPInt &oDen) : num(oNum), den(oDen) {
     if (den < 0) {
       num = -num;
       den = -den;
     }
   }
   /// Overloads for passing literals.
-  Fraction(const MPInt &num, int64_t den = 1) : Fraction(num, MPInt(den)) {}
-  Fraction(int64_t num, const MPInt &den = MPInt(1)) : Fraction(MPInt(num), den) {}
+  Fraction(const MPInt &num, int64_t den) : Fraction(num, MPInt(den)) {}
+  Fraction(int64_t num, const MPInt &den) : Fraction(MPInt(num), den) {}
   Fraction(int64_t num, int64_t den) : Fraction(MPInt(num), MPInt(den)) {}
 
   // Return the value of the fraction as an integer. This should only be called
@@ -48,10 +48,6 @@ struct Fraction {
     return num / den;
   }
 
-  llvm::raw_ostream &print(llvm::raw_ostream &os) const {
-    return os << "(" << num << "/" << den << ")";
-  }
-
   /// The numerator and denominator, respectively. The denominator is always
   /// positive.
   MPInt num{0}, den{1};
@@ -164,23 +160,6 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
   return os;
 }
 
-inline Fraction operator/(const Fraction &x, const Fraction &y) {
-  return Fraction(x.num * y.den, x.den * y.num);
-}
-
-inline Fraction operator+(const Fraction &x, const Fraction &y) {
-  return Fraction(x.num * y.den + x.den * y.num, x.den * y.den);
-}
-
-inline Fraction operator-(const Fraction &x, const Fraction &y) {
-  return Fraction(x.num * y.den - x.den * y.num, x.den * y.den);
-}
-
-inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
-  x.print(os);
-  return os;
-}
-
 } // namespace presburger
 } // namespace mlir
 
diff --git a/mlir/lib/Analysis/Presburger/Matrix.cpp b/mlir/lib/Analysis/Presburger/Matrix.cpp
index e526af9809ee0e2..814c93049f15bfc 100644
--- a/mlir/lib/Analysis/Presburger/Matrix.cpp
+++ b/mlir/lib/Analysis/Presburger/Matrix.cpp
@@ -202,7 +202,7 @@ template <typename T> void Matrix<T>::addToRow(unsigned row, ArrayRef<T> rowVec,
   if (scale == 0)
     return;
   for (unsigned col = 0; col < nColumns; ++col)
-    at(row, col) = at(row, col) + scale * rowVec[col];
+    at(row, col) += scale * rowVec[col];
 }
 
 template <typename T> void Matrix<T>::addToColumn(unsigned sourceColumn, unsigned targetColumn,
@@ -210,7 +210,7 @@ template <typename T> void Matrix<T>::addToColumn(unsigned sourceColumn, unsigne
   if (scale == 0)
     return;
   for (unsigned row = 0, e = getNumRows(); row < e; ++row)
-    at(row, targetColumn) = at(row, targetColumn) + scale * at(row, sourceColumn);
+    at(row, targetColumn) += scale * at(row, sourceColumn);
 }
 
 template <typename T> void Matrix<T>::negateColumn(unsigned column) {
@@ -237,7 +237,7 @@ template <typename T> SmallVector<T, 8> Matrix<T>::preMultiplyWithRow(ArrayRef<T
   SmallVector<T, 8> result(getNumColumns(), T(0));
   for (unsigned col = 0, e = getNumColumns(); col < e; ++col)
     for (unsigned i = 0, e = getNumRows(); i < e; ++i)
-      result[col] = result[col] + rowVec[i] * at(i, col);
+      result[col] += rowVec[i] * at(i, col);
   return result;
 }
 
@@ -249,7 +249,7 @@ Matrix<T>::postMultiplyWithColumn(ArrayRef<T> colVec) const {
   SmallVector<T, 8> result(getNumRows(), T(0));
   for (unsigned row = 0, e = getNumRows(); row < e; row++)
     for (unsigned i = 0, e = getNumColumns(); i < e; i++)
-      result[row] = result[row] + at(row, i) * colVec[i];
+      result[row] += at(row, i) * colVec[i];
   return result;
 }
 

>From a34225996fa2e86c1210597ddf5eb3f32c61782e Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Tue, 5 Sep 2023 17:57:49 +0100
Subject: [PATCH 10/27] Revert "Make compatible with fraction patch"

This reverts commit 2871b0127a3cbc8d2a4cf294e731aade1ed56424.
---
 .../mlir/Analysis/Presburger/Fraction.h       | 29 ++++++++++++++++---
 mlir/lib/Analysis/Presburger/Matrix.cpp       |  8 ++---
 2 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Fraction.h b/mlir/include/mlir/Analysis/Presburger/Fraction.h
index 732a378a77b32dd..ee3835d7e544617 100644
--- a/mlir/include/mlir/Analysis/Presburger/Fraction.h
+++ b/mlir/include/mlir/Analysis/Presburger/Fraction.h
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This is a simple class to represent fractions. It supports multiplication,
+// This is a simple class to represent fractions. It supports arithmetic,
 // comparison, floor, and ceiling operations.
 //
 //===----------------------------------------------------------------------===//
@@ -30,15 +30,15 @@ struct Fraction {
   Fraction() = default;
 
   /// Construct a Fraction from a numerator and denominator.
-  Fraction(const MPInt &oNum, const MPInt &oDen) : num(oNum), den(oDen) {
+  Fraction(const MPInt &oNum, const MPInt &oDen = MPInt(1)) : num(oNum), den(oDen) {
     if (den < 0) {
       num = -num;
       den = -den;
     }
   }
   /// Overloads for passing literals.
-  Fraction(const MPInt &num, int64_t den) : Fraction(num, MPInt(den)) {}
-  Fraction(int64_t num, const MPInt &den) : Fraction(MPInt(num), den) {}
+  Fraction(const MPInt &num, int64_t den = 1) : Fraction(num, MPInt(den)) {}
+  Fraction(int64_t num, const MPInt &den = MPInt(1)) : Fraction(MPInt(num), den) {}
   Fraction(int64_t num, int64_t den) : Fraction(MPInt(num), MPInt(den)) {}
 
   // Return the value of the fraction as an integer. This should only be called
@@ -48,6 +48,10 @@ struct Fraction {
     return num / den;
   }
 
+  llvm::raw_ostream &print(llvm::raw_ostream &os) const {
+    return os << "(" << num << "/" << den << ")";
+  }
+
   /// The numerator and denominator, respectively. The denominator is always
   /// positive.
   MPInt num{0}, den{1};
@@ -160,6 +164,23 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
   return os;
 }
 
+inline Fraction operator/(const Fraction &x, const Fraction &y) {
+  return Fraction(x.num * y.den, x.den * y.num);
+}
+
+inline Fraction operator+(const Fraction &x, const Fraction &y) {
+  return Fraction(x.num * y.den + x.den * y.num, x.den * y.den);
+}
+
+inline Fraction operator-(const Fraction &x, const Fraction &y) {
+  return Fraction(x.num * y.den - x.den * y.num, x.den * y.den);
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
+  x.print(os);
+  return os;
+}
+
 } // namespace presburger
 } // namespace mlir
 
diff --git a/mlir/lib/Analysis/Presburger/Matrix.cpp b/mlir/lib/Analysis/Presburger/Matrix.cpp
index 814c93049f15bfc..e526af9809ee0e2 100644
--- a/mlir/lib/Analysis/Presburger/Matrix.cpp
+++ b/mlir/lib/Analysis/Presburger/Matrix.cpp
@@ -202,7 +202,7 @@ template <typename T> void Matrix<T>::addToRow(unsigned row, ArrayRef<T> rowVec,
   if (scale == 0)
     return;
   for (unsigned col = 0; col < nColumns; ++col)
-    at(row, col) += scale * rowVec[col];
+    at(row, col) = at(row, col) + scale * rowVec[col];
 }
 
 template <typename T> void Matrix<T>::addToColumn(unsigned sourceColumn, unsigned targetColumn,
@@ -210,7 +210,7 @@ template <typename T> void Matrix<T>::addToColumn(unsigned sourceColumn, unsigne
   if (scale == 0)
     return;
   for (unsigned row = 0, e = getNumRows(); row < e; ++row)
-    at(row, targetColumn) += scale * at(row, sourceColumn);
+    at(row, targetColumn) = at(row, targetColumn) + scale * at(row, sourceColumn);
 }
 
 template <typename T> void Matrix<T>::negateColumn(unsigned column) {
@@ -237,7 +237,7 @@ template <typename T> SmallVector<T, 8> Matrix<T>::preMultiplyWithRow(ArrayRef<T
   SmallVector<T, 8> result(getNumColumns(), T(0));
   for (unsigned col = 0, e = getNumColumns(); col < e; ++col)
     for (unsigned i = 0, e = getNumRows(); i < e; ++i)
-      result[col] += rowVec[i] * at(i, col);
+      result[col] = result[col] + rowVec[i] * at(i, col);
   return result;
 }
 
@@ -249,7 +249,7 @@ Matrix<T>::postMultiplyWithColumn(ArrayRef<T> colVec) const {
   SmallVector<T, 8> result(getNumRows(), T(0));
   for (unsigned row = 0, e = getNumRows(); row < e; row++)
     for (unsigned i = 0, e = getNumColumns(); i < e; i++)
-      result[row] += at(row, i) * colVec[i];
+      result[row] = result[row] + at(row, i) * colVec[i];
   return result;
 }
 

>From 24bee0ed5389cc0bf3c8552143031d002d1efac9 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Tue, 5 Sep 2023 17:59:22 +0100
Subject: [PATCH 11/27] Remove duplicate definitions

---
 .../mlir/Analysis/Presburger/Fraction.h       | 34 -------------------
 1 file changed, 34 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Fraction.h b/mlir/include/mlir/Analysis/Presburger/Fraction.h
index ee3835d7e544617..74127a900d53ed2 100644
--- a/mlir/include/mlir/Analysis/Presburger/Fraction.h
+++ b/mlir/include/mlir/Analysis/Presburger/Fraction.h
@@ -147,40 +147,6 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
   return os;
 }
 
-inline Fraction operator/(const Fraction &x, const Fraction &y) {
-  return Fraction(x.num * y.den, x.den * y.num);
-}
-
-inline Fraction operator+(const Fraction &x, const Fraction &y) {
-  return Fraction(x.num * y.den + x.den * y.num, x.den * y.den);
-}
-
-inline Fraction operator-(const Fraction &x, const Fraction &y) {
-  return Fraction(x.num * y.den - x.den * y.num, x.den * y.den);
-}
-
-inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
-  x.print(os);
-  return os;
-}
-
-inline Fraction operator/(const Fraction &x, const Fraction &y) {
-  return Fraction(x.num * y.den, x.den * y.num);
-}
-
-inline Fraction operator+(const Fraction &x, const Fraction &y) {
-  return Fraction(x.num * y.den + x.den * y.num, x.den * y.den);
-}
-
-inline Fraction operator-(const Fraction &x, const Fraction &y) {
-  return Fraction(x.num * y.den - x.den * y.num, x.den * y.den);
-}
-
-inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
-  x.print(os);
-  return os;
-}
-
 } // namespace presburger
 } // namespace mlir
 

>From ac6d4a6d0ac295d01540919e6f271ac84ef32c78 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Thu, 31 Aug 2023 17:30:17 +0100
Subject: [PATCH 12/27] Template Matrix to Matrix<T> (for MPInt and Fraction)
 with explicit instantiation Duplicate makeMatrix to makeIntMatrix and
 makeFracMatrix

Implement arithmetic operations for Fraction for compatibility
---
 .../mlir/Analysis/Presburger/Fraction.h        | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/mlir/include/mlir/Analysis/Presburger/Fraction.h b/mlir/include/mlir/Analysis/Presburger/Fraction.h
index 74127a900d53ed2..2c3e43021707e16 100644
--- a/mlir/include/mlir/Analysis/Presburger/Fraction.h
+++ b/mlir/include/mlir/Analysis/Presburger/Fraction.h
@@ -15,6 +15,7 @@
 #define MLIR_ANALYSIS_PRESBURGER_FRACTION_H
 
 #include "mlir/Analysis/Presburger/MPInt.h"
+#include "mlir/Analysis/Presburger/Utils.h"
 #include "mlir/Support/MathExtras.h"
 
 namespace mlir {
@@ -147,6 +148,23 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
   return os;
 }
 
+inline Fraction operator/(const Fraction &x, const Fraction &y) {
+  return Fraction(x.num * y.den, x.den * y.num);
+}
+
+inline Fraction operator+(const Fraction &x, const Fraction &y) {
+  return Fraction(x.num * y.den + x.den * y.num, x.den * y.den);
+}
+
+inline Fraction operator-(const Fraction &x, const Fraction &y) {
+  return Fraction(x.num * y.den - x.den * y.num, x.den * y.den);
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
+  x.print(os);
+  return os;
+}
+
 } // namespace presburger
 } // namespace mlir
 

>From 6d2d304e85f01074f74884d7d1c3ab6e8791b9d1 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Thu, 31 Aug 2023 17:30:17 +0100
Subject: [PATCH 13/27] Template Matrix to Matrix<T> (for MPInt and Fraction)
 with explicit instantiation Duplicate makeMatrix to makeIntMatrix and
 makeFracMatrix

Implement arithmetic operations for Fraction for compatibility
---
 .../include/mlir/Analysis/Presburger/Fraction.h | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/mlir/include/mlir/Analysis/Presburger/Fraction.h b/mlir/include/mlir/Analysis/Presburger/Fraction.h
index 2c3e43021707e16..fdcd82a48729d0b 100644
--- a/mlir/include/mlir/Analysis/Presburger/Fraction.h
+++ b/mlir/include/mlir/Analysis/Presburger/Fraction.h
@@ -165,6 +165,23 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
   return os;
 }
 
+inline Fraction operator/(const Fraction &x, const Fraction &y) {
+  return Fraction(x.num * y.den, x.den * y.num);
+}
+
+inline Fraction operator+(const Fraction &x, const Fraction &y) {
+  return Fraction(x.num * y.den + x.den * y.num, x.den * y.den);
+}
+
+inline Fraction operator-(const Fraction &x, const Fraction &y) {
+  return Fraction(x.num * y.den - x.den * y.num, x.den * y.den);
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
+  x.print(os);
+  return os;
+}
+
 } // namespace presburger
 } // namespace mlir
 

>From 2c2909f5b3dbe67c87caa24b38ded76fb229c89e Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Mon, 4 Sep 2023 13:36:14 +0100
Subject: [PATCH 14/27] Add static assert

---
 mlir/include/mlir/Analysis/Presburger/Fraction.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Fraction.h b/mlir/include/mlir/Analysis/Presburger/Fraction.h
index fdcd82a48729d0b..ee3835d7e544617 100644
--- a/mlir/include/mlir/Analysis/Presburger/Fraction.h
+++ b/mlir/include/mlir/Analysis/Presburger/Fraction.h
@@ -15,7 +15,6 @@
 #define MLIR_ANALYSIS_PRESBURGER_FRACTION_H
 
 #include "mlir/Analysis/Presburger/MPInt.h"
-#include "mlir/Analysis/Presburger/Utils.h"
 #include "mlir/Support/MathExtras.h"
 
 namespace mlir {

>From c94405fc35f60e479d629095057bc07488622aeb Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Wed, 6 Sep 2023 14:35:27 +0100
Subject: [PATCH 15/27] Fix duplicates and use increment operators for Fraction

---
 .../mlir/Analysis/Presburger/Fraction.h       | 34 -------------------
 mlir/lib/Analysis/Presburger/Matrix.cpp       |  4 +--
 2 files changed, 2 insertions(+), 36 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Fraction.h b/mlir/include/mlir/Analysis/Presburger/Fraction.h
index ee3835d7e544617..74127a900d53ed2 100644
--- a/mlir/include/mlir/Analysis/Presburger/Fraction.h
+++ b/mlir/include/mlir/Analysis/Presburger/Fraction.h
@@ -147,40 +147,6 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
   return os;
 }
 
-inline Fraction operator/(const Fraction &x, const Fraction &y) {
-  return Fraction(x.num * y.den, x.den * y.num);
-}
-
-inline Fraction operator+(const Fraction &x, const Fraction &y) {
-  return Fraction(x.num * y.den + x.den * y.num, x.den * y.den);
-}
-
-inline Fraction operator-(const Fraction &x, const Fraction &y) {
-  return Fraction(x.num * y.den - x.den * y.num, x.den * y.den);
-}
-
-inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
-  x.print(os);
-  return os;
-}
-
-inline Fraction operator/(const Fraction &x, const Fraction &y) {
-  return Fraction(x.num * y.den, x.den * y.num);
-}
-
-inline Fraction operator+(const Fraction &x, const Fraction &y) {
-  return Fraction(x.num * y.den + x.den * y.num, x.den * y.den);
-}
-
-inline Fraction operator-(const Fraction &x, const Fraction &y) {
-  return Fraction(x.num * y.den - x.den * y.num, x.den * y.den);
-}
-
-inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Fraction &x) {
-  x.print(os);
-  return os;
-}
-
 } // namespace presburger
 } // namespace mlir
 
diff --git a/mlir/lib/Analysis/Presburger/Matrix.cpp b/mlir/lib/Analysis/Presburger/Matrix.cpp
index e526af9809ee0e2..c94681b87695510 100644
--- a/mlir/lib/Analysis/Presburger/Matrix.cpp
+++ b/mlir/lib/Analysis/Presburger/Matrix.cpp
@@ -237,7 +237,7 @@ template <typename T> SmallVector<T, 8> Matrix<T>::preMultiplyWithRow(ArrayRef<T
   SmallVector<T, 8> result(getNumColumns(), T(0));
   for (unsigned col = 0, e = getNumColumns(); col < e; ++col)
     for (unsigned i = 0, e = getNumRows(); i < e; ++i)
-      result[col] = result[col] + rowVec[i] * at(i, col);
+      result[col] += rowVec[i] * at(i, col);
   return result;
 }
 
@@ -249,7 +249,7 @@ Matrix<T>::postMultiplyWithColumn(ArrayRef<T> colVec) const {
   SmallVector<T, 8> result(getNumRows(), T(0));
   for (unsigned row = 0, e = getNumRows(); row < e; row++)
     for (unsigned i = 0, e = getNumColumns(); i < e; i++)
-      result[row] = result[row] + at(row, i) * colVec[i];
+      result[row] += at(row, i) * colVec[i];
   return result;
 }
 

>From e65109de7fd010b21d71ec990b23f8467456fc2b Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Wed, 6 Sep 2023 14:42:21 +0100
Subject: [PATCH 16/27] Fix duplicates and delete extra files

---
 libcxx/modules/std/mdspan.cppm          | 33 -------------------------
 libcxx/modules/std/print.cppm           | 25 -------------------
 mlir/lib/Analysis/Presburger/Matrix.cpp |  4 +--
 3 files changed, 2 insertions(+), 60 deletions(-)
 delete mode 100644 libcxx/modules/std/mdspan.cppm
 delete mode 100644 libcxx/modules/std/print.cppm

diff --git a/libcxx/modules/std/mdspan.cppm b/libcxx/modules/std/mdspan.cppm
deleted file mode 100644
index 40426cce3fce8c2..000000000000000
--- a/libcxx/modules/std/mdspan.cppm
+++ /dev/null
@@ -1,33 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-module;
-#include <mdspan>
-
-export module std:mdspan;
-export namespace std {
-#if _LIBCPP_STD_VER >= 23
-  // [mdspan.extents], class template extents
-  using std::extents;
-
-  // [mdspan.extents.dextents], alias template dextents
-  using std::dextents;
-
-  // [mdspan.layout], layout mapping
-  using std::layout_left;
-  using std::layout_right;
-  // using std::layout_stride;
-
-  // [mdspan.accessor.default], class template default_accessor
-  using std::default_accessor;
-
-  // [mdspan.mdspan], class template mdspan
-  using std::mdspan;
-#endif // _LIBCPP_STD_VER >= 23
-} // namespace std
diff --git a/libcxx/modules/std/print.cppm b/libcxx/modules/std/print.cppm
deleted file mode 100644
index 02362633c6d9fbb..000000000000000
--- a/libcxx/modules/std/print.cppm
+++ /dev/null
@@ -1,25 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-module;
-#include <print>
-
-export module std:print;
-export namespace std {
-#if _LIBCPP_STD_VER >= 23
-  // [print.fun], print functions
-  using std::print;
-  using std::println;
-
-  using std::vprint_nonunicode;
-#  ifndef _LIBCPP_HAS_NO_UNICODE
-  using std::vprint_unicode;
-#  endif // _LIBCPP_HAS_NO_UNICODE
-#endif   // _LIBCPP_STD_VER >= 23
-} // namespace std
diff --git a/mlir/lib/Analysis/Presburger/Matrix.cpp b/mlir/lib/Analysis/Presburger/Matrix.cpp
index c94681b87695510..814c93049f15bfc 100644
--- a/mlir/lib/Analysis/Presburger/Matrix.cpp
+++ b/mlir/lib/Analysis/Presburger/Matrix.cpp
@@ -202,7 +202,7 @@ template <typename T> void Matrix<T>::addToRow(unsigned row, ArrayRef<T> rowVec,
   if (scale == 0)
     return;
   for (unsigned col = 0; col < nColumns; ++col)
-    at(row, col) = at(row, col) + scale * rowVec[col];
+    at(row, col) += scale * rowVec[col];
 }
 
 template <typename T> void Matrix<T>::addToColumn(unsigned sourceColumn, unsigned targetColumn,
@@ -210,7 +210,7 @@ template <typename T> void Matrix<T>::addToColumn(unsigned sourceColumn, unsigne
   if (scale == 0)
     return;
   for (unsigned row = 0, e = getNumRows(); row < e; ++row)
-    at(row, targetColumn) = at(row, targetColumn) + scale * at(row, sourceColumn);
+    at(row, targetColumn) += scale * at(row, sourceColumn);
 }
 
 template <typename T> void Matrix<T>::negateColumn(unsigned column) {

>From c668acd80eb68ff2395e748cab8e4b23a2d55d39 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Mon, 18 Sep 2023 16:48:01 +0100
Subject: [PATCH 17/27] Fix comment

---
 mlir/include/mlir/Analysis/Presburger/Matrix.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Matrix.h b/mlir/include/mlir/Analysis/Presburger/Matrix.h
index 79044e6fbb8a01a..0a6bcee3a02819f 100644
--- a/mlir/include/mlir/Analysis/Presburger/Matrix.h
+++ b/mlir/include/mlir/Analysis/Presburger/Matrix.h
@@ -34,9 +34,11 @@ namespace presburger {
 /// (i, j) is stored at data[i*nReservedColumns + j]. The reserved but unused
 /// columns always have all zero values. The reserved rows are just reserved
 /// space in the underlying SmallVector's capacity.
+/// This class only works for the types MPInt and Fraction, since the method
+/// implementations are in the Matrix.cpp file. Only these two types have
+/// been explicitly instantiated there.
 template<typename T>
 class Matrix {
-  // This class is not intended for general use: it supports only integers and rational numbers.
 static_assert(std::is_same_v<T,MPInt> || std::is_same_v<T,Fraction>, "T must be MPInt or Fraction.");
 public:
   Matrix() = delete;

>From 8e863dbc339d4011b6849abc84d97c58a60f6ab7 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Wed, 20 Sep 2023 11:55:36 +0100
Subject: [PATCH 18/27] Create IntMatrix for hermite normal form and row
 normalisation

---
 .../Analysis/Presburger/IntegerRelation.h     |  6 +-
 .../Analysis/Presburger/LinearTransform.h     |  8 +-
 .../include/mlir/Analysis/Presburger/Matrix.h | 63 ++++++++-----
 .../mlir/Analysis/Presburger/PWMAFunction.h   |  8 +-
 .../mlir/Analysis/Presburger/Simplex.h        |  4 +-
 mlir/include/mlir/Analysis/Presburger/Utils.h |  2 +-
 .../Analysis/Presburger/IntegerRelation.cpp   |  8 +-
 .../Analysis/Presburger/LinearTransform.cpp   |  6 +-
 mlir/lib/Analysis/Presburger/Matrix.cpp       | 88 ++++++++++---------
 mlir/lib/Analysis/Presburger/Simplex.cpp      |  6 +-
 .../Presburger/LinearTransformTest.cpp        | 14 +--
 .../Analysis/Presburger/MatrixTest.cpp        | 38 ++++----
 mlir/unittests/Analysis/Presburger/Parser.h   |  2 +-
 mlir/unittests/Analysis/Presburger/Utils.h    |  4 +-
 14 files changed, 144 insertions(+), 113 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/IntegerRelation.h b/mlir/include/mlir/Analysis/Presburger/IntegerRelation.h
index d4e58ef0d04666c..56484622ec980cd 100644
--- a/mlir/include/mlir/Analysis/Presburger/IntegerRelation.h
+++ b/mlir/include/mlir/Analysis/Presburger/IntegerRelation.h
@@ -366,7 +366,7 @@ class IntegerRelation {
   /// bounded. The span of the returned vectors is guaranteed to contain all
   /// such vectors. The returned vectors are NOT guaranteed to be linearly
   /// independent. This function should not be called on empty sets.
-  Matrix<MPInt> getBoundedDirections() const;
+  IntMatrix getBoundedDirections() const;
 
   /// Find an integer sample point satisfying the constraints using a
   /// branch and bound algorithm with generalized basis reduction, with some
@@ -792,10 +792,10 @@ class IntegerRelation {
   PresburgerSpace space;
 
   /// Coefficients of affine equalities (in == 0 form).
-  Matrix<MPInt> equalities;
+  IntMatrix equalities;
 
   /// Coefficients of affine inequalities (in >= 0 form).
-  Matrix<MPInt> inequalities;
+  IntMatrix inequalities;
 };
 
 /// An IntegerPolyhedron represents the set of points from a PresburgerSpace
diff --git a/mlir/include/mlir/Analysis/Presburger/LinearTransform.h b/mlir/include/mlir/Analysis/Presburger/LinearTransform.h
index 686e846a16c78a7..67dc9e87facb9ad 100644
--- a/mlir/include/mlir/Analysis/Presburger/LinearTransform.h
+++ b/mlir/include/mlir/Analysis/Presburger/LinearTransform.h
@@ -22,8 +22,8 @@ namespace presburger {
 
 class LinearTransform {
 public:
-  explicit LinearTransform(Matrix<MPInt> &&oMatrix);
-  explicit LinearTransform(const Matrix<MPInt> &oMatrix);
+  explicit LinearTransform(IntMatrix &&oMatrix);
+  explicit LinearTransform(const IntMatrix &oMatrix);
 
   // Returns a linear transform T such that MT is M in column echelon form.
   // Also returns the number of non-zero columns in MT.
@@ -32,7 +32,7 @@ class LinearTransform {
   // strictly below that of the previous column, and all columns which have only
   // zeros are at the end.
   static std::pair<unsigned, LinearTransform>
-  makeTransformToColumnEchelon(const Matrix<MPInt> &m);
+  makeTransformToColumnEchelon(const IntMatrix &m);
 
   // Returns an IntegerRelation having a constraint vector vT for every
   // constraint vector v in rel, where T is this transform.
@@ -55,7 +55,7 @@ class LinearTransform {
   MPInt determinant();
 
 private:
-  Matrix<MPInt> matrix;
+  IntMatrix matrix;
 };
 
 } // namespace presburger
diff --git a/mlir/include/mlir/Analysis/Presburger/Matrix.h b/mlir/include/mlir/Analysis/Presburger/Matrix.h
index 0a6bcee3a02819f..f05a4fb2ffbb70d 100644
--- a/mlir/include/mlir/Analysis/Presburger/Matrix.h
+++ b/mlir/include/mlir/Analysis/Presburger/Matrix.h
@@ -157,13 +157,6 @@ static_assert(std::is_same_v<T,MPInt> || std::is_same_v<T,Fraction>, "T must be
   /// Negate the specified row.
   void negateRow(unsigned row);
 
-  /// Divide the first `nCols` of the specified row by their GCD.
-  /// Returns the GCD of the first `nCols` of the specified row.
-  T normalizeRow(unsigned row, unsigned nCols);
-  /// Divide the columns of the specified row by their GCD.
-  /// Returns the GCD of the columns of the specified row.
-  T normalizeRow(unsigned row);
-
   /// The given vector is interpreted as a row vector v. Post-multiply v with
   /// this matrix, say M, and return vM.
   SmallVector<T, 8> preMultiplyWithRow(ArrayRef<T> rowVec) const;
@@ -172,18 +165,6 @@ static_assert(std::is_same_v<T,MPInt> || std::is_same_v<T,Fraction>, "T must be
   /// this matrix, say M, and return Mv.
   SmallVector<T, 8> postMultiplyWithColumn(ArrayRef<T> colVec) const;
 
-  /// Given the current matrix M, returns the matrices H, U such that H is the
-  /// column hermite normal form of M, i.e. H = M * U, where U is unimodular and
-  /// the matrix H has the following restrictions:
-  ///  - H is lower triangular.
-  ///  - The leading coefficient (the first non-zero entry from the top, called
-  ///    the pivot) of a non-zero column is always strictly below of the leading
-  ///    coefficient of the column before it; moreover, it is positive.
-  ///  - The elements to the right of the pivots are zero and the elements to
-  ///    the left of the pivots are nonnegative and strictly smaller than the
-  ///    pivot.
-  std::pair<Matrix, Matrix> computeHermiteNormalForm() const;
-
   /// Resize the matrix to the specified dimensions. If a dimension is smaller,
   /// the values are truncated; if it is bigger, the new values are initialized
   /// to zero.
@@ -221,7 +202,49 @@ static_assert(std::is_same_v<T,MPInt> || std::is_same_v<T,Fraction>, "T must be
   SmallVector<T, 16> data;
 };
 
+// An inherited class for integer matrices, with no new data attributes.
+// This is only used for the matrix-related methods which apply only
+// to integers (hermite normal form computation and row normalisation).
+class IntMatrix : public Matrix<MPInt>
+{
+public:
+  IntMatrix(unsigned rows, unsigned columns, unsigned reservedRows = 0,
+            unsigned reservedColumns = 0) :
+    Matrix<MPInt>(rows, columns, reservedRows, reservedColumns) {};
+
+  IntMatrix(Matrix<MPInt> m) :
+    Matrix<MPInt>(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 IntMatrix identity(unsigned dimension);
+
+  /// Given the current matrix M, returns the matrices H, U such that H is the
+  /// column hermite normal form of M, i.e. H = M * U, where U is unimodular and
+  /// the matrix H has the following restrictions:
+  ///  - H is lower triangular.
+  ///  - The leading coefficient (the first non-zero entry from the top, called
+  ///    the pivot) of a non-zero column is always strictly below of the leading
+  ///    coefficient of the column before it; moreover, it is positive.
+  ///  - The elements to the right of the pivots are zero and the elements to
+  ///    the left of the pivots are nonnegative and strictly smaller than the
+  ///    pivot.
+  std::pair<IntMatrix, IntMatrix> computeHermiteNormalForm() const;
+
+  /// Divide the first `nCols` of the specified row by their GCD.
+  /// Returns the GCD of the first `nCols` of the specified row.
+  MPInt normalizeRow(unsigned row, unsigned nCols);
+  /// Divide the columns of the specified row by their GCD.
+  /// Returns the GCD of the columns of the specified row.
+  MPInt normalizeRow(unsigned row);
+
+};
+
 } // namespace presburger
 } // namespace mlir
 
-#endif // MLIR_ANALYSIS_PRESBURGER_MATRIX_H
+#endif // MLIR_ANALYSIS_PRESBURGER_MATRIX_H
\ No newline at end of file
diff --git a/mlir/include/mlir/Analysis/Presburger/PWMAFunction.h b/mlir/include/mlir/Analysis/Presburger/PWMAFunction.h
index 0b3804fc08a60e0..236cc90ad66acd3 100644
--- a/mlir/include/mlir/Analysis/Presburger/PWMAFunction.h
+++ b/mlir/include/mlir/Analysis/Presburger/PWMAFunction.h
@@ -40,13 +40,13 @@ enum class OrderingKind { EQ, NE, LT, LE, GT, GE };
 /// value of the function at a specified point.
 class MultiAffineFunction {
 public:
-  MultiAffineFunction(const PresburgerSpace &space, const Matrix<MPInt> &output)
+  MultiAffineFunction(const PresburgerSpace &space, const IntMatrix &output)
       : space(space), output(output),
         divs(space.getNumVars() - space.getNumRangeVars()) {
     assertIsConsistent();
   }
 
-  MultiAffineFunction(const PresburgerSpace &space, const Matrix<MPInt> &output,
+  MultiAffineFunction(const PresburgerSpace &space, const IntMatrix &output,
                       const DivisionRepr &divs)
       : space(space), output(output), divs(divs) {
     assertIsConsistent();
@@ -65,7 +65,7 @@ class MultiAffineFunction {
   PresburgerSpace getOutputSpace() const { return space.getRangeSpace(); }
 
   /// Get a matrix with each row representing row^th output expression.
-  const Matrix<MPInt> &getOutputMatrix() const { return output; }
+  const IntMatrix &getOutputMatrix() const { return output; }
   /// Get the `i^th` output expression.
   ArrayRef<MPInt> getOutputExpr(unsigned i) const { return output.getRow(i); }
 
@@ -124,7 +124,7 @@ class MultiAffineFunction {
   /// The function's output is a tuple of integers, with the ith element of the
   /// tuple defined by the affine expression given by the ith row of this output
   /// matrix.
-  Matrix<MPInt> output;
+  IntMatrix output;
 
   /// Storage for division representation for each local variable in space.
   DivisionRepr divs;
diff --git a/mlir/include/mlir/Analysis/Presburger/Simplex.h b/mlir/include/mlir/Analysis/Presburger/Simplex.h
index 922b0cb33168fb6..9482f69b31cd666 100644
--- a/mlir/include/mlir/Analysis/Presburger/Simplex.h
+++ b/mlir/include/mlir/Analysis/Presburger/Simplex.h
@@ -338,7 +338,7 @@ class SimplexBase {
   unsigned nSymbol;
 
   /// The matrix representing the tableau.
-  Matrix<MPInt> tableau;
+  IntMatrix tableau;
 
   /// This is true if the tableau has been detected to be empty, false
   /// otherwise.
@@ -861,7 +861,7 @@ class Simplex : public SimplexBase {
 
   /// Reduce the given basis, starting at the specified level, using general
   /// basis reduction.
-  void reduceBasis(Matrix<MPInt> &basis, unsigned level);
+  void reduceBasis(IntMatrix &basis, unsigned level);
 };
 
 /// Takes a snapshot of the simplex state on construction and rolls back to the
diff --git a/mlir/include/mlir/Analysis/Presburger/Utils.h b/mlir/include/mlir/Analysis/Presburger/Utils.h
index d3822ed572f8ee8..a451ae8bf55723e 100644
--- a/mlir/include/mlir/Analysis/Presburger/Utils.h
+++ b/mlir/include/mlir/Analysis/Presburger/Utils.h
@@ -182,7 +182,7 @@ class DivisionRepr {
   /// Each row of the Matrix represents a single division dividend. The
   /// `i^th` row represents the dividend of the variable at `divOffset + i`
   /// in the constraint system (and the `i^th` local variable).
-  Matrix<MPInt> dividends;
+  IntMatrix dividends;
 
   /// Denominators of each division. If a denominator of a division is `0`, the
   /// division variable is considered to not have a division representation.
diff --git a/mlir/lib/Analysis/Presburger/IntegerRelation.cpp b/mlir/lib/Analysis/Presburger/IntegerRelation.cpp
index 118ed1f19ce62a0..be764bd7c9176b9 100644
--- a/mlir/lib/Analysis/Presburger/IntegerRelation.cpp
+++ b/mlir/lib/Analysis/Presburger/IntegerRelation.cpp
@@ -304,7 +304,7 @@ SymbolicLexOpt IntegerRelation::findSymbolicIntegerLexMax() const {
   // Get lexmax by flipping range sign in the PWMA constraints.
   for (auto &flippedPiece :
        flippedSymbolicIntegerLexMax.lexopt.getAllPieces()) {
-    Matrix<MPInt> mat = flippedPiece.output.getOutputMatrix();
+    IntMatrix mat = flippedPiece.output.getOutputMatrix();
     for (unsigned i = 0, e = mat.getNumRows(); i < e; i++)
       mat.negateRow(i);
     MultiAffineFunction maf(flippedPiece.output.getSpace(), mat);
@@ -738,7 +738,7 @@ bool IntegerRelation::isEmptyByGCDTest() const {
 //
 // It is sufficient to check the perpendiculars of the constraints, as the set
 // of perpendiculars which are bounded must span all bounded directions.
-Matrix<MPInt> IntegerRelation::getBoundedDirections() const {
+IntMatrix IntegerRelation::getBoundedDirections() const {
   // Note that it is necessary to add the equalities too (which the constructor
   // does) even though we don't need to check if they are bounded; whether an
   // inequality is bounded or not depends on what other constraints, including
@@ -759,7 +759,7 @@ Matrix<MPInt> IntegerRelation::getBoundedDirections() const {
   // The direction vector is given by the coefficients and does not include the
   // constant term, so the matrix has one fewer column.
   unsigned dirsNumCols = getNumCols() - 1;
-  Matrix<MPInt> dirs(boundedIneqs.size() + getNumEqualities(), dirsNumCols);
+  IntMatrix dirs(boundedIneqs.size() + getNumEqualities(), dirsNumCols);
 
   // Copy the bounded inequalities.
   unsigned row = 0;
@@ -845,7 +845,7 @@ IntegerRelation::findIntegerSample() const {
   // m is a matrix containing, in each row, a vector in which S is
   // bounded, such that the linear span of all these dimensions contains all
   // bounded dimensions in S.
-  Matrix<MPInt> m = getBoundedDirections();
+  IntMatrix m = getBoundedDirections();
   // In column echelon form, each row of m occupies only the first rank(m)
   // columns and has zeros on the other columns. The transform T that brings S
   // to column echelon form is unimodular as well, so this is a suitable
diff --git a/mlir/lib/Analysis/Presburger/LinearTransform.cpp b/mlir/lib/Analysis/Presburger/LinearTransform.cpp
index d25e76d9229f605..32b21f5079fdc4f 100644
--- a/mlir/lib/Analysis/Presburger/LinearTransform.cpp
+++ b/mlir/lib/Analysis/Presburger/LinearTransform.cpp
@@ -12,11 +12,11 @@
 using namespace mlir;
 using namespace presburger;
 
-LinearTransform::LinearTransform(Matrix<MPInt> &&oMatrix) : matrix(oMatrix) {}
-LinearTransform::LinearTransform(const Matrix<MPInt> &oMatrix) : matrix(oMatrix) {}
+LinearTransform::LinearTransform(IntMatrix &&oMatrix) : matrix(oMatrix) {}
+LinearTransform::LinearTransform(const IntMatrix &oMatrix) : matrix(oMatrix) {}
 
 std::pair<unsigned, LinearTransform>
-LinearTransform::makeTransformToColumnEchelon(const Matrix<MPInt> &m) {
+LinearTransform::makeTransformToColumnEchelon(const IntMatrix &m) {
   // Compute the hermite normal form of m. This, is by definition, is in column
   // echelon form.
   auto [h, u] = m.computeHermiteNormalForm();
diff --git a/mlir/lib/Analysis/Presburger/Matrix.cpp b/mlir/lib/Analysis/Presburger/Matrix.cpp
index 814c93049f15bfc..bda7b6263cf7d79 100644
--- a/mlir/lib/Analysis/Presburger/Matrix.cpp
+++ b/mlir/lib/Analysis/Presburger/Matrix.cpp
@@ -223,14 +223,6 @@ template <typename T> void Matrix<T>::negateRow(unsigned row) {
     at(row, column) = -at(row, column);
 }
 
-template <> MPInt Matrix<MPInt>::normalizeRow(unsigned row, unsigned cols) {
-  return normalizeRange(getRow(row).slice(0, cols));
-}
-
-template <> MPInt Matrix<MPInt>::normalizeRow(unsigned row) {
-  return normalizeRow(row, getNumColumns());
-}
-
 template <typename T> SmallVector<T, 8> Matrix<T>::preMultiplyWithRow(ArrayRef<T> rowVec) const {
   assert(rowVec.size() == getNumRows() && "Invalid row vector dimension!");
 
@@ -267,12 +259,53 @@ static void modEntryColumnOperation(Matrix<MPInt> &m, unsigned row, unsigned sou
   otherMatrix.addToColumn(sourceCol, targetCol, ratio);
 }
 
-template <> std::pair<Matrix<MPInt>, Matrix<MPInt>> Matrix<MPInt>::computeHermiteNormalForm() const {
+template <typename T> void Matrix<T>::print(raw_ostream &os) const {
+  for (unsigned row = 0; row < nRows; ++row) {
+    for (unsigned column = 0; column < nColumns; ++column)
+      os << at(row, column) << ' ';
+    os << '\n';
+  }
+}
+
+template <typename T> void Matrix<T>::dump() const { print(llvm::errs()); }
+
+template <typename T> bool Matrix<T>::hasConsistentState() const {
+  if (data.size() != nRows * nReservedColumns)
+    return false;
+  if (nColumns > nReservedColumns)
+    return false;
+#ifdef EXPENSIVE_CHECKS
+  for (unsigned r = 0; r < nRows; ++r)
+    for (unsigned c = nColumns; c < nReservedColumns; ++c)
+      if (data[r * nReservedColumns + c] != 0)
+        return false;
+#endif
+  return true;
+}
+
+namespace mlir
+{
+namespace presburger
+{
+template class Matrix<MPInt>;
+template class Matrix<Fraction>;
+}
+}
+
+IntMatrix IntMatrix::identity(unsigned dimension) {
+  IntMatrix matrix(dimension, dimension);
+  for (unsigned i = 0; i < dimension; ++i)
+    matrix(i, i) = 1;
+  return matrix;
+}
+
+
+std::pair<IntMatrix, IntMatrix> IntMatrix::computeHermiteNormalForm() const {
   // We start with u as an identity matrix and perform operations on h until h
   // is in hermite normal form. We apply the same sequence of operations on u to
   // obtain a transform that takes h to hermite normal form.
-  Matrix<MPInt> h = *this;
-  Matrix<MPInt> u = Matrix<MPInt>::identity(h.getNumColumns());
+  IntMatrix h = *this;
+  IntMatrix u = IntMatrix::identity(h.getNumColumns());
 
   unsigned echelonCol = 0;
   // Invariant: in all rows above row, all columns from echelonCol onwards
@@ -353,35 +386,10 @@ template <> std::pair<Matrix<MPInt>, Matrix<MPInt>> Matrix<MPInt>::computeHermit
   return {h, u};
 }
 
-template <typename T> void Matrix<T>::print(raw_ostream &os) const {
-  for (unsigned row = 0; row < nRows; ++row) {
-    for (unsigned column = 0; column < nColumns; ++column)
-      os << at(row, column) << ' ';
-    os << '\n';
-  }
-}
-
-template <typename T> void Matrix<T>::dump() const { print(llvm::errs()); }
-
-template <typename T> bool Matrix<T>::hasConsistentState() const {
-  if (data.size() != nRows * nReservedColumns)
-    return false;
-  if (nColumns > nReservedColumns)
-    return false;
-#ifdef EXPENSIVE_CHECKS
-  for (unsigned r = 0; r < nRows; ++r)
-    for (unsigned c = nColumns; c < nReservedColumns; ++c)
-      if (data[r * nReservedColumns + c] != 0)
-        return false;
-#endif
-  return true;
+MPInt IntMatrix::normalizeRow(unsigned row, unsigned cols) {
+  return normalizeRange(getRow(row).slice(0, cols));
 }
 
-namespace mlir
-{
-namespace presburger
-{
-template class Matrix<MPInt>;
-template class Matrix<Fraction>;
-}
+MPInt IntMatrix::normalizeRow(unsigned row) {
+  return normalizeRow(row, getNumColumns());
 }
\ No newline at end of file
diff --git a/mlir/lib/Analysis/Presburger/Simplex.cpp b/mlir/lib/Analysis/Presburger/Simplex.cpp
index f8d274a7a4d17f3..ba840cad6b315e8 100644
--- a/mlir/lib/Analysis/Presburger/Simplex.cpp
+++ b/mlir/lib/Analysis/Presburger/Simplex.cpp
@@ -436,7 +436,7 @@ LogicalResult SymbolicLexSimplex::addSymbolicCut(unsigned row) {
 }
 
 void SymbolicLexSimplex::recordOutput(SymbolicLexOpt &result) const {
-  Matrix<MPInt> output(0, domainPoly.getNumVars() + 1);
+  IntMatrix output(0, domainPoly.getNumVars() + 1);
   output.reserveRows(result.lexopt.getNumOutputs());
   for (const Unknown &u : var) {
     if (u.isSymbol)
@@ -1801,7 +1801,7 @@ class presburger::GBRSimplex {
 ///
 /// When incrementing i, no cached f values get invalidated. However, the cached
 /// duals do get invalidated as the duals for the higher levels are different.
-void Simplex::reduceBasis(Matrix<MPInt> &basis, unsigned level) {
+void Simplex::reduceBasis(IntMatrix &basis, unsigned level) {
   const Fraction epsilon(3, 4);
 
   if (level == basis.getNumRows() - 1)
@@ -1975,7 +1975,7 @@ std::optional<SmallVector<MPInt, 8>> Simplex::findIntegerSample() {
     return {};
 
   unsigned nDims = var.size();
-  Matrix<MPInt> basis = Matrix<MPInt>::identity(nDims);
+  IntMatrix basis = IntMatrix::identity(nDims);
 
   unsigned level = 0;
   // The snapshot just before constraining a direction to a value at each level.
diff --git a/mlir/unittests/Analysis/Presburger/LinearTransformTest.cpp b/mlir/unittests/Analysis/Presburger/LinearTransformTest.cpp
index 07c1f9069bca21c..721d1fd6e253591 100644
--- a/mlir/unittests/Analysis/Presburger/LinearTransformTest.cpp
+++ b/mlir/unittests/Analysis/Presburger/LinearTransformTest.cpp
@@ -13,7 +13,7 @@
 using namespace mlir;
 using namespace presburger;
 
-void testColumnEchelonForm(const Matrix<MPInt> &m, unsigned expectedRank) {
+void testColumnEchelonForm(const IntMatrix &m, unsigned expectedRank) {
   unsigned lastAllowedNonZeroCol = 0;
   std::pair<unsigned, LinearTransform> result =
       LinearTransform::makeTransformToColumnEchelon(m);
@@ -42,21 +42,21 @@ void testColumnEchelonForm(const Matrix<MPInt> &m, unsigned expectedRank) {
 
 TEST(LinearTransformTest, transformToColumnEchelonTest) {
   // m1, m2, m3 are rank 1 matrices -- the first and second rows are identical.
-  Matrix<MPInt> m1(2, 2);
+  IntMatrix m1(2, 2);
   m1(0, 0) = 4;
   m1(0, 1) = -7;
   m1(1, 0) = 4;
   m1(1, 1) = -7;
   testColumnEchelonForm(m1, 1u);
 
-  Matrix<MPInt> m2(2, 2);
+  IntMatrix m2(2, 2);
   m2(0, 0) = -4;
   m2(0, 1) = 7;
   m2(1, 0) = 4;
   m2(1, 1) = -7;
   testColumnEchelonForm(m2, 1u);
 
-  Matrix<MPInt> m3(2, 2);
+  IntMatrix m3(2, 2);
   m3(0, 0) = -4;
   m3(0, 1) = -7;
   m3(1, 0) = -4;
@@ -64,21 +64,21 @@ TEST(LinearTransformTest, transformToColumnEchelonTest) {
   testColumnEchelonForm(m3, 1u);
 
   // m4, m5, m6 are rank 2 matrices -- the first and second rows are different.
-  Matrix<MPInt> m4(2, 2);
+  IntMatrix m4(2, 2);
   m4(0, 0) = 4;
   m4(0, 1) = -7;
   m4(1, 0) = -4;
   m4(1, 1) = -7;
   testColumnEchelonForm(m4, 2u);
 
-  Matrix<MPInt> m5(2, 2);
+  IntMatrix m5(2, 2);
   m5(0, 0) = -4;
   m5(0, 1) = 7;
   m5(1, 0) = 4;
   m5(1, 1) = 7;
   testColumnEchelonForm(m5, 2u);
 
-  Matrix<MPInt> m6(2, 2);
+  IntMatrix m6(2, 2);
   m6(0, 0) = -4;
   m6(0, 1) = -7;
   m6(1, 0) = 4;
diff --git a/mlir/unittests/Analysis/Presburger/MatrixTest.cpp b/mlir/unittests/Analysis/Presburger/MatrixTest.cpp
index 7a226936c5751eb..6b23cedabf624ec 100644
--- a/mlir/unittests/Analysis/Presburger/MatrixTest.cpp
+++ b/mlir/unittests/Analysis/Presburger/MatrixTest.cpp
@@ -16,7 +16,7 @@ using namespace mlir;
 using namespace presburger;
 
 TEST(MatrixTest, ReadWrite) {
-  Matrix<MPInt> mat(5, 5);
+  IntMatrix mat(5, 5);
   for (unsigned row = 0; row < 5; ++row)
     for (unsigned col = 0; col < 5; ++col)
       mat(row, col) = 10 * row + col;
@@ -26,7 +26,7 @@ TEST(MatrixTest, ReadWrite) {
 }
 
 TEST(MatrixTest, SwapColumns) {
-  Matrix<MPInt> mat(5, 5);
+  IntMatrix mat(5, 5);
   for (unsigned row = 0; row < 5; ++row)
     for (unsigned col = 0; col < 5; ++col)
       mat(row, col) = col == 3 ? 1 : 0;
@@ -48,7 +48,7 @@ TEST(MatrixTest, SwapColumns) {
 }
 
 TEST(MatrixTest, SwapRows) {
-  Matrix<MPInt> mat(5, 5);
+  IntMatrix mat(5, 5);
   for (unsigned row = 0; row < 5; ++row)
     for (unsigned col = 0; col < 5; ++col)
       mat(row, col) = row == 2 ? 1 : 0;
@@ -70,7 +70,7 @@ TEST(MatrixTest, SwapRows) {
 }
 
 TEST(MatrixTest, resizeVertically) {
-  Matrix<MPInt> mat(5, 5);
+  IntMatrix mat(5, 5);
   EXPECT_EQ(mat.getNumRows(), 5u);
   EXPECT_EQ(mat.getNumColumns(), 5u);
   for (unsigned row = 0; row < 5; ++row)
@@ -95,7 +95,7 @@ TEST(MatrixTest, resizeVertically) {
 }
 
 TEST(MatrixTest, insertColumns) {
-  Matrix<MPInt> mat(5, 5, 5, 10);
+  IntMatrix mat(5, 5, 5, 10);
   EXPECT_EQ(mat.getNumRows(), 5u);
   EXPECT_EQ(mat.getNumColumns(), 5u);
   for (unsigned row = 0; row < 5; ++row)
@@ -132,7 +132,7 @@ TEST(MatrixTest, insertColumns) {
 }
 
 TEST(MatrixTest, insertRows) {
-  Matrix<MPInt> mat(5, 5, 5, 10);
+  IntMatrix mat(5, 5, 5, 10);
   ASSERT_TRUE(mat.hasConsistentState());
   EXPECT_EQ(mat.getNumRows(), 5u);
   EXPECT_EQ(mat.getNumColumns(), 5u);
@@ -170,7 +170,7 @@ TEST(MatrixTest, insertRows) {
 }
 
 TEST(MatrixTest, resize) {
-  Matrix<MPInt> mat(5, 5);
+  IntMatrix mat(5, 5);
   EXPECT_EQ(mat.getNumRows(), 5u);
   EXPECT_EQ(mat.getNumColumns(), 5u);
   for (unsigned row = 0; row < 5; ++row)
@@ -194,8 +194,8 @@ TEST(MatrixTest, resize) {
       EXPECT_EQ(mat(row, col), row >= 3 || col >= 3 ? 0 : int(10 * row + col));
 }
 
-static void checkHermiteNormalForm(const Matrix<MPInt> &mat,
-                                   const Matrix<MPInt> &hermiteForm) {
+static void checkHermiteNormalForm(const IntMatrix &mat,
+                                   const IntMatrix &hermiteForm) {
   auto [h, u] = mat.computeHermiteNormalForm();
 
   for (unsigned row = 0; row < mat.getNumRows(); row++)
@@ -209,41 +209,41 @@ TEST(MatrixTest, computeHermiteNormalForm) {
 
   {
     // Hermite form of a unimodular matrix is the identity matrix.
-    Matrix<MPInt> mat = makeIntMatrix(3, 3, {{2, 3, 6}, {3, 2, 3}, {17, 11, 16}});
-    Matrix<MPInt> hermiteForm = makeIntMatrix(3, 3, {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}});
+    IntMatrix mat = makeIntMatrix(3, 3, {{2, 3, 6}, {3, 2, 3}, {17, 11, 16}});
+    IntMatrix hermiteForm = makeIntMatrix(3, 3, {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}});
     checkHermiteNormalForm(mat, hermiteForm);
   }
 
   {
     // Hermite form of a unimodular is the identity matrix.
-    Matrix<MPInt> mat = makeIntMatrix(
+    IntMatrix mat = makeIntMatrix(
         4, 4,
         {{-6, -1, -19, -20}, {0, 1, 0, 0}, {-5, 0, -15, -16}, {6, 0, 18, 19}});
-    Matrix<MPInt> hermiteForm = makeIntMatrix(
+    IntMatrix hermiteForm = makeIntMatrix(
         4, 4, {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}});
     checkHermiteNormalForm(mat, hermiteForm);
   }
 
   {
-    Matrix<MPInt> mat = makeIntMatrix(
+    IntMatrix mat = makeIntMatrix(
         4, 4, {{3, 3, 1, 4}, {0, 1, 0, 0}, {0, 0, 19, 16}, {0, 0, 0, 3}});
-    Matrix<MPInt> hermiteForm = makeIntMatrix(
+    IntMatrix hermiteForm = makeIntMatrix(
         4, 4, {{1, 0, 0, 0}, {0, 1, 0, 0}, {1, 0, 3, 0}, {18, 0, 54, 57}});
     checkHermiteNormalForm(mat, hermiteForm);
   }
 
   {
-    Matrix<MPInt> mat = makeIntMatrix(
+    IntMatrix mat = makeIntMatrix(
         4, 4, {{3, 3, 1, 4}, {0, 1, 0, 0}, {0, 0, 19, 16}, {0, 0, 0, 3}});
-    Matrix<MPInt> hermiteForm = makeIntMatrix(
+    IntMatrix hermiteForm = makeIntMatrix(
         4, 4, {{1, 0, 0, 0}, {0, 1, 0, 0}, {1, 0, 3, 0}, {18, 0, 54, 57}});
     checkHermiteNormalForm(mat, hermiteForm);
   }
 
   {
-    Matrix<MPInt> mat =
+    IntMatrix mat =
         makeIntMatrix(3, 5, {{0, 2, 0, 7, 1}, {-1, 0, 0, -3, 0}, {0, 4, 1, 0, 8}});
-    Matrix<MPInt> hermiteForm =
+    IntMatrix hermiteForm =
         makeIntMatrix(3, 5, {{1, 0, 0, 0, 0}, {0, 1, 0, 0, 0}, {0, 0, 1, 0, 0}});
     checkHermiteNormalForm(mat, hermiteForm);
   }
diff --git a/mlir/unittests/Analysis/Presburger/Parser.h b/mlir/unittests/Analysis/Presburger/Parser.h
index bd9b6f07664c7e7..d6a715b102bd5e9 100644
--- a/mlir/unittests/Analysis/Presburger/Parser.h
+++ b/mlir/unittests/Analysis/Presburger/Parser.h
@@ -52,7 +52,7 @@ inline MultiAffineFunction parseMultiAffineFunction(StringRef str) {
 
   // TODO: Add default constructor for MultiAffineFunction.
   MultiAffineFunction multiAff(PresburgerSpace::getRelationSpace(),
-                               Matrix<MPInt>(0, 1));
+                               IntMatrix(0, 1));
   if (getMultiAffineFunctionFromMap(parseAffineMap(str, &context), multiAff)
           .failed())
     llvm_unreachable(
diff --git a/mlir/unittests/Analysis/Presburger/Utils.h b/mlir/unittests/Analysis/Presburger/Utils.h
index 8a7f86c866b7056..ef4a67d0b8c004f 100644
--- a/mlir/unittests/Analysis/Presburger/Utils.h
+++ b/mlir/unittests/Analysis/Presburger/Utils.h
@@ -27,9 +27,9 @@
 namespace mlir {
 namespace presburger {
 
-inline Matrix<MPInt> makeIntMatrix(unsigned numRow, unsigned numColumns,
+inline IntMatrix makeIntMatrix(unsigned numRow, unsigned numColumns,
                          ArrayRef<SmallVector<int, 8>> matrix) {
-  Matrix<MPInt> results(numRow, numColumns);
+  IntMatrix results(numRow, numColumns);
   assert(matrix.size() == numRow);
   for (unsigned i = 0; i < numRow; ++i) {
     assert(matrix[i].size() == numColumns &&

>From 63c81aabb37de50b5a08043c54c430a0b4012369 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Wed, 20 Sep 2023 14:17:09 +0100
Subject: [PATCH 19/27] Put opening braces on same line

---
 mlir/lib/Analysis/Presburger/Matrix.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/mlir/lib/Analysis/Presburger/Matrix.cpp b/mlir/lib/Analysis/Presburger/Matrix.cpp
index bda7b6263cf7d79..f0bcb09fb28f7b1 100644
--- a/mlir/lib/Analysis/Presburger/Matrix.cpp
+++ b/mlir/lib/Analysis/Presburger/Matrix.cpp
@@ -283,10 +283,8 @@ template <typename T> bool Matrix<T>::hasConsistentState() const {
   return true;
 }
 
-namespace mlir
-{
-namespace presburger
-{
+namespace mlir {
+namespace presburger {
 template class Matrix<MPInt>;
 template class Matrix<Fraction>;
 }

>From 80f1d9654f09667679f7565101fbb62ce2d6aaa6 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Tue, 26 Sep 2023 00:15:50 +0100
Subject: [PATCH 20/27] Inherit Matrix<Fraction> to FracMatrix and define
 inverse Fix reduce() method in Fraction

---
 .../mlir/Analysis/Presburger/Fraction.h       |  2 +-
 .../include/mlir/Analysis/Presburger/Matrix.h | 26 ++++++++
 mlir/lib/Analysis/Presburger/Matrix.cpp       | 66 +++++++++++++++++++
 mlir/unittests/Analysis/Presburger/Utils.h    |  4 +-
 4 files changed, 95 insertions(+), 3 deletions(-)

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/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 &&

>From 69cce307842ab6bfbca10f44d3826623379a0385 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Tue, 26 Sep 2023 00:17:47 +0100
Subject: [PATCH 21/27] Add test for matrix inverse

---
 mlir/unittests/Analysis/Presburger/MatrixTest.cpp | 11 +++++++++++
 1 file changed, 11 insertions(+)

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));
+}

>From 033a11081f989cba349b8cd17b6f2d5a6a29ec3c Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Tue, 26 Sep 2023 11:06:48 +0100
Subject: [PATCH 22/27] Formatting

---
 .../include/mlir/Analysis/Presburger/Matrix.h | 15 ++-
 mlir/lib/Analysis/Presburger/Matrix.cpp       | 96 +++++++++----------
 .../Analysis/Presburger/MatrixTest.cpp        | 20 ++--
 mlir/unittests/Analysis/Presburger/Utils.h    |  2 +-
 4 files changed, 67 insertions(+), 66 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Matrix.h b/mlir/include/mlir/Analysis/Presburger/Matrix.h
index b9048334c39f1f3..236a20a3383aabe 100644
--- a/mlir/include/mlir/Analysis/Presburger/Matrix.h
+++ b/mlir/include/mlir/Analysis/Presburger/Matrix.h
@@ -247,21 +247,20 @@ 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>
-{
+class FracMatrix : public Matrix<Fraction> {
 public:
   FracMatrix(unsigned rows, unsigned columns, unsigned reservedRows = 0,
-            unsigned reservedColumns = 0) :
-    Matrix<Fraction>(rows, columns, reservedRows, reservedColumns) {};
+            unsigned reservedColumns = 0)
+      : Matrix<Fraction>(rows, columns, reservedRows, reservedColumns) {};
 
-  FracMatrix(Matrix<Fraction> m) :
-    Matrix<Fraction>(m.getNumRows(), m.getNumColumns(), m.getNumReservedRows(), m.getNumReservedColumns())
-  {
+  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);
 
diff --git a/mlir/lib/Analysis/Presburger/Matrix.cpp b/mlir/lib/Analysis/Presburger/Matrix.cpp
index c0fbc688be2e1b2..8b16f0723576a7e 100644
--- a/mlir/lib/Analysis/Presburger/Matrix.cpp
+++ b/mlir/lib/Analysis/Presburger/Matrix.cpp
@@ -392,7 +392,6 @@ 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)
@@ -400,60 +399,59 @@ FracMatrix FracMatrix::identity(unsigned dimension) {
   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.
+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();
+  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++)
+  // 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))
         {
-            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
+            augmented.addToRow(i, augmented.getRow(j), Fraction(1, 1));
+            break;
         }
-    }
-    
-    // Now only diagonal elements are nonzero, but they are
-    // not necessarily 1.
-    for (unsigned i = 0; i < dim; i++)
+
+    b = augmented(i, i);
+    for (unsigned j = 0; j < dim; j++)
     {
-        a = augmented(i, i);
-        for (unsigned j = dim; j < dim + dim; j++)
-            augmented(i, j) = augmented(i, j) / a;
+      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);
+  // 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;
+  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 d07318617e1a249..efa6d4507d16e56 100644
--- a/mlir/unittests/Analysis/Presburger/MatrixTest.cpp
+++ b/mlir/unittests/Analysis/Presburger/MatrixTest.cpp
@@ -250,12 +250,16 @@ TEST(MatrixTest, computeHermiteNormalForm) {
 }
 
 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));
+  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 c652daa583a882c..ce149c32ffa3821 100644
--- a/mlir/unittests/Analysis/Presburger/Utils.h
+++ b/mlir/unittests/Analysis/Presburger/Utils.h
@@ -41,7 +41,7 @@ inline IntMatrix makeIntMatrix(unsigned numRow, unsigned numColumns,
 }
 
 inline FracMatrix makeFracMatrix(unsigned numRow, unsigned numColumns,
-                         ArrayRef<SmallVector<Fraction, 8>> matrix) {
+                                 ArrayRef<SmallVector<Fraction, 8>> matrix) {
   FracMatrix results(numRow, numColumns);
   assert(matrix.size() == numRow);
   for (unsigned i = 0; i < numRow; ++i) {

>From 7febde05d576d7f305f5f89d50a27c9a42cb1bb8 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Fri, 29 Sep 2023 11:01:30 +0100
Subject: [PATCH 23/27] Shift determinant from LinearTransform to Matrix<T>

---
 .../Analysis/Presburger/LinearTransform.h     |  4 ---
 .../include/mlir/Analysis/Presburger/Matrix.h |  4 +++
 mlir/lib/Analysis/Presburger/Matrix.cpp       | 32 +++++++++++++++++++
 3 files changed, 36 insertions(+), 4 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/LinearTransform.h b/mlir/include/mlir/Analysis/Presburger/LinearTransform.h
index 67dc9e87facb9ad..b5c761439f0b7e6 100644
--- a/mlir/include/mlir/Analysis/Presburger/LinearTransform.h
+++ b/mlir/include/mlir/Analysis/Presburger/LinearTransform.h
@@ -50,10 +50,6 @@ class LinearTransform {
     return matrix.postMultiplyWithColumn(colVec);
   }
 
-  // Compute the determinant of the transform by converting it to row echelon
-  // form and then taking the product of the diagonal.
-  MPInt determinant();
-
 private:
   IntMatrix matrix;
 };
diff --git a/mlir/include/mlir/Analysis/Presburger/Matrix.h b/mlir/include/mlir/Analysis/Presburger/Matrix.h
index 236a20a3383aabe..1aa7bd65d301122 100644
--- a/mlir/include/mlir/Analysis/Presburger/Matrix.h
+++ b/mlir/include/mlir/Analysis/Presburger/Matrix.h
@@ -190,6 +190,10 @@ static_assert(std::is_same_v<T,MPInt> || std::is_same_v<T,Fraction>, "T must be
   /// invariants satisfied.
   bool hasConsistentState() const;
 
+  // Compute the determinant of the matrix by converting it to row echelon
+  // form and then taking the product of the diagonal.
+  T determinant();
+
 private:
   /// The current number of rows, columns, and reserved columns. The underlying
   /// data vector is viewed as an nRows x nReservedColumns matrix, of which the
diff --git a/mlir/lib/Analysis/Presburger/Matrix.cpp b/mlir/lib/Analysis/Presburger/Matrix.cpp
index 8b16f0723576a7e..ab8f7535c54b2b9 100644
--- a/mlir/lib/Analysis/Presburger/Matrix.cpp
+++ b/mlir/lib/Analysis/Presburger/Matrix.cpp
@@ -283,6 +283,38 @@ template <typename T> bool Matrix<T>::hasConsistentState() const {
   return true;
 }
 
+template<typename T> T Matrix<T>::determinant()
+{
+    unsigned r = getNumRows();
+    unsigned c = getNumColumns();
+    if (r == 1)
+        return at(0, 0);
+    if (r == 2)
+        return (at(0, 0) * at(1, 1) - at(0, 1) * at(1, 0));
+
+    T sign(-1), determinant(0);
+    Matrix<T> cofactor(r-1, c-1);
+
+    // Cofactor matrix consists of all columns other than the
+    // current one, and all rows except the first.
+    for (unsigned i = 0; i < c; i++)
+    {
+        sign = -sign;
+        unsigned n = 0;
+        for (unsigned j = 0; j < c; j++)
+        {
+            if (j == i) continue;
+            for (unsigned k = 0; k < r-1; k++)
+                cofactor(k, n) = at(k+1, j);
+            n++;
+        }
+
+        determinant = determinant + at(0, i) * sign * cofactor.determinant();
+    }
+
+    return determinant;
+}
+
 namespace mlir {
 namespace presburger {
 template class Matrix<MPInt>;

>From 05369caf71f058e0cf57571288c94e9d9d8b59b8 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Fri, 29 Sep 2023 11:03:45 +0100
Subject: [PATCH 24/27] Implement integer inverse for integer matrix

---
 .../include/mlir/Analysis/Presburger/Matrix.h |  2 ++
 mlir/lib/Analysis/Presburger/Matrix.cpp       | 19 +++++++++++++
 .../Analysis/Presburger/MatrixTest.cpp        | 27 +++++++++++++++++++
 3 files changed, 48 insertions(+)

diff --git a/mlir/include/mlir/Analysis/Presburger/Matrix.h b/mlir/include/mlir/Analysis/Presburger/Matrix.h
index 1aa7bd65d301122..ed3ed7ac5ba08d1 100644
--- a/mlir/include/mlir/Analysis/Presburger/Matrix.h
+++ b/mlir/include/mlir/Analysis/Presburger/Matrix.h
@@ -246,6 +246,8 @@ class IntMatrix : public Matrix<MPInt>
   /// Returns the GCD of the columns of the specified row.
   MPInt normalizeRow(unsigned row);
 
+  // Return the integer inverse of the matrix, leaving the calling object unmodified.
+  IntMatrix integerInverse();
 };
 
 // An inherited class for rational matrices, with no new data attributes.
diff --git a/mlir/lib/Analysis/Presburger/Matrix.cpp b/mlir/lib/Analysis/Presburger/Matrix.cpp
index ab8f7535c54b2b9..1499d02eccf11bb 100644
--- a/mlir/lib/Analysis/Presburger/Matrix.cpp
+++ b/mlir/lib/Analysis/Presburger/Matrix.cpp
@@ -424,6 +424,25 @@ MPInt IntMatrix::normalizeRow(unsigned row) {
   return normalizeRow(row, getNumColumns());
 }
 
+IntMatrix IntMatrix::integerInverse()
+{
+    Fraction det = Fraction(determinant(), 1);
+    FracMatrix newMat(getNumRows(), getNumColumns());
+    for (unsigned i = 0; i < getNumRows(); i++)
+      for (unsigned j = 0; j < getNumColumns(); j++)
+        newMat(i, j) = Fraction(at(i, j), 1);
+
+    FracMatrix fracInverse = newMat.inverse();
+    
+    IntMatrix intInverse(getNumRows(), getNumColumns());
+    for (unsigned i = 0; i < getNumRows(); i++)
+      for (unsigned j = 0; j < getNumColumns(); j++)
+        intInverse(i, j) = (fracInverse(i, j) * det).getAsInteger();
+
+    return intInverse;
+}
+
+
 FracMatrix FracMatrix::identity(unsigned dimension) {
   FracMatrix matrix(dimension, dimension);
   for (unsigned i = 0; i < dimension; ++i)
diff --git a/mlir/unittests/Analysis/Presburger/MatrixTest.cpp b/mlir/unittests/Analysis/Presburger/MatrixTest.cpp
index efa6d4507d16e56..7b838d7925e0c6c 100644
--- a/mlir/unittests/Analysis/Presburger/MatrixTest.cpp
+++ b/mlir/unittests/Analysis/Presburger/MatrixTest.cpp
@@ -263,3 +263,30 @@ TEST(MatrixTest, inverse) {
     for (unsigned col = 0; col < 2; col++)
       EXPECT_EQ(inv(row, col), inverse(row, col));
 }
+
+TEST(MatrixTest, intInverse) {
+    IntMatrix mat = makeIntMatrix(2, 2, {{2, 1}, {7, 0}});
+    IntMatrix inverse = makeIntMatrix(2, 2, {{0, -1}, {-7, 2}});
+    
+    IntMatrix inv = mat.integerInverse();
+
+    for (unsigned i = 0; i < 2u; i++)
+      for (unsigned j = 0; j < 2u; j++)
+        EXPECT_EQ(inv(i, j), inverse(i, j));
+
+    mat = makeIntMatrix(4, 4, {{ 4, 14, 11,  3},
+                               {13,  5, 14, 12},
+                               {13,  9,  7, 14},
+                               { 2,  3, 12,  7}});
+    inverse = makeIntMatrix(4, 4, {{155, 1636, -579, -1713},
+                                   {725, -743, 537, -111},
+                                   {210, 735, -855, 360},
+                                   {-715, -1409, 1401, 1482}});
+
+    inv = mat.integerInverse();
+
+    for (unsigned i = 0; i < 2u; i++)
+      for (unsigned j = 0; j < 2u; j++)
+        EXPECT_EQ(inv(i, j), inverse(i, j));
+
+}
\ No newline at end of file

>From 2273874ffde818616540ff69ac32d327eb26d394 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Fri, 29 Sep 2023 11:06:11 +0100
Subject: [PATCH 25/27] Formatting

---
 .../include/mlir/Analysis/Presburger/Matrix.h |  35 ++-
 mlir/lib/Analysis/Presburger/Matrix.cpp       | 247 ++++++++++--------
 2 files changed, 158 insertions(+), 124 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Matrix.h b/mlir/include/mlir/Analysis/Presburger/Matrix.h
index ed3ed7ac5ba08d1..bbc4acd1d0470c9 100644
--- a/mlir/include/mlir/Analysis/Presburger/Matrix.h
+++ b/mlir/include/mlir/Analysis/Presburger/Matrix.h
@@ -15,9 +15,9 @@
 #ifndef MLIR_ANALYSIS_PRESBURGER_MATRIX_H
 #define MLIR_ANALYSIS_PRESBURGER_MATRIX_H
 
-#include "mlir/Support/LLVM.h"
 #include "mlir/Analysis/Presburger/Fraction.h"
 #include "mlir/Analysis/Presburger/Matrix.h"
+#include "mlir/Support/LLVM.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -37,9 +37,11 @@ namespace presburger {
 /// This class only works for the types MPInt and Fraction, since the method
 /// implementations are in the Matrix.cpp file. Only these two types have
 /// been explicitly instantiated there.
-template<typename T>
+template <typename T>
 class Matrix {
-static_assert(std::is_same_v<T,MPInt> || std::is_same_v<T,Fraction>, "T must be MPInt or Fraction.");
+  static_assert(std::is_same_v<T, MPInt> || std::is_same_v<T, Fraction>,
+                "T must be MPInt or Fraction.");
+
 public:
   Matrix() = delete;
 
@@ -70,9 +72,7 @@ static_assert(std::is_same_v<T,MPInt> || std::is_same_v<T,Fraction>, "T must be
 
   T &operator()(unsigned row, unsigned column) { return at(row, column); }
 
-  T operator()(unsigned row, unsigned column) const {
-    return at(row, column);
-  }
+  T operator()(unsigned row, unsigned column) const { return at(row, column); }
 
   /// Swap the given columns.
   void swapColumns(unsigned column, unsigned otherColumn);
@@ -209,21 +209,20 @@ static_assert(std::is_same_v<T,MPInt> || std::is_same_v<T,Fraction>, "T must be
 // An inherited class for integer matrices, with no new data attributes.
 // This is only used for the matrix-related methods which apply only
 // to integers (hermite normal form computation and row normalisation).
-class IntMatrix : public Matrix<MPInt>
-{
+class IntMatrix : public Matrix<MPInt> {
 public:
   IntMatrix(unsigned rows, unsigned columns, unsigned reservedRows = 0,
-            unsigned reservedColumns = 0) :
-    Matrix<MPInt>(rows, columns, reservedRows, reservedColumns) {};
+            unsigned reservedColumns = 0)
+      : Matrix<MPInt>(rows, columns, reservedRows, reservedColumns){};
 
-  IntMatrix(Matrix<MPInt> m) :
-    Matrix<MPInt>(m.getNumRows(), m.getNumColumns(), m.getNumReservedRows(), m.getNumReservedColumns())
-  {
+  IntMatrix(Matrix<MPInt> m)
+      : Matrix<MPInt>(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 IntMatrix identity(unsigned dimension);
 
@@ -246,7 +245,8 @@ class IntMatrix : public Matrix<MPInt>
   /// Returns the GCD of the columns of the specified row.
   MPInt normalizeRow(unsigned row);
 
-  // Return the integer inverse of the matrix, leaving the calling object unmodified.
+  // Return the integer inverse of the matrix, leaving the calling object
+  // unmodified.
   IntMatrix integerInverse();
 };
 
@@ -256,8 +256,8 @@ class IntMatrix : public Matrix<MPInt>
 class FracMatrix : public Matrix<Fraction> {
 public:
   FracMatrix(unsigned rows, unsigned columns, unsigned reservedRows = 0,
-            unsigned reservedColumns = 0)
-      : Matrix<Fraction>(rows, columns, reservedRows, reservedColumns) {};
+             unsigned reservedColumns = 0)
+      : Matrix<Fraction>(rows, columns, reservedRows, reservedColumns){};
 
   FracMatrix(Matrix<Fraction> m)
       : Matrix<Fraction>(m.getNumRows(), m.getNumColumns(),
@@ -272,7 +272,6 @@ class FracMatrix : public Matrix<Fraction> {
 
   // Return the inverse of the matrix, leaving the calling object unmodified.
   FracMatrix inverse();
-
 };
 
 } // namespace presburger
diff --git a/mlir/lib/Analysis/Presburger/Matrix.cpp b/mlir/lib/Analysis/Presburger/Matrix.cpp
index 1499d02eccf11bb..a51489b6667641b 100644
--- a/mlir/lib/Analysis/Presburger/Matrix.cpp
+++ b/mlir/lib/Analysis/Presburger/Matrix.cpp
@@ -14,35 +14,41 @@
 using namespace mlir;
 using namespace presburger;
 
-template <typename T> Matrix<T>::Matrix(unsigned rows, unsigned columns, unsigned reservedRows,
-               unsigned reservedColumns)
+template <typename T>
+Matrix<T>::Matrix(unsigned rows, unsigned columns, unsigned reservedRows,
+                  unsigned reservedColumns)
     : nRows(rows), nColumns(columns),
       nReservedColumns(std::max(nColumns, reservedColumns)),
       data(nRows * nReservedColumns) {
   data.reserve(std::max(nRows, reservedRows) * nReservedColumns);
 }
 
-template <typename T> Matrix<T> Matrix<T>::identity(unsigned dimension) {
+template <typename T>
+Matrix<T> Matrix<T>::identity(unsigned dimension) {
   Matrix matrix(dimension, dimension);
   for (unsigned i = 0; i < dimension; ++i)
     matrix(i, i) = 1;
   return matrix;
 }
 
-template <typename T> unsigned Matrix<T>::getNumReservedRows() const {
+template <typename T>
+unsigned Matrix<T>::getNumReservedRows() const {
   return data.capacity() / nReservedColumns;
 }
 
-template <typename T> void Matrix<T>::reserveRows(unsigned rows) {
+template <typename T>
+void Matrix<T>::reserveRows(unsigned rows) {
   data.reserve(rows * nReservedColumns);
 }
 
-template <typename T> unsigned Matrix<T>::appendExtraRow() {
+template <typename T>
+unsigned Matrix<T>::appendExtraRow() {
   resizeVertically(nRows + 1);
   return nRows - 1;
 }
 
-template <typename T> unsigned Matrix<T>::appendExtraRow(ArrayRef<T> elems) {
+template <typename T>
+unsigned Matrix<T>::appendExtraRow(ArrayRef<T> elems) {
   assert(elems.size() == nColumns && "elems must match row length!");
   unsigned row = appendExtraRow();
   for (unsigned col = 0; col < nColumns; ++col)
@@ -50,24 +56,28 @@ template <typename T> unsigned Matrix<T>::appendExtraRow(ArrayRef<T> elems) {
   return row;
 }
 
-template <typename T> void Matrix<T>::resizeHorizontally(unsigned newNColumns) {
+template <typename T>
+void Matrix<T>::resizeHorizontally(unsigned newNColumns) {
   if (newNColumns < nColumns)
     removeColumns(newNColumns, nColumns - newNColumns);
   if (newNColumns > nColumns)
     insertColumns(nColumns, newNColumns - nColumns);
 }
 
-template <typename T> void Matrix<T>::resize(unsigned newNRows, unsigned newNColumns) {
+template <typename T>
+void Matrix<T>::resize(unsigned newNRows, unsigned newNColumns) {
   resizeHorizontally(newNColumns);
   resizeVertically(newNRows);
 }
 
-template <typename T> void Matrix<T>::resizeVertically(unsigned newNRows) {
+template <typename T>
+void Matrix<T>::resizeVertically(unsigned newNRows) {
   nRows = newNRows;
   data.resize(nRows * nReservedColumns);
 }
 
-template <typename T> void Matrix<T>::swapRows(unsigned row, unsigned otherRow) {
+template <typename T>
+void Matrix<T>::swapRows(unsigned row, unsigned otherRow) {
   assert((row < getNumRows() && otherRow < getNumRows()) &&
          "Given row out of bounds");
   if (row == otherRow)
@@ -76,7 +86,8 @@ template <typename T> void Matrix<T>::swapRows(unsigned row, unsigned otherRow)
     std::swap(at(row, col), at(otherRow, col));
 }
 
-template <typename T> void Matrix<T>::swapColumns(unsigned column, unsigned otherColumn) {
+template <typename T>
+void Matrix<T>::swapColumns(unsigned column, unsigned otherColumn) {
   assert((column < getNumColumns() && otherColumn < getNumColumns()) &&
          "Given column out of bounds");
   if (column == otherColumn)
@@ -85,23 +96,30 @@ template <typename T> void Matrix<T>::swapColumns(unsigned column, unsigned othe
     std::swap(at(row, column), at(row, otherColumn));
 }
 
-template <typename T> MutableArrayRef<T> Matrix<T>::getRow(unsigned row) {
+template <typename T>
+MutableArrayRef<T> Matrix<T>::getRow(unsigned row) {
   return {&data[row * nReservedColumns], nColumns};
 }
 
-template <typename T> ArrayRef<T> Matrix<T>::getRow(unsigned row) const {
+template <typename T>
+ArrayRef<T> Matrix<T>::getRow(unsigned row) const {
   return {&data[row * nReservedColumns], nColumns};
 }
 
-template <typename T> void Matrix<T>::setRow(unsigned row, ArrayRef<T> elems) {
+template <typename T>
+void Matrix<T>::setRow(unsigned row, ArrayRef<T> elems) {
   assert(elems.size() == getNumColumns() &&
          "elems size must match row length!");
   for (unsigned i = 0, e = getNumColumns(); i < e; ++i)
     at(row, i) = elems[i];
 }
 
-template <typename T> void Matrix<T>::insertColumn(unsigned pos) { insertColumns(pos, 1); }
-template <typename T> void Matrix<T>::insertColumns(unsigned pos, unsigned count) {
+template <typename T>
+void Matrix<T>::insertColumn(unsigned pos) {
+  insertColumns(pos, 1);
+}
+template <typename T>
+void Matrix<T>::insertColumns(unsigned pos, unsigned count) {
   if (count == 0)
     return;
   assert(pos <= nColumns);
@@ -142,8 +160,12 @@ template <typename T> void Matrix<T>::insertColumns(unsigned pos, unsigned count
   }
 }
 
-template <typename T> void Matrix<T>::removeColumn(unsigned pos) { removeColumns(pos, 1); }
-template <typename T> void Matrix<T>::removeColumns(unsigned pos, unsigned count) {
+template <typename T>
+void Matrix<T>::removeColumn(unsigned pos) {
+  removeColumns(pos, 1);
+}
+template <typename T>
+void Matrix<T>::removeColumns(unsigned pos, unsigned count) {
   if (count == 0)
     return;
   assert(pos + count - 1 < nColumns);
@@ -156,8 +178,12 @@ template <typename T> void Matrix<T>::removeColumns(unsigned pos, unsigned count
   nColumns -= count;
 }
 
-template <typename T> void Matrix<T>::insertRow(unsigned pos) { insertRows(pos, 1); }
-template <typename T> void Matrix<T>::insertRows(unsigned pos, unsigned count) {
+template <typename T>
+void Matrix<T>::insertRow(unsigned pos) {
+  insertRows(pos, 1);
+}
+template <typename T>
+void Matrix<T>::insertRows(unsigned pos, unsigned count) {
   if (count == 0)
     return;
 
@@ -170,8 +196,12 @@ template <typename T> void Matrix<T>::insertRows(unsigned pos, unsigned count) {
       at(r, c) = 0;
 }
 
-template <typename T> void Matrix<T>::removeRow(unsigned pos) { removeRows(pos, 1); }
-template <typename T> void Matrix<T>::removeRows(unsigned pos, unsigned count) {
+template <typename T>
+void Matrix<T>::removeRow(unsigned pos) {
+  removeRows(pos, 1);
+}
+template <typename T>
+void Matrix<T>::removeRows(unsigned pos, unsigned count) {
   if (count == 0)
     return;
   assert(pos + count - 1 <= nRows);
@@ -180,50 +210,57 @@ template <typename T> void Matrix<T>::removeRows(unsigned pos, unsigned count) {
   resizeVertically(nRows - count);
 }
 
-template <typename T> void Matrix<T>::copyRow(unsigned sourceRow, unsigned targetRow) {
+template <typename T>
+void Matrix<T>::copyRow(unsigned sourceRow, unsigned targetRow) {
   if (sourceRow == targetRow)
     return;
   for (unsigned c = 0; c < nColumns; ++c)
     at(targetRow, c) = at(sourceRow, c);
 }
 
-template <typename T> void Matrix<T>::fillRow(unsigned row, const T &value) {
+template <typename T>
+void Matrix<T>::fillRow(unsigned row, const T &value) {
   for (unsigned col = 0; col < nColumns; ++col)
     at(row, col) = value;
 }
 
-template <typename T> void Matrix<T>::addToRow(unsigned sourceRow, unsigned targetRow,
-                      const T &scale) {
+template <typename T>
+void Matrix<T>::addToRow(unsigned sourceRow, unsigned targetRow,
+                         const T &scale) {
   addToRow(targetRow, getRow(sourceRow), scale);
 }
 
-template <typename T> void Matrix<T>::addToRow(unsigned row, ArrayRef<T> rowVec,
-                      const T &scale) {
+template <typename T>
+void Matrix<T>::addToRow(unsigned row, ArrayRef<T> rowVec, const T &scale) {
   if (scale == 0)
     return;
   for (unsigned col = 0; col < nColumns; ++col)
     at(row, col) += scale * rowVec[col];
 }
 
-template <typename T> void Matrix<T>::addToColumn(unsigned sourceColumn, unsigned targetColumn,
-                         const T &scale) {
+template <typename T>
+void Matrix<T>::addToColumn(unsigned sourceColumn, unsigned targetColumn,
+                            const T &scale) {
   if (scale == 0)
     return;
   for (unsigned row = 0, e = getNumRows(); row < e; ++row)
     at(row, targetColumn) += scale * at(row, sourceColumn);
 }
 
-template <typename T> void Matrix<T>::negateColumn(unsigned column) {
+template <typename T>
+void Matrix<T>::negateColumn(unsigned column) {
   for (unsigned row = 0, e = getNumRows(); row < e; ++row)
     at(row, column) = -at(row, column);
 }
 
-template <typename T> void Matrix<T>::negateRow(unsigned row) {
+template <typename T>
+void Matrix<T>::negateRow(unsigned row) {
   for (unsigned column = 0, e = getNumColumns(); column < e; ++column)
     at(row, column) = -at(row, column);
 }
 
-template <typename T> SmallVector<T, 8> Matrix<T>::preMultiplyWithRow(ArrayRef<T> rowVec) const {
+template <typename T>
+SmallVector<T, 8> Matrix<T>::preMultiplyWithRow(ArrayRef<T> rowVec) const {
   assert(rowVec.size() == getNumRows() && "Invalid row vector dimension!");
 
   SmallVector<T, 8> result(getNumColumns(), T(0));
@@ -233,8 +270,8 @@ template <typename T> SmallVector<T, 8> Matrix<T>::preMultiplyWithRow(ArrayRef<T
   return result;
 }
 
-template <typename T> SmallVector<T, 8>
-Matrix<T>::postMultiplyWithColumn(ArrayRef<T> colVec) const {
+template <typename T>
+SmallVector<T, 8> Matrix<T>::postMultiplyWithColumn(ArrayRef<T> colVec) const {
   assert(getNumColumns() == colVec.size() &&
          "Invalid column vector dimension!");
 
@@ -250,8 +287,9 @@ Matrix<T>::postMultiplyWithColumn(ArrayRef<T> colVec) const {
 /// sourceCol. This brings M(row, targetCol) to the range [0, M(row,
 /// sourceCol)). Apply the same column operation to otherMatrix, with the same
 /// integer multiple.
-static void modEntryColumnOperation(Matrix<MPInt> &m, unsigned row, unsigned sourceCol,
-                                    unsigned targetCol, Matrix<MPInt> &otherMatrix) {
+static void modEntryColumnOperation(Matrix<MPInt> &m, unsigned row,
+                                    unsigned sourceCol, unsigned targetCol,
+                                    Matrix<MPInt> &otherMatrix) {
   assert(m(row, sourceCol) != 0 && "Cannot divide by zero!");
   assert(m(row, sourceCol) > 0 && "Source must be positive!");
   MPInt ratio = -floorDiv(m(row, targetCol), m(row, sourceCol));
@@ -259,7 +297,8 @@ static void modEntryColumnOperation(Matrix<MPInt> &m, unsigned row, unsigned sou
   otherMatrix.addToColumn(sourceCol, targetCol, ratio);
 }
 
-template <typename T> void Matrix<T>::print(raw_ostream &os) const {
+template <typename T>
+void Matrix<T>::print(raw_ostream &os) const {
   for (unsigned row = 0; row < nRows; ++row) {
     for (unsigned column = 0; column < nColumns; ++column)
       os << at(row, column) << ' ';
@@ -267,9 +306,13 @@ template <typename T> void Matrix<T>::print(raw_ostream &os) const {
   }
 }
 
-template <typename T> void Matrix<T>::dump() const { print(llvm::errs()); }
+template <typename T>
+void Matrix<T>::dump() const {
+  print(llvm::errs());
+}
 
-template <typename T> bool Matrix<T>::hasConsistentState() const {
+template <typename T>
+bool Matrix<T>::hasConsistentState() const {
   if (data.size() != nRows * nReservedColumns)
     return false;
   if (nColumns > nReservedColumns)
@@ -283,44 +326,43 @@ template <typename T> bool Matrix<T>::hasConsistentState() const {
   return true;
 }
 
-template<typename T> T Matrix<T>::determinant()
-{
-    unsigned r = getNumRows();
-    unsigned c = getNumColumns();
-    if (r == 1)
-        return at(0, 0);
-    if (r == 2)
-        return (at(0, 0) * at(1, 1) - at(0, 1) * at(1, 0));
-
-    T sign(-1), determinant(0);
-    Matrix<T> cofactor(r-1, c-1);
-
-    // Cofactor matrix consists of all columns other than the
-    // current one, and all rows except the first.
-    for (unsigned i = 0; i < c; i++)
-    {
-        sign = -sign;
-        unsigned n = 0;
-        for (unsigned j = 0; j < c; j++)
-        {
-            if (j == i) continue;
-            for (unsigned k = 0; k < r-1; k++)
-                cofactor(k, n) = at(k+1, j);
-            n++;
-        }
-
-        determinant = determinant + at(0, i) * sign * cofactor.determinant();
+template <typename T>
+T Matrix<T>::determinant() {
+  unsigned r = getNumRows();
+  unsigned c = getNumColumns();
+  if (r == 1)
+    return at(0, 0);
+  if (r == 2)
+    return (at(0, 0) * at(1, 1) - at(0, 1) * at(1, 0));
+
+  T sign(-1), determinant(0);
+  Matrix<T> cofactor(r - 1, c - 1);
+
+  // Cofactor matrix consists of all columns other than the
+  // current one, and all rows except the first.
+  for (unsigned i = 0; i < c; i++) {
+    sign = -sign;
+    unsigned n = 0;
+    for (unsigned j = 0; j < c; j++) {
+      if (j == i)
+        continue;
+      for (unsigned k = 0; k < r - 1; k++)
+        cofactor(k, n) = at(k + 1, j);
+      n++;
     }
 
-    return determinant;
+    determinant = determinant + at(0, i) * sign * cofactor.determinant();
+  }
+
+  return determinant;
 }
 
 namespace mlir {
 namespace presburger {
 template class Matrix<MPInt>;
 template class Matrix<Fraction>;
-}
-}
+} // namespace presburger
+} // namespace mlir
 
 IntMatrix IntMatrix::identity(unsigned dimension) {
   IntMatrix matrix(dimension, dimension);
@@ -329,7 +371,6 @@ IntMatrix IntMatrix::identity(unsigned dimension) {
   return matrix;
 }
 
-
 std::pair<IntMatrix, IntMatrix> IntMatrix::computeHermiteNormalForm() const {
   // We start with u as an identity matrix and perform operations on h until h
   // is in hermite normal form. We apply the same sequence of operations on u to
@@ -424,24 +465,22 @@ MPInt IntMatrix::normalizeRow(unsigned row) {
   return normalizeRow(row, getNumColumns());
 }
 
-IntMatrix IntMatrix::integerInverse()
-{
-    Fraction det = Fraction(determinant(), 1);
-    FracMatrix newMat(getNumRows(), getNumColumns());
-    for (unsigned i = 0; i < getNumRows(); i++)
-      for (unsigned j = 0; j < getNumColumns(); j++)
-        newMat(i, j) = Fraction(at(i, j), 1);
+IntMatrix IntMatrix::integerInverse() {
+  Fraction det = Fraction(determinant(), 1);
+  FracMatrix newMat(getNumRows(), getNumColumns());
+  for (unsigned i = 0; i < getNumRows(); i++)
+    for (unsigned j = 0; j < getNumColumns(); j++)
+      newMat(i, j) = Fraction(at(i, j), 1);
 
-    FracMatrix fracInverse = newMat.inverse();
-    
-    IntMatrix intInverse(getNumRows(), getNumColumns());
-    for (unsigned i = 0; i < getNumRows(); i++)
-      for (unsigned j = 0; j < getNumColumns(); j++)
-        intInverse(i, j) = (fracInverse(i, j) * det).getAsInteger();
+  FracMatrix fracInverse = newMat.inverse();
 
-    return intInverse;
-}
+  IntMatrix intInverse(getNumRows(), getNumColumns());
+  for (unsigned i = 0; i < getNumRows(); i++)
+    for (unsigned j = 0; j < getNumColumns(); j++)
+      intInverse(i, j) = (fracInverse(i, j) * det).getAsInteger();
 
+  return intInverse;
+}
 
 FracMatrix FracMatrix::identity(unsigned dimension) {
   FracMatrix matrix(dimension, dimension);
@@ -459,40 +498,36 @@ FracMatrix FracMatrix::inverse() {
 
   // Construct the augmented matrix [M | I]
   FracMatrix augmented(dim, dim + dim);
-  for (unsigned i = 0; i < dim; i++)
-  {
+  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;
+      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++)
-  {
+  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;
+      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;
+    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++)
-  {
+  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;
@@ -502,7 +537,7 @@ FracMatrix FracMatrix::inverse() {
   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);
+      inverse(i, j) = augmented(i, j + dim);
 
   return inverse;
 }
\ No newline at end of file

>From 15cfbe08d080d1451784772f8b01e1acad214a18 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Mon, 2 Oct 2023 13:25:24 +0100
Subject: [PATCH 26/27] Revert "Inherit Matrix<Fraction> to FracMatrix and
 define inverse"

This reverts commit 80f1d9654f09667679f7565101fbb62ce2d6aaa6.
---
 .../mlir/Analysis/Presburger/Fraction.h       |   2 +-
 .../Analysis/Presburger/LinearTransform.h     |   4 +
 .../include/mlir/Analysis/Presburger/Matrix.h |  58 ++---
 mlir/lib/Analysis/Presburger/Matrix.cpp       | 238 ++++--------------
 .../Analysis/Presburger/MatrixTest.cpp        |  42 ----
 mlir/unittests/Analysis/Presburger/Utils.h    |   6 +-
 6 files changed, 66 insertions(+), 284 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Fraction.h b/mlir/include/mlir/Analysis/Presburger/Fraction.h
index f633192a870c8d4..74127a900d53ed2 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(abs(f.num), abs(f.den));
+  MPInt g = gcd(f.num, f.den);
   return Fraction(f.num / g, f.den / g);
 }
 
diff --git a/mlir/include/mlir/Analysis/Presburger/LinearTransform.h b/mlir/include/mlir/Analysis/Presburger/LinearTransform.h
index b5c761439f0b7e6..67dc9e87facb9ad 100644
--- a/mlir/include/mlir/Analysis/Presburger/LinearTransform.h
+++ b/mlir/include/mlir/Analysis/Presburger/LinearTransform.h
@@ -50,6 +50,10 @@ class LinearTransform {
     return matrix.postMultiplyWithColumn(colVec);
   }
 
+  // Compute the determinant of the transform by converting it to row echelon
+  // form and then taking the product of the diagonal.
+  MPInt determinant();
+
 private:
   IntMatrix matrix;
 };
diff --git a/mlir/include/mlir/Analysis/Presburger/Matrix.h b/mlir/include/mlir/Analysis/Presburger/Matrix.h
index bbc4acd1d0470c9..f05a4fb2ffbb70d 100644
--- a/mlir/include/mlir/Analysis/Presburger/Matrix.h
+++ b/mlir/include/mlir/Analysis/Presburger/Matrix.h
@@ -15,9 +15,9 @@
 #ifndef MLIR_ANALYSIS_PRESBURGER_MATRIX_H
 #define MLIR_ANALYSIS_PRESBURGER_MATRIX_H
 
+#include "mlir/Support/LLVM.h"
 #include "mlir/Analysis/Presburger/Fraction.h"
 #include "mlir/Analysis/Presburger/Matrix.h"
-#include "mlir/Support/LLVM.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -37,11 +37,9 @@ namespace presburger {
 /// This class only works for the types MPInt and Fraction, since the method
 /// implementations are in the Matrix.cpp file. Only these two types have
 /// been explicitly instantiated there.
-template <typename T>
+template<typename T>
 class Matrix {
-  static_assert(std::is_same_v<T, MPInt> || std::is_same_v<T, Fraction>,
-                "T must be MPInt or Fraction.");
-
+static_assert(std::is_same_v<T,MPInt> || std::is_same_v<T,Fraction>, "T must be MPInt or Fraction.");
 public:
   Matrix() = delete;
 
@@ -72,7 +70,9 @@ class Matrix {
 
   T &operator()(unsigned row, unsigned column) { return at(row, column); }
 
-  T operator()(unsigned row, unsigned column) const { return at(row, column); }
+  T operator()(unsigned row, unsigned column) const {
+    return at(row, column);
+  }
 
   /// Swap the given columns.
   void swapColumns(unsigned column, unsigned otherColumn);
@@ -190,10 +190,6 @@ class Matrix {
   /// invariants satisfied.
   bool hasConsistentState() const;
 
-  // Compute the determinant of the matrix by converting it to row echelon
-  // form and then taking the product of the diagonal.
-  T determinant();
-
 private:
   /// The current number of rows, columns, and reserved columns. The underlying
   /// data vector is viewed as an nRows x nReservedColumns matrix, of which the
@@ -209,20 +205,21 @@ class Matrix {
 // An inherited class for integer matrices, with no new data attributes.
 // This is only used for the matrix-related methods which apply only
 // to integers (hermite normal form computation and row normalisation).
-class IntMatrix : public Matrix<MPInt> {
+class IntMatrix : public Matrix<MPInt>
+{
 public:
   IntMatrix(unsigned rows, unsigned columns, unsigned reservedRows = 0,
-            unsigned reservedColumns = 0)
-      : Matrix<MPInt>(rows, columns, reservedRows, reservedColumns){};
+            unsigned reservedColumns = 0) :
+    Matrix<MPInt>(rows, columns, reservedRows, reservedColumns) {};
 
-  IntMatrix(Matrix<MPInt> m)
-      : Matrix<MPInt>(m.getNumRows(), m.getNumColumns(), m.getNumReservedRows(),
-                      m.getNumReservedColumns()) {
+  IntMatrix(Matrix<MPInt> m) :
+    Matrix<MPInt>(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 IntMatrix identity(unsigned dimension);
 
@@ -245,33 +242,6 @@ class IntMatrix : public Matrix<MPInt> {
   /// Returns the GCD of the columns of the specified row.
   MPInt normalizeRow(unsigned row);
 
-  // Return the integer inverse of the matrix, leaving the calling object
-  // unmodified.
-  IntMatrix integerInverse();
-};
-
-// 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
diff --git a/mlir/lib/Analysis/Presburger/Matrix.cpp b/mlir/lib/Analysis/Presburger/Matrix.cpp
index a51489b6667641b..f0bcb09fb28f7b1 100644
--- a/mlir/lib/Analysis/Presburger/Matrix.cpp
+++ b/mlir/lib/Analysis/Presburger/Matrix.cpp
@@ -14,41 +14,35 @@
 using namespace mlir;
 using namespace presburger;
 
-template <typename T>
-Matrix<T>::Matrix(unsigned rows, unsigned columns, unsigned reservedRows,
-                  unsigned reservedColumns)
+template <typename T> Matrix<T>::Matrix(unsigned rows, unsigned columns, unsigned reservedRows,
+               unsigned reservedColumns)
     : nRows(rows), nColumns(columns),
       nReservedColumns(std::max(nColumns, reservedColumns)),
       data(nRows * nReservedColumns) {
   data.reserve(std::max(nRows, reservedRows) * nReservedColumns);
 }
 
-template <typename T>
-Matrix<T> Matrix<T>::identity(unsigned dimension) {
+template <typename T> Matrix<T> Matrix<T>::identity(unsigned dimension) {
   Matrix matrix(dimension, dimension);
   for (unsigned i = 0; i < dimension; ++i)
     matrix(i, i) = 1;
   return matrix;
 }
 
-template <typename T>
-unsigned Matrix<T>::getNumReservedRows() const {
+template <typename T> unsigned Matrix<T>::getNumReservedRows() const {
   return data.capacity() / nReservedColumns;
 }
 
-template <typename T>
-void Matrix<T>::reserveRows(unsigned rows) {
+template <typename T> void Matrix<T>::reserveRows(unsigned rows) {
   data.reserve(rows * nReservedColumns);
 }
 
-template <typename T>
-unsigned Matrix<T>::appendExtraRow() {
+template <typename T> unsigned Matrix<T>::appendExtraRow() {
   resizeVertically(nRows + 1);
   return nRows - 1;
 }
 
-template <typename T>
-unsigned Matrix<T>::appendExtraRow(ArrayRef<T> elems) {
+template <typename T> unsigned Matrix<T>::appendExtraRow(ArrayRef<T> elems) {
   assert(elems.size() == nColumns && "elems must match row length!");
   unsigned row = appendExtraRow();
   for (unsigned col = 0; col < nColumns; ++col)
@@ -56,28 +50,24 @@ unsigned Matrix<T>::appendExtraRow(ArrayRef<T> elems) {
   return row;
 }
 
-template <typename T>
-void Matrix<T>::resizeHorizontally(unsigned newNColumns) {
+template <typename T> void Matrix<T>::resizeHorizontally(unsigned newNColumns) {
   if (newNColumns < nColumns)
     removeColumns(newNColumns, nColumns - newNColumns);
   if (newNColumns > nColumns)
     insertColumns(nColumns, newNColumns - nColumns);
 }
 
-template <typename T>
-void Matrix<T>::resize(unsigned newNRows, unsigned newNColumns) {
+template <typename T> void Matrix<T>::resize(unsigned newNRows, unsigned newNColumns) {
   resizeHorizontally(newNColumns);
   resizeVertically(newNRows);
 }
 
-template <typename T>
-void Matrix<T>::resizeVertically(unsigned newNRows) {
+template <typename T> void Matrix<T>::resizeVertically(unsigned newNRows) {
   nRows = newNRows;
   data.resize(nRows * nReservedColumns);
 }
 
-template <typename T>
-void Matrix<T>::swapRows(unsigned row, unsigned otherRow) {
+template <typename T> void Matrix<T>::swapRows(unsigned row, unsigned otherRow) {
   assert((row < getNumRows() && otherRow < getNumRows()) &&
          "Given row out of bounds");
   if (row == otherRow)
@@ -86,8 +76,7 @@ void Matrix<T>::swapRows(unsigned row, unsigned otherRow) {
     std::swap(at(row, col), at(otherRow, col));
 }
 
-template <typename T>
-void Matrix<T>::swapColumns(unsigned column, unsigned otherColumn) {
+template <typename T> void Matrix<T>::swapColumns(unsigned column, unsigned otherColumn) {
   assert((column < getNumColumns() && otherColumn < getNumColumns()) &&
          "Given column out of bounds");
   if (column == otherColumn)
@@ -96,30 +85,23 @@ void Matrix<T>::swapColumns(unsigned column, unsigned otherColumn) {
     std::swap(at(row, column), at(row, otherColumn));
 }
 
-template <typename T>
-MutableArrayRef<T> Matrix<T>::getRow(unsigned row) {
+template <typename T> MutableArrayRef<T> Matrix<T>::getRow(unsigned row) {
   return {&data[row * nReservedColumns], nColumns};
 }
 
-template <typename T>
-ArrayRef<T> Matrix<T>::getRow(unsigned row) const {
+template <typename T> ArrayRef<T> Matrix<T>::getRow(unsigned row) const {
   return {&data[row * nReservedColumns], nColumns};
 }
 
-template <typename T>
-void Matrix<T>::setRow(unsigned row, ArrayRef<T> elems) {
+template <typename T> void Matrix<T>::setRow(unsigned row, ArrayRef<T> elems) {
   assert(elems.size() == getNumColumns() &&
          "elems size must match row length!");
   for (unsigned i = 0, e = getNumColumns(); i < e; ++i)
     at(row, i) = elems[i];
 }
 
-template <typename T>
-void Matrix<T>::insertColumn(unsigned pos) {
-  insertColumns(pos, 1);
-}
-template <typename T>
-void Matrix<T>::insertColumns(unsigned pos, unsigned count) {
+template <typename T> void Matrix<T>::insertColumn(unsigned pos) { insertColumns(pos, 1); }
+template <typename T> void Matrix<T>::insertColumns(unsigned pos, unsigned count) {
   if (count == 0)
     return;
   assert(pos <= nColumns);
@@ -160,12 +142,8 @@ void Matrix<T>::insertColumns(unsigned pos, unsigned count) {
   }
 }
 
-template <typename T>
-void Matrix<T>::removeColumn(unsigned pos) {
-  removeColumns(pos, 1);
-}
-template <typename T>
-void Matrix<T>::removeColumns(unsigned pos, unsigned count) {
+template <typename T> void Matrix<T>::removeColumn(unsigned pos) { removeColumns(pos, 1); }
+template <typename T> void Matrix<T>::removeColumns(unsigned pos, unsigned count) {
   if (count == 0)
     return;
   assert(pos + count - 1 < nColumns);
@@ -178,12 +156,8 @@ void Matrix<T>::removeColumns(unsigned pos, unsigned count) {
   nColumns -= count;
 }
 
-template <typename T>
-void Matrix<T>::insertRow(unsigned pos) {
-  insertRows(pos, 1);
-}
-template <typename T>
-void Matrix<T>::insertRows(unsigned pos, unsigned count) {
+template <typename T> void Matrix<T>::insertRow(unsigned pos) { insertRows(pos, 1); }
+template <typename T> void Matrix<T>::insertRows(unsigned pos, unsigned count) {
   if (count == 0)
     return;
 
@@ -196,12 +170,8 @@ void Matrix<T>::insertRows(unsigned pos, unsigned count) {
       at(r, c) = 0;
 }
 
-template <typename T>
-void Matrix<T>::removeRow(unsigned pos) {
-  removeRows(pos, 1);
-}
-template <typename T>
-void Matrix<T>::removeRows(unsigned pos, unsigned count) {
+template <typename T> void Matrix<T>::removeRow(unsigned pos) { removeRows(pos, 1); }
+template <typename T> void Matrix<T>::removeRows(unsigned pos, unsigned count) {
   if (count == 0)
     return;
   assert(pos + count - 1 <= nRows);
@@ -210,57 +180,50 @@ void Matrix<T>::removeRows(unsigned pos, unsigned count) {
   resizeVertically(nRows - count);
 }
 
-template <typename T>
-void Matrix<T>::copyRow(unsigned sourceRow, unsigned targetRow) {
+template <typename T> void Matrix<T>::copyRow(unsigned sourceRow, unsigned targetRow) {
   if (sourceRow == targetRow)
     return;
   for (unsigned c = 0; c < nColumns; ++c)
     at(targetRow, c) = at(sourceRow, c);
 }
 
-template <typename T>
-void Matrix<T>::fillRow(unsigned row, const T &value) {
+template <typename T> void Matrix<T>::fillRow(unsigned row, const T &value) {
   for (unsigned col = 0; col < nColumns; ++col)
     at(row, col) = value;
 }
 
-template <typename T>
-void Matrix<T>::addToRow(unsigned sourceRow, unsigned targetRow,
-                         const T &scale) {
+template <typename T> void Matrix<T>::addToRow(unsigned sourceRow, unsigned targetRow,
+                      const T &scale) {
   addToRow(targetRow, getRow(sourceRow), scale);
 }
 
-template <typename T>
-void Matrix<T>::addToRow(unsigned row, ArrayRef<T> rowVec, const T &scale) {
+template <typename T> void Matrix<T>::addToRow(unsigned row, ArrayRef<T> rowVec,
+                      const T &scale) {
   if (scale == 0)
     return;
   for (unsigned col = 0; col < nColumns; ++col)
     at(row, col) += scale * rowVec[col];
 }
 
-template <typename T>
-void Matrix<T>::addToColumn(unsigned sourceColumn, unsigned targetColumn,
-                            const T &scale) {
+template <typename T> void Matrix<T>::addToColumn(unsigned sourceColumn, unsigned targetColumn,
+                         const T &scale) {
   if (scale == 0)
     return;
   for (unsigned row = 0, e = getNumRows(); row < e; ++row)
     at(row, targetColumn) += scale * at(row, sourceColumn);
 }
 
-template <typename T>
-void Matrix<T>::negateColumn(unsigned column) {
+template <typename T> void Matrix<T>::negateColumn(unsigned column) {
   for (unsigned row = 0, e = getNumRows(); row < e; ++row)
     at(row, column) = -at(row, column);
 }
 
-template <typename T>
-void Matrix<T>::negateRow(unsigned row) {
+template <typename T> void Matrix<T>::negateRow(unsigned row) {
   for (unsigned column = 0, e = getNumColumns(); column < e; ++column)
     at(row, column) = -at(row, column);
 }
 
-template <typename T>
-SmallVector<T, 8> Matrix<T>::preMultiplyWithRow(ArrayRef<T> rowVec) const {
+template <typename T> SmallVector<T, 8> Matrix<T>::preMultiplyWithRow(ArrayRef<T> rowVec) const {
   assert(rowVec.size() == getNumRows() && "Invalid row vector dimension!");
 
   SmallVector<T, 8> result(getNumColumns(), T(0));
@@ -270,8 +233,8 @@ SmallVector<T, 8> Matrix<T>::preMultiplyWithRow(ArrayRef<T> rowVec) const {
   return result;
 }
 
-template <typename T>
-SmallVector<T, 8> Matrix<T>::postMultiplyWithColumn(ArrayRef<T> colVec) const {
+template <typename T> SmallVector<T, 8>
+Matrix<T>::postMultiplyWithColumn(ArrayRef<T> colVec) const {
   assert(getNumColumns() == colVec.size() &&
          "Invalid column vector dimension!");
 
@@ -287,9 +250,8 @@ SmallVector<T, 8> Matrix<T>::postMultiplyWithColumn(ArrayRef<T> colVec) const {
 /// sourceCol. This brings M(row, targetCol) to the range [0, M(row,
 /// sourceCol)). Apply the same column operation to otherMatrix, with the same
 /// integer multiple.
-static void modEntryColumnOperation(Matrix<MPInt> &m, unsigned row,
-                                    unsigned sourceCol, unsigned targetCol,
-                                    Matrix<MPInt> &otherMatrix) {
+static void modEntryColumnOperation(Matrix<MPInt> &m, unsigned row, unsigned sourceCol,
+                                    unsigned targetCol, Matrix<MPInt> &otherMatrix) {
   assert(m(row, sourceCol) != 0 && "Cannot divide by zero!");
   assert(m(row, sourceCol) > 0 && "Source must be positive!");
   MPInt ratio = -floorDiv(m(row, targetCol), m(row, sourceCol));
@@ -297,8 +259,7 @@ static void modEntryColumnOperation(Matrix<MPInt> &m, unsigned row,
   otherMatrix.addToColumn(sourceCol, targetCol, ratio);
 }
 
-template <typename T>
-void Matrix<T>::print(raw_ostream &os) const {
+template <typename T> void Matrix<T>::print(raw_ostream &os) const {
   for (unsigned row = 0; row < nRows; ++row) {
     for (unsigned column = 0; column < nColumns; ++column)
       os << at(row, column) << ' ';
@@ -306,13 +267,9 @@ void Matrix<T>::print(raw_ostream &os) const {
   }
 }
 
-template <typename T>
-void Matrix<T>::dump() const {
-  print(llvm::errs());
-}
+template <typename T> void Matrix<T>::dump() const { print(llvm::errs()); }
 
-template <typename T>
-bool Matrix<T>::hasConsistentState() const {
+template <typename T> bool Matrix<T>::hasConsistentState() const {
   if (data.size() != nRows * nReservedColumns)
     return false;
   if (nColumns > nReservedColumns)
@@ -326,43 +283,12 @@ bool Matrix<T>::hasConsistentState() const {
   return true;
 }
 
-template <typename T>
-T Matrix<T>::determinant() {
-  unsigned r = getNumRows();
-  unsigned c = getNumColumns();
-  if (r == 1)
-    return at(0, 0);
-  if (r == 2)
-    return (at(0, 0) * at(1, 1) - at(0, 1) * at(1, 0));
-
-  T sign(-1), determinant(0);
-  Matrix<T> cofactor(r - 1, c - 1);
-
-  // Cofactor matrix consists of all columns other than the
-  // current one, and all rows except the first.
-  for (unsigned i = 0; i < c; i++) {
-    sign = -sign;
-    unsigned n = 0;
-    for (unsigned j = 0; j < c; j++) {
-      if (j == i)
-        continue;
-      for (unsigned k = 0; k < r - 1; k++)
-        cofactor(k, n) = at(k + 1, j);
-      n++;
-    }
-
-    determinant = determinant + at(0, i) * sign * cofactor.determinant();
-  }
-
-  return determinant;
-}
-
 namespace mlir {
 namespace presburger {
 template class Matrix<MPInt>;
 template class Matrix<Fraction>;
-} // namespace presburger
-} // namespace mlir
+}
+}
 
 IntMatrix IntMatrix::identity(unsigned dimension) {
   IntMatrix matrix(dimension, dimension);
@@ -371,6 +297,7 @@ IntMatrix IntMatrix::identity(unsigned dimension) {
   return matrix;
 }
 
+
 std::pair<IntMatrix, IntMatrix> IntMatrix::computeHermiteNormalForm() const {
   // We start with u as an identity matrix and perform operations on h until h
   // is in hermite normal form. We apply the same sequence of operations on u to
@@ -463,81 +390,4 @@ MPInt IntMatrix::normalizeRow(unsigned row, unsigned cols) {
 
 MPInt IntMatrix::normalizeRow(unsigned row) {
   return normalizeRow(row, getNumColumns());
-}
-
-IntMatrix IntMatrix::integerInverse() {
-  Fraction det = Fraction(determinant(), 1);
-  FracMatrix newMat(getNumRows(), getNumColumns());
-  for (unsigned i = 0; i < getNumRows(); i++)
-    for (unsigned j = 0; j < getNumColumns(); j++)
-      newMat(i, j) = Fraction(at(i, j), 1);
-
-  FracMatrix fracInverse = newMat.inverse();
-
-  IntMatrix intInverse(getNumRows(), getNumColumns());
-  for (unsigned i = 0; i < getNumRows(); i++)
-    for (unsigned j = 0; j < getNumColumns(); j++)
-      intInverse(i, j) = (fracInverse(i, j) * det).getAsInteger();
-
-  return intInverse;
-}
-
-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 7b838d7925e0c6c..6b23cedabf624ec 100644
--- a/mlir/unittests/Analysis/Presburger/MatrixTest.cpp
+++ b/mlir/unittests/Analysis/Presburger/MatrixTest.cpp
@@ -248,45 +248,3 @@ 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));
-}
-
-TEST(MatrixTest, intInverse) {
-    IntMatrix mat = makeIntMatrix(2, 2, {{2, 1}, {7, 0}});
-    IntMatrix inverse = makeIntMatrix(2, 2, {{0, -1}, {-7, 2}});
-    
-    IntMatrix inv = mat.integerInverse();
-
-    for (unsigned i = 0; i < 2u; i++)
-      for (unsigned j = 0; j < 2u; j++)
-        EXPECT_EQ(inv(i, j), inverse(i, j));
-
-    mat = makeIntMatrix(4, 4, {{ 4, 14, 11,  3},
-                               {13,  5, 14, 12},
-                               {13,  9,  7, 14},
-                               { 2,  3, 12,  7}});
-    inverse = makeIntMatrix(4, 4, {{155, 1636, -579, -1713},
-                                   {725, -743, 537, -111},
-                                   {210, 735, -855, 360},
-                                   {-715, -1409, 1401, 1482}});
-
-    inv = mat.integerInverse();
-
-    for (unsigned i = 0; i < 2u; i++)
-      for (unsigned j = 0; j < 2u; j++)
-        EXPECT_EQ(inv(i, j), inverse(i, j));
-
-}
\ No newline at end of file
diff --git a/mlir/unittests/Analysis/Presburger/Utils.h b/mlir/unittests/Analysis/Presburger/Utils.h
index ce149c32ffa3821..ef4a67d0b8c004f 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 FracMatrix makeFracMatrix(unsigned numRow, unsigned numColumns,
-                                 ArrayRef<SmallVector<Fraction, 8>> matrix) {
-  FracMatrix results(numRow, numColumns);
+inline Matrix<Fraction> makeFracMatrix(unsigned numRow, unsigned numColumns,
+                         ArrayRef<SmallVector<Fraction, 8>> matrix) {
+  Matrix<Fraction> results(numRow, numColumns);
   assert(matrix.size() == numRow);
   for (unsigned i = 0; i < numRow; ++i) {
     assert(matrix[i].size() == numColumns &&

>From fc689df00f12b67cf09cd7f0697337d89b995794 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Mon, 2 Oct 2023 13:40:41 +0100
Subject: [PATCH 27/27] Fix reduce and add Fraction tests

---
 .../mlir/Analysis/Presburger/Fraction.h       |  2 +-
 .../Analysis/Presburger/CMakeLists.txt        |  1 +
 .../Analysis/Presburger/FractionTest.cpp      | 51 +++++++++++++++++++
 3 files changed, 53 insertions(+), 1 deletion(-)
 create mode 100644 mlir/unittests/Analysis/Presburger/FractionTest.cpp

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/unittests/Analysis/Presburger/CMakeLists.txt b/mlir/unittests/Analysis/Presburger/CMakeLists.txt
index 7b0124ee24c352e..b6ce273e35a0ee7 100644
--- a/mlir/unittests/Analysis/Presburger/CMakeLists.txt
+++ b/mlir/unittests/Analysis/Presburger/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_mlir_unittest(MLIRPresburgerTests
+  FractionTest.cpp
   IntegerPolyhedronTest.cpp
   IntegerRelationTest.cpp
   LinearTransformTest.cpp
diff --git a/mlir/unittests/Analysis/Presburger/FractionTest.cpp b/mlir/unittests/Analysis/Presburger/FractionTest.cpp
new file mode 100644
index 000000000000000..38b97c48969642e
--- /dev/null
+++ b/mlir/unittests/Analysis/Presburger/FractionTest.cpp
@@ -0,0 +1,51 @@
+#include "mlir/Analysis/Presburger/Fraction.h"
+#include "./Utils.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace mlir;
+using namespace presburger;
+
+TEST(FractionTest, getAsInteger) {
+    Fraction f(3, 1);
+    EXPECT_EQ(f.getAsInteger(), MPInt(3));
+}
+
+TEST(FractionTest, nearIntegers) {
+    Fraction f(52, 14);
+
+    EXPECT_EQ(floor(f), 3);
+    EXPECT_EQ(ceil(f), 4);
+}
+
+TEST(FractionTest, reduce) {
+    Fraction f(20, 35), g(-56, 63);
+    EXPECT_EQ(f, Fraction(4, 7));
+    EXPECT_EQ(g, Fraction(-8, 9));
+}
+
+TEST(FractionTest, arithmetic) {
+    Fraction f(3, 4), g(-2, 3);
+
+    EXPECT_EQ(f / g, Fraction(-9, 8));
+    EXPECT_EQ(f * g, Fraction(-1, 2));
+    EXPECT_EQ(f + g, Fraction(1, 12));
+    EXPECT_EQ(f - g, Fraction(17, 12));
+
+    f /= g;
+    EXPECT_EQ(f, Fraction(-9, 8));
+    f *= g;
+    EXPECT_EQ(f, Fraction(3, 4));
+    f += g;
+    EXPECT_EQ(f, Fraction(Fraction(1, 12)));
+    f -= g;
+    EXPECT_EQ(f, Fraction(3, 4));
+}
+
+TEST(FractionTest, relational) {
+    Fraction f(2, 5), g(3, 7);
+    ASSERT_TRUE(f < g);
+    ASSERT_FALSE(g < f);
+
+    EXPECT_EQ(f, Fraction(4, 10));
+}
\ No newline at end of file



More information about the libcxx-commits mailing list