Skip to content
Snippets Groups Projects
Commit 2e7932e0 authored by Paul A. Rubin's avatar Paul A. Rubin
Browse files

Added a CP solver.

parent 84e7261c
No related branches found
No related tags found
No related merge requests found
package wolfgoatcabbage;
import ilog.concert.IloConstraint;
import ilog.concert.IloException;
import ilog.concert.IloIntVar;
import ilog.cp.IloCP;
import static wolfgoatcabbage.Problem.CABBAGE;
import static wolfgoatcabbage.Problem.GOAT;
import static wolfgoatcabbage.Problem.ITEMCOUNT;
import static wolfgoatcabbage.Problem.TMAX;
import static wolfgoatcabbage.Problem.WOLF;
/**
* CP implements a constraint programming model for the logic puzzle.
*
* @author Paul A. Rubin (rubin@msu.edu)
*/
public final class CP implements AutoCloseable {
/* CPO objects.
* For the variables `far` and `farmer`, value 1 signals the entity ends the
* period on the far bank while value 0 signals the entity ends the period
* on the near bank.
*/
private final IloCP cp; // the model instance
private final IloIntVar[][] far; // far[t][i] is the location of item i
// at time t
private final IloIntVar[][] tFar; // transpose of far
private final IloIntVar[] farmer; // location of the farmer at time t
private final IloIntVar[] carry; // carry[t] is the index of the item
// carried across the river at time t
// (ITEMCOUNT if the farmer is deadheading)
private final IloIntVar done; // the time period at which the problem
// is done
/**
* Constructor.
* @throws IloException if the model cannot be created
*/
public CP() throws IloException {
// Instantiate the model.
cp = new IloCP();
// Create the variables.
done = cp.intVar(0, TMAX - 1);
far = new IloIntVar[TMAX][ITEMCOUNT + 1];
tFar = new IloIntVar[ITEMCOUNT + 1][TMAX];
carry = new IloIntVar[TMAX];
farmer = new IloIntVar[TMAX];
for (int t = 0; t < TMAX; t++) {
carry[t] = cp.intVar(0, ITEMCOUNT);
farmer[t] = cp.boolVar();
for (int i = 0; i < ITEMCOUNT + 1; i++) {
far[t][i] = cp.boolVar();
tFar[i][t] = far[t][i];
}
}
// The objective is to minimize the time at which the trip is done.
cp.addMinimize(done);
// All inventory is on the near bank at the end of period 0.
for (int i = 0; i < ITEMCOUNT + 1; i++) {
cp.addEq(far[0][i], 0);
}
// The farmer also starts on the near bank.
cp.addEq(farmer[0], 0);
// Nothing is carried in period 0.
cp.addEq(carry[0], ITEMCOUNT);
// The necessary condition for being done is that all items be on the
// far bank.
for (int i = 0; i < ITEMCOUNT; i++) {
cp.addEq(cp.element(tFar[i], done), 1);
}
// In each period, the status of the item carried (if any) flips while
// the status of other items does not change.
for (int t = 1; t < TMAX; t++) {
for (int i = 0; i < ITEMCOUNT; i++) {
IloConstraint c1 = cp.eq(carry[t], i);
IloConstraint c2 = cp.eq(cp.sum(far[t - 1][i], far[t][i]), 1);
IloConstraint c3 = cp.eq(far[t - 1][i], far[t][i]);
cp.add(cp.ifThenElse(c1, c2, c3));
}
}
// In odd numbered periods, trips are from near bank to far bank, and only
// items on the near bank can be carried. In even numbered periods, trips
// are from far bank to near bank, and only items on the far bank can
// be carried.
for (int t = 1; t < TMAX; t++) {
int z = (t % 2 == 0) ? 1 : 0;
cp.addEq(cp.element(far[t - 1], carry[t]), z);
}
// Until the last trip, the farmer ends up on the far bank at the end of
// odd numbered periods and the near bank at the end of even numbered
// periods. After the last trip, the farmer stays on the far bank.
for (int t = 1; t < TMAX; t++) {
IloConstraint c1 = cp.le(done, t);
IloConstraint c2 = cp.eq(farmer[t], 1);
IloConstraint c3 = cp.eq(farmer[t], t % 2);
cp.add(cp.ifThenElse(c1, c2, c3));
}
// If the wolf and goat are in the same place at the end of any period,
// the farmer must also be there. The same is true if the goat and cabbage
// are in the same place.
for (int t = 1; t < TMAX; t++) {
IloConstraint c1 = cp.eq(far[t][WOLF], far[t][GOAT]);
IloConstraint c2 = cp.eq(far[t][GOAT], far[t][CABBAGE]);
IloConstraint c3 = cp.eq(far[t][GOAT], farmer[t]);
cp.add(cp.ifThen(c1, c3));
cp.add(cp.ifThen(c2, c3));
}
// Suppress solver output.
cp.setOut(null);
}
/**
* Solves the model.
* @return the number of trips required
* @throws IloException if the solver fails
*/
public int solve() throws IloException {
cp.solve();
return cp.getIntValue(done);
}
/**
* Gets the solution to the puzzle.
* @return a string displaying the solution
* @throws IloException if the solution does not exist
*/
public String getSolution() throws IloException {
int nTrips = cp.getIntValue(done);
double[][] x = new double[nTrips + 1][ITEMCOUNT];
// Get the values of the far[][] array for actual items and trips used.
for (int t = 0; t <= nTrips; t++) {
for (int i = 0; i < ITEMCOUNT; i++) {
x[t][i] = cp.getValue(far[t][i]);
}
}
// Get the values of the carry[] array for trips actually used.
double[] y = new double[nTrips + 1];
for (int t = 0; t <= nTrips; t++) {
y[t] = cp.getValue(carry[t]);
}
return Problem.report(nTrips, x, y);
}
/**
* Closes the model.
*/
@Override
public void close() {
cp.end();
}
}
......@@ -18,6 +18,7 @@ public final class WolfGoatCabbage {
* @param args the command line arguments (ignored)
*/
public static void main(final String[] args) {
System.out.println("Applying the MIP model.");
try (MIP model = new MIP()) {
double z = model.solve();
System.out.println("Optimal number of trips = " + z + ".");
......@@ -26,6 +27,15 @@ public final class WolfGoatCabbage {
} catch (IloException ex) {
System.out.println("CPLEX exception:\n" + ex.getMessage());
}
System.out.println("\nApplying the CP model:");
try (CP model = new CP()) {
int z = model.solve();
System.out.println("Optimal number of trips = " + z + ".");
System.out.println("Solution:");
System.out.println(model.getSolution());
} catch (IloException ex) {
System.out.println("CPOptimizer exception:\n" + ex.getMessage());
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment