1d5a29442SArjun P //===- PWMAFunction.cpp - MLIR PWMAFunction Class -------------------------===//
2d5a29442SArjun P //
3d5a29442SArjun P // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4d5a29442SArjun P // See https://llvm.org/LICENSE.txt for license information.
5d5a29442SArjun P // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d5a29442SArjun P //
7d5a29442SArjun P //===----------------------------------------------------------------------===//
8d5a29442SArjun P
9d5a29442SArjun P #include "mlir/Analysis/Presburger/PWMAFunction.h"
10d5a29442SArjun P #include "mlir/Analysis/Presburger/Simplex.h"
11d5a29442SArjun P
12d5a29442SArjun P using namespace mlir;
130c1f6865SGroverkss using namespace presburger;
14d5a29442SArjun P
15d5a29442SArjun P // Return the result of subtracting the two given vectors pointwise.
16d5a29442SArjun P // The vectors must be of the same size.
17d5a29442SArjun P // e.g., [3, 4, 6] - [2, 5, 1] = [1, -1, 5].
subtract(ArrayRef<int64_t> vecA,ArrayRef<int64_t> vecB)18d5a29442SArjun P static SmallVector<int64_t, 8> subtract(ArrayRef<int64_t> vecA,
19d5a29442SArjun P ArrayRef<int64_t> vecB) {
20d5a29442SArjun P assert(vecA.size() == vecB.size() &&
21d5a29442SArjun P "Cannot subtract vectors of differing lengths!");
22d5a29442SArjun P SmallVector<int64_t, 8> result;
23d5a29442SArjun P result.reserve(vecA.size());
24d5a29442SArjun P for (unsigned i = 0, e = vecA.size(); i < e; ++i)
25d5a29442SArjun P result.push_back(vecA[i] - vecB[i]);
26d5a29442SArjun P return result;
27d5a29442SArjun P }
28d5a29442SArjun P
getDomain() const29d5a29442SArjun P PresburgerSet PWMAFunction::getDomain() const {
30a5a598beSGroverkss PresburgerSet domain = PresburgerSet::getEmpty(getSpace());
31d5a29442SArjun P for (const MultiAffineFunction &piece : pieces)
32abc2c230SGroverkss domain.unionInPlace(piece.getDomain());
33d5a29442SArjun P return domain;
34d5a29442SArjun P }
35d5a29442SArjun P
36d5a29442SArjun P Optional<SmallVector<int64_t, 8>>
valueAt(ArrayRef<int64_t> point) const37d5a29442SArjun P MultiAffineFunction::valueAt(ArrayRef<int64_t> point) const {
38d95140a5SGroverkss assert(point.size() == domainSet.getNumDimAndSymbolVars() &&
394418669fSArjun P "Point has incorrect dimensionality!");
40d5a29442SArjun P
414418669fSArjun P Optional<SmallVector<int64_t, 8>> maybeLocalValues =
424418669fSArjun P getDomain().containsPointNoLocal(point);
434418669fSArjun P if (!maybeLocalValues)
44d5a29442SArjun P return {};
45d5a29442SArjun P
46d5a29442SArjun P // The point lies in the domain, so we need to compute the output value.
474418669fSArjun P SmallVector<int64_t, 8> pointHomogenous{llvm::to_vector(point)};
484418669fSArjun P // The given point didn't include the values of locals which the output is a
494418669fSArjun P // function of; we have computed one possible set of values and use them
50d95140a5SGroverkss // here. The function is not allowed to have local vars that take more than
514418669fSArjun P // one possible value.
524418669fSArjun P pointHomogenous.append(*maybeLocalValues);
53d5a29442SArjun P // The matrix `output` has an affine expression in the ith row, corresponding
54d5a29442SArjun P // to the expression for the ith value in the output vector. The last column
55d5a29442SArjun P // of the matrix contains the constant term. Let v be the input point with
56d5a29442SArjun P // a 1 appended at the end. We can see that output * v gives the desired
57d5a29442SArjun P // output vector.
58094ad066SArjun P pointHomogenous.emplace_back(1);
59d5a29442SArjun P SmallVector<int64_t, 8> result =
60d5a29442SArjun P output.postMultiplyWithColumn(pointHomogenous);
61d5a29442SArjun P assert(result.size() == getNumOutputs());
62d5a29442SArjun P return result;
63d5a29442SArjun P }
64d5a29442SArjun P
65d5a29442SArjun P Optional<SmallVector<int64_t, 8>>
valueAt(ArrayRef<int64_t> point) const66d5a29442SArjun P PWMAFunction::valueAt(ArrayRef<int64_t> point) const {
67d5a29442SArjun P assert(point.size() == getNumInputs() &&
68d5a29442SArjun P "Point has incorrect dimensionality!");
69d5a29442SArjun P for (const MultiAffineFunction &piece : pieces)
70d5a29442SArjun P if (Optional<SmallVector<int64_t, 8>> output = piece.valueAt(point))
71d5a29442SArjun P return output;
72d5a29442SArjun P return {};
73d5a29442SArjun P }
74d5a29442SArjun P
print(raw_ostream & os) const75d5a29442SArjun P void MultiAffineFunction::print(raw_ostream &os) const {
76d5a29442SArjun P os << "Domain:";
7715650b32SGroverkss domainSet.print(os);
78d5a29442SArjun P os << "Output:\n";
79d5a29442SArjun P output.print(os);
80d5a29442SArjun P os << "\n";
81d5a29442SArjun P }
82d5a29442SArjun P
dump() const83d5a29442SArjun P void MultiAffineFunction::dump() const { print(llvm::errs()); }
84d5a29442SArjun P
isEqual(const MultiAffineFunction & other) const85d5a29442SArjun P bool MultiAffineFunction::isEqual(const MultiAffineFunction &other) const {
8615650b32SGroverkss return getDomainSpace().isCompatible(other.getDomainSpace()) &&
8720aedb14SGroverkss getDomain().isEqual(other.getDomain()) &&
88d5a29442SArjun P isEqualWhereDomainsOverlap(other);
89d5a29442SArjun P }
90d5a29442SArjun P
insertVar(VarKind kind,unsigned pos,unsigned num)91d95140a5SGroverkss unsigned MultiAffineFunction::insertVar(VarKind kind, unsigned pos,
92d5a29442SArjun P unsigned num) {
93d95140a5SGroverkss assert(kind != VarKind::Domain && "Domain has to be zero in a set");
94d95140a5SGroverkss unsigned absolutePos = domainSet.getVarKindOffset(kind) + pos;
95d5a29442SArjun P output.insertColumns(absolutePos, num);
96d95140a5SGroverkss return domainSet.insertVar(kind, pos, num);
97d5a29442SArjun P }
98d5a29442SArjun P
removeVarRange(VarKind kind,unsigned varStart,unsigned varLimit)99d95140a5SGroverkss void MultiAffineFunction::removeVarRange(VarKind kind, unsigned varStart,
100d95140a5SGroverkss unsigned varLimit) {
101d95140a5SGroverkss output.removeColumns(varStart + domainSet.getVarKindOffset(kind),
102d95140a5SGroverkss varLimit - varStart);
103d95140a5SGroverkss domainSet.removeVarRange(kind, varStart, varLimit);
104d5a29442SArjun P }
105d5a29442SArjun P
truncateOutput(unsigned count)10679ad5fb2SArjun P void MultiAffineFunction::truncateOutput(unsigned count) {
10779ad5fb2SArjun P assert(count <= output.getNumRows());
10879ad5fb2SArjun P output.resizeVertically(count);
10979ad5fb2SArjun P }
11079ad5fb2SArjun P
truncateOutput(unsigned count)11179ad5fb2SArjun P void PWMAFunction::truncateOutput(unsigned count) {
11279ad5fb2SArjun P assert(count <= numOutputs);
11379ad5fb2SArjun P for (MultiAffineFunction &piece : pieces)
11479ad5fb2SArjun P piece.truncateOutput(count);
11579ad5fb2SArjun P numOutputs = count;
11679ad5fb2SArjun P }
11779ad5fb2SArjun P
mergeLocalVars(MultiAffineFunction & other)118d95140a5SGroverkss void MultiAffineFunction::mergeLocalVars(MultiAffineFunction &other) {
119d95140a5SGroverkss // Merge output local vars of both functions without using division
120d95140a5SGroverkss // information i.e. append local vars of `other` to `this` and insert
121d95140a5SGroverkss // local vars of `this` to `other` at the start of it's local vars.
122d95140a5SGroverkss output.insertColumns(domainSet.getVarKindEnd(VarKind::Local),
123d95140a5SGroverkss other.domainSet.getNumLocalVars());
124d95140a5SGroverkss other.output.insertColumns(other.domainSet.getVarKindOffset(VarKind::Local),
125d95140a5SGroverkss domainSet.getNumLocalVars());
12615650b32SGroverkss
12715650b32SGroverkss auto merge = [this, &other](unsigned i, unsigned j) -> bool {
12815650b32SGroverkss // Merge local at position j into local at position i in function domain.
129d95140a5SGroverkss domainSet.eliminateRedundantLocalVar(i, j);
130d95140a5SGroverkss other.domainSet.eliminateRedundantLocalVar(i, j);
13115650b32SGroverkss
132d95140a5SGroverkss unsigned localOffset = domainSet.getVarKindOffset(VarKind::Local);
13315650b32SGroverkss
13415650b32SGroverkss // Merge local at position j into local at position i in output domain.
13515650b32SGroverkss output.addToColumn(localOffset + j, localOffset + i, 1);
13615650b32SGroverkss output.removeColumn(localOffset + j);
13715650b32SGroverkss other.output.addToColumn(localOffset + j, localOffset + i, 1);
13815650b32SGroverkss other.output.removeColumn(localOffset + j);
13915650b32SGroverkss
14015650b32SGroverkss return true;
14115650b32SGroverkss };
14215650b32SGroverkss
143d95140a5SGroverkss presburger::mergeLocalVars(domainSet, other.domainSet, merge);
14415650b32SGroverkss }
14515650b32SGroverkss
isEqualWhereDomainsOverlap(MultiAffineFunction other) const146d5a29442SArjun P bool MultiAffineFunction::isEqualWhereDomainsOverlap(
147d5a29442SArjun P MultiAffineFunction other) const {
14815650b32SGroverkss if (!getDomainSpace().isCompatible(other.getDomainSpace()))
149d5a29442SArjun P return false;
150d5a29442SArjun P
151d5a29442SArjun P // `commonFunc` has the same output as `this`.
152d5a29442SArjun P MultiAffineFunction commonFunc = *this;
153d95140a5SGroverkss // After this merge, `commonFunc` and `other` have the same local vars; they
154d5a29442SArjun P // are merged.
155d95140a5SGroverkss commonFunc.mergeLocalVars(other);
156d5a29442SArjun P // After this, the domain of `commonFunc` will be the intersection of the
157d5a29442SArjun P // domains of `this` and `other`.
15815650b32SGroverkss commonFunc.domainSet.append(other.domainSet);
159d5a29442SArjun P
160d5a29442SArjun P // `commonDomainMatching` contains the subset of the common domain
161d5a29442SArjun P // where the outputs of `this` and `other` match.
162d5a29442SArjun P //
163d5a29442SArjun P // We want to add constraints equating the outputs of `this` and `other`.
164d95140a5SGroverkss // However, `this` may have difference local vars from `other`, whereas we
165d5a29442SArjun P // need both to have the same locals. Accordingly, we use `commonFunc.output`
166d5a29442SArjun P // in place of `this->output`, since `commonFunc` has the same output but also
167d5a29442SArjun P // has its locals merged.
168d5a29442SArjun P IntegerPolyhedron commonDomainMatching = commonFunc.getDomain();
169d5a29442SArjun P for (unsigned row = 0, e = getNumOutputs(); row < e; ++row)
170d5a29442SArjun P commonDomainMatching.addEquality(
171d5a29442SArjun P subtract(commonFunc.output.getRow(row), other.output.getRow(row)));
172d5a29442SArjun P
173d5a29442SArjun P // If the whole common domain is a subset of commonDomainMatching, then they
174d5a29442SArjun P // are equal and the two functions match on the whole common domain.
175d5a29442SArjun P return commonFunc.getDomain().isSubsetOf(commonDomainMatching);
176d5a29442SArjun P }
177d5a29442SArjun P
178d5a29442SArjun P /// Two PWMAFunctions are equal if they have the same dimensionalities,
179d5a29442SArjun P /// the same domain, and take the same value at every point in the domain.
isEqual(const PWMAFunction & other) const180d5a29442SArjun P bool PWMAFunction::isEqual(const PWMAFunction &other) const {
18120aedb14SGroverkss if (!space.isCompatible(other.space))
182d5a29442SArjun P return false;
183d5a29442SArjun P
184d5a29442SArjun P if (!this->getDomain().isEqual(other.getDomain()))
185d5a29442SArjun P return false;
186d5a29442SArjun P
187d5a29442SArjun P // Check if, whenever the domains of a piece of `this` and a piece of `other`
188d5a29442SArjun P // overlap, they take the same output value. If `this` and `other` have the
189d5a29442SArjun P // same domain (checked above), then this check passes iff the two functions
190d5a29442SArjun P // have the same output at every point in the domain.
191d5a29442SArjun P for (const MultiAffineFunction &aPiece : this->pieces)
192d5a29442SArjun P for (const MultiAffineFunction &bPiece : other.pieces)
193d5a29442SArjun P if (!aPiece.isEqualWhereDomainsOverlap(bPiece))
194d5a29442SArjun P return false;
195d5a29442SArjun P return true;
196d5a29442SArjun P }
197d5a29442SArjun P
addPiece(const MultiAffineFunction & piece)198d5a29442SArjun P void PWMAFunction::addPiece(const MultiAffineFunction &piece) {
19915650b32SGroverkss assert(space.isCompatible(piece.getDomainSpace()) &&
200d5a29442SArjun P "Piece to be added is not compatible with this PWMAFunction!");
201d5a29442SArjun P assert(piece.isConsistent() && "Piece is internally inconsistent!");
202d5a29442SArjun P assert(this->getDomain()
203d5a29442SArjun P .intersect(PresburgerSet(piece.getDomain()))
204d5a29442SArjun P .isIntegerEmpty() &&
205d5a29442SArjun P "New piece's domain overlaps with that of existing pieces!");
206d5a29442SArjun P pieces.push_back(piece);
207d5a29442SArjun P }
208d5a29442SArjun P
addPiece(const IntegerPolyhedron & domain,const Matrix & output)209d5a29442SArjun P void PWMAFunction::addPiece(const IntegerPolyhedron &domain,
210d5a29442SArjun P const Matrix &output) {
211d5a29442SArjun P addPiece(MultiAffineFunction(domain, output));
212d5a29442SArjun P }
213d5a29442SArjun P
addPiece(const PresburgerSet & domain,const Matrix & output)214*a18f843fSGroverkss void PWMAFunction::addPiece(const PresburgerSet &domain, const Matrix &output) {
215*a18f843fSGroverkss for (const IntegerRelation &newDom : domain.getAllDisjuncts())
216*a18f843fSGroverkss addPiece(IntegerPolyhedron(newDom), output);
217*a18f843fSGroverkss }
218*a18f843fSGroverkss
print(raw_ostream & os) const219d5a29442SArjun P void PWMAFunction::print(raw_ostream &os) const {
220d5a29442SArjun P os << pieces.size() << " pieces:\n";
221d5a29442SArjun P for (const MultiAffineFunction &piece : pieces)
222d5a29442SArjun P piece.print(os);
223d5a29442SArjun P }
224888894b6SArjun P
dump() const225888894b6SArjun P void PWMAFunction::dump() const { print(llvm::errs()); }
226*a18f843fSGroverkss
unionFunction(const PWMAFunction & func,llvm::function_ref<PresburgerSet (MultiAffineFunction maf1,MultiAffineFunction maf2)> tiebreak) const227*a18f843fSGroverkss PWMAFunction PWMAFunction::unionFunction(
228*a18f843fSGroverkss const PWMAFunction &func,
229*a18f843fSGroverkss llvm::function_ref<PresburgerSet(MultiAffineFunction maf1,
230*a18f843fSGroverkss MultiAffineFunction maf2)>
231*a18f843fSGroverkss tiebreak) const {
232*a18f843fSGroverkss assert(getNumOutputs() == func.getNumOutputs() &&
233*a18f843fSGroverkss "Number of outputs of functions should be same.");
234*a18f843fSGroverkss assert(getSpace().isCompatible(func.getSpace()) &&
235*a18f843fSGroverkss "Space is not compatible.");
236*a18f843fSGroverkss
237*a18f843fSGroverkss // The algorithm used here is as follows:
238*a18f843fSGroverkss // - Add the output of funcB for the part of the domain where both funcA and
239*a18f843fSGroverkss // funcB are defined, and `tiebreak` chooses the output of funcB.
240*a18f843fSGroverkss // - Add the output of funcA, where funcB is not defined or `tiebreak` chooses
241*a18f843fSGroverkss // funcA over funcB.
242*a18f843fSGroverkss // - Add the output of funcB, where funcA is not defined.
243*a18f843fSGroverkss
244*a18f843fSGroverkss // Add parts of the common domain where funcB's output is used. Also
245*a18f843fSGroverkss // add all the parts where funcA's output is used, both common and non-common.
246*a18f843fSGroverkss PWMAFunction result(getSpace(), getNumOutputs());
247*a18f843fSGroverkss for (const MultiAffineFunction &funcA : pieces) {
248*a18f843fSGroverkss PresburgerSet dom(funcA.getDomain());
249*a18f843fSGroverkss for (const MultiAffineFunction &funcB : func.pieces) {
250*a18f843fSGroverkss PresburgerSet better = tiebreak(funcB, funcA);
251*a18f843fSGroverkss // Add the output of funcB, where it is better than output of funcA.
252*a18f843fSGroverkss // The disjuncts in "better" will be disjoint as tiebreak should gurantee
253*a18f843fSGroverkss // that.
254*a18f843fSGroverkss result.addPiece(better, funcB.getOutputMatrix());
255*a18f843fSGroverkss dom = dom.subtract(better);
256*a18f843fSGroverkss }
257*a18f843fSGroverkss // Add output of funcA, where it is better than funcB, or funcB is not
258*a18f843fSGroverkss // defined.
259*a18f843fSGroverkss //
260*a18f843fSGroverkss // `dom` here is guranteed to be disjoint from already added pieces
261*a18f843fSGroverkss // because because the pieces added before are either:
262*a18f843fSGroverkss // - Subsets of the domain of other MAFs in `this`, which are guranteed
263*a18f843fSGroverkss // to be disjoint from `dom`, or
264*a18f843fSGroverkss // - They are one of the pieces added for `funcB`, and we have been
265*a18f843fSGroverkss // subtracting all such pieces from `dom`, so `dom` is disjoint from those
266*a18f843fSGroverkss // pieces as well.
267*a18f843fSGroverkss result.addPiece(dom, funcA.getOutputMatrix());
268*a18f843fSGroverkss }
269*a18f843fSGroverkss
270*a18f843fSGroverkss // Add parts of funcB which are not shared with funcA.
271*a18f843fSGroverkss PresburgerSet dom = getDomain();
272*a18f843fSGroverkss for (const MultiAffineFunction &funcB : func.pieces)
273*a18f843fSGroverkss result.addPiece(funcB.getDomain().subtract(dom), funcB.getOutputMatrix());
274*a18f843fSGroverkss
275*a18f843fSGroverkss return result;
276*a18f843fSGroverkss }
277*a18f843fSGroverkss
278*a18f843fSGroverkss /// A tiebreak function which breaks ties by comparing the outputs
279*a18f843fSGroverkss /// lexicographically. If `lexMin` is true, then the ties are broken by
280*a18f843fSGroverkss /// taking the lexicographically smaller output and otherwise, by taking the
281*a18f843fSGroverkss /// lexicographically larger output.
282*a18f843fSGroverkss template <bool lexMin>
tiebreakLex(const MultiAffineFunction & mafA,const MultiAffineFunction & mafB)283*a18f843fSGroverkss static PresburgerSet tiebreakLex(const MultiAffineFunction &mafA,
284*a18f843fSGroverkss const MultiAffineFunction &mafB) {
285*a18f843fSGroverkss // TODO: Support local variables here.
286*a18f843fSGroverkss assert(mafA.getDomainSpace().isCompatible(mafB.getDomainSpace()) &&
287*a18f843fSGroverkss "Domain spaces should be compatible.");
288*a18f843fSGroverkss assert(mafA.getNumOutputs() == mafB.getNumOutputs() &&
289*a18f843fSGroverkss "Number of outputs of both functions should be same.");
290*a18f843fSGroverkss assert(mafA.getDomain().getNumLocalVars() == 0 &&
291*a18f843fSGroverkss "Local variables are not supported yet.");
292*a18f843fSGroverkss
293*a18f843fSGroverkss PresburgerSpace compatibleSpace = mafA.getDomain().getSpaceWithoutLocals();
294*a18f843fSGroverkss const PresburgerSpace &space = mafA.getDomain().getSpace();
295*a18f843fSGroverkss
296*a18f843fSGroverkss // We first create the set `result`, corresponding to the set where output
297*a18f843fSGroverkss // of mafA is lexicographically larger/smaller than mafB. This is done by
298*a18f843fSGroverkss // creating a PresburgerSet with the following constraints:
299*a18f843fSGroverkss //
300*a18f843fSGroverkss // (outA[0] > outB[0]) U
301*a18f843fSGroverkss // (outA[0] = outB[0], outA[1] > outA[1]) U
302*a18f843fSGroverkss // (outA[0] = outB[0], outA[1] = outA[1], outA[2] > outA[2]) U
303*a18f843fSGroverkss // ...
304*a18f843fSGroverkss // (outA[0] = outB[0], ..., outA[n-2] = outB[n-2], outA[n-1] > outB[n-1])
305*a18f843fSGroverkss //
306*a18f843fSGroverkss // where `n` is the number of outputs.
307*a18f843fSGroverkss // If `lexMin` is set, the complement inequality is used:
308*a18f843fSGroverkss //
309*a18f843fSGroverkss // (outA[0] < outB[0]) U
310*a18f843fSGroverkss // (outA[0] = outB[0], outA[1] < outA[1]) U
311*a18f843fSGroverkss // (outA[0] = outB[0], outA[1] = outA[1], outA[2] < outA[2]) U
312*a18f843fSGroverkss // ...
313*a18f843fSGroverkss // (outA[0] = outB[0], ..., outA[n-2] = outB[n-2], outA[n-1] < outB[n-1])
314*a18f843fSGroverkss PresburgerSet result = PresburgerSet::getEmpty(compatibleSpace);
315*a18f843fSGroverkss IntegerPolyhedron levelSet(/*numReservedInequalities=*/1,
316*a18f843fSGroverkss /*numReservedEqualities=*/mafA.getNumOutputs(),
317*a18f843fSGroverkss /*numReservedCols=*/space.getNumVars() + 1, space);
318*a18f843fSGroverkss for (unsigned level = 0; level < mafA.getNumOutputs(); ++level) {
319*a18f843fSGroverkss
320*a18f843fSGroverkss // Create the expression `outA - outB` for this level.
321*a18f843fSGroverkss SmallVector<int64_t, 8> subExpr =
322*a18f843fSGroverkss subtract(mafA.getOutputExpr(level), mafB.getOutputExpr(level));
323*a18f843fSGroverkss
324*a18f843fSGroverkss if (lexMin) {
325*a18f843fSGroverkss // For lexMin, we add an upper bound of -1:
326*a18f843fSGroverkss // outA - outB <= -1
327*a18f843fSGroverkss // outA <= outB - 1
328*a18f843fSGroverkss // outA < outB
329*a18f843fSGroverkss levelSet.addBound(IntegerPolyhedron::BoundType::UB, subExpr, -1);
330*a18f843fSGroverkss } else {
331*a18f843fSGroverkss // For lexMax, we add a lower bound of 1:
332*a18f843fSGroverkss // outA - outB >= 1
333*a18f843fSGroverkss // outA > outB + 1
334*a18f843fSGroverkss // outA > outB
335*a18f843fSGroverkss levelSet.addBound(IntegerPolyhedron::BoundType::LB, subExpr, 1);
336*a18f843fSGroverkss }
337*a18f843fSGroverkss
338*a18f843fSGroverkss // Union the set with the result.
339*a18f843fSGroverkss result.unionInPlace(levelSet);
340*a18f843fSGroverkss // There is only 1 inequality in `levelSet`, so the index is always 0.
341*a18f843fSGroverkss levelSet.removeInequality(0);
342*a18f843fSGroverkss // Add equality `outA - outB == 0` for this level for next iteration.
343*a18f843fSGroverkss levelSet.addEquality(subExpr);
344*a18f843fSGroverkss }
345*a18f843fSGroverkss
346*a18f843fSGroverkss // We then intersect `result` with the domain of mafA and mafB, to only
347*a18f843fSGroverkss // tiebreak on the domain where both are defined.
348*a18f843fSGroverkss result = result.intersect(PresburgerSet(mafA.getDomain()))
349*a18f843fSGroverkss .intersect(PresburgerSet(mafB.getDomain()));
350*a18f843fSGroverkss
351*a18f843fSGroverkss return result;
352*a18f843fSGroverkss }
353*a18f843fSGroverkss
unionLexMin(const PWMAFunction & func)354*a18f843fSGroverkss PWMAFunction PWMAFunction::unionLexMin(const PWMAFunction &func) {
355*a18f843fSGroverkss return unionFunction(func, tiebreakLex</*lexMin=*/true>);
356*a18f843fSGroverkss }
357*a18f843fSGroverkss
unionLexMax(const PWMAFunction & func)358*a18f843fSGroverkss PWMAFunction PWMAFunction::unionLexMax(const PWMAFunction &func) {
359*a18f843fSGroverkss return unionFunction(func, tiebreakLex</*lexMin=*/false>);
360*a18f843fSGroverkss }
361