[clang-tools-extra] [mlir] [llvm] [compiler-rt] [flang] [clang] [MLIR][Presburger] Function to compute the generating function corresponding to a unimodular cone (PR #77199)

via cfe-commits cfe-commits at lists.llvm.org
Sat Jan 6 06:06:28 PST 2024


https://github.com/Abhinav271828 created https://github.com/llvm/llvm-project/pull/77199

We implement a function to compute the generating function for a signed unimodular cone with a parametric vertex.
These functions, summed over tangential cones, provide the generating function corresponding to a parametric polyhedron.

>From e500c63cccbe4a332e2667350781bcbb229e6b55 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sat, 30 Dec 2023 22:45:31 +0530
Subject: [PATCH 01/32] initial commit

---
 .../mlir/Analysis/Presburger/Barvinok.h       | 54 +++++++++++++++
 .../Analysis/Presburger/GeneratingFunction.h  |  4 +-
 mlir/lib/Analysis/Presburger/Barvinok.cpp     | 65 +++++++++++++++++++
 mlir/lib/Analysis/Presburger/CMakeLists.txt   |  1 +
 4 files changed, 123 insertions(+), 1 deletion(-)
 create mode 100644 mlir/include/mlir/Analysis/Presburger/Barvinok.h
 rename mlir/{lib => include/mlir}/Analysis/Presburger/GeneratingFunction.h (97%)
 create mode 100644 mlir/lib/Analysis/Presburger/Barvinok.cpp

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
new file mode 100644
index 00000000000000..c63ee1e230c8bf
--- /dev/null
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -0,0 +1,54 @@
+//===- Barvinok.h - Barvinok's Algorithm ------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Functions relating to Barvinok's algorithm.
+// These include functions to manipulate cones (define a cone object, get its
+// dual, and find its index).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
+#define MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
+
+#include "mlir/Analysis/Presburger/Matrix.h"
+#include "mlir/Analysis/Presburger/IntegerRelation.h"
+#include <optional>
+
+namespace mlir {
+namespace presburger {
+
+using PolyhedronH = IntegerRelation;
+using PolyhedronV = IntMatrix;
+using ConeH = PolyhedronH;
+using ConeV = PolyhedronV;
+
+inline ConeH defineHRep(int num_ineqs, int num_vars, int num_params = 0)
+{
+    // We don't distinguish between domain and range variables, so
+    // we set the number of domain variables as 0 and the number of
+    // range variables as the number of actual variables.
+    // There are no symbols (non-parametric for now) and no local
+    // (existentially quantified) variables.
+    ConeH cone(PresburgerSpace::getRelationSpace(0, num_vars, num_params, 0));
+    return cone;
+}
+
+// Get the index of a cone.
+// If it has more rays than the dimension, return 0.
+MPInt getIndex(ConeV);
+
+// Get the dual of a cone in H-representation, returning the V-representation of it.
+ConeV getDual(ConeH);
+
+// Get the dual of a cone in V-representation, returning the H-representation of it.
+ConeH getDual(ConeV);
+
+} // namespace presburger
+} // namespace mlir
+
+#endif // MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
\ No newline at end of file
diff --git a/mlir/lib/Analysis/Presburger/GeneratingFunction.h b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
similarity index 97%
rename from mlir/lib/Analysis/Presburger/GeneratingFunction.h
rename to mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
index f7deba921ea51e..770d17fe17c307 100644
--- a/mlir/lib/Analysis/Presburger/GeneratingFunction.h
+++ b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
@@ -19,6 +19,7 @@
 
 namespace mlir {
 namespace presburger {
+namespace internal {
 
 // A parametric point is a vector, each of whose elements
 // is an affine function of n parameters. Each row
@@ -128,7 +129,8 @@ class GeneratingFunction {
   std::vector<std::vector<Point>> denominators;
 };
 
+} // namespace internal
 } // namespace presburger
 } // namespace mlir
 
-#endif // MLIR_ANALYSIS_PRESBURGER_GENERATINGFUNCTION_H
+#endif // MLIR_ANALYSIS_PRESBURGER_GENERATINGFUNCTION_H
\ No newline at end of file
diff --git a/mlir/lib/Analysis/Presburger/Barvinok.cpp b/mlir/lib/Analysis/Presburger/Barvinok.cpp
new file mode 100644
index 00000000000000..ddb24d1a79993f
--- /dev/null
+++ b/mlir/lib/Analysis/Presburger/Barvinok.cpp
@@ -0,0 +1,65 @@
+//===- QuasiPolynomial.cpp - Barvinok's Algorithm ---------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Analysis/Presburger/Barvinok.h"
+
+using namespace mlir;
+using namespace presburger;
+
+// Assuming that the input cone is pointed at the origin,
+// converts it to its dual in V-representation.
+// Essentially we just remove the all-zeroes constant column.
+ConeV mlir::presburger::getDual(ConeH cone)
+{
+    ConeV dual(cone.getNumInequalities(), cone.getNumCols()-1, 0, 0);
+    // Assuming that an inequality of the form
+    // a1*x1 + ... + an*xn + b ≥ 0
+    // is represented as a row [a1, ..., an, b]
+    // and that b = 0.
+
+    for (unsigned i = 0; i < cone.getNumInequalities(); i++)
+    {
+        assert(dual.at(i, cone.getNumCols()-1) == 0 && "H-representation of cone is not centred at the origin!");
+        for (unsigned j = 0; j < cone.getNumCols()-1; j++)
+        {
+            dual.at(i, j) = cone.atIneq(i, j);
+        }
+    }
+
+    // Now dual is of the form [ [a1, ..., an] , ... ]
+    // which is the V-representation of the dual.
+    return dual;
+}
+
+// Converts a cone in V-representation to the H-representation
+// of its dual, pointed at the origin (not at the original vertex).
+// Essentially adds a column consisting only of zeroes to the end.
+ConeH mlir::presburger::getDual(ConeV cone)
+{
+    ConeH dual = defineHRep(cone.getNumRows(), cone.getNumColumns());
+    cone.insertColumn(cone.getNumColumns());
+
+    for (unsigned i = 0; i < cone.getNumRows(); i++)
+        dual.addInequality(cone.getRow(i));
+
+    // Now dual is of the form [ [a1, ..., an, 0] , ... ]
+    // which is the H-representation of the dual.
+    return dual;
+}
+
+// Find the index of a cone in V-representation.
+// If there are more rays than variables, return 0.
+MPInt mlir::presburger::getIndex(ConeV cone)
+{
+    unsigned rows = cone.getNumRows();
+    unsigned cols = cone.getNumColumns();
+    if (rows > cols)
+        return MPInt(0);
+
+    return cone.determinant();
+}
\ No newline at end of file
diff --git a/mlir/lib/Analysis/Presburger/CMakeLists.txt b/mlir/lib/Analysis/Presburger/CMakeLists.txt
index e77e1623dae175..83d0514c9e7d17 100644
--- a/mlir/lib/Analysis/Presburger/CMakeLists.txt
+++ b/mlir/lib/Analysis/Presburger/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_mlir_library(MLIRPresburger
+  Barvinok.cpp
   IntegerRelation.cpp
   LinearTransform.cpp
   Matrix.cpp

>From b2566609ac319a9effad78405e7c8f948b3490ce Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sat, 30 Dec 2023 22:53:15 +0530
Subject: [PATCH 02/32] Formatting

---
 .../mlir/Analysis/Presburger/Barvinok.h       | 33 +++++----
 mlir/lib/Analysis/Presburger/Barvinok.cpp     | 70 +++++++++----------
 2 files changed, 55 insertions(+), 48 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index c63ee1e230c8bf..6ffdf96502fd20 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -15,37 +15,46 @@
 #ifndef MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
 #define MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
 
-#include "mlir/Analysis/Presburger/Matrix.h"
 #include "mlir/Analysis/Presburger/IntegerRelation.h"
+#include "mlir/Analysis/Presburger/Matrix.h"
 #include <optional>
 
 namespace mlir {
 namespace presburger {
 
+// A polyhedron in H-representation is a set of relations
+// in d variables with integer coefficients.
 using PolyhedronH = IntegerRelation;
+
+// A polyhedron in V-representation is a set of rays, i.e.,
+// vectors, stored as rows of a matrix.
 using PolyhedronV = IntMatrix;
+
+// A cone in either representation is a special case of
+// a polyhedron in that representation.
 using ConeH = PolyhedronH;
 using ConeV = PolyhedronV;
 
-inline ConeH defineHRep(int num_ineqs, int num_vars, int num_params = 0)
-{
-    // We don't distinguish between domain and range variables, so
-    // we set the number of domain variables as 0 and the number of
-    // range variables as the number of actual variables.
-    // There are no symbols (non-parametric for now) and no local
-    // (existentially quantified) variables.
-    ConeH cone(PresburgerSpace::getRelationSpace(0, num_vars, num_params, 0));
-    return cone;
+inline ConeH defineHRep(int num_ineqs, int num_vars, int num_params = 0) {
+  // We don't distinguish between domain and range variables, so
+  // we set the number of domain variables as 0 and the number of
+  // range variables as the number of actual variables.
+  // There are no symbols (non-parametric for now) and no local
+  // (existentially quantified) variables.
+  return ConeH(PresburgerSpace::getRelationSpace(/*numDomain=*/0,
+                                                 /*numRange=*/num_vars,
+                                                 /*numSymbols=*/num_params,
+                                                 /*numLocals=*/0));
 }
 
 // Get the index of a cone.
 // If it has more rays than the dimension, return 0.
 MPInt getIndex(ConeV);
 
-// Get the dual of a cone in H-representation, returning the V-representation of it.
+// Get the dual of a cone in H-representation, returning its V-representation.
 ConeV getDual(ConeH);
 
-// Get the dual of a cone in V-representation, returning the H-representation of it.
+// Get the dual of a cone in V-representation, returning its H-representation.
 ConeH getDual(ConeV);
 
 } // namespace presburger
diff --git a/mlir/lib/Analysis/Presburger/Barvinok.cpp b/mlir/lib/Analysis/Presburger/Barvinok.cpp
index ddb24d1a79993f..698dde6f15d6f4 100644
--- a/mlir/lib/Analysis/Presburger/Barvinok.cpp
+++ b/mlir/lib/Analysis/Presburger/Barvinok.cpp
@@ -14,52 +14,50 @@ using namespace presburger;
 // Assuming that the input cone is pointed at the origin,
 // converts it to its dual in V-representation.
 // Essentially we just remove the all-zeroes constant column.
-ConeV mlir::presburger::getDual(ConeH cone)
-{
-    ConeV dual(cone.getNumInequalities(), cone.getNumCols()-1, 0, 0);
-    // Assuming that an inequality of the form
-    // a1*x1 + ... + an*xn + b ≥ 0
-    // is represented as a row [a1, ..., an, b]
-    // and that b = 0.
-
-    for (unsigned i = 0; i < cone.getNumInequalities(); i++)
-    {
-        assert(dual.at(i, cone.getNumCols()-1) == 0 && "H-representation of cone is not centred at the origin!");
-        for (unsigned j = 0; j < cone.getNumCols()-1; j++)
-        {
-            dual.at(i, j) = cone.atIneq(i, j);
-        }
+ConeV mlir::presburger::getDual(ConeH cone) {
+  unsigned inequalities = cone.getNumInequalities();
+  unsigned variables = cone.getNumCols() - 1;
+  ConeV dual(inequalities, variables, 0, 0);
+  // Assuming that an inequality of the form
+  // a1*x1 + ... + an*xn + b ≥ 0
+  // is represented as a row [a1, ..., an, b]
+  // and that b = 0.
+
+  for (unsigned i = 0; i < inequalities; i++) {
+    assert(dual.at(i, variables) == 0 &&
+           "H-representation of cone is not centred at the origin!");
+    for (unsigned j = 0; j < variables; j++) {
+      dual.at(i, j) = cone.atIneq(i, j);
     }
+  }
 
-    // Now dual is of the form [ [a1, ..., an] , ... ]
-    // which is the V-representation of the dual.
-    return dual;
+  // Now dual is of the form [ [a1, ..., an] , ... ]
+  // which is the V-representation of the dual.
+  return dual;
 }
 
 // Converts a cone in V-representation to the H-representation
 // of its dual, pointed at the origin (not at the original vertex).
 // Essentially adds a column consisting only of zeroes to the end.
-ConeH mlir::presburger::getDual(ConeV cone)
-{
-    ConeH dual = defineHRep(cone.getNumRows(), cone.getNumColumns());
-    cone.insertColumn(cone.getNumColumns());
-
-    for (unsigned i = 0; i < cone.getNumRows(); i++)
-        dual.addInequality(cone.getRow(i));
-
-    // Now dual is of the form [ [a1, ..., an, 0] , ... ]
-    // which is the H-representation of the dual.
-    return dual;
+ConeH mlir::presburger::getDual(ConeV cone) {
+  unsigned rows = cone.getNumRows();
+  unsigned columns = cone.getNumColumns();
+  ConeH dual = defineHRep(rows, columns);
+  cone.insertColumn(columns);
+
+  for (unsigned i = 0; i < rows; i++)
+    dual.addInequality(cone.getRow(i));
+
+  // Now dual is of the form [ [a1, ..., an, 0] , ... ]
+  // which is the H-representation of the dual.
+  return dual;
 }
 
 // Find the index of a cone in V-representation.
 // If there are more rays than variables, return 0.
-MPInt mlir::presburger::getIndex(ConeV cone)
-{
-    unsigned rows = cone.getNumRows();
-    unsigned cols = cone.getNumColumns();
-    if (rows > cols)
-        return MPInt(0);
+MPInt mlir::presburger::getIndex(ConeV cone) {
+  if (cone.getNumRows() > cone.getNumColumns())
+    return MPInt(0);
 
-    return cone.determinant();
+  return cone.determinant();
 }
\ No newline at end of file

>From b76e6f6da58d2bbe1bc22be248ee88452ea71d17 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sat, 30 Dec 2023 23:32:49 +0530
Subject: [PATCH 03/32] Add tests for cone fns

---
 .../mlir/Analysis/Presburger/Barvinok.h       |  7 +--
 mlir/lib/Analysis/Presburger/Barvinok.cpp     |  6 ++-
 .../Analysis/Presburger/BarvinokTest.cpp      | 47 +++++++++++++++++++
 .../Analysis/Presburger/CMakeLists.txt        |  1 +
 4 files changed, 56 insertions(+), 5 deletions(-)
 create mode 100644 mlir/unittests/Analysis/Presburger/BarvinokTest.cpp

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index 6ffdf96502fd20..665227a20fc258 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -35,15 +35,16 @@ using PolyhedronV = IntMatrix;
 using ConeH = PolyhedronH;
 using ConeV = PolyhedronV;
 
-inline ConeH defineHRep(int num_ineqs, int num_vars, int num_params = 0) {
+inline ConeH defineHRep(int num_vars) {
   // We don't distinguish between domain and range variables, so
   // we set the number of domain variables as 0 and the number of
   // range variables as the number of actual variables.
-  // There are no symbols (non-parametric for now) and no local
+  // There are no symbols (we don't work with parametric cones) and no local
   // (existentially quantified) variables.
+  // Once the cone is defined, we use `addInequality()` to set inequalities.
   return ConeH(PresburgerSpace::getRelationSpace(/*numDomain=*/0,
                                                  /*numRange=*/num_vars,
-                                                 /*numSymbols=*/num_params,
+                                                 /*numSymbols=*/0,
                                                  /*numLocals=*/0));
 }
 
diff --git a/mlir/lib/Analysis/Presburger/Barvinok.cpp b/mlir/lib/Analysis/Presburger/Barvinok.cpp
index 698dde6f15d6f4..8c6fc9a6e3f53d 100644
--- a/mlir/lib/Analysis/Presburger/Barvinok.cpp
+++ b/mlir/lib/Analysis/Presburger/Barvinok.cpp
@@ -24,7 +24,7 @@ ConeV mlir::presburger::getDual(ConeH cone) {
   // and that b = 0.
 
   for (unsigned i = 0; i < inequalities; i++) {
-    assert(dual.at(i, variables) == 0 &&
+    assert(cone.atIneq(i, variables) == 0 &&
            "H-representation of cone is not centred at the origin!");
     for (unsigned j = 0; j < variables; j++) {
       dual.at(i, j) = cone.atIneq(i, j);
@@ -42,7 +42,9 @@ ConeV mlir::presburger::getDual(ConeH cone) {
 ConeH mlir::presburger::getDual(ConeV cone) {
   unsigned rows = cone.getNumRows();
   unsigned columns = cone.getNumColumns();
-  ConeH dual = defineHRep(rows, columns);
+  ConeH dual = defineHRep(columns);
+  // Add a new column (for constants) at the end.
+  // This will be initialized to zero.
   cone.insertColumn(columns);
 
   for (unsigned i = 0; i < rows; i++)
diff --git a/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp b/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp
new file mode 100644
index 00000000000000..2b7f0491d588eb
--- /dev/null
+++ b/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp
@@ -0,0 +1,47 @@
+#include "mlir/Analysis/Presburger/Barvinok.h"
+#include "./Utils.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace mlir;
+using namespace presburger;
+
+// We randomly generate 3 vectors with 4 entries each
+// and define a cone's H-representation using these
+// numbers. We check that the dual contains the same
+// numbers.
+// We do the same in the reverse case.
+TEST(BarvinokTest, getDual) {
+  ConeH cone1 = defineHRep(4);
+  cone1.addInequality({1, 2, 3, 4, 0});
+  cone1.addInequality({3, 4, 2, 5, 0});
+  cone1.addInequality({6, 2, 6, 1, 0});
+
+  ConeV dual1 = getDual(cone1);
+
+  EXPECT_EQ_INT_MATRIX(
+      dual1, makeIntMatrix(3, 4, {{1, 2, 3, 4}, {3, 4, 2, 5}, {6, 2, 6, 1}}));
+
+  ConeV cone2 = makeIntMatrix(3, 4, {{3, 6, 1, 5}, {3, 1, 7, 2}, {9, 3, 2, 7}});
+
+  ConeH dual2 = getDual(cone2);
+
+  ConeH expected = defineHRep(4);
+  expected.addInequality({3, 6, 1, 5, 0});
+  expected.addInequality({3, 1, 7, 2, 0});
+  expected.addInequality({9, 3, 2, 7, 0});
+
+  EXPECT_TRUE(dual2.isEqual(expected));
+}
+
+// We randomly generate a nxn matrix to use as a cone
+// with n inequalities in n variables and check for
+// the determinant being equal to the index.
+TEST(BarvinokTest, getIndex) {
+  ConeV cone = makeIntMatrix(3, 3, {{4, 2, 1}, {5, 2, 7}, {4, 1, 6}});
+  EXPECT_EQ(getIndex(cone), cone.determinant());
+
+  cone = makeIntMatrix(
+      4, 4, {{4, 2, 5, 1}, {4, 1, 3, 6}, {8, 2, 5, 6}, {5, 2, 5, 7}});
+  EXPECT_EQ(getIndex(cone), cone.determinant());
+}
diff --git a/mlir/unittests/Analysis/Presburger/CMakeLists.txt b/mlir/unittests/Analysis/Presburger/CMakeLists.txt
index e37133354e53ca..25f9e5939e4a25 100644
--- a/mlir/unittests/Analysis/Presburger/CMakeLists.txt
+++ b/mlir/unittests/Analysis/Presburger/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_mlir_unittest(MLIRPresburgerTests
+  BarvinokTest.cpp
   FractionTest.cpp
   IntegerPolyhedronTest.cpp
   IntegerRelationTest.cpp

>From 855bcb46c775c970fd56768759a2681bdc52a9b2 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sun, 31 Dec 2023 00:18:43 +0530
Subject: [PATCH 04/32] Use public_namespace_name::detail

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

diff --git a/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
index 770d17fe17c307..e29478e97be02c 100644
--- a/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
+++ b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
@@ -19,7 +19,7 @@
 
 namespace mlir {
 namespace presburger {
-namespace internal {
+namespace public_namespace_name::detail {
 
 // A parametric point is a vector, each of whose elements
 // is an affine function of n parameters. Each row

>From df7549fdc05937216611b3af1830e90ad22d9bb7 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sun, 31 Dec 2023 10:14:19 +0530
Subject: [PATCH 05/32] Resolve conflict

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

diff --git a/mlir/lib/Analysis/Presburger/Matrix.cpp b/mlir/lib/Analysis/Presburger/Matrix.cpp
index 25300f84cfc047..a17565efbce95b 100644
--- a/mlir/lib/Analysis/Presburger/Matrix.cpp
+++ b/mlir/lib/Analysis/Presburger/Matrix.cpp
@@ -452,6 +452,8 @@ MPInt IntMatrix::determinant(IntMatrix *inverse) const {
   if (detM == 0)
     return MPInt(0);
 
+  if (!inverse) return detM;
+
   *inverse = IntMatrix(nRows, nColumns);
   for (unsigned i = 0; i < nRows; i++)
     for (unsigned j = 0; j < nColumns; j++)

>From 5a9c4bd13f384a17bc7399f696cf62c80dc3e82d Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sat, 30 Dec 2023 22:45:31 +0530
Subject: [PATCH 06/32] initial commit

---
 .../mlir/Analysis/Presburger/Barvinok.h       | 54 +++++++++++++++
 .../Analysis/Presburger/GeneratingFunction.h  |  4 +-
 mlir/lib/Analysis/Presburger/Barvinok.cpp     | 65 +++++++++++++++++++
 mlir/lib/Analysis/Presburger/CMakeLists.txt   |  1 +
 4 files changed, 123 insertions(+), 1 deletion(-)
 create mode 100644 mlir/include/mlir/Analysis/Presburger/Barvinok.h
 rename mlir/{lib => include/mlir}/Analysis/Presburger/GeneratingFunction.h (97%)
 create mode 100644 mlir/lib/Analysis/Presburger/Barvinok.cpp

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
new file mode 100644
index 00000000000000..c63ee1e230c8bf
--- /dev/null
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -0,0 +1,54 @@
+//===- Barvinok.h - Barvinok's Algorithm ------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Functions relating to Barvinok's algorithm.
+// These include functions to manipulate cones (define a cone object, get its
+// dual, and find its index).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
+#define MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
+
+#include "mlir/Analysis/Presburger/Matrix.h"
+#include "mlir/Analysis/Presburger/IntegerRelation.h"
+#include <optional>
+
+namespace mlir {
+namespace presburger {
+
+using PolyhedronH = IntegerRelation;
+using PolyhedronV = IntMatrix;
+using ConeH = PolyhedronH;
+using ConeV = PolyhedronV;
+
+inline ConeH defineHRep(int num_ineqs, int num_vars, int num_params = 0)
+{
+    // We don't distinguish between domain and range variables, so
+    // we set the number of domain variables as 0 and the number of
+    // range variables as the number of actual variables.
+    // There are no symbols (non-parametric for now) and no local
+    // (existentially quantified) variables.
+    ConeH cone(PresburgerSpace::getRelationSpace(0, num_vars, num_params, 0));
+    return cone;
+}
+
+// Get the index of a cone.
+// If it has more rays than the dimension, return 0.
+MPInt getIndex(ConeV);
+
+// Get the dual of a cone in H-representation, returning the V-representation of it.
+ConeV getDual(ConeH);
+
+// Get the dual of a cone in V-representation, returning the H-representation of it.
+ConeH getDual(ConeV);
+
+} // namespace presburger
+} // namespace mlir
+
+#endif // MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
\ No newline at end of file
diff --git a/mlir/lib/Analysis/Presburger/GeneratingFunction.h b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
similarity index 97%
rename from mlir/lib/Analysis/Presburger/GeneratingFunction.h
rename to mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
index f7deba921ea51e..770d17fe17c307 100644
--- a/mlir/lib/Analysis/Presburger/GeneratingFunction.h
+++ b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
@@ -19,6 +19,7 @@
 
 namespace mlir {
 namespace presburger {
+namespace internal {
 
 // A parametric point is a vector, each of whose elements
 // is an affine function of n parameters. Each row
@@ -128,7 +129,8 @@ class GeneratingFunction {
   std::vector<std::vector<Point>> denominators;
 };
 
+} // namespace internal
 } // namespace presburger
 } // namespace mlir
 
-#endif // MLIR_ANALYSIS_PRESBURGER_GENERATINGFUNCTION_H
+#endif // MLIR_ANALYSIS_PRESBURGER_GENERATINGFUNCTION_H
\ No newline at end of file
diff --git a/mlir/lib/Analysis/Presburger/Barvinok.cpp b/mlir/lib/Analysis/Presburger/Barvinok.cpp
new file mode 100644
index 00000000000000..ddb24d1a79993f
--- /dev/null
+++ b/mlir/lib/Analysis/Presburger/Barvinok.cpp
@@ -0,0 +1,65 @@
+//===- QuasiPolynomial.cpp - Barvinok's Algorithm ---------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Analysis/Presburger/Barvinok.h"
+
+using namespace mlir;
+using namespace presburger;
+
+// Assuming that the input cone is pointed at the origin,
+// converts it to its dual in V-representation.
+// Essentially we just remove the all-zeroes constant column.
+ConeV mlir::presburger::getDual(ConeH cone)
+{
+    ConeV dual(cone.getNumInequalities(), cone.getNumCols()-1, 0, 0);
+    // Assuming that an inequality of the form
+    // a1*x1 + ... + an*xn + b ≥ 0
+    // is represented as a row [a1, ..., an, b]
+    // and that b = 0.
+
+    for (unsigned i = 0; i < cone.getNumInequalities(); i++)
+    {
+        assert(dual.at(i, cone.getNumCols()-1) == 0 && "H-representation of cone is not centred at the origin!");
+        for (unsigned j = 0; j < cone.getNumCols()-1; j++)
+        {
+            dual.at(i, j) = cone.atIneq(i, j);
+        }
+    }
+
+    // Now dual is of the form [ [a1, ..., an] , ... ]
+    // which is the V-representation of the dual.
+    return dual;
+}
+
+// Converts a cone in V-representation to the H-representation
+// of its dual, pointed at the origin (not at the original vertex).
+// Essentially adds a column consisting only of zeroes to the end.
+ConeH mlir::presburger::getDual(ConeV cone)
+{
+    ConeH dual = defineHRep(cone.getNumRows(), cone.getNumColumns());
+    cone.insertColumn(cone.getNumColumns());
+
+    for (unsigned i = 0; i < cone.getNumRows(); i++)
+        dual.addInequality(cone.getRow(i));
+
+    // Now dual is of the form [ [a1, ..., an, 0] , ... ]
+    // which is the H-representation of the dual.
+    return dual;
+}
+
+// Find the index of a cone in V-representation.
+// If there are more rays than variables, return 0.
+MPInt mlir::presburger::getIndex(ConeV cone)
+{
+    unsigned rows = cone.getNumRows();
+    unsigned cols = cone.getNumColumns();
+    if (rows > cols)
+        return MPInt(0);
+
+    return cone.determinant();
+}
\ No newline at end of file
diff --git a/mlir/lib/Analysis/Presburger/CMakeLists.txt b/mlir/lib/Analysis/Presburger/CMakeLists.txt
index e77e1623dae175..83d0514c9e7d17 100644
--- a/mlir/lib/Analysis/Presburger/CMakeLists.txt
+++ b/mlir/lib/Analysis/Presburger/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_mlir_library(MLIRPresburger
+  Barvinok.cpp
   IntegerRelation.cpp
   LinearTransform.cpp
   Matrix.cpp

>From d7e4ee018d8f8f8e19376dcf01406f5cef64e2c5 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sat, 30 Dec 2023 22:53:15 +0530
Subject: [PATCH 07/32] Formatting

---
 .../mlir/Analysis/Presburger/Barvinok.h       | 33 +++++----
 mlir/lib/Analysis/Presburger/Barvinok.cpp     | 70 +++++++++----------
 2 files changed, 55 insertions(+), 48 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index c63ee1e230c8bf..6ffdf96502fd20 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -15,37 +15,46 @@
 #ifndef MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
 #define MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
 
-#include "mlir/Analysis/Presburger/Matrix.h"
 #include "mlir/Analysis/Presburger/IntegerRelation.h"
+#include "mlir/Analysis/Presburger/Matrix.h"
 #include <optional>
 
 namespace mlir {
 namespace presburger {
 
+// A polyhedron in H-representation is a set of relations
+// in d variables with integer coefficients.
 using PolyhedronH = IntegerRelation;
+
+// A polyhedron in V-representation is a set of rays, i.e.,
+// vectors, stored as rows of a matrix.
 using PolyhedronV = IntMatrix;
+
+// A cone in either representation is a special case of
+// a polyhedron in that representation.
 using ConeH = PolyhedronH;
 using ConeV = PolyhedronV;
 
-inline ConeH defineHRep(int num_ineqs, int num_vars, int num_params = 0)
-{
-    // We don't distinguish between domain and range variables, so
-    // we set the number of domain variables as 0 and the number of
-    // range variables as the number of actual variables.
-    // There are no symbols (non-parametric for now) and no local
-    // (existentially quantified) variables.
-    ConeH cone(PresburgerSpace::getRelationSpace(0, num_vars, num_params, 0));
-    return cone;
+inline ConeH defineHRep(int num_ineqs, int num_vars, int num_params = 0) {
+  // We don't distinguish between domain and range variables, so
+  // we set the number of domain variables as 0 and the number of
+  // range variables as the number of actual variables.
+  // There are no symbols (non-parametric for now) and no local
+  // (existentially quantified) variables.
+  return ConeH(PresburgerSpace::getRelationSpace(/*numDomain=*/0,
+                                                 /*numRange=*/num_vars,
+                                                 /*numSymbols=*/num_params,
+                                                 /*numLocals=*/0));
 }
 
 // Get the index of a cone.
 // If it has more rays than the dimension, return 0.
 MPInt getIndex(ConeV);
 
-// Get the dual of a cone in H-representation, returning the V-representation of it.
+// Get the dual of a cone in H-representation, returning its V-representation.
 ConeV getDual(ConeH);
 
-// Get the dual of a cone in V-representation, returning the H-representation of it.
+// Get the dual of a cone in V-representation, returning its H-representation.
 ConeH getDual(ConeV);
 
 } // namespace presburger
diff --git a/mlir/lib/Analysis/Presburger/Barvinok.cpp b/mlir/lib/Analysis/Presburger/Barvinok.cpp
index ddb24d1a79993f..698dde6f15d6f4 100644
--- a/mlir/lib/Analysis/Presburger/Barvinok.cpp
+++ b/mlir/lib/Analysis/Presburger/Barvinok.cpp
@@ -14,52 +14,50 @@ using namespace presburger;
 // Assuming that the input cone is pointed at the origin,
 // converts it to its dual in V-representation.
 // Essentially we just remove the all-zeroes constant column.
-ConeV mlir::presburger::getDual(ConeH cone)
-{
-    ConeV dual(cone.getNumInequalities(), cone.getNumCols()-1, 0, 0);
-    // Assuming that an inequality of the form
-    // a1*x1 + ... + an*xn + b ≥ 0
-    // is represented as a row [a1, ..., an, b]
-    // and that b = 0.
-
-    for (unsigned i = 0; i < cone.getNumInequalities(); i++)
-    {
-        assert(dual.at(i, cone.getNumCols()-1) == 0 && "H-representation of cone is not centred at the origin!");
-        for (unsigned j = 0; j < cone.getNumCols()-1; j++)
-        {
-            dual.at(i, j) = cone.atIneq(i, j);
-        }
+ConeV mlir::presburger::getDual(ConeH cone) {
+  unsigned inequalities = cone.getNumInequalities();
+  unsigned variables = cone.getNumCols() - 1;
+  ConeV dual(inequalities, variables, 0, 0);
+  // Assuming that an inequality of the form
+  // a1*x1 + ... + an*xn + b ≥ 0
+  // is represented as a row [a1, ..., an, b]
+  // and that b = 0.
+
+  for (unsigned i = 0; i < inequalities; i++) {
+    assert(dual.at(i, variables) == 0 &&
+           "H-representation of cone is not centred at the origin!");
+    for (unsigned j = 0; j < variables; j++) {
+      dual.at(i, j) = cone.atIneq(i, j);
     }
+  }
 
-    // Now dual is of the form [ [a1, ..., an] , ... ]
-    // which is the V-representation of the dual.
-    return dual;
+  // Now dual is of the form [ [a1, ..., an] , ... ]
+  // which is the V-representation of the dual.
+  return dual;
 }
 
 // Converts a cone in V-representation to the H-representation
 // of its dual, pointed at the origin (not at the original vertex).
 // Essentially adds a column consisting only of zeroes to the end.
-ConeH mlir::presburger::getDual(ConeV cone)
-{
-    ConeH dual = defineHRep(cone.getNumRows(), cone.getNumColumns());
-    cone.insertColumn(cone.getNumColumns());
-
-    for (unsigned i = 0; i < cone.getNumRows(); i++)
-        dual.addInequality(cone.getRow(i));
-
-    // Now dual is of the form [ [a1, ..., an, 0] , ... ]
-    // which is the H-representation of the dual.
-    return dual;
+ConeH mlir::presburger::getDual(ConeV cone) {
+  unsigned rows = cone.getNumRows();
+  unsigned columns = cone.getNumColumns();
+  ConeH dual = defineHRep(rows, columns);
+  cone.insertColumn(columns);
+
+  for (unsigned i = 0; i < rows; i++)
+    dual.addInequality(cone.getRow(i));
+
+  // Now dual is of the form [ [a1, ..., an, 0] , ... ]
+  // which is the H-representation of the dual.
+  return dual;
 }
 
 // Find the index of a cone in V-representation.
 // If there are more rays than variables, return 0.
-MPInt mlir::presburger::getIndex(ConeV cone)
-{
-    unsigned rows = cone.getNumRows();
-    unsigned cols = cone.getNumColumns();
-    if (rows > cols)
-        return MPInt(0);
+MPInt mlir::presburger::getIndex(ConeV cone) {
+  if (cone.getNumRows() > cone.getNumColumns())
+    return MPInt(0);
 
-    return cone.determinant();
+  return cone.determinant();
 }
\ No newline at end of file

>From 3c6f4554019ac0c964e62351772cfc43db93b63f Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sat, 30 Dec 2023 23:32:49 +0530
Subject: [PATCH 08/32] Add tests for cone fns

---
 .../mlir/Analysis/Presburger/Barvinok.h       |  7 +--
 mlir/lib/Analysis/Presburger/Barvinok.cpp     |  6 ++-
 .../Analysis/Presburger/BarvinokTest.cpp      | 47 +++++++++++++++++++
 .../Analysis/Presburger/CMakeLists.txt        |  1 +
 4 files changed, 56 insertions(+), 5 deletions(-)
 create mode 100644 mlir/unittests/Analysis/Presburger/BarvinokTest.cpp

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index 6ffdf96502fd20..665227a20fc258 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -35,15 +35,16 @@ using PolyhedronV = IntMatrix;
 using ConeH = PolyhedronH;
 using ConeV = PolyhedronV;
 
-inline ConeH defineHRep(int num_ineqs, int num_vars, int num_params = 0) {
+inline ConeH defineHRep(int num_vars) {
   // We don't distinguish between domain and range variables, so
   // we set the number of domain variables as 0 and the number of
   // range variables as the number of actual variables.
-  // There are no symbols (non-parametric for now) and no local
+  // There are no symbols (we don't work with parametric cones) and no local
   // (existentially quantified) variables.
+  // Once the cone is defined, we use `addInequality()` to set inequalities.
   return ConeH(PresburgerSpace::getRelationSpace(/*numDomain=*/0,
                                                  /*numRange=*/num_vars,
-                                                 /*numSymbols=*/num_params,
+                                                 /*numSymbols=*/0,
                                                  /*numLocals=*/0));
 }
 
diff --git a/mlir/lib/Analysis/Presburger/Barvinok.cpp b/mlir/lib/Analysis/Presburger/Barvinok.cpp
index 698dde6f15d6f4..8c6fc9a6e3f53d 100644
--- a/mlir/lib/Analysis/Presburger/Barvinok.cpp
+++ b/mlir/lib/Analysis/Presburger/Barvinok.cpp
@@ -24,7 +24,7 @@ ConeV mlir::presburger::getDual(ConeH cone) {
   // and that b = 0.
 
   for (unsigned i = 0; i < inequalities; i++) {
-    assert(dual.at(i, variables) == 0 &&
+    assert(cone.atIneq(i, variables) == 0 &&
            "H-representation of cone is not centred at the origin!");
     for (unsigned j = 0; j < variables; j++) {
       dual.at(i, j) = cone.atIneq(i, j);
@@ -42,7 +42,9 @@ ConeV mlir::presburger::getDual(ConeH cone) {
 ConeH mlir::presburger::getDual(ConeV cone) {
   unsigned rows = cone.getNumRows();
   unsigned columns = cone.getNumColumns();
-  ConeH dual = defineHRep(rows, columns);
+  ConeH dual = defineHRep(columns);
+  // Add a new column (for constants) at the end.
+  // This will be initialized to zero.
   cone.insertColumn(columns);
 
   for (unsigned i = 0; i < rows; i++)
diff --git a/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp b/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp
new file mode 100644
index 00000000000000..2b7f0491d588eb
--- /dev/null
+++ b/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp
@@ -0,0 +1,47 @@
+#include "mlir/Analysis/Presburger/Barvinok.h"
+#include "./Utils.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace mlir;
+using namespace presburger;
+
+// We randomly generate 3 vectors with 4 entries each
+// and define a cone's H-representation using these
+// numbers. We check that the dual contains the same
+// numbers.
+// We do the same in the reverse case.
+TEST(BarvinokTest, getDual) {
+  ConeH cone1 = defineHRep(4);
+  cone1.addInequality({1, 2, 3, 4, 0});
+  cone1.addInequality({3, 4, 2, 5, 0});
+  cone1.addInequality({6, 2, 6, 1, 0});
+
+  ConeV dual1 = getDual(cone1);
+
+  EXPECT_EQ_INT_MATRIX(
+      dual1, makeIntMatrix(3, 4, {{1, 2, 3, 4}, {3, 4, 2, 5}, {6, 2, 6, 1}}));
+
+  ConeV cone2 = makeIntMatrix(3, 4, {{3, 6, 1, 5}, {3, 1, 7, 2}, {9, 3, 2, 7}});
+
+  ConeH dual2 = getDual(cone2);
+
+  ConeH expected = defineHRep(4);
+  expected.addInequality({3, 6, 1, 5, 0});
+  expected.addInequality({3, 1, 7, 2, 0});
+  expected.addInequality({9, 3, 2, 7, 0});
+
+  EXPECT_TRUE(dual2.isEqual(expected));
+}
+
+// We randomly generate a nxn matrix to use as a cone
+// with n inequalities in n variables and check for
+// the determinant being equal to the index.
+TEST(BarvinokTest, getIndex) {
+  ConeV cone = makeIntMatrix(3, 3, {{4, 2, 1}, {5, 2, 7}, {4, 1, 6}});
+  EXPECT_EQ(getIndex(cone), cone.determinant());
+
+  cone = makeIntMatrix(
+      4, 4, {{4, 2, 5, 1}, {4, 1, 3, 6}, {8, 2, 5, 6}, {5, 2, 5, 7}});
+  EXPECT_EQ(getIndex(cone), cone.determinant());
+}
diff --git a/mlir/unittests/Analysis/Presburger/CMakeLists.txt b/mlir/unittests/Analysis/Presburger/CMakeLists.txt
index e37133354e53ca..25f9e5939e4a25 100644
--- a/mlir/unittests/Analysis/Presburger/CMakeLists.txt
+++ b/mlir/unittests/Analysis/Presburger/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_mlir_unittest(MLIRPresburgerTests
+  BarvinokTest.cpp
   FractionTest.cpp
   IntegerPolyhedronTest.cpp
   IntegerRelationTest.cpp

>From 08d6cd624edf9ddb92550fc6d65bc41f5d011fcf Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sun, 31 Dec 2023 00:18:43 +0530
Subject: [PATCH 09/32] Use public_namespace_name::detail

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

diff --git a/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
index 770d17fe17c307..e29478e97be02c 100644
--- a/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
+++ b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
@@ -19,7 +19,7 @@
 
 namespace mlir {
 namespace presburger {
-namespace internal {
+namespace public_namespace_name::detail {
 
 // A parametric point is a vector, each of whose elements
 // is an affine function of n parameters. Each row

>From 6592268fdb1d8e31bb795b37b3d63707d312c08d Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sun, 31 Dec 2023 10:25:36 +0530
Subject: [PATCH 10/32] Formatting

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

diff --git a/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
index e29478e97be02c..abf9cce8c9d4d4 100644
--- a/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
+++ b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
@@ -129,7 +129,7 @@ class GeneratingFunction {
   std::vector<std::vector<Point>> denominators;
 };
 
-} // namespace internal
+} // namespace public_namespace_name::detail
 } // namespace presburger
 } // namespace mlir
 

>From 7007cf83615ed479a0d7daab81a2b1eeb7514bbc Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sun, 31 Dec 2023 21:17:54 +0530
Subject: [PATCH 11/32] Documentation

---
 mlir/include/mlir/Analysis/Presburger/Barvinok.h | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index 665227a20fc258..d39d0e704bf4e4 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -22,11 +22,11 @@
 namespace mlir {
 namespace presburger {
 
-// A polyhedron in H-representation is a set of relations
+// A polyhedron in H-representation is a set of inequalities
 // in d variables with integer coefficients.
 using PolyhedronH = IntegerRelation;
 
-// A polyhedron in V-representation is a set of rays, i.e.,
+// A polyhedron in V-representation is a set of rays and points, i.e.,
 // vectors, stored as rows of a matrix.
 using PolyhedronV = IntMatrix;
 
@@ -48,14 +48,21 @@ inline ConeH defineHRep(int num_vars) {
                                                  /*numLocals=*/0));
 }
 
-// Get the index of a cone.
+// Get the index of a cone, i.e., the volume of the parallelepiped
+// spanned by its generators, which is equal to the number of integer
+// points in its fundamental parallelepiped.
+// If the index is 1, the cone is unimodular.
+// Barvinok, A., and J. E. Pommersheim. "An algorithmic theory of lattice points in polyhedra."
+// p. 107
 // If it has more rays than the dimension, return 0.
 MPInt getIndex(ConeV);
 
 // Get the dual of a cone in H-representation, returning its V-representation.
+// This assumes that the input is pointed at the origin; it fails otherwise.
 ConeV getDual(ConeH);
 
 // Get the dual of a cone in V-representation, returning its H-representation.
+// The returned cone is pointed at the origin.
 ConeH getDual(ConeV);
 
 } // namespace presburger

>From 9419d5b426261476d6bfda938b9457a030fe6f39 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sun, 31 Dec 2023 21:20:33 +0530
Subject: [PATCH 12/32] Use getSetSpace

---
 mlir/include/mlir/Analysis/Presburger/Barvinok.h | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index d39d0e704bf4e4..2acf9f68cb3c9e 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -42,10 +42,9 @@ inline ConeH defineHRep(int num_vars) {
   // There are no symbols (we don't work with parametric cones) and no local
   // (existentially quantified) variables.
   // Once the cone is defined, we use `addInequality()` to set inequalities.
-  return ConeH(PresburgerSpace::getRelationSpace(/*numDomain=*/0,
-                                                 /*numRange=*/num_vars,
-                                                 /*numSymbols=*/0,
-                                                 /*numLocals=*/0));
+  return ConeH(PresburgerSpace::getSetSpace(/*numDims=*/num_vars,
+                                            /*numSymbols=*/0,
+                                            /*numLocals=*/0));
 }
 
 // Get the index of a cone, i.e., the volume of the parallelepiped

>From edf909e8945f629abf0c04865d669d130dd390da Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sun, 31 Dec 2023 21:21:28 +0530
Subject: [PATCH 13/32] Clang-format

---
 mlir/include/mlir/Analysis/Presburger/Barvinok.h | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index 2acf9f68cb3c9e..c8d61641a47b5a 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -51,9 +51,8 @@ inline ConeH defineHRep(int num_vars) {
 // spanned by its generators, which is equal to the number of integer
 // points in its fundamental parallelepiped.
 // If the index is 1, the cone is unimodular.
-// Barvinok, A., and J. E. Pommersheim. "An algorithmic theory of lattice points in polyhedra."
-// p. 107
-// If it has more rays than the dimension, return 0.
+// Barvinok, A., and J. E. Pommersheim. "An algorithmic theory of lattice points
+// in polyhedra." p. 107 If it has more rays than the dimension, return 0.
 MPInt getIndex(ConeV);
 
 // Get the dual of a cone in H-representation, returning its V-representation.

>From e5bcf072b98e5bb13ceae52ce44a7e80e87a9141 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sun, 31 Dec 2023 21:47:21 +0530
Subject: [PATCH 14/32] Add newlines

---
 mlir/include/mlir/Analysis/Presburger/Barvinok.h           | 2 +-
 mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h | 2 +-
 mlir/lib/Analysis/Presburger/Barvinok.cpp                  | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index c8d61641a47b5a..c168ddf12be1e8 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -66,4 +66,4 @@ ConeH getDual(ConeV);
 } // namespace presburger
 } // namespace mlir
 
-#endif // MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
\ No newline at end of file
+#endif // MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
diff --git a/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
index abf9cce8c9d4d4..fcc5c8c1dea15c 100644
--- a/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
+++ b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
@@ -133,4 +133,4 @@ class GeneratingFunction {
 } // namespace presburger
 } // namespace mlir
 
-#endif // MLIR_ANALYSIS_PRESBURGER_GENERATINGFUNCTION_H
\ No newline at end of file
+#endif // MLIR_ANALYSIS_PRESBURGER_GENERATINGFUNCTION_H
diff --git a/mlir/lib/Analysis/Presburger/Barvinok.cpp b/mlir/lib/Analysis/Presburger/Barvinok.cpp
index 8c6fc9a6e3f53d..348797a8a3f137 100644
--- a/mlir/lib/Analysis/Presburger/Barvinok.cpp
+++ b/mlir/lib/Analysis/Presburger/Barvinok.cpp
@@ -62,4 +62,4 @@ MPInt mlir::presburger::getIndex(ConeV cone) {
     return MPInt(0);
 
   return cone.determinant();
-}
\ No newline at end of file
+}

>From 3cf91b99ce361eddfd2ed470f7f9d7e1ead3c959 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Thu, 4 Jan 2024 21:38:37 +0530
Subject: [PATCH 15/32] Documentation and var namesg

---
 mlir/include/mlir/Analysis/Presburger/Barvinok.h     |  6 ++++--
 .../mlir/Analysis/Presburger/GeneratingFunction.h    |  2 --
 mlir/lib/Analysis/Presburger/Barvinok.cpp            | 12 ++++++------
 3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index c168ddf12be1e8..cc98f1272bdd45 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -52,11 +52,13 @@ inline ConeH defineHRep(int num_vars) {
 // points in its fundamental parallelepiped.
 // If the index is 1, the cone is unimodular.
 // Barvinok, A., and J. E. Pommersheim. "An algorithmic theory of lattice points
-// in polyhedra." p. 107 If it has more rays than the dimension, return 0.
+// in polyhedra." p. 107
+// If it has more rays than the dimension, return 0.
 MPInt getIndex(ConeV);
 
 // Get the dual of a cone in H-representation, returning its V-representation.
-// This assumes that the input is pointed at the origin; it fails otherwise.
+// This assumes that the input is pointed at the origin; it assert-fails
+// otherwise.
 ConeV getDual(ConeH);
 
 // Get the dual of a cone in V-representation, returning its H-representation.
diff --git a/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
index fcc5c8c1dea15c..f7deba921ea51e 100644
--- a/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
+++ b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
@@ -19,7 +19,6 @@
 
 namespace mlir {
 namespace presburger {
-namespace public_namespace_name::detail {
 
 // A parametric point is a vector, each of whose elements
 // is an affine function of n parameters. Each row
@@ -129,7 +128,6 @@ class GeneratingFunction {
   std::vector<std::vector<Point>> denominators;
 };
 
-} // namespace public_namespace_name::detail
 } // namespace presburger
 } // namespace mlir
 
diff --git a/mlir/lib/Analysis/Presburger/Barvinok.cpp b/mlir/lib/Analysis/Presburger/Barvinok.cpp
index 348797a8a3f137..f3c70aa0b5a1f9 100644
--- a/mlir/lib/Analysis/Presburger/Barvinok.cpp
+++ b/mlir/lib/Analysis/Presburger/Barvinok.cpp
@@ -15,18 +15,18 @@ using namespace presburger;
 // converts it to its dual in V-representation.
 // Essentially we just remove the all-zeroes constant column.
 ConeV mlir::presburger::getDual(ConeH cone) {
-  unsigned inequalities = cone.getNumInequalities();
-  unsigned variables = cone.getNumCols() - 1;
-  ConeV dual(inequalities, variables, 0, 0);
+  unsigned numIneq = cone.getNumInequalities();
+  unsigned numVar = cone.getNumCols() - 1;
+  ConeV dual(numIneq, numVar, 0, 0);
   // Assuming that an inequality of the form
   // a1*x1 + ... + an*xn + b ≥ 0
   // is represented as a row [a1, ..., an, b]
   // and that b = 0.
 
-  for (unsigned i = 0; i < inequalities; i++) {
-    assert(cone.atIneq(i, variables) == 0 &&
+  for (unsigned i = 0; i < numIneq; i++) {
+    assert(cone.atIneq(i, numVar) == 0 &&
            "H-representation of cone is not centred at the origin!");
-    for (unsigned j = 0; j < variables; j++) {
+    for (unsigned j = 0; j < numVar; j++) {
       dual.at(i, j) = cone.atIneq(i, j);
     }
   }

>From b634957c9829564de2c15a599bdaf1f885a2bea0 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Thu, 4 Jan 2024 21:41:09 +0530
Subject: [PATCH 16/32] Namespace detail for Barvinok.h

---
 mlir/include/mlir/Analysis/Presburger/Barvinok.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index cc98f1272bdd45..de7d75aedd5f18 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -21,6 +21,7 @@
 
 namespace mlir {
 namespace presburger {
+namespace detail {
 
 // A polyhedron in H-representation is a set of inequalities
 // in d variables with integer coefficients.
@@ -65,6 +66,7 @@ ConeV getDual(ConeH);
 // The returned cone is pointed at the origin.
 ConeH getDual(ConeV);
 
+} // namespace detail
 } // namespace presburger
 } // namespace mlir
 

>From a23d7e71ac91ad115dda3e181af0a409e07038dc Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Fri, 5 Jan 2024 14:26:24 +0530
Subject: [PATCH 17/32] Update doc

---
 mlir/unittests/Analysis/Presburger/BarvinokTest.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp b/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp
index 2b7f0491d588eb..301b1b200b32e4 100644
--- a/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp
+++ b/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp
@@ -6,10 +6,10 @@
 using namespace mlir;
 using namespace presburger;
 
-// We randomly generate 3 vectors with 4 entries each
-// and define a cone's H-representation using these
-// numbers. We check that the dual contains the same
-// numbers.
+// The following are 3 randomly generated vectors with 4
+// entries each and define a cone's H-representation
+// using these numbers. We check that the dual contains
+// the same numbers.
 // We do the same in the reverse case.
 TEST(BarvinokTest, getDual) {
   ConeH cone1 = defineHRep(4);

>From 5a286e50eb3cf7a5d744ce36153020badf664819 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Fri, 5 Jan 2024 14:54:28 +0530
Subject: [PATCH 18/32] Remove buggy namespace detail and shift GF back

---
 mlir/include/mlir/Analysis/Presburger/Barvinok.h                | 2 --
 .../mlir => lib}/Analysis/Presburger/GeneratingFunction.h       | 0
 2 files changed, 2 deletions(-)
 rename mlir/{include/mlir => lib}/Analysis/Presburger/GeneratingFunction.h (100%)

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index de7d75aedd5f18..cc98f1272bdd45 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -21,7 +21,6 @@
 
 namespace mlir {
 namespace presburger {
-namespace detail {
 
 // A polyhedron in H-representation is a set of inequalities
 // in d variables with integer coefficients.
@@ -66,7 +65,6 @@ ConeV getDual(ConeH);
 // The returned cone is pointed at the origin.
 ConeH getDual(ConeV);
 
-} // namespace detail
 } // namespace presburger
 } // namespace mlir
 
diff --git a/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h b/mlir/lib/Analysis/Presburger/GeneratingFunction.h
similarity index 100%
rename from mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
rename to mlir/lib/Analysis/Presburger/GeneratingFunction.h

>From 6ec7090a66caa73b4122238e355772f96f9b6fca Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Fri, 5 Jan 2024 14:58:39 +0530
Subject: [PATCH 19/32] Add namespace detail

---
 mlir/include/mlir/Analysis/Presburger/Barvinok.h    | 2 ++
 mlir/lib/Analysis/Presburger/Barvinok.cpp           | 7 ++++---
 mlir/unittests/Analysis/Presburger/BarvinokTest.cpp | 1 +
 3 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index cc98f1272bdd45..7165eee82772ad 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -21,6 +21,7 @@
 
 namespace mlir {
 namespace presburger {
+namespace detail {
 
 // A polyhedron in H-representation is a set of inequalities
 // in d variables with integer coefficients.
@@ -65,6 +66,7 @@ ConeV getDual(ConeH);
 // The returned cone is pointed at the origin.
 ConeH getDual(ConeV);
 
+} // namespace mlir::presburger::detail
 } // namespace presburger
 } // namespace mlir
 
diff --git a/mlir/lib/Analysis/Presburger/Barvinok.cpp b/mlir/lib/Analysis/Presburger/Barvinok.cpp
index f3c70aa0b5a1f9..c01a13db2d96ac 100644
--- a/mlir/lib/Analysis/Presburger/Barvinok.cpp
+++ b/mlir/lib/Analysis/Presburger/Barvinok.cpp
@@ -10,11 +10,12 @@
 
 using namespace mlir;
 using namespace presburger;
+using namespace mlir::presburger::detail;
 
 // Assuming that the input cone is pointed at the origin,
 // converts it to its dual in V-representation.
 // Essentially we just remove the all-zeroes constant column.
-ConeV mlir::presburger::getDual(ConeH cone) {
+ConeV mlir::presburger::detail::getDual(ConeH cone) {
   unsigned numIneq = cone.getNumInequalities();
   unsigned numVar = cone.getNumCols() - 1;
   ConeV dual(numIneq, numVar, 0, 0);
@@ -39,7 +40,7 @@ ConeV mlir::presburger::getDual(ConeH cone) {
 // Converts a cone in V-representation to the H-representation
 // of its dual, pointed at the origin (not at the original vertex).
 // Essentially adds a column consisting only of zeroes to the end.
-ConeH mlir::presburger::getDual(ConeV cone) {
+ConeH mlir::presburger::detail::getDual(ConeV cone) {
   unsigned rows = cone.getNumRows();
   unsigned columns = cone.getNumColumns();
   ConeH dual = defineHRep(columns);
@@ -57,7 +58,7 @@ ConeH mlir::presburger::getDual(ConeV cone) {
 
 // Find the index of a cone in V-representation.
 // If there are more rays than variables, return 0.
-MPInt mlir::presburger::getIndex(ConeV cone) {
+MPInt mlir::presburger::detail::getIndex(ConeV cone) {
   if (cone.getNumRows() > cone.getNumColumns())
     return MPInt(0);
 
diff --git a/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp b/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp
index 301b1b200b32e4..ae5bb65571cfc4 100644
--- a/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp
+++ b/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp
@@ -5,6 +5,7 @@
 
 using namespace mlir;
 using namespace presburger;
+using namespace mlir::presburger::detail;
 
 // The following are 3 randomly generated vectors with 4
 // entries each and define a cone's H-representation

>From b8c7e1084d8b43c9dc6904b2010f7366d080a21c Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Fri, 5 Jan 2024 15:01:22 +0530
Subject: [PATCH 20/32] Formatting

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

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index 7165eee82772ad..de7d75aedd5f18 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -66,7 +66,7 @@ ConeV getDual(ConeH);
 // The returned cone is pointed at the origin.
 ConeH getDual(ConeV);
 
-} // namespace mlir::presburger::detail
+} // namespace detail
 } // namespace presburger
 } // namespace mlir
 

>From 71060a8921bbb7855fae6db83ab61c6ab6359248 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Fri, 5 Jan 2024 18:47:09 +0530
Subject: [PATCH 21/32] Fix style

---
 .../mlir/Analysis/Presburger/Barvinok.h       | 64 +++++++++++--------
 mlir/lib/Analysis/Presburger/Barvinok.cpp     | 43 ++++++-------
 .../Analysis/Presburger/BarvinokTest.cpp      | 16 ++---
 3 files changed, 65 insertions(+), 58 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index de7d75aedd5f18..e937f0ea64b40a 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -6,10 +6,16 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// Functions relating to Barvinok's algorithm.
+// Functions relating to an implementation of Barvinok's algorithm.
 // These include functions to manipulate cones (define a cone object, get its
 // dual, and find its index).
 //
+// Barvinok, Alexander, and James E. Pommersheim. "An algorithmic theory of
+// lattice points in polyhedra." New perspectives in algebraic combinatorics
+// 38 (1999): 91-147.
+// Verdoolaege, Sven, et al. "Counting integer points in parametric polytopes
+// using Barvinok's rational functions." Algorithmica 48 (2007): 37-66.
+//
 //===----------------------------------------------------------------------===//
 
 #ifndef MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
@@ -23,48 +29,50 @@ namespace mlir {
 namespace presburger {
 namespace detail {
 
-// A polyhedron in H-representation is a set of inequalities
-// in d variables with integer coefficients.
+/// A polyhedron in H-representation is a set of inequalities
+/// in d variables with integer coefficients.
 using PolyhedronH = IntegerRelation;
 
-// A polyhedron in V-representation is a set of rays and points, i.e.,
-// vectors, stored as rows of a matrix.
+/// A polyhedron in V-representation is a set of rays and points, i.e.,
+/// vectors, stored as rows of a matrix.
 using PolyhedronV = IntMatrix;
 
-// A cone in either representation is a special case of
-// a polyhedron in that representation.
+/// A cone in either representation is a special case of
+/// a polyhedron in that representation.
 using ConeH = PolyhedronH;
 using ConeV = PolyhedronV;
 
 inline ConeH defineHRep(int num_vars) {
-  // We don't distinguish between domain and range variables, so
-  // we set the number of domain variables as 0 and the number of
-  // range variables as the number of actual variables.
-  // There are no symbols (we don't work with parametric cones) and no local
-  // (existentially quantified) variables.
-  // Once the cone is defined, we use `addInequality()` to set inequalities.
+  /// We don't distinguish between domain and range variables, so
+  /// we set the number of domain variables as 0 and the number of
+  /// range variables as the number of actual variables.
+  /// There are no symbols (we don't work with parametric cones) and no local
+  /// (existentially quantified) variables.
+  /// Once the cone is defined, we use `addInequality()` to set inequalities.
   return ConeH(PresburgerSpace::getSetSpace(/*numDims=*/num_vars,
                                             /*numSymbols=*/0,
                                             /*numLocals=*/0));
 }
 
-// Get the index of a cone, i.e., the volume of the parallelepiped
-// spanned by its generators, which is equal to the number of integer
-// points in its fundamental parallelepiped.
-// If the index is 1, the cone is unimodular.
-// Barvinok, A., and J. E. Pommersheim. "An algorithmic theory of lattice points
-// in polyhedra." p. 107
-// If it has more rays than the dimension, return 0.
-MPInt getIndex(ConeV);
+/// Get the index of a cone, i.e., the volume of the parallelepiped
+/// spanned by its generators, which is equal to the number of integer
+/// points in its fundamental parallelepiped.
+/// If the index is 1, the cone is unimodular.
+/// Barvinok, A., and J. E. Pommersheim. "An algorithmic theory of lattice
+/// points in polyhedra." p. 107 If it has more rays than the dimension, return
+/// 0.
+MPInt getIndex(ConeV cone);
 
-// Get the dual of a cone in H-representation, returning its V-representation.
-// This assumes that the input is pointed at the origin; it assert-fails
-// otherwise.
-ConeV getDual(ConeH);
+/// Given a cone in H-representation, return its dual. The dual cone is in
+/// V-representation.
+/// This assumes that the input is pointed at the origin; it assert-fails
+/// otherwise.
+ConeV getDual(ConeH cone);
 
-// Get the dual of a cone in V-representation, returning its H-representation.
-// The returned cone is pointed at the origin.
-ConeH getDual(ConeV);
+/// Given a cone in V-representation, return its dual. The dual cone is in
+/// H-representation.
+/// The returned cone is pointed at the origin.
+ConeH getDual(ConeV cone);
 
 } // namespace detail
 } // namespace presburger
diff --git a/mlir/lib/Analysis/Presburger/Barvinok.cpp b/mlir/lib/Analysis/Presburger/Barvinok.cpp
index c01a13db2d96ac..a857d4a51514f5 100644
--- a/mlir/lib/Analysis/Presburger/Barvinok.cpp
+++ b/mlir/lib/Analysis/Presburger/Barvinok.cpp
@@ -1,4 +1,4 @@
-//===- QuasiPolynomial.cpp - Barvinok's Algorithm ---------------*- C++ -*-===//
+//===- Barvinok.cpp - Barvinok's Algorithm ----------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -12,52 +12,51 @@ using namespace mlir;
 using namespace presburger;
 using namespace mlir::presburger::detail;
 
-// Assuming that the input cone is pointed at the origin,
-// converts it to its dual in V-representation.
-// Essentially we just remove the all-zeroes constant column.
+/// Assuming that the input cone is pointed at the origin,
+/// converts it to its dual in V-representation.
+/// Essentially we just remove the all-zeroes constant column.
 ConeV mlir::presburger::detail::getDual(ConeH cone) {
   unsigned numIneq = cone.getNumInequalities();
   unsigned numVar = cone.getNumCols() - 1;
   ConeV dual(numIneq, numVar, 0, 0);
-  // Assuming that an inequality of the form
-  // a1*x1 + ... + an*xn + b ≥ 0
-  // is represented as a row [a1, ..., an, b]
-  // and that b = 0.
+  /// Assuming that an inequality of the form
+  /// a1*x1 + ... + an*xn + b ≥ 0
+  /// is represented as a row [a1, ..., an, b]
+  /// and that b = 0.
 
-  for (unsigned i = 0; i < numIneq; i++) {
+  for (unsigned i = 0; i < numIneq; ++i) {
     assert(cone.atIneq(i, numVar) == 0 &&
            "H-representation of cone is not centred at the origin!");
-    for (unsigned j = 0; j < numVar; j++) {
+    for (unsigned j = 0; j < numVar; ++j) {
       dual.at(i, j) = cone.atIneq(i, j);
     }
   }
 
-  // Now dual is of the form [ [a1, ..., an] , ... ]
-  // which is the V-representation of the dual.
+  /// Now dual is of the form [ [a1, ..., an] , ... ]
+  /// which is the V-representation of the dual.
   return dual;
 }
 
-// Converts a cone in V-representation to the H-representation
-// of its dual, pointed at the origin (not at the original vertex).
-// Essentially adds a column consisting only of zeroes to the end.
+/// Converts a cone in V-representation to the H-representation
+/// of its dual, pointed at the origin (not at the original vertex).
+/// Essentially adds a column consisting only of zeroes to the end.
 ConeH mlir::presburger::detail::getDual(ConeV cone) {
   unsigned rows = cone.getNumRows();
   unsigned columns = cone.getNumColumns();
   ConeH dual = defineHRep(columns);
-  // Add a new column (for constants) at the end.
-  // This will be initialized to zero.
+  /// Add a new column (for constants) at the end.
+  /// This will be initialized to zero.
   cone.insertColumn(columns);
 
-  for (unsigned i = 0; i < rows; i++)
+  for (unsigned i = 0; i < rows; ++i)
     dual.addInequality(cone.getRow(i));
 
-  // Now dual is of the form [ [a1, ..., an, 0] , ... ]
-  // which is the H-representation of the dual.
+  /// Now dual is of the form [ [a1, ..., an, 0] , ... ]
+  /// which is the H-representation of the dual.
   return dual;
 }
 
-// Find the index of a cone in V-representation.
-// If there are more rays than variables, return 0.
+/// Find the index of a cone in V-representation.
 MPInt mlir::presburger::detail::getIndex(ConeV cone) {
   if (cone.getNumRows() > cone.getNumColumns())
     return MPInt(0);
diff --git a/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp b/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp
index ae5bb65571cfc4..b88baa6c6b48a4 100644
--- a/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp
+++ b/mlir/unittests/Analysis/Presburger/BarvinokTest.cpp
@@ -7,11 +7,11 @@ using namespace mlir;
 using namespace presburger;
 using namespace mlir::presburger::detail;
 
-// The following are 3 randomly generated vectors with 4
-// entries each and define a cone's H-representation
-// using these numbers. We check that the dual contains
-// the same numbers.
-// We do the same in the reverse case.
+/// The following are 3 randomly generated vectors with 4
+/// entries each and define a cone's H-representation
+/// using these numbers. We check that the dual contains
+/// the same numbers.
+/// We do the same in the reverse case.
 TEST(BarvinokTest, getDual) {
   ConeH cone1 = defineHRep(4);
   cone1.addInequality({1, 2, 3, 4, 0});
@@ -35,9 +35,9 @@ TEST(BarvinokTest, getDual) {
   EXPECT_TRUE(dual2.isEqual(expected));
 }
 
-// We randomly generate a nxn matrix to use as a cone
-// with n inequalities in n variables and check for
-// the determinant being equal to the index.
+/// We randomly generate a nxn matrix to use as a cone
+/// with n inequalities in n variables and check for
+/// the determinant being equal to the index.
 TEST(BarvinokTest, getIndex) {
   ConeV cone = makeIntMatrix(3, 3, {{4, 2, 1}, {5, 2, 7}, {4, 1, 6}});
   EXPECT_EQ(getIndex(cone), cone.determinant());

>From e30dbbcd513b58a73faf87872c5ef793c41bf39b Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Fri, 5 Jan 2024 19:00:22 +0530
Subject: [PATCH 22/32] Doc fix

---
 mlir/include/mlir/Analysis/Presburger/Barvinok.h | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index e937f0ea64b40a..a472ef7c1cfa3e 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -10,11 +10,12 @@
 // These include functions to manipulate cones (define a cone object, get its
 // dual, and find its index).
 //
-// Barvinok, Alexander, and James E. Pommersheim. "An algorithmic theory of
-// lattice points in polyhedra." New perspectives in algebraic combinatorics
-// 38 (1999): 91-147.
-// Verdoolaege, Sven, et al. "Counting integer points in parametric polytopes
-// using Barvinok's rational functions." Algorithmica 48 (2007): 37-66.
+// The implementation is based on:
+// 1. Barvinok, Alexander, and James E. Pommersheim. "An algorithmic theory of
+//    lattice points in polyhedra." New perspectives in algebraic combinatorics
+//    38 (1999): 91-147.
+// 2. Verdoolaege, Sven, et al. "Counting integer points in parametric polytopes
+//    using Barvinok's rational functions." Algorithmica 48 (2007): 37-66.
 //
 //===----------------------------------------------------------------------===//
 

>From 097d97dd16ac91904361095f06ef66127412fd01 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Fri, 5 Jan 2024 19:00:46 +0530
Subject: [PATCH 23/32] Formatting

---
 mlir/include/mlir/Analysis/Presburger/Barvinok.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index a472ef7c1cfa3e..ad753e5bb05e15 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -14,8 +14,9 @@
 // 1. Barvinok, Alexander, and James E. Pommersheim. "An algorithmic theory of
 //    lattice points in polyhedra." New perspectives in algebraic combinatorics
 //    38 (1999): 91-147.
-// 2. Verdoolaege, Sven, et al. "Counting integer points in parametric polytopes
-//    using Barvinok's rational functions." Algorithmica 48 (2007): 37-66.
+// 2. Verdoolaege, Sven, et al. "Counting integer points in parametric
+//    polytopes using Barvinok's rational functions." Algorithmica 48 (2007):
+//    37-66.
 //
 //===----------------------------------------------------------------------===//
 

>From d781192c336b9883fb22e1a0a32b72d6584d5aec Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Fri, 5 Jan 2024 19:02:13 +0530
Subject: [PATCH 24/32] Make WIP explicit

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

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index ad753e5bb05e15..362d3ea7cf3160 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -6,7 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// Functions relating to an implementation of Barvinok's algorithm.
+// Implementation of Barvinok's algorithm and related utility functions.
+// Currently a work in progress.
 // These include functions to manipulate cones (define a cone object, get its
 // dual, and find its index).
 //

>From b96b9fb3ca140e98e75f5ebe58781186fcecefb6 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Fri, 5 Jan 2024 19:09:02 +0530
Subject: [PATCH 25/32] Fix comment style

---
 .../mlir/Analysis/Presburger/Barvinok.h       | 12 +++++------
 mlir/lib/Analysis/Presburger/Barvinok.cpp     | 20 +++++++++----------
 2 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index 362d3ea7cf3160..6110a476a633bb 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -46,12 +46,12 @@ using ConeH = PolyhedronH;
 using ConeV = PolyhedronV;
 
 inline ConeH defineHRep(int num_vars) {
-  /// We don't distinguish between domain and range variables, so
-  /// we set the number of domain variables as 0 and the number of
-  /// range variables as the number of actual variables.
-  /// There are no symbols (we don't work with parametric cones) and no local
-  /// (existentially quantified) variables.
-  /// Once the cone is defined, we use `addInequality()` to set inequalities.
+  // We don't distinguish between domain and range variables, so
+  // we set the number of domain variables as 0 and the number of
+  // range variables as the number of actual variables.
+  // There are no symbols (we don't work with parametric cones) and no local
+  // (existentially quantified) variables.
+  // Once the cone is defined, we use `addInequality()` to set inequalities.
   return ConeH(PresburgerSpace::getSetSpace(/*numDims=*/num_vars,
                                             /*numSymbols=*/0,
                                             /*numLocals=*/0));
diff --git a/mlir/lib/Analysis/Presburger/Barvinok.cpp b/mlir/lib/Analysis/Presburger/Barvinok.cpp
index a857d4a51514f5..9152b66968a1f5 100644
--- a/mlir/lib/Analysis/Presburger/Barvinok.cpp
+++ b/mlir/lib/Analysis/Presburger/Barvinok.cpp
@@ -19,10 +19,10 @@ ConeV mlir::presburger::detail::getDual(ConeH cone) {
   unsigned numIneq = cone.getNumInequalities();
   unsigned numVar = cone.getNumCols() - 1;
   ConeV dual(numIneq, numVar, 0, 0);
-  /// Assuming that an inequality of the form
-  /// a1*x1 + ... + an*xn + b ≥ 0
-  /// is represented as a row [a1, ..., an, b]
-  /// and that b = 0.
+  // Assuming that an inequality of the form
+  // a1*x1 + ... + an*xn + b ≥ 0
+  // is represented as a row [a1, ..., an, b]
+  // and that b = 0.
 
   for (unsigned i = 0; i < numIneq; ++i) {
     assert(cone.atIneq(i, numVar) == 0 &&
@@ -32,8 +32,8 @@ ConeV mlir::presburger::detail::getDual(ConeH cone) {
     }
   }
 
-  /// Now dual is of the form [ [a1, ..., an] , ... ]
-  /// which is the V-representation of the dual.
+  // Now dual is of the form [ [a1, ..., an] , ... ]
+  // which is the V-representation of the dual.
   return dual;
 }
 
@@ -44,15 +44,15 @@ ConeH mlir::presburger::detail::getDual(ConeV cone) {
   unsigned rows = cone.getNumRows();
   unsigned columns = cone.getNumColumns();
   ConeH dual = defineHRep(columns);
-  /// Add a new column (for constants) at the end.
-  /// This will be initialized to zero.
+  // Add a new column (for constants) at the end.
+  // This will be initialized to zero.
   cone.insertColumn(columns);
 
   for (unsigned i = 0; i < rows; ++i)
     dual.addInequality(cone.getRow(i));
 
-  /// Now dual is of the form [ [a1, ..., an, 0] , ... ]
-  /// which is the H-representation of the dual.
+  // Now dual is of the form [ [a1, ..., an, 0] , ... ]
+  // which is the H-representation of the dual.
   return dual;
 }
 

>From 3cc29c3ce2e9c5af6bc493eacb06d42f26b2a6a5 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Fri, 5 Jan 2024 21:45:46 +0530
Subject: [PATCH 26/32] Fix variable name

---
 mlir/include/mlir/Analysis/Presburger/Barvinok.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index 6110a476a633bb..15e805860db237 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -45,14 +45,14 @@ using PolyhedronV = IntMatrix;
 using ConeH = PolyhedronH;
 using ConeV = PolyhedronV;
 
-inline ConeH defineHRep(int num_vars) {
+inline ConeH defineHRep(int numVars) {
   // We don't distinguish between domain and range variables, so
   // we set the number of domain variables as 0 and the number of
   // range variables as the number of actual variables.
   // There are no symbols (we don't work with parametric cones) and no local
   // (existentially quantified) variables.
   // Once the cone is defined, we use `addInequality()` to set inequalities.
-  return ConeH(PresburgerSpace::getSetSpace(/*numDims=*/num_vars,
+  return ConeH(PresburgerSpace::getSetSpace(/*numDims=*/numVars,
                                             /*numSymbols=*/0,
                                             /*numLocals=*/0));
 }

>From 8fe3212272ed113eebeac99a35f8a3f9a97f2d3f Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Fri, 5 Jan 2024 21:55:19 +0530
Subject: [PATCH 27/32] Shift GF and make namespace

---
 .../mlir}/Analysis/Presburger/GeneratingFunction.h              | 2 ++
 1 file changed, 2 insertions(+)
 rename mlir/{lib => include/mlir}/Analysis/Presburger/GeneratingFunction.h (99%)

diff --git a/mlir/lib/Analysis/Presburger/GeneratingFunction.h b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
similarity index 99%
rename from mlir/lib/Analysis/Presburger/GeneratingFunction.h
rename to mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
index f7deba921ea51e..318f1a6429a6c0 100644
--- a/mlir/lib/Analysis/Presburger/GeneratingFunction.h
+++ b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
@@ -19,6 +19,7 @@
 
 namespace mlir {
 namespace presburger {
+namespace detail {
 
 // A parametric point is a vector, each of whose elements
 // is an affine function of n parameters. Each row
@@ -128,6 +129,7 @@ class GeneratingFunction {
   std::vector<std::vector<Point>> denominators;
 };
 
+} // namespace detail
 } // namespace presburger
 } // namespace mlir
 

>From f28ec4a9ac4035e8a784f393ce92a84e3616b1a8 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sat, 6 Jan 2024 16:04:20 +0530
Subject: [PATCH 28/32] Add GF test

---
 .../Analysis/Presburger/GeneratingFunction.h  |  2 +-
 .../Analysis/Presburger/CMakeLists.txt        |  1 +
 .../Presburger/GeneratingFunctionTest.cpp     | 30 +++++++++++++++++
 mlir/unittests/Analysis/Presburger/Utils.h    | 32 +++++++++++++++++++
 4 files changed, 64 insertions(+), 1 deletion(-)
 create mode 100644 mlir/unittests/Analysis/Presburger/GeneratingFunctionTest.cpp

diff --git a/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
index 318f1a6429a6c0..0ef095dc80e604 100644
--- a/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
+++ b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
@@ -84,7 +84,7 @@ class GeneratingFunction {
     std::vector<std::vector<Point>> sumDenominators = denominators;
     sumDenominators.insert(sumDenominators.end(), gf.denominators.begin(),
                            gf.denominators.end());
-    return GeneratingFunction(0, sumSigns, sumNumerators, sumDenominators);
+    return GeneratingFunction(numParam, sumSigns, sumNumerators, sumDenominators);
   }
 
   llvm::raw_ostream &print(llvm::raw_ostream &os) const {
diff --git a/mlir/unittests/Analysis/Presburger/CMakeLists.txt b/mlir/unittests/Analysis/Presburger/CMakeLists.txt
index e37133354e53ca..54a841726cd11f 100644
--- a/mlir/unittests/Analysis/Presburger/CMakeLists.txt
+++ b/mlir/unittests/Analysis/Presburger/CMakeLists.txt
@@ -1,5 +1,6 @@
 add_mlir_unittest(MLIRPresburgerTests
   FractionTest.cpp
+  GeneratingFunctionTest.cpp
   IntegerPolyhedronTest.cpp
   IntegerRelationTest.cpp
   LinearTransformTest.cpp
diff --git a/mlir/unittests/Analysis/Presburger/GeneratingFunctionTest.cpp b/mlir/unittests/Analysis/Presburger/GeneratingFunctionTest.cpp
new file mode 100644
index 00000000000000..bb3345db6240a0
--- /dev/null
+++ b/mlir/unittests/Analysis/Presburger/GeneratingFunctionTest.cpp
@@ -0,0 +1,30 @@
+//===- MatrixTest.cpp - Tests for QuasiPolynomial -------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Analysis/Presburger/GeneratingFunction.h"
+#include "./Utils.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace mlir;
+using namespace presburger;
+using namespace mlir::presburger::detail;
+
+TEST(GeneratingFunctionTest, sum) {
+  GeneratingFunction gf1(2, {1, -1},
+                         {makeFracMatrix(2, 3, {{1, 2, 5}, {7, 2, 6}}), makeFracMatrix(2, 3, {{5, 2, 5}, {3, 7, 2}})},
+                         {{{3, 6}, {7, 2}}, {{2, 8}, {6, 3}}});
+  GeneratingFunction gf2(2, {1, 1},
+                         {makeFracMatrix(2, 3, {{6, 2, 1}, {4, 2, 6}}), makeFracMatrix(2, 3, {{3, 2, 6}, {9, 2, 5}})},
+                         {{{3, 7}, {5, 1}}, {{5, 2}, {6, 2}}});
+                        
+  GeneratingFunction sum = gf1 + gf2;
+  EXPECT_EQ_REPR_GENERATINGFUNCTION(sum, GeneratingFunction(2, {1, -1, 1, 1},
+    {makeFracMatrix(2, 3, {{1, 2, 5}, {7, 2, 6}}), makeFracMatrix(2, 3, {{5, 2, 5}, {3, 7, 2}}), makeFracMatrix(2, 3, {{6, 2, 1}, {4, 2, 6}}), makeFracMatrix(2, 3, {{3, 2, 6}, {9, 2, 5}})},
+                    {{{3, 6}, {7, 2}}, {{2, 8}, {6, 3}}, {{3, 7}, {5, 1}}, {{5, 2}, {6, 2}}}));
+}
\ No newline at end of file
diff --git a/mlir/unittests/Analysis/Presburger/Utils.h b/mlir/unittests/Analysis/Presburger/Utils.h
index 2a9966c7ce2ea5..38c44aec4047f0 100644
--- a/mlir/unittests/Analysis/Presburger/Utils.h
+++ b/mlir/unittests/Analysis/Presburger/Utils.h
@@ -13,6 +13,7 @@
 #ifndef MLIR_UNITTESTS_ANALYSIS_PRESBURGER_UTILS_H
 #define MLIR_UNITTESTS_ANALYSIS_PRESBURGER_UTILS_H
 
+#include "mlir/Analysis/Presburger/GeneratingFunction.h"
 #include "mlir/Analysis/Presburger/IntegerRelation.h"
 #include "mlir/Analysis/Presburger/Matrix.h"
 #include "mlir/Analysis/Presburger/PWMAFunction.h"
@@ -72,6 +73,37 @@ inline void EXPECT_EQ_FRAC_MATRIX(FracMatrix a, FracMatrix b) {
       EXPECT_EQ(a(row, col), b(row, col));
 }
 
+// Check the coefficients (in order) of two generating functions.
+// Note that this is not a true equality check.
+inline void EXPECT_EQ_REPR_GENERATINGFUNCTION(detail::GeneratingFunction a, detail::GeneratingFunction b) {
+  EXPECT_EQ(a.getNumParams(), b.getNumParams());
+
+  SmallVector<int> aSigns = a.getSigns();
+  SmallVector<int> bSigns = b.getSigns();
+  EXPECT_EQ(aSigns.size(), bSigns.size());
+  for (unsigned i = 0, e = aSigns.size(); i < e; i++)
+    EXPECT_EQ(aSigns[i], bSigns[i]);
+
+  std::vector<detail::ParamPoint> aNums = a.getNumerators();
+  std::vector<detail::ParamPoint> bNums = b.getNumerators();
+  EXPECT_EQ(aNums.size(), bNums.size());
+  for (unsigned i = 0, e = aNums.size(); i < e; i++)
+    EXPECT_EQ_FRAC_MATRIX(aNums[i], bNums[i]);
+
+  std::vector<std::vector<detail::Point>> aDens = a.getDenominators();
+  std::vector<std::vector<detail::Point>> bDens = b.getDenominators();
+  EXPECT_EQ(aDens.size(), bDens.size());
+  for (unsigned i = 0, e = aDens.size(); i < e; i++) {
+    EXPECT_EQ(aDens[i].size(), bDens[i].size());
+    for (unsigned j = 0, f = aDens[i].size(); j < f; j++) {
+      EXPECT_EQ(aDens[i][j].size(), bDens[i][j].size());
+      for (unsigned k = 0, g = aDens[i][j].size(); k < g; k++) {
+        EXPECT_EQ(aDens[i][j][k], bDens[i][j][k]);
+      }
+    }
+  }
+}
+
 // Check the coefficients (in order) of two quasipolynomials.
 // Note that this is not a true equality check.
 inline void EXPECT_EQ_REPR_QUASIPOLYNOMIAL(QuasiPolynomial a, QuasiPolynomial b) {

>From 364ca80e2988abd3b521bb7886a17b0088dce8f7 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sat, 6 Jan 2024 16:05:25 +0530
Subject: [PATCH 29/32] Formatting

---
 .../Presburger/GeneratingFunctionTest.cpp     | 21 +++++++++++++------
 mlir/unittests/Analysis/Presburger/Utils.h    |  6 ++++--
 2 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/mlir/unittests/Analysis/Presburger/GeneratingFunctionTest.cpp b/mlir/unittests/Analysis/Presburger/GeneratingFunctionTest.cpp
index bb3345db6240a0..c2701a441efd04 100644
--- a/mlir/unittests/Analysis/Presburger/GeneratingFunctionTest.cpp
+++ b/mlir/unittests/Analysis/Presburger/GeneratingFunctionTest.cpp
@@ -17,14 +17,23 @@ using namespace mlir::presburger::detail;
 
 TEST(GeneratingFunctionTest, sum) {
   GeneratingFunction gf1(2, {1, -1},
-                         {makeFracMatrix(2, 3, {{1, 2, 5}, {7, 2, 6}}), makeFracMatrix(2, 3, {{5, 2, 5}, {3, 7, 2}})},
+                         {makeFracMatrix(2, 3, {{1, 2, 5}, {7, 2, 6}}),
+                          makeFracMatrix(2, 3, {{5, 2, 5}, {3, 7, 2}})},
                          {{{3, 6}, {7, 2}}, {{2, 8}, {6, 3}}});
   GeneratingFunction gf2(2, {1, 1},
-                         {makeFracMatrix(2, 3, {{6, 2, 1}, {4, 2, 6}}), makeFracMatrix(2, 3, {{3, 2, 6}, {9, 2, 5}})},
+                         {makeFracMatrix(2, 3, {{6, 2, 1}, {4, 2, 6}}),
+                          makeFracMatrix(2, 3, {{3, 2, 6}, {9, 2, 5}})},
                          {{{3, 7}, {5, 1}}, {{5, 2}, {6, 2}}});
-                        
+
   GeneratingFunction sum = gf1 + gf2;
-  EXPECT_EQ_REPR_GENERATINGFUNCTION(sum, GeneratingFunction(2, {1, -1, 1, 1},
-    {makeFracMatrix(2, 3, {{1, 2, 5}, {7, 2, 6}}), makeFracMatrix(2, 3, {{5, 2, 5}, {3, 7, 2}}), makeFracMatrix(2, 3, {{6, 2, 1}, {4, 2, 6}}), makeFracMatrix(2, 3, {{3, 2, 6}, {9, 2, 5}})},
-                    {{{3, 6}, {7, 2}}, {{2, 8}, {6, 3}}, {{3, 7}, {5, 1}}, {{5, 2}, {6, 2}}}));
+  EXPECT_EQ_REPR_GENERATINGFUNCTION(
+      sum, GeneratingFunction(2, {1, -1, 1, 1},
+                              {makeFracMatrix(2, 3, {{1, 2, 5}, {7, 2, 6}}),
+                               makeFracMatrix(2, 3, {{5, 2, 5}, {3, 7, 2}}),
+                               makeFracMatrix(2, 3, {{6, 2, 1}, {4, 2, 6}}),
+                               makeFracMatrix(2, 3, {{3, 2, 6}, {9, 2, 5}})},
+                              {{{3, 6}, {7, 2}},
+                               {{2, 8}, {6, 3}},
+                               {{3, 7}, {5, 1}},
+                               {{5, 2}, {6, 2}}}));
 }
\ No newline at end of file
diff --git a/mlir/unittests/Analysis/Presburger/Utils.h b/mlir/unittests/Analysis/Presburger/Utils.h
index 38c44aec4047f0..6b00898a7e2749 100644
--- a/mlir/unittests/Analysis/Presburger/Utils.h
+++ b/mlir/unittests/Analysis/Presburger/Utils.h
@@ -75,7 +75,8 @@ inline void EXPECT_EQ_FRAC_MATRIX(FracMatrix a, FracMatrix b) {
 
 // Check the coefficients (in order) of two generating functions.
 // Note that this is not a true equality check.
-inline void EXPECT_EQ_REPR_GENERATINGFUNCTION(detail::GeneratingFunction a, detail::GeneratingFunction b) {
+inline void EXPECT_EQ_REPR_GENERATINGFUNCTION(detail::GeneratingFunction a,
+                                              detail::GeneratingFunction b) {
   EXPECT_EQ(a.getNumParams(), b.getNumParams());
 
   SmallVector<int> aSigns = a.getSigns();
@@ -106,7 +107,8 @@ inline void EXPECT_EQ_REPR_GENERATINGFUNCTION(detail::GeneratingFunction a, deta
 
 // Check the coefficients (in order) of two quasipolynomials.
 // Note that this is not a true equality check.
-inline void EXPECT_EQ_REPR_QUASIPOLYNOMIAL(QuasiPolynomial a, QuasiPolynomial b) {
+inline void EXPECT_EQ_REPR_QUASIPOLYNOMIAL(QuasiPolynomial a,
+                                           QuasiPolynomial b) {
   EXPECT_EQ(a.getNumInputs(), b.getNumInputs());
 
   SmallVector<Fraction> aCoeffs = a.getCoefficients(),

>From bfda840eaca761f091b42027203d3cacdc6a4e90 Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sat, 6 Jan 2024 16:08:16 +0530
Subject: [PATCH 30/32] Formatting

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

diff --git a/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
index 0ef095dc80e604..4dd692c251563b 100644
--- a/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
+++ b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
@@ -84,7 +84,8 @@ class GeneratingFunction {
     std::vector<std::vector<Point>> sumDenominators = denominators;
     sumDenominators.insert(sumDenominators.end(), gf.denominators.begin(),
                            gf.denominators.end());
-    return GeneratingFunction(numParam, sumSigns, sumNumerators, sumDenominators);
+    return GeneratingFunction(numParam, sumSigns, sumNumerators,
+                              sumDenominators);
   }
 
   llvm::raw_ostream &print(llvm::raw_ostream &os) const {

>From dad5d41652fbfccaf6da6d41981bf0fe7307d69b Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sat, 6 Jan 2024 16:15:08 +0530
Subject: [PATCH 31/32] Newline

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

diff --git a/mlir/unittests/Analysis/Presburger/GeneratingFunctionTest.cpp b/mlir/unittests/Analysis/Presburger/GeneratingFunctionTest.cpp
index c2701a441efd04..5df1a5a0f64c05 100644
--- a/mlir/unittests/Analysis/Presburger/GeneratingFunctionTest.cpp
+++ b/mlir/unittests/Analysis/Presburger/GeneratingFunctionTest.cpp
@@ -36,4 +36,4 @@ TEST(GeneratingFunctionTest, sum) {
                                {{2, 8}, {6, 3}},
                                {{3, 7}, {5, 1}},
                                {{5, 2}, {6, 2}}}));
-}
\ No newline at end of file
+}

>From 5094545a399f8c5741a6788a8fcd4946b027006c Mon Sep 17 00:00:00 2001
From: Abhinav271828 <abhinav.m at research.iiit.ac.in>
Date: Sat, 6 Jan 2024 17:56:30 +0530
Subject: [PATCH 32/32] Initial commit

---
 .../mlir/Analysis/Presburger/Barvinok.h       |  6 ++
 mlir/lib/Analysis/Presburger/Barvinok.cpp     | 69 +++++++++++++++++++
 2 files changed, 75 insertions(+)

diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
index 15e805860db237..93b29e2d718e59 100644
--- a/mlir/include/mlir/Analysis/Presburger/Barvinok.h
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -24,6 +24,7 @@
 #ifndef MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
 #define MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
 
+#include "mlir/Analysis/Presburger/GeneratingFunction.h"
 #include "mlir/Analysis/Presburger/IntegerRelation.h"
 #include "mlir/Analysis/Presburger/Matrix.h"
 #include <optional>
@@ -77,6 +78,11 @@ ConeV getDual(ConeH cone);
 /// The returned cone is pointed at the origin.
 ConeH getDual(ConeV cone);
 
+/// Compute the generating function for a unimodular cone.
+/// It assert-fails if the input cone is not unimodular.
+GeneratingFunction unimodularConeGeneratingFunction(ParamPoint vertex, int sign,
+                                                    ConeH cone);
+
 } // namespace detail
 } // namespace presburger
 } // namespace mlir
diff --git a/mlir/lib/Analysis/Presburger/Barvinok.cpp b/mlir/lib/Analysis/Presburger/Barvinok.cpp
index 9152b66968a1f5..31fafbda1129bf 100644
--- a/mlir/lib/Analysis/Presburger/Barvinok.cpp
+++ b/mlir/lib/Analysis/Presburger/Barvinok.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "mlir/Analysis/Presburger/Barvinok.h"
+#include "mlir/Analysis/Presburger/GeneratingFunction.h"
 
 using namespace mlir;
 using namespace presburger;
@@ -63,3 +64,71 @@ MPInt mlir::presburger::detail::getIndex(ConeV cone) {
 
   return cone.determinant();
 }
+
+/// Compute the generating function for a unimodular cone.
+GeneratingFunction mlir::presburger::detail::unimodularConeGeneratingFunction(
+    ParamPoint vertex, int sign, ConeH cone) {
+  // `cone` is assumed to be unimodular.
+  assert(getIndex(getDual(cone)) == 1 && "input cone is not unimodular!");
+
+  unsigned numVar = cone.getNumVars();
+  unsigned numIneq = cone.getNumInequalities();
+
+  // Thus its ray matrix, U, is the inverse of the
+  // transpose of its inequality matrix, `cone`.
+  FracMatrix transp(numVar, numIneq);
+  for (unsigned i = 0; i < numVar; i++)
+    for (unsigned j = 0; j < numIneq; j++)
+      transp(j, i) = Fraction(cone.atIneq(i, j), 1);
+
+  FracMatrix generators(numVar, numIneq);
+  transp.determinant(&generators); // This is the U-matrix.
+
+  // The denominators of the generating function
+  // are given by the generators of the cone, i.e.,
+  // the rows of the matrix U.
+  std::vector<Point> denominator(numIneq);
+  ArrayRef<Fraction> row;
+  for (unsigned i = 0; i < numVar; i++) {
+    row = generators.getRow(i);
+    denominator[i] = Point(row);
+  }
+
+  // The vertex is v : [d, n+1].
+  // We need to find affine functions of parameters λi(p)
+  // such that v = Σ λi(p)*ui.
+  // The λi are given by the columns of Λ = v^T @ U^{-1} = v^T @ transp.
+  // Then the numerator will be Σ -floor(-λi(p))*u_i.
+  // Thus we store the numerator as the affine function -Λ,
+  // since the generators are already stored in the denominator.
+  // Note that the outer -1 will have to be accounted for, as it is not stored.
+  // See end for an example.
+
+  unsigned numColumns = vertex.getNumColumns();
+  unsigned numRows = vertex.getNumRows();
+  ParamPoint numerator(numColumns, numRows);
+  SmallVector<Fraction> ithCol(numRows);
+  for (unsigned i = 0; i < numColumns; i++) {
+    for (unsigned j = 0; j < numRows; j++)
+      ithCol[j] = vertex(j, i);
+    numerator.setRow(i, transp.preMultiplyWithRow(ithCol));
+    numerator.negateRow(i);
+  }
+
+  return GeneratingFunction(numColumns, SmallVector<int>(1, sign),
+                            std::vector({numerator}),
+                            std::vector({denominator}));
+
+  // Suppose the vertex is given by the matrix [ 2  2   0], with 2 params
+  //                                           [-1 -1/2 1]
+  // and the cone has H-representation [0  -1] => U-matrix [ 2 -1]
+  //                                   [-1 -2]             [-1  0]
+  // Therefore Λ will be given by [ 1    0 ] and the negation of this will be
+  // stored as the numerator.
+  //                              [ 1/2 -1 ]
+  //                              [ -1  -2 ]
+
+  // Algebraically, the numerator exponent is
+  // [ -2 ⌊ -N - M/2 +1 ⌋ + 1 ⌊ 0 +M +2 ⌋ ] -> first  COLUMN of U is [2, -1]
+  // [  1 ⌊ -N - M/2 +1 ⌋ + 0 ⌊ 0 +M +2 ⌋ ] -> second COLUMN of U is [-1, 0]
+}



More information about the cfe-commits mailing list