Skip to content

Commit 1940e2c

Browse files
author
git apple-llvm automerger
committed
Merge commit '4c8dbb681389' from llvm.org/main into next
2 parents ebf7e05 + 4c8dbb6 commit 1940e2c

File tree

5 files changed

+199
-0
lines changed

5 files changed

+199
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//===- Barvinok.h - Barvinok's Algorithm ------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Implementation of Barvinok's algorithm and related utility functions.
10+
// Currently a work in progress.
11+
// These include functions to manipulate cones (define a cone object, get its
12+
// dual, and find its index).
13+
//
14+
// The implementation is based on:
15+
// 1. Barvinok, Alexander, and James E. Pommersheim. "An algorithmic theory of
16+
// lattice points in polyhedra." New perspectives in algebraic combinatorics
17+
// 38 (1999): 91-147.
18+
// 2. Verdoolaege, Sven, et al. "Counting integer points in parametric
19+
// polytopes using Barvinok's rational functions." Algorithmica 48 (2007):
20+
// 37-66.
21+
//
22+
//===----------------------------------------------------------------------===//
23+
24+
#ifndef MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
25+
#define MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
26+
27+
#include "mlir/Analysis/Presburger/IntegerRelation.h"
28+
#include "mlir/Analysis/Presburger/Matrix.h"
29+
#include <optional>
30+
31+
namespace mlir {
32+
namespace presburger {
33+
namespace detail {
34+
35+
/// A polyhedron in H-representation is a set of inequalities
36+
/// in d variables with integer coefficients.
37+
using PolyhedronH = IntegerRelation;
38+
39+
/// A polyhedron in V-representation is a set of rays and points, i.e.,
40+
/// vectors, stored as rows of a matrix.
41+
using PolyhedronV = IntMatrix;
42+
43+
/// A cone in either representation is a special case of
44+
/// a polyhedron in that representation.
45+
using ConeH = PolyhedronH;
46+
using ConeV = PolyhedronV;
47+
48+
inline ConeH defineHRep(int numVars) {
49+
// We don't distinguish between domain and range variables, so
50+
// we set the number of domain variables as 0 and the number of
51+
// range variables as the number of actual variables.
52+
// There are no symbols (we don't work with parametric cones) and no local
53+
// (existentially quantified) variables.
54+
// Once the cone is defined, we use `addInequality()` to set inequalities.
55+
return ConeH(PresburgerSpace::getSetSpace(/*numDims=*/numVars,
56+
/*numSymbols=*/0,
57+
/*numLocals=*/0));
58+
}
59+
60+
/// Get the index of a cone, i.e., the volume of the parallelepiped
61+
/// spanned by its generators, which is equal to the number of integer
62+
/// points in its fundamental parallelepiped.
63+
/// If the index is 1, the cone is unimodular.
64+
/// Barvinok, A., and J. E. Pommersheim. "An algorithmic theory of lattice
65+
/// points in polyhedra." p. 107 If it has more rays than the dimension, return
66+
/// 0.
67+
MPInt getIndex(ConeV cone);
68+
69+
/// Given a cone in H-representation, return its dual. The dual cone is in
70+
/// V-representation.
71+
/// This assumes that the input is pointed at the origin; it assert-fails
72+
/// otherwise.
73+
ConeV getDual(ConeH cone);
74+
75+
/// Given a cone in V-representation, return its dual. The dual cone is in
76+
/// H-representation.
77+
/// The returned cone is pointed at the origin.
78+
ConeH getDual(ConeV cone);
79+
80+
} // namespace detail
81+
} // namespace presburger
82+
} // namespace mlir
83+
84+
#endif // MLIR_ANALYSIS_PRESBURGER_BARVINOK_H
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//===- Barvinok.cpp - Barvinok's Algorithm ----------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "mlir/Analysis/Presburger/Barvinok.h"
10+
11+
using namespace mlir;
12+
using namespace presburger;
13+
using namespace mlir::presburger::detail;
14+
15+
/// Assuming that the input cone is pointed at the origin,
16+
/// converts it to its dual in V-representation.
17+
/// Essentially we just remove the all-zeroes constant column.
18+
ConeV mlir::presburger::detail::getDual(ConeH cone) {
19+
unsigned numIneq = cone.getNumInequalities();
20+
unsigned numVar = cone.getNumCols() - 1;
21+
ConeV dual(numIneq, numVar, 0, 0);
22+
// Assuming that an inequality of the form
23+
// a1*x1 + ... + an*xn + b ≥ 0
24+
// is represented as a row [a1, ..., an, b]
25+
// and that b = 0.
26+
27+
for (unsigned i = 0; i < numIneq; ++i) {
28+
assert(cone.atIneq(i, numVar) == 0 &&
29+
"H-representation of cone is not centred at the origin!");
30+
for (unsigned j = 0; j < numVar; ++j) {
31+
dual.at(i, j) = cone.atIneq(i, j);
32+
}
33+
}
34+
35+
// Now dual is of the form [ [a1, ..., an] , ... ]
36+
// which is the V-representation of the dual.
37+
return dual;
38+
}
39+
40+
/// Converts a cone in V-representation to the H-representation
41+
/// of its dual, pointed at the origin (not at the original vertex).
42+
/// Essentially adds a column consisting only of zeroes to the end.
43+
ConeH mlir::presburger::detail::getDual(ConeV cone) {
44+
unsigned rows = cone.getNumRows();
45+
unsigned columns = cone.getNumColumns();
46+
ConeH dual = defineHRep(columns);
47+
// Add a new column (for constants) at the end.
48+
// This will be initialized to zero.
49+
cone.insertColumn(columns);
50+
51+
for (unsigned i = 0; i < rows; ++i)
52+
dual.addInequality(cone.getRow(i));
53+
54+
// Now dual is of the form [ [a1, ..., an, 0] , ... ]
55+
// which is the H-representation of the dual.
56+
return dual;
57+
}
58+
59+
/// Find the index of a cone in V-representation.
60+
MPInt mlir::presburger::detail::getIndex(ConeV cone) {
61+
if (cone.getNumRows() > cone.getNumColumns())
62+
return MPInt(0);
63+
64+
return cone.determinant();
65+
}

mlir/lib/Analysis/Presburger/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_mlir_library(MLIRPresburger
2+
Barvinok.cpp
23
IntegerRelation.cpp
34
LinearTransform.cpp
45
Matrix.cpp
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include "mlir/Analysis/Presburger/Barvinok.h"
2+
#include "./Utils.h"
3+
#include <gmock/gmock.h>
4+
#include <gtest/gtest.h>
5+
6+
using namespace mlir;
7+
using namespace presburger;
8+
using namespace mlir::presburger::detail;
9+
10+
/// The following are 3 randomly generated vectors with 4
11+
/// entries each and define a cone's H-representation
12+
/// using these numbers. We check that the dual contains
13+
/// the same numbers.
14+
/// We do the same in the reverse case.
15+
TEST(BarvinokTest, getDual) {
16+
ConeH cone1 = defineHRep(4);
17+
cone1.addInequality({1, 2, 3, 4, 0});
18+
cone1.addInequality({3, 4, 2, 5, 0});
19+
cone1.addInequality({6, 2, 6, 1, 0});
20+
21+
ConeV dual1 = getDual(cone1);
22+
23+
EXPECT_EQ_INT_MATRIX(
24+
dual1, makeIntMatrix(3, 4, {{1, 2, 3, 4}, {3, 4, 2, 5}, {6, 2, 6, 1}}));
25+
26+
ConeV cone2 = makeIntMatrix(3, 4, {{3, 6, 1, 5}, {3, 1, 7, 2}, {9, 3, 2, 7}});
27+
28+
ConeH dual2 = getDual(cone2);
29+
30+
ConeH expected = defineHRep(4);
31+
expected.addInequality({3, 6, 1, 5, 0});
32+
expected.addInequality({3, 1, 7, 2, 0});
33+
expected.addInequality({9, 3, 2, 7, 0});
34+
35+
EXPECT_TRUE(dual2.isEqual(expected));
36+
}
37+
38+
/// We randomly generate a nxn matrix to use as a cone
39+
/// with n inequalities in n variables and check for
40+
/// the determinant being equal to the index.
41+
TEST(BarvinokTest, getIndex) {
42+
ConeV cone = makeIntMatrix(3, 3, {{4, 2, 1}, {5, 2, 7}, {4, 1, 6}});
43+
EXPECT_EQ(getIndex(cone), cone.determinant());
44+
45+
cone = makeIntMatrix(
46+
4, 4, {{4, 2, 5, 1}, {4, 1, 3, 6}, {8, 2, 5, 6}, {5, 2, 5, 7}});
47+
EXPECT_EQ(getIndex(cone), cone.determinant());
48+
}

mlir/unittests/Analysis/Presburger/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_mlir_unittest(MLIRPresburgerTests
2+
BarvinokTest.cpp
23
FractionTest.cpp
34
GeneratingFunctionTest.cpp
45
IntegerPolyhedronTest.cpp

0 commit comments

Comments
 (0)