org.chocosolver.solver.constraints.extension.nary.PropLargeGACSTRPos Maven / Gradle / Ivy
/*
* This file is part of choco-solver, http://choco-solver.org/
*
* Copyright (c) 2022, IMT Atlantique. All rights reserved.
*
* Licensed under the BSD 4-clause license.
*
* See LICENSE file in the project root for full license information.
*/
package org.chocosolver.solver.constraints.extension.nary;
import org.chocosolver.memory.IStateInt;
import org.chocosolver.solver.constraints.extension.Tuples;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.util.iterators.DisposableValueIterator;
import org.chocosolver.util.objects.setDataStructures.iterable.IntIterableBitSet;
import java.util.Arrays;
import java.util.BitSet;
/**
* GAC maintaind by STR
*
*
* @author Charles Prud'homme, Hadrien Cambazard
* @since 24/04/2014
*/
public class PropLargeGACSTRPos extends PropLargeCSP {
// check if none of the tuple is trivially outside
// the domains and if yes use a fast valid check
// by avoiding checking the bounds
private final ValidityChecker valcheck;
/**
* size of the scope
*/
private final int arity;
/**
* original lower bounds
*/
private final int[] offsets;
/**
* Variables that are not proved to be GAC yet
*/
private final BitSet futureVars;
/**
* Values that have found a support for each variable
*/
private final BitSet[] gacValues;
private final int[] nbGacValues;
/**
* The backtrackable list of tuples representing the current
* allowed tuples of the constraint
*/
private final IStateInt last;
private final int[] listuples;
private final IntIterableBitSet vrms;
private PropLargeGACSTRPos(IntVar[] vs, TuplesList relation) {
super(vs, relation, false);
this.arity = vs.length;
this.futureVars = new BitSet(arity);
this.gacValues = new BitSet[arity];
this.nbGacValues = new int[arity];
this.offsets = new int[arity];
int min = Integer.MAX_VALUE;
for (int i = 0; i < arity; i++) {
this.offsets[i] = vs[i].getLB();
this.gacValues[i] = new BitSet(vs[i].getDomainSize());
min = Math.min(min, offsets[i]);
}
vrms = new IntIterableBitSet();
vrms.setOffset(min);
listuples = new int[this.relation.getTupleTable().length];
for (int i = 0; i < listuples.length; i++) {
listuples[i] = i;
}
last = model.getEnvironment().makeInt(listuples.length - 1);
int[][] tt = this.relation.getTupleTable();
boolean fastBooleanValidCheckAllowed = true;
// check if all tuples are within the range
// of the domain and if so set up a faster validity checker
// that avoids checking original bounds first
loop:
for (int i = 0; i < tt.length; i++) {
for (int j = 0; j < tt[i].length; j++) {
int lb = vs[j].getLB();
int ub = vs[j].getUB();
if (lb < 0 || ub > 1) {
fastBooleanValidCheckAllowed = false;
break loop;
}
}
}
if (fastBooleanValidCheckAllowed) {
valcheck = new FastBooleanValidityChecker(arity, vars);
} else valcheck = new ValidityChecker(arity, vars);
}
public PropLargeGACSTRPos(IntVar[] vs, Tuples tuples) {
this(vs, RelationFactory.makeListBasedRelation(tuples, vs));
}
@Override
public void propagate(int evtmask) throws ContradictionException {
valcheck.sortvars();
gacstr();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void initializeData() {
//INITIALIZATION
Arrays.fill(nbGacValues, 0);
futureVars.set(0, arity);
for (int i = 0; i < arity; i++) {
gacValues[i].clear();
}
}
private void pruningPhase() throws ContradictionException {
for (int i = futureVars.nextSetBit(0); i > -1; i = futureVars.nextSetBit(i + 1)) {
IntVar v = vars[i];
DisposableValueIterator it3 = v.getValueIterator(true);
vrms.clear();
try {
while (it3.hasNext()) {
int val = it3.next();
if (!gacValues[i].get(val - offsets[i])) {
vrms.add(val);
// v.removeVal(val, this, false);
}
}
v.removeValues(vrms, this);
} finally {
it3.dispose();
}
}
}
/**
* maintain the list by checking all variable within isValid
*/
//maintain the list by checking only the variable that has changed when
//* checking if a tuple is valid.
//*
//* @param idx : the variable changed
private void maintainList(/*int idx*/) {
int cidx = 0;
int nLast = last.get();
while (cidx <= nLast) {
int idxt = listuples[cidx++];
int[] tuple = relation.getTuple(idxt);
if (valcheck.isValid(tuple/*,idx*/)) {
//extract the supports
for (int i = futureVars.nextSetBit(0); i > -1; i = futureVars.nextSetBit(i + 1)) {
if (!gacValues[i].get(tuple[i] - offsets[i])) {
gacValues[i].set(tuple[i] - offsets[i]);
nbGacValues[i]++;
if (nbGacValues[i] == vars[i].getDomainSize()) {
futureVars.clear(i);
}
}
}
} else {
//remove the tuple from the current list
cidx--;
final int temp = listuples[nLast];
listuples[nLast] = listuples[cidx];
listuples[cidx] = temp;
last.add(-1);
nLast--;
}
}
}
/**
* Main propagation loop. It maintains the list of valid tuples
* through the search
*
* @throws ContradictionException
*/
private void gacstr() throws ContradictionException {
initializeData();
maintainList();
pruningPhase();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy