Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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 @@ -1779,14 +1779,51 @@ default Constraint element(IntVar value, IntVar[] table, IntVar index, int offse
* Creates a global cardinality constraint (GCC):
* Each value values[i] should be taken by exactly occurrences[i] variables of vars.
* <br/>
* This constraint does not ensure any well-defined level of consistency, yet.
* Uses {@link GlobalCardinality#defaultConsistency()} (see
* {@link #globalCardinality(IntVar[], int[], IntVar[], boolean, String)}) — {@code "BC"}
* unless overridden via the {@value GlobalCardinality#CONSISTENCY_PROPERTY} system property.
*
* @param vars collection of variables
* @param values collection of constrained values
* @param occurrences collection of cardinality variables
* @param closed restricts domains of vars to values if set to true
*/
default Constraint globalCardinality(IntVar[] vars, int[] values, IntVar[] occurrences, boolean closed) {
return globalCardinality(vars, values, occurrences, closed,
GlobalCardinality.defaultConsistency().name());
}

/**
* Creates a global cardinality constraint (GCC):
* Each value values[i] should be taken by exactly occurrences[i] variables of vars.
*
* @param vars collection of variables
* @param values collection of constrained values
* @param occurrences collection of cardinality variables
* @param closed restricts domains of vars to values if set to true
* @param consistency consistency level, among {"DEFAULT", "BC", "AC"}
* <p>
* <b>DEFAULT</b>:
* <br/>
* Fast filtering, without any well-defined level of consistency.
* <p>
* <b>BC</b>:
* <br/>
* Bound-consistency, based on:
* C.-G. Quimper, P. van Beek, A. Lopez-Ortiz, A. Golynski, and S.B. Sadjad.
* "An efficient bounds consistency algorithm for the global cardinality
* constraint." CP-2003.
* Posted in addition to the {@code "DEFAULT"} filtering.
* <p>
* <b>AC</b>:
* <br/>
* Arc-consistency, based on:
* J.-C. Regin. "Generalized Arc Consistency for Global Cardinality
* Constraint." AAAI-96.
* Posted in addition to the {@code "DEFAULT"} filtering.
*/
default Constraint globalCardinality(IntVar[] vars, int[] values, IntVar[] occurrences,
boolean closed, String consistency) {
if (ref().getSolver().isLCG()) {
if (ref().getSettings().warnUser()) {
ref().getSolver().log().white().println("Warning: globalCardinality constraint is decomposed (due to LCG).");
Expand Down Expand Up @@ -1827,10 +1864,10 @@ default Constraint globalCardinality(IntVar[] vars, int[] values, IntVar[] occur
v2[i] = toAdd.get(i - values.length);
cards[i] = vars[0].getModel().intVar(0);
}
return new GlobalCardinality(vars, v2, cards);
return new GlobalCardinality(vars, v2, cards, consistency);
}
}
return new GlobalCardinality(vars, values, occurrences);
return new GlobalCardinality(vars, values, occurrences, consistency);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,74 @@
*/
public class GlobalCardinality extends Constraint {

/**
* Consistency level enforced by the propagator(s) posted for a {@link GlobalCardinality}
* constraint.
*/
public enum Consistency {
/**
* Fast filtering (see {@link PropFastGCC}), without any well-defined consistency level
* guarantee.
*/
DEFAULT,
/**
* Bound-consistency (see {@link PropGccBC}), following:
* C.-G. Quimper, P. van Beek, A. Lopez-Ortiz, A. Golynski, and S.B. Sadjad.
* "An efficient bounds consistency algorithm for the global cardinality constraint."
* CP-2003.
*/
BC,
/**
* Arc-consistency (see {@link PropGccAC}), following:
* J.-C. Regin. "Generalized Arc Consistency for Global Cardinality Constraint." AAAI-96.
*/
AC
}

/**
* System property used to override the default {@link Consistency} level, e.g.
* {@code -Dchoco.gcc.consistency=AC}. See {@link #defaultConsistency()}.
*/
public static final String CONSISTENCY_PROPERTY = "choco.gcc.consistency";

/**
* Returns the {@link Consistency} level used when none is explicitly specified, e.g. by
* {@link #GlobalCardinality(IntVar[], int[], IntVar[])} or by
* {@link org.chocosolver.solver.constraints.IIntConstraintFactory#globalCardinality(IntVar[], int[], IntVar[], boolean)}.
* <p>
* Defaults to {@link Consistency#BC}, which matches or beats {@link Consistency#AC} on
* solution quality while being cheaper to propagate, and both markedly outperform
* {@link Consistency#DEFAULT} on tightly-constrained instances.
* <p>
* Can be overridden via the {@value #CONSISTENCY_PROPERTY} system property (e.g. to
* benchmark alternative filtering levels without changing calling code).
*
* @return the default consistency level
* @throws IllegalArgumentException if the {@value #CONSISTENCY_PROPERTY} property is set to
* a value that is not a valid {@link Consistency} name
*/
public static Consistency defaultConsistency() {
return Consistency.valueOf(System.getProperty(CONSISTENCY_PROPERTY, Consistency.BC.name()));
}

/**
* Creates a global cardinality constraint using the {@linkplain #defaultConsistency() default
* consistency level}.
*
* @param vars collection of variables
* @param values collection of constrained values
* @param cards collection of cardinality variables
*/
public GlobalCardinality(IntVar[] vars, int[] values, IntVar[] cards) {
super(ConstraintsName.GCC, createProp(vars, values, cards));
this(vars, values, cards, defaultConsistency().name());
}

public GlobalCardinality(IntVar[] vars, int[] values, IntVar[] cards, String consistency) {
super(ConstraintsName.GCC, createProp(vars, values, cards, Consistency.valueOf(consistency)));
}

private static Propagator<IntVar> createProp(IntVar[] vars, int[] values, IntVar[] cards) {
private static Propagator<IntVar>[] createProp(IntVar[] vars, int[] values, IntVar[] cards,
Consistency consistency) {
assert values.length == cards.length;
TIntIntHashMap map = new TIntIntHashMap();
int idx = 0;
Expand All @@ -41,7 +104,18 @@ private static Propagator<IntVar> createProp(IntVar[] vars, int[] values, IntVar
throw new UnsupportedOperationException("ERROR: multiple occurrences of value: " + v);
}
}
return new PropFastGCC(vars, values, map, cards);
PropFastGCC fast = new PropFastGCC(vars, values, map, cards);
switch (consistency) {
case BC:
//noinspection unchecked
return new Propagator[]{fast, new PropGccBC(vars, values, cards)};
case AC:
//noinspection unchecked
return new Propagator[]{fast, new PropGccAC(vars, values, cards)};
default:
//noinspection unchecked
return new Propagator[]{fast};
}
}

public static Constraint reformulate(IntVar[] vars, IntVar[] card, Model model) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* This file is part of choco-solver, http://choco-solver.org/
* Copyright (c) 1999, IMT Atlantique.
* SPDX-License-Identifier: BSD-3-Clause.
* See LICENSE file in the project root for full license information.
*/
package org.chocosolver.solver.constraints.nary.globalcardinality;

import org.chocosolver.solver.constraints.Propagator;
import org.chocosolver.solver.constraints.PropagatorPriority;
import org.chocosolver.solver.constraints.nary.globalcardinality.algo.AlgoGccAC;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.util.ESat;
import org.chocosolver.util.tools.ArrayUtils;

import java.util.Arrays;

/**
* Arc-consistency propagator for the Global Cardinality Constraint (GCC), based on:
* J.-C. Regin. "Generalized Arc Consistency for Global Cardinality Constraint." AAAI-96.
* <p>
* Meant to be posted alongside {@link PropFastGCC}, which is left in charge of tightening the
* bounds of the cardinality variables and of the soundness/completeness of the constraint; this
* propagator only brings arc-consistency on the decision variables.
*
* @author Charles Prud'homme
*/
public class PropGccAC extends Propagator<IntVar> {

//***********************************************************************************
// VARIABLES
//***********************************************************************************

private final int n;
private final int n2;
private final int[] values;
private final AlgoGccAC filter;

//***********************************************************************************
// CONSTRUCTORS
//***********************************************************************************

/**
* @param decvars array of decision variables
* @param restrictedValues array of restricted values
* @param valueCardinalities array of cardinality variables, one per restricted value
*/
public PropGccAC(IntVar[] decvars, int[] restrictedValues, IntVar[] valueCardinalities) {
super(ArrayUtils.append(decvars, valueCardinalities), PropagatorPriority.QUADRATIC, false);
this.values = restrictedValues;
this.n = decvars.length;
this.n2 = values.length;
this.filter = new AlgoGccAC(this);
filter.reset(decvars);
}

//***********************************************************************************
// PROPAGATION
//***********************************************************************************

@Override
public void propagate(int evtmask) throws ContradictionException {
int gMin = Integer.MAX_VALUE;
int gMax = Integer.MIN_VALUE;
for (int i = 0; i < n; i++) {
gMin = Math.min(gMin, vars[i].getLB());
gMax = Math.max(gMax, vars[i].getUB());
}
for (int v : values) {
gMin = Math.min(gMin, v);
gMax = Math.max(gMax, v);
}
int range = gMax - gMin + 1;
int[] minOcc = new int[range];
int[] maxOcc = new int[range];
// values out of the restricted list are unconstrained: [0, n]
Arrays.fill(maxOcc, n);
for (int i = 0; i < n2; i++) {
IntVar card = vars[n + i];
int idx = values[i] - gMin;
minOcc[idx] = card.getLB();
maxOcc[idx] = card.getUB();
}
filter.filter(minOcc, maxOcc, gMin);
}

//***********************************************************************************
// INFO
//***********************************************************************************

@Override
public ESat isEntailed() {
return ESat.TRUE; // redundant propagator, PropFastGCC already checks correctness
}

@Override
public String toString() {
StringBuilder st = new StringBuilder();
st.append("PropGccAC_(");
int i = 0;
for (; i < Math.min(4, vars.length); i++) {
st.append(vars[i].getName()).append(", ");
}
if (i < vars.length - 2) {
st.append("...,");
}
st.append(vars[vars.length - 1].getName()).append(")");
return st.toString();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* This file is part of choco-solver, http://choco-solver.org/
* Copyright (c) 1999, IMT Atlantique.
* SPDX-License-Identifier: BSD-3-Clause.
* See LICENSE file in the project root for full license information.
*/
package org.chocosolver.solver.constraints.nary.globalcardinality;

import org.chocosolver.solver.constraints.Propagator;
import org.chocosolver.solver.constraints.PropagatorPriority;
import org.chocosolver.solver.constraints.nary.globalcardinality.algo.AlgoGccBC;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.solver.variables.events.IntEventType;
import org.chocosolver.util.ESat;
import org.chocosolver.util.tools.ArrayUtils;

import java.util.Arrays;

/**
* Bound-consistency propagator for the Global Cardinality Constraint (GCC), based on:
* C.-G. Quimper, P. van Beek, A. Lopez-Ortiz, A. Golynski, and S.B. Sadjad.
* "An efficient bounds consistency algorithm for the global cardinality constraint." CP-2003.
* <p>
* Meant to be posted alongside {@link PropFastGCC}, which is left in charge of tightening
* the bounds of the cardinality variables and of the soundness/completeness of the constraint;
* this propagator only brings bound-consistency on the decision variables.
*
* @author Charles Prud'homme
*/
public class PropGccBC extends Propagator<IntVar> {

//***********************************************************************************
// VARIABLES
//***********************************************************************************

private final int n;
private final int n2;
private final int[] values;
private final AlgoGccBC filter;

//***********************************************************************************
// CONSTRUCTORS
//***********************************************************************************

/**
* @param decvars array of decision variables
* @param restrictedValues array of restricted values
* @param valueCardinalities array of cardinality variables, one per restricted value
*/
public PropGccBC(IntVar[] decvars, int[] restrictedValues, IntVar[] valueCardinalities) {
super(ArrayUtils.append(decvars, valueCardinalities), PropagatorPriority.LINEAR, false);
this.values = restrictedValues;
this.n = decvars.length;
this.n2 = values.length;
this.filter = new AlgoGccBC(this);
filter.reset(decvars);
}

//***********************************************************************************
// PROPAGATION
//***********************************************************************************

@Override
public void propagate(int evtmask) throws ContradictionException {
int gMin = Integer.MAX_VALUE;
int gMax = Integer.MIN_VALUE;
for (int i = 0; i < n; i++) {
gMin = Math.min(gMin, vars[i].getLB());
gMax = Math.max(gMax, vars[i].getUB());
}
for (int v : values) {
gMin = Math.min(gMin, v);
gMax = Math.max(gMax, v);
}
int range = gMax - gMin + 1;
int[] minOcc = new int[range];
int[] maxOcc = new int[range];
// values out of the restricted list are unconstrained: [0, n]
Arrays.fill(maxOcc, n);
for (int i = 0; i < n2; i++) {
IntVar card = vars[n + i];
int idx = values[i] - gMin;
minOcc[idx] = card.getLB();
maxOcc[idx] = card.getUB();
}
filter.filter(minOcc, maxOcc, gMin);
}

//***********************************************************************************
// INFO
//***********************************************************************************

@Override
public int getPropagationConditions(int vIdx) {
return IntEventType.boundAndInst();
}

@Override
public ESat isEntailed() {
return ESat.TRUE; // redundant propagator, PropFastGCC already checks correctness
}

@Override
public String toString() {
StringBuilder st = new StringBuilder();
st.append("PropGccBC_(");
int i = 0;
for (; i < Math.min(4, vars.length); i++) {
st.append(vars[i].getName()).append(", ");
}
if (i < vars.length - 2) {
st.append("...,");
}
st.append(vars[vars.length - 1].getName()).append(")");
return st.toString();
}

}
Loading
Loading