Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Use only half-reified constraints where appropriate (#34) #67

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ public static class BenchmarkState {
@Nullable Model model = null;

@Param({"true", "false"})
static boolean fullReification;
static boolean fullReificationJoinPrefs;

@Param({"true", "false"})
@Param({"true"})
static boolean useCumulative;

@Param({"true", "false"})
@Param({"true"})
static boolean useScalarProduct;

@Setup(Level.Iteration)
Expand All @@ -77,10 +77,10 @@ public void setUp() {
"select * from t2 " +
"join t1 " +
" on t2.controllable__c1 = t1.c1 " +
"having capacity_constraint(t2.controllable__c1, t1.c1, " +
"check capacity_constraint(t2.controllable__c1, t1.c1, " +
" t2.d1, t1.c2) = true",
"create view constraint_symmetry as " +
"select * from t2 group by d1 having increasing(controllable__c1) = true"
"select * from t2 group by d1 check increasing(controllable__c1) = true"
) : List.of(
"create view load_view as " +
"select t1.c2 as capacity, sum(t2.d1) as load from t2 " +
Expand All @@ -93,7 +93,7 @@ public void setUp() {
"create view objective_c2 as " +
"select min(load) from load_view",
"create view constraint_symmetry as " +
"select * from t2 group by d1 having increasing(controllable__c1) = true"
"select * from t2 group by d1 check increasing(controllable__c1) = true"
);

for (int i = 0; i < 1000; i++) {
Expand All @@ -105,7 +105,7 @@ public void setUp() {
}

final OrToolsSolver solver = new OrToolsSolver.Builder()
.setUseFullReifiedConstraintsForJoinPreferences(fullReification)
.setUseFullReifiedConstraintsForJoinPreferences(fullReificationJoinPrefs)
.setTryScalarProductEncoding(useScalarProduct)
.setMaxTimeInSeconds(100)
.build();
Expand Down
180 changes: 109 additions & 71 deletions dcm/src/main/java/com/vmware/dcm/backend/Ops.java
Original file line number Diff line number Diff line change
Expand Up @@ -187,38 +187,42 @@ public boolean eq(final long left, final long right) {
return left == right;
}

public IntVar eq(final String left, final IntVar right) {
return eq(right, left);
public IntVar eq(final String left, final IntVar right, final boolean halfReify) {
return eq(right, left, halfReify);
}

public IntVar eq(final IntVar left, final String right) {
return eq(left, encoder.toLong(right));
public IntVar eq(final IntVar left, final String right, final boolean halfReify) {
return eq(left, encoder.toLong(right), halfReify);
}

public IntVar eq(final long left, final IntVar right) {
return eq(right, left);
public IntVar eq(final long left, final IntVar right, final boolean halfReify) {
return eq(right, left, halfReify);
}

public IntVar eq(final IntVar left, final long right) {
public IntVar eq(final IntVar left, final long right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
model.addEquality(left, right).onlyEnforceIf(bool);
model.addDifferent(left, right).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addDifferent(left, right).onlyEnforceIf(bool.not());
}
return bool;
}

public IntVar eq(final IntVar left, final IntVar right) {
public IntVar eq(final IntVar left, final IntVar right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
model.addEquality(left, right).onlyEnforceIf(bool);
model.addDifferent(left, right).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addDifferent(left, right).onlyEnforceIf(bool.not());
}
return bool;
}

public IntVar eq(final IntVar left, final boolean right) {
return eq(left, right ? 1 : 0);
public IntVar eq(final IntVar left, final boolean right, final boolean halfReify) {
return eq(left, right ? 1 : 0, halfReify);
}

public IntVar eq(final boolean left, final IntVar right) {
return eq(right, left);
public IntVar eq(final boolean left, final IntVar right, final boolean halfReify) {
return eq(right, left, halfReify);
}

public boolean ne(final boolean left, final boolean right) {
Expand All @@ -237,94 +241,114 @@ public boolean ne(final long left, final long right) {
return left != right;
}

public IntVar ne(final String left, final IntVar right) {
return ne(right, left);
public IntVar ne(final String left, final IntVar right, final boolean halfReify) {
return ne(right, left, halfReify);
}

public IntVar ne(final IntVar left, final String right) {
return ne(left, encoder.toLong(right));
public IntVar ne(final IntVar left, final String right, final boolean halfReify) {
return ne(left, encoder.toLong(right), halfReify);
}

public IntVar ne(final long left, final IntVar right) {
return ne(right, left);
public IntVar ne(final long left, final IntVar right, final boolean halfReify) {
return ne(right, left, halfReify);
}

public IntVar ne(final IntVar left, final long right) {
public IntVar ne(final IntVar left, final long right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
model.addDifferent(left, right).onlyEnforceIf(bool);
model.addEquality(left, right).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addEquality(left, right).onlyEnforceIf(bool.not());
}
return bool;
}

public IntVar ne(final IntVar left, final IntVar right) {
public IntVar ne(final IntVar left, final IntVar right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
model.addDifferent(left, right).onlyEnforceIf(bool);
model.addEquality(left, right).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addEquality(left, right).onlyEnforceIf(bool.not());
}
return bool;
}

public IntVar ne(final boolean left, final IntVar right) {
return ne(right, left);
public IntVar ne(final boolean left, final IntVar right, final boolean halfReify) {
return ne(right, left, halfReify);
}

public IntVar ne(final IntVar left, final boolean right) {
return ne(left, right ? 1 : 0);
public IntVar ne(final IntVar left, final boolean right, final boolean halfReify) {
return ne(left, right ? 1 : 0, halfReify);
}

public IntVar lt(final IntVar left, final long right) {
public IntVar lt(final IntVar left, final long right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
model.addLessThan(left, right).onlyEnforceIf(bool);
model.addGreaterOrEqual(left, right).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addGreaterOrEqual(left, right).onlyEnforceIf(bool.not());
}
return bool;
}

public IntVar lt(final IntVar left, final IntVar right) {
public IntVar lt(final IntVar left, final IntVar right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
model.addLessThan(left, right).onlyEnforceIf(bool);
model.addGreaterOrEqual(left, right).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addGreaterOrEqual(left, right).onlyEnforceIf(bool.not());
}
return bool;
}

public IntVar leq(final IntVar left, final long right) {
public IntVar leq(final IntVar left, final long right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
model.addLessOrEqual(left, right).onlyEnforceIf(bool);
model.addGreaterThan(left, right).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addGreaterThan(left, right).onlyEnforceIf(bool.not());
}
return bool;
}

public IntVar leq(final IntVar left, final IntVar right) {
public IntVar leq(final IntVar left, final IntVar right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
model.addLessOrEqual(left, right).onlyEnforceIf(bool);
model.addGreaterThan(left, right).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addGreaterThan(left, right).onlyEnforceIf(bool.not());
}
return bool;
}


public IntVar gt(final IntVar left, final long right) {
public IntVar gt(final IntVar left, final long right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
model.addGreaterThan(left, right).onlyEnforceIf(bool);
model.addLessOrEqual(left, right).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addLessOrEqual(left, right).onlyEnforceIf(bool.not());
}
return bool;
}

public IntVar gt(final IntVar left, final IntVar right) {
public IntVar gt(final IntVar left, final IntVar right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
model.addGreaterThan(left, right).onlyEnforceIf(bool);
model.addLessOrEqual(left, right).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addLessOrEqual(left, right).onlyEnforceIf(bool.not());
}
return bool;
}

public IntVar geq(final IntVar left, final long right) {
public IntVar geq(final IntVar left, final long right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
model.addGreaterOrEqual(left, right).onlyEnforceIf(bool);
model.addLessThan(left, right).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addLessThan(left, right).onlyEnforceIf(bool.not());
}
return bool;
}

public IntVar geq(final IntVar left, final IntVar right) {
public IntVar geq(final IntVar left, final IntVar right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
model.addGreaterOrEqual(left, right).onlyEnforceIf(bool);
model.addLessThan(left, right).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addLessThan(left, right).onlyEnforceIf(bool.not());
}
return bool;
}

Expand All @@ -350,7 +374,7 @@ public boolean in(final long left, final List<Long> right) {
return right.contains(left);
}

public IntVar inObjectArr(final IntVar left, final Object[] right) {
public IntVar inObjectArr(final IntVar left, final Object[] right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
assert right.length > 0;
final Domain domain;
Expand All @@ -366,85 +390,99 @@ public IntVar inObjectArr(final IntVar left, final Object[] right) {
throw new RuntimeException("Unexpected object array " + Arrays.toString(right));
}
model.addLinearExpressionInDomain(left, domain).onlyEnforceIf(bool);
model.addLinearExpressionInDomain(left, domain.complement()).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addLinearExpressionInDomain(left, domain.complement()).onlyEnforceIf(bool.not());
}
return bool;
}

public IntVar inString(final IntVar left, final List<String> right) {
public IntVar inString(final IntVar left, final List<String> right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
final Domain domain = Domain.fromValues(right.stream().mapToLong(encoder::toLong).toArray());
model.addLinearExpressionInDomain(left, domain).onlyEnforceIf(bool);
model.addLinearExpressionInDomain(left, domain.complement()).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addLinearExpressionInDomain(left, domain.complement()).onlyEnforceIf(bool.not());
}
return bool;
}

public IntVar inLong(final IntVar left, final List<Long> right) {
public IntVar inLong(final IntVar left, final List<Long> right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
final Domain domain = Domain.fromValues(right.stream().mapToLong(encoder::toLong).toArray());
model.addLinearExpressionInDomain(left, domain).onlyEnforceIf(bool);
model.addLinearExpressionInDomain(left, domain.complement()).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addLinearExpressionInDomain(left, domain.complement()).onlyEnforceIf(bool.not());
}
return bool;
}

public IntVar inInteger(final IntVar left, final List<Integer> right) {
public IntVar inInteger(final IntVar left, final List<Integer> right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
final Domain domain = Domain.fromValues(right.stream().mapToLong(encoder::toLong).toArray());
model.addLinearExpressionInDomain(left, domain).onlyEnforceIf(bool);
model.addLinearExpressionInDomain(left, domain.complement()).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addLinearExpressionInDomain(left, domain.complement()).onlyEnforceIf(bool.not());
}
return bool;
}

public IntVar inIntVar(final IntVar left, final List<IntVar> right) {
public IntVar inIntVar(final IntVar left, final List<IntVar> right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
final Literal[] literals = new Literal[right.size()];
for (int i = 0; i < right.size(); i++) {
literals[i] = eq(left, right.get(i));
literals[i] = eq(left, right.get(i), halfReify);
}
model.addBoolOr(literals).onlyEnforceIf(bool);

for (int i = 0; i < right.size(); i++) {
literals[i] = literals[i].not();
if (!halfReify) {
for (int i = 0; i < right.size(); i++) {
literals[i] = literals[i].not();
}
model.addBoolAnd(literals).onlyEnforceIf(bool.not());
}
model.addBoolAnd(literals).onlyEnforceIf(bool.not());
return bool;
}

public IntVar or(final boolean left, final IntVar right) {
public IntVar or(final boolean left, final IntVar right, final boolean halfReify) {
return left ? trueVar : right;
}

public IntVar or(final IntVar left, final boolean right) {
return or(right, left);
public IntVar or(final IntVar left, final boolean right, final boolean halfReify) {
return or(right, left, halfReify);
}

public IntVar or(final IntVar left, final IntVar right) {
public IntVar or(final IntVar left, final IntVar right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
model.addBoolOr(new Literal[]{left, right}).onlyEnforceIf(bool);
model.addBoolAnd(new Literal[]{left.not(), right.not()}).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addBoolAnd(new Literal[]{left.not(), right.not()}).onlyEnforceIf(bool.not());
}
return bool;
}


public IntVar and(final boolean left, final IntVar right) {
public IntVar and(final boolean left, final IntVar right, final boolean halfReify) {
return left ? right : falseVar;
}

public IntVar and(final IntVar left, final boolean right) {
return and(right, left);
public IntVar and(final IntVar left, final boolean right, final boolean halfReify) {
return and(right, left, halfReify);
}

public IntVar and(final IntVar left, final IntVar right) {
public IntVar and(final IntVar left, final IntVar right, final boolean halfReify) {
final IntVar bool = model.newBoolVar("");
model.addBoolAnd(new Literal[]{left, right}).onlyEnforceIf(bool);
model.addBoolOr(new Literal[]{left.not(), right.not()}).onlyEnforceIf(bool.not());
if (!halfReify) {
model.addBoolOr(new Literal[]{left.not(), right.not()}).onlyEnforceIf(bool.not());
}
return bool;
}

public IntVar not(final IntVar var) {
return eq(var, 0L);
public IntVar not(final IntVar var, final boolean halfReify) {
return eq(var, 0L, halfReify);
}

public boolean not(final boolean var) {
public boolean not(final boolean var, final boolean halfReify) {
return !var;
}

Expand Down Expand Up @@ -594,7 +632,7 @@ public void capacityConstraint(final List<IntVar> varsToAssign, final long[] dom
for (final IntVar assignmentVar: taskToNodeAssignment) {
final IntVar boolVar;
if (configUseFullReifiedConstraintsForJoinPreferences) {
boolVar = inLong(assignmentVar, Arrays.asList(ArrayUtils.toObject(subArray)));
boolVar = inLong(assignmentVar, Arrays.asList(ArrayUtils.toObject(subArray)), true);
} else {
boolVar = model.newBoolVar("");
model.addLinearExpressionInDomain(assignmentVar, Domain.fromValues(subArray))
Expand Down
Loading