org.chocosolver.parser.xcsp.tools.XConstraints Maven / Gradle / Ivy
package org.chocosolver.parser.xcsp.tools;
import org.chocosolver.parser.xcsp.tools.XEnums.TypeAtt;
import org.chocosolver.parser.xcsp.tools.XEnums.TypeChild;
import org.chocosolver.parser.xcsp.tools.XEnums.TypeCtr;
import org.chocosolver.parser.xcsp.tools.XEnums.TypeExpr;
import org.chocosolver.parser.xcsp.tools.XVariables.Var;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import java.lang.reflect.Array;
import java.util.*;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* In this class, we find intern classes for managing stand-alone constraints, groups of constraints, and meta-constraints.
*/
public class XConstraints {
/**
* The class used for representing parameters (tokens of the form %i or %...) when handling constraint templates.
*/
public static final class Parameter {
/**
* The number associated with the parameter. We have -1 for %..., 0 for %0, 1 for %1, and so on.
*/
public final int number;
public Parameter(int number) {
this.number = number;
}
@Override
public String toString() {
return "%" + (number == -1 ? "..." : number);
}
}
/**
* The interface used for handling abstraction in constraint templates.
*/
private static interface Abstraction {
}
/**
* The class for basic abstraction. It is used for constraint templates when only one child element is abstract (i.e., contains parameters). In that case,
* either the constraint is (and parameters can be anywhere in the predicate expression) or the unique abstract child element must have the form
* %..., or %0 %1 ... %r, or %0 %1 ... %i %...
*/
public static final class AbstractionBasic implements Abstraction {
/**
* The position of the unique abstract child element (in basic form) in the list of child elements of a constraint template.
*/
public final int abstractChildPosition;
protected AbstractionBasic(int abstractChildPosition) {
this.abstractChildPosition = abstractChildPosition;
}
}
/**
* The class for any complex (i.e., not basic) form of abstraction. In practice, should be very rare. To be written
*/
public static final class AbstractionComplex implements Abstraction {
// TODO
}
/**
* The root class of any element that is an entry in (except for ) or of a child element of a constraint (template).
*/
private static abstract class Root {
/**
* The attributes that are associated with the element. For example, we can have pairs such as (startIndex,integer) or (reifiedBy,variable). We just
* collect XMl attributes into a map (using an enum type for keys, and String for values). Values will have to be handled by the parser (for example, by
* using Integer.parseInt for an integer), which is rather immediate.
*/
public final Map attributes = new HashMap<>();
/**
* The set of variables involved in the element. This is used as a cache (lazy initialization, as seen in method getVars()).
*/
private Var[] vars;
/**
* Returns the set of variables involved in the element.
*/
public Var[] getVars() {
return vars != null ? vars : (vars = collectVars(new LinkedHashSet<>()).toArray(new Var[0]));
}
/**
* Collect the set of variables involved in the element, and add them to the specified set.
*/
public abstract Set collectVars(Set set);
/**
* Collect the XMl attributes of the specified element into a map (using an enum type for keys, and String for values).
*/
public void copyAttributesOf(Element elt) {
NamedNodeMap al = elt.getAttributes();
IntStream.range(0, al.getLength()).forEach(i -> attributes.put(TypeAtt.valOf(al.item(i).getNodeName()), al.item(i).getNodeValue()));
}
/**
* Returns true iff the element is subject to abstraction, i.e., contains parameters (tokens of the form %i or %...).
*/
public abstract boolean subjectToAbstraction();
@Override
public String toString() {
return "(" + (attributes == null ? "" : XUtility.join(attributes, ":", " ")) + ")";
}
}
/**
* The class for representing a child element of a constraint (template). It is used e.g. for representing an element or an element .
*/
public static final class Child extends Root {
/**
* The type of the child. For example list, supports, or transitions.
*/
public final TypeChild type;
/**
* The value of the child. It is actually the parsed textual content of the child. After parsing, it may be a variable, an integer, an array of
* variables, an array of parameters ...
*/
public final Object value;
/**
* Build an object representing a child element of a constraint (template). The specified type corresponds to the tag name of the child, and the value
* corresponds to the parsed textual content of the child.
*/
protected Child(TypeChild type, Object value) {
this.type = type;
this.value = value;
}
/**
* Returns true iff a set variable is involved in the (value field of the) element.
*/
public boolean setVariableInvolved() {
return XUtility.check(value, obj -> (obj instanceof Var && ((Var) obj).type.isSet()));
}
@Override
public Set collectVars(Set set) {
return XUtility.collectVarsIn(value, set);
}
@Override
public boolean subjectToAbstraction() {
return XUtility.check(value, obj -> obj instanceof Parameter);
}
/**
* Returns true iff the value of the child has the form %..., or %0 %1 ... %r, or %0 %1 ... %i %..., which we call candidate for basic abstraction.
*/
public boolean isCandidateForBasicAbstraction() {
if (!(value instanceof Object[]))
return value instanceof Parameter && (((Parameter) value).number == -1 || ((Parameter) value).number == 0);
int size = Array.getLength(value);
if (size == 0
|| IntStream.range(0, size - 1).anyMatch(i -> !(Array.get(value, i) instanceof Parameter) || ((Parameter) Array.get(value, i)).number != i))
return false;
Object last = Array.get(value, size - 1);
return last instanceof Parameter && (((Parameter) last).number == -1 || (((Parameter) last).number == size - 1));
}
@Override
public String toString() {
return type + super.toString() + " : " + (value == null ? "" : value.getClass().isArray() ? XUtility.arrayToString(value) : value.toString());
}
}
/**
* The class for representing any entry in , except for .
*/
public abstract static class Entry extends Root {
/**
* The variable associated with the entry, in case of (half) reification). Of course, it is null if the entry is not (half) reified.
*/
public Var reificationVar;
/**
* The object representing the element , in case of relaxation. Of course, it is null if the entry is nor relaxed/softened.
*/
public Child cost;
/**
* Returns the name of the variable used for (half) reification, or null.
*/
public String getNameOfReificationVar() {
return attributes.getOrDefault(TypeAtt.reifiedBy, attributes.getOrDefault(TypeAtt.hreifiedFrom, attributes.get(TypeAtt.hreifiedTo)));
}
/**
* Returns the form of reification: full reification (reifiedBy), half reification (hreifiedFrom or hreifiedTo) or null (if no reification).
*/
public TypeAtt getReificationForm() {
return attributes.containsKey(TypeAtt.reifiedBy) ? TypeAtt.reifiedBy : attributes.containsKey(TypeAtt.hreifiedFrom) ? TypeAtt.hreifiedFrom
: attributes.containsKey(TypeAtt.hreifiedTo) ? TypeAtt.hreifiedTo : null;
}
@Override
public Set collectVars(Set set) {
if (reificationVar != null)
set.add(reificationVar);
if (cost != null)
cost.collectVars(set);
return set;
}
}
/**
* The class for representing a stand-alone constraint.
*/
public final static class Ctr extends Entry {
/**
* The type of the constraint. For example intension, extension, or regular.
*/
public final TypeCtr type;
/**
* The child elements of the constraint. For example, we have a first child for and a second child for if the constraint is .
*/
public final Child[] childs;
/**
* The object for handling abstraction. Of course, it is null if the constraint is not abstract, i.e., is not a constraint template.
*/
public Abstraction abstraction;
/**
* Build an object representing a stand-alone constraint (template).
*/
protected Ctr(TypeCtr type, Child... childs) {
this.type = type;
this.childs = childs;
if (type == TypeCtr.intension) {
if (((XNodeExpr) (childs[0].value)).canFindleafWith(TypeExpr.PAR))
abstraction = new AbstractionBasic(0);
} else
for (int i = 0; i < childs.length; i++)
if (childs[i].isCandidateForBasicAbstraction()) {
XUtility.control(abstraction == null, "Complex forms of abstraction (including multi basic abstractions) not currently handled");
abstraction = new AbstractionBasic(i);
} else
XUtility.control(!childs[i].subjectToAbstraction(), "Complex abstraction forms not implemented");
}
@Override
public Set collectVars(Set set) {
Stream.of(childs).forEach(child -> child.collectVars(set));
return super.collectVars(set);
}
public int getBasicAbstractionPosition() {
return !(abstraction instanceof AbstractionBasic) ? -1 : ((AbstractionBasic) abstraction).abstractChildPosition;
}
@Override
public boolean subjectToAbstraction() {
return abstraction != null;
}
@Override
public String toString() {
return type + super.toString() + "\n\t" + XUtility.join(childs, "\n\t") + (cost == null ? "" : "\n\t" + cost.toString());
}
}
/**
* The class for representing a group of constraints.
*/
public final static class Group extends Entry {
/**
* The constraint template for the group. It is either a stand-alone constraint template or an element containing a stand-alone constraint
* template.
*/
public final Entry template;
/**
* A two-dimensional array representing the sequence of arguments.
*/
public final Object[][] argss;
/**
* The scope of each constraint of the group. This is used as a cache (lazy initialization, as seen in method getScope(i)).
*/
private Var[][] scopes;
/**
* Returns the scope of the ith constraint of the group.
*/
public Var[] getScope(int i) {
if (scopes == null)
scopes = new Var[argss.length][];
if (scopes[i] != null)
return scopes[i];
return scopes[i] = XUtility.collectVarsIn(argss[i], new LinkedHashSet<>(Arrays.asList(template.getVars()))).toArray(new Var[0]);
}
public Group(Entry template, Object[][] argss) {
this.template = template;
this.argss = argss;
}
@Override
public Set collectVars(Set set) {
template.collectVars(set);
Stream.of(argss).forEach(t -> XUtility.collectVarsIn(t, set));
return super.collectVars(set);
}
@Override
public boolean subjectToAbstraction() {
return true;
}
@Override
public String toString() {
return "group" + super.toString() + "\n" + template.toString() + "\n\t" + XUtility.join(argss, "\n\t", " ")
+ (cost == null ? "" : "\n\t" + cost.toString());
}
}
/**
* The class for representing the meta-constraint .
*/
public final static class Slide extends Entry {
/**
* Builds the scopes of the constraints involved in the meta-constraint.
*/
public static Var[][] buildScopes(Var[][] varsOfLists, int[] offset, int[] collect, boolean circular) {
int[] indexes = new int[collect.length];
List list = new ArrayList<>();
Var[] tmp = new Var[Arrays.stream(collect).sum()];
while (true) {
if (!circular && indexes[0] + collect[0] > varsOfLists[0].length)
break;
boolean lastTurn = indexes[0] + offset[0] >= varsOfLists[0].length;
for (int i = 0, cnt = 0; i < collect.length; i++) {
for (int j = 0; j < collect[i]; j++)
tmp[cnt++] = varsOfLists[i][(indexes[i] + j) % varsOfLists[i].length];
indexes[i] += offset[i];
}
list.add(tmp.clone());
if (lastTurn)
break;
}
return list.toArray(new Var[list.size()][]);
}
/**
* The sequence of child elements . Usually, only one such child.
*/
public final Child[] lists;
/**
* The values of the attributes offset and collect for each list.
*/
public final int[] offset, collect;
/**
* The constraint template for slide. It is a stand-alone constraint template.
*/
public final Ctr template;
/**
* A two-dimensional array representing the scopes of the constraints involved in the meta-constraint.
*/
public final Var[][] scopes;
public Slide(Child[] lists, int[] offset, int[] collect, Ctr template, Var[][] scopes) {
this.lists = lists;
this.offset = offset;
this.collect = collect;
this.template = template;
this.scopes = scopes;
}
@Override
public Set collectVars(Set set) {
Stream.of(lists).forEach(t -> XUtility.collectVarsIn(t, set));
template.collectVars(set);
return super.collectVars(set);
}
@Override
public boolean subjectToAbstraction() {
return true;
}
@Override
public String toString() {
return "slide" + super.toString() + "\n\t" + XUtility.join(lists, "\n\t") + "\n\tcollect=" + Arrays.toString(collect) + " offset="
+ Arrays.toString(offset) + "\n\t" + template.toString() + "\n\tscopes=" + XUtility.arrayToString(scopes)
+ (cost == null ? "" : "\n\t" + cost.toString());
}
}
/**
* The class for representing the meta-constraint .
*/
public final static class Seqbin extends Entry {
/**
* The child element of the meta-constraint.
*/
public final Child list;
/**
* The two constraint templates for the meta-constraint. The first one is hard, and the second one can be violated.
*/
public final Ctr template1, template2;
/**
* The child element used for counting the number of violations. Its value is either an object Long or Var.
*/
public final Child number;
public final Var[][] scopes;
public Seqbin(Child list, Ctr template1, Ctr template2, Child number, Var[][] scopes) {
this.list = list;
this.template1 = template1;
this.template2 = template2;
this.number = number;
this.scopes = scopes;
}
@Override
public Set collectVars(Set set) {
XUtility.collectVarsIn(list, set);
template1.collectVars(set);
template2.collectVars(set);
if (number.value instanceof Var)
set.add(((Var) number.value));
return super.collectVars(set);
}
@Override
public boolean subjectToAbstraction() {
return true;
}
@Override
public String toString() {
return "seqbin" + super.toString() + "\n\t" + list + "\n\t" + template1.toString() + "\n\t" + template2.toString() + "\n\t" + number + " "
+ "\n\tscopes=" + XUtility.arrayToString(scopes) + (cost == null ? "" : "\n\t" + cost.toString());
}
}
/**
* The class for representing a logical meta-constraint , or .
*/
public final static class Logic extends Entry {
/**
* The type of the meta-constraint.
*/
public final TypeCtr type;
/**
* The components involved in the logical meta-constraint. Usually, these components are stand-alone constraints.
*/
public final Entry[] components;
public Logic(TypeCtr type, Entry... components) {
this.type = type;
this.components = components;
XUtility.control(type.isLogical() && (type != TypeCtr.not || components.length == 1), "Bad logic construction");
}
@Override
public Set collectVars(Set set) {
Stream.of(components).forEach(c -> c.collectVars(set));
return super.collectVars(set);
}
@Override
public boolean subjectToAbstraction() {
return Arrays.stream(components).anyMatch(c -> c.subjectToAbstraction());
}
@Override
public String toString() {
return type + super.toString() + "\n" + XUtility.join(components, "\n") + (cost == null ? "" : "\n" + cost.toString());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy