[Mlir-commits] [mlir] [MLIR][Presburger] Definitions for basic functions related to cones (PR #76650)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Thu Jan 4 05:00:15 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir-presburger

Author: None (Abhinav271828)

<details>
<summary>Changes</summary>

We add some basic type aliases and function definitions relating to cones for Barvinok's algorithm.
These include functions to get the dual of a cone and find its index.

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


6 Files Affected:

- (added) mlir/include/mlir/Analysis/Presburger/Barvinok.h (+69) 
- (renamed) mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h (+2) 
- (added) mlir/lib/Analysis/Presburger/Barvinok.cpp (+65) 
- (modified) mlir/lib/Analysis/Presburger/CMakeLists.txt (+1) 
- (added) mlir/unittests/Analysis/Presburger/BarvinokTest.cpp (+47) 
- (modified) mlir/unittests/Analysis/Presburger/CMakeLists.txt (+1) 


``````````diff
diff --git a/mlir/include/mlir/Analysis/Presburger/Barvinok.h b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
new file mode 100644
index 00000000000000..c168ddf12be1e8
--- /dev/null
+++ b/mlir/include/mlir/Analysis/Presburger/Barvinok.h
@@ -0,0 +1,69 @@
+//===- 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/IntegerRelation.h"
+#include "mlir/Analysis/Presburger/Matrix.h"
+#include <optional>
+
+namespace mlir {
+namespace presburger {
+
+// 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.
+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_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.
+  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 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
+} // namespace mlir
+
+#endif // MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
diff --git a/mlir/lib/Analysis/Presburger/GeneratingFunction.h b/mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
similarity index 98%
rename from mlir/lib/Analysis/Presburger/GeneratingFunction.h
rename to mlir/include/mlir/Analysis/Presburger/GeneratingFunction.h
index f7deba921ea51e..fcc5c8c1dea15c 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 public_namespace_name::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 public_namespace_name::detail
 } // namespace presburger
 } // namespace mlir
 
diff --git a/mlir/lib/Analysis/Presburger/Barvinok.cpp b/mlir/lib/Analysis/Presburger/Barvinok.cpp
new file mode 100644
index 00000000000000..348797a8a3f137
--- /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) {
+  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(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);
+    }
+  }
+
+  // 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) {
+  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.
+  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) {
+  if (cone.getNumRows() > cone.getNumColumns())
+    return MPInt(0);
+
+  return cone.determinant();
+}
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
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

``````````

</details>


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


More information about the Mlir-commits mailing list