All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xcsp.modeler.api.ProblemAPIBase Maven / Gradle / Ivy

Go to download

Java Tools for parsing XCSP3 instances, compiling JvCSP3 models, and checking solutions. For more information about XCSP3, follow www.xcsp.org

The newest version!
package org.xcsp.modeler.api;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.function.IntConsumer;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import org.xcsp.common.Condition;
import org.xcsp.common.Condition.ConditionIntset;
import org.xcsp.common.Condition.ConditionIntvl;
import org.xcsp.common.Condition.ConditionVal;
import org.xcsp.common.Condition.ConditionVar;
import org.xcsp.common.Constants;
import org.xcsp.common.FunctionalInterfaces.Intx2Consumer;
import org.xcsp.common.FunctionalInterfaces.Intx2Predicate;
import org.xcsp.common.FunctionalInterfaces.Intx3Consumer;
import org.xcsp.common.FunctionalInterfaces.Intx4Consumer;
import org.xcsp.common.FunctionalInterfaces.Intx5Consumer;
import org.xcsp.common.FunctionalInterfaces.Intx6Consumer;
import org.xcsp.common.IVar.Var;
import org.xcsp.common.Range;
import org.xcsp.common.Range.Rangesx2;
import org.xcsp.common.Range.Rangesx3;
import org.xcsp.common.Range.Rangesx4;
import org.xcsp.common.Range.Rangesx5;
import org.xcsp.common.Range.Rangesx6;
import org.xcsp.common.Types.StandardClass;
import org.xcsp.common.Types.TypeClass;
import org.xcsp.common.Types.TypeConditionOperatorRel;
import org.xcsp.common.Types.TypeConditionOperatorSet;
import org.xcsp.common.Types.TypeObjective;
import org.xcsp.common.Types.TypeOperatorRel;
import org.xcsp.common.Types.TypeRank;
import org.xcsp.common.Utilities;
import org.xcsp.common.structures.Automaton;
import org.xcsp.common.structures.Table;
import org.xcsp.common.structures.Transition;
import org.xcsp.common.structures.Transitions;
import org.xcsp.modeler.api.ProblemAPIBase.Occurrences.OccurrencesInt;
import org.xcsp.modeler.api.ProblemAPIBase.Occurrences.OccurrencesInt1D;
import org.xcsp.modeler.api.ProblemAPIBase.Occurrences.OccurrencesIntRange;
import org.xcsp.modeler.api.ProblemAPIBase.Occurrences.OccurrencesIntRange1D;
import org.xcsp.modeler.api.ProblemAPIBase.Occurrences.OccurrencesVar1D;
import org.xcsp.modeler.entities.CtrEntities.CtrArray;
import org.xcsp.modeler.implementation.ProblemIMP;

public interface ProblemAPIBase {

	// ************************************************************************
	// ***** Constants
	// ************************************************************************

	/**
	 * A constant denoting the relational operator "strictly Less Than", which is useful for expressing conditions, as for example in
	 * {@code sum(x, LT, 10)} or {@code count(x, takingValue(0), LT, 5)}.
	 */
	TypeConditionOperatorRel LT = TypeConditionOperatorRel.LT;

	/**
	 * A constant denoting the relational operator "Less than or Equal", which is useful for expressing conditions, as for example in
	 *  sum(x, LE, 10)  or  count(x, takingValue(0), LE, 5) .
	 */
	TypeConditionOperatorRel LE = TypeConditionOperatorRel.LE;

	/**
	 * A constant denoting the relational operator "Greater than or Equal", which is useful for expressing conditions, as for example in
	 *  sum(x, GE, 10)  or  count(x, takingValue(0), GE, 5) .
	 */
	TypeConditionOperatorRel GE = TypeConditionOperatorRel.GE;

	/**
	 * A constant denoting the relational operator "strictly Greater Than", which is useful for expressing conditions, as for example in
	 *  sum(x, GT, 10)  or  count(x, takingValue(0), GT, 5) .
	 */
	TypeConditionOperatorRel GT = TypeConditionOperatorRel.GT;

	/**
	 * A constant denoting the relational operator "Not Equal", which is useful for expressing conditions, as for example in
	 *  sum(x, NE, 10)  or  count(x, takingValue(takingValue(0), NE, 5) .
	 */
	TypeConditionOperatorRel NE = TypeConditionOperatorRel.NE;

	/**
	 * A constant denoting the relational operator "Equal", which is useful for expressing conditions, as for example in  sum(x, EQ, 10) 
	 * or  count(x, takingValue(0), EQ, 5) .
	 */
	TypeConditionOperatorRel EQ = TypeConditionOperatorRel.EQ;

	/**
	 * A constant denoting the set operator "In", which is useful for expressing conditions, as for example in  sum(x, IN, 5, 10)  or
	 *  count(x, takingValue(0), IN, 5, 10) .
	 */
	TypeConditionOperatorSet IN = TypeConditionOperatorSet.IN;

	/**
	 * A constant denoting the set operator "Not In", which is useful for expressing conditions, as for example in  sum(x, NOTIN, 5, 10) 
	 * or  count(x, takingValue(0), NOTIN, 5, 10) .
	 */
	TypeConditionOperatorSet NOTIN = TypeConditionOperatorSet.NOTIN;

	/**
	 * A constant denoting the relational operator "strictly Less Than", which is useful for expressing an ordering, as for example in
	 *  ordered(x, STRICTLY_INCREASING)  or  lex(x, STRICTLY_INCREASING) .
	 */
	TypeOperatorRel STRICTLY_INCREASING = TypeOperatorRel.LT;

	/**
	 * A constant denoting the relational operator "Less than or Equal", which is useful for expressing an ordering, as for example in
	 *  ordered(x, INCREASING)  or  lex(x, INCREASING) .
	 */
	TypeOperatorRel INCREASING = TypeOperatorRel.LE;

	/**
	 * A constant denoting the relational operator "Greater than or Equal", which is useful for expressing an ordering, as for example in
	 *  ordered(x, DECREASING)  or  lex(x, DECREASING) .
	 */
	TypeOperatorRel DECREASING = TypeOperatorRel.GE;

	/**
	 * A constant denoting the relational operator "strictly Greater Than", which is useful for expressing an ordering, as for example in
	 *  ordered(x, STRICTLY_DECREASING)  or  lex(x, STRICTLY_DECREASING) .
	 */
	TypeOperatorRel STRICTLY_DECREASING = TypeOperatorRel.GT;

	/**
	 * A constant denoting the type "expression" for an objective function, as for example in  minimize(EXPRESSION, add(x,mul(y,3)) .
	 */
	TypeObjective EXPRESSION = TypeObjective.EXPRESSION;

	/**
	 * A constant denoting the type "sum" for an objective function, as for example in  minimize(SUM, x, y, z) .
	 */
	TypeObjective SUM = TypeObjective.SUM;

	/**
	 * A constant denoting the type "product" for an objective function, as for example in  minimize(PRODUCT, x, y, z) .
	 */
	TypeObjective PRODUCT = TypeObjective.PRODUCT;

	/**
	 * A constant denoting the type "minimum" for an objective function, as for example in  maximize(MINIMUM, x, y, z) .
	 */
	TypeObjective MINIMUM = TypeObjective.MINIMUM;

	/**
	 * A constant denoting the type "maximum" for an objective function, as for example in  minimize(MAXIMUM, x, y, z) .
	 */
	TypeObjective MAXIMUM = TypeObjective.MAXIMUM;

	/**
	 * A constant denoting the type "nValues" for an objective function, as for example in  minimize(NVALUES, x) .
	 */
	TypeObjective NVALUES = TypeObjective.NVALUES;

	/**
	 * A constant denoting the type "lex" for an objective function, as for example in  minimize(LEX, x, y, z) .
	 */
	TypeObjective LEX = TypeObjective.LEX;

	/**
	 * The constant "channeling" that can be used for tagging elements such as variables, constraints, blocks, groups, ...
	 */
	TypeClass CHANNELING = StandardClass.CHANNELING;

	/**
	 * The constant "clues" that can be used for tagging elements such as variables, constraints, blocks, groups, ...
	 */
	TypeClass CLUES = StandardClass.CLUES;

	/**
	 * The constant "rows" that can be used for tagging elements such as variables, constraints, blocks, groups, ...
	 */
	TypeClass ROWS = StandardClass.ROWS;

	/**
	 * The constant "columns" that can be used for tagging elements such as variables, constraints, blocks, groups, ...
	 */
	TypeClass COLUMNS = StandardClass.COLUMNS;

	/**
	 * The constant "blocks" that can be used for tagging elements such as variables, constraints, blocks, groups, ...
	 */
	TypeClass BLOCKS = StandardClass.BLOCKS;

	/**
	 * The constant "diagonals" that can be used for tagging elements such as variables, constraints, blocks, groups, ...
	 */
	TypeClass DIAGONALS = StandardClass.DIAGONALS;

	/**
	 * The constant "symmetryBreaking" that can be used for tagging elements such as variables, constraints, blocks, groups, ...
	 */
	TypeClass SYMMETRY_BREAKING = StandardClass.SYMMETRY_BREAKING;

	/**
	 * The constant "redundantConstraints" that can be used for tagging elements such as variables, constraints, blocks, groups, ...
	 */
	TypeClass REDUNDANT_CONSTRAINTS = StandardClass.REDUNDANT_CONSTRAINTS;

	/**
	 * The constant "nogoods" that can be used for tagging elements such as variables, constraints, blocks, groups, ...
	 */
	TypeClass NOGOODS = StandardClass.NOGOODS;

	/**
	 * A constant denoting that a search is conducted with respect to the first object (typically, variable) of a structure (typically, a
	 * 1-dimensional array of variables) having a certain property.
	 */
	TypeRank FIRST = TypeRank.FIRST;

	/**
	 * A constant denoting that a search is conducted with respect to the last object (typically, variable) of a structure (typically, a 1-dimensional
	 * array of variables) having a certain property.
	 */
	TypeRank LAST = TypeRank.LAST;

	/**
	 * A constant denoting that a search is conducted with respect to any object (typically, variable) of a structure (typically, a 1-dimensional
	 * array of variables) having a certain property.
	 */
	TypeRank ANY = TypeRank.ANY;

	/**
	 * A constant, equal to Boolean.TRUE, that can be used to indicate that a set of tuples corresponds to supports.
	 */
	Boolean POSITIVE = Boolean.TRUE;

	/**
	 * A constant, equal to Boolean.FALSE, that can be used to indicate that a set of tuples corresponds to conflicts.
	 */
	Boolean NEGATIVE = Boolean.FALSE;

	/**
	 * A constant, equal to Boolean.TRUE, that can be used to indicate that some variables must take their values in some set of values (e.g., for the
	 * constraint {@code cardinality}.
	 */
	Boolean CLOSED = Boolean.TRUE;

	/**
	 * The constant used for denoting "*" in integer tuples.
	 */
	int STAR = Constants.STAR_INT;

	/**
	 * The constant used for denoting "*" in integer tuples.
	 */
	int STAR_INT = Constants.STAR_INT;

	/**
	 * The constant used for denoting the symbol "*".
	 */
	String STAR_SYMBOL = Constants.STAR_SYMBOL;

	// ************************************************************************
	// ***** Base Methods
	// ************************************************************************

	/**
	 * Advanced Use: you shouldn't normally use this map that relates {@code ProblemAPI} objects with {@code ProblemIMP} objects.
	 */
	static Map api2imp = new HashMap<>();

	/**
	 * Advanced Use: you shouldn't normally use the {@code ProblemIMP} object that offers implementation stuff for this object.
	 * 
	 * @return the {@code ProblemIMP} object that offers implementation stuff for this {@code ProblemAPI} object
	 */
	default ProblemIMP imp() {
		control(api2imp.get(this) != null, "The method has been called before the associated problem implementation object was created.");
		return api2imp.get(this);
	}

	/**
	 * Controls that the specified {@code boolean} argument is {@code true}. If it is not the case, the program will stop and specified objects will
	 * be displayed.
	 * 
	 * @param b
	 *            a {@code boolean} value to be controlled to be {@code true}
	 * @param objects
	 *            a sequence of objects used for displaying information when the specified {@code boolean} argument is {@code false}
	 */
	default void control(boolean b, Object... objects) {
		ProblemIMP.control(b, objects);
	}

	/**
	 * Returns the name of this object (i.e., the name of this problem instance). By default, this is the name of the class implementing
	 * {@code ProblemAPI} followed by the values of all parameters (separated by the symbol '-'). The parameters are the fields, used as data, which
	 * are declared in the class implementing {@code ProblemAPI}, or the name of a JSON file, if one is given. Possibly, the name of a model variant,
	 * if used, is inserted after the name of the class.
	 */
	default String name() {
		return imp().name();
	}

	/**
	 * Returns the name of the model variant. If no model variant has been explicitly specified, it is {@code null}.
	 * 
	 * @return the name of the model variant, or ({@code null} is no model variant has been explicitly specified)
	 */
	default String modelVariant() {
		return imp().modelVariant;
	}

	/**
	 * Returns {@code true} iff the user has indicated (through the compiler by using the argument -variant=) that the model variant corresponds to
	 * the value of the specified string.
	 * 
	 * @param s
	 *            a string representing the name of a model variant
	 * @return {@code true} iff the model variant corresponds to the specified string
	 */
	default boolean modelVariant(String s) {
		return s.equals(modelVariant());
	}

	@Deprecated
	/**
	 * Use {@code modelVariant} instead.
	 */
	default boolean isModel(String s) {
		return modelVariant(s);
	}

	/**
	 * Returns a stream of objects from class T, after converting each non-empty trimmed line of the specified file
	 * 
	 * @param filename
	 *            the name of a file
	 * @param f
	 *            a function mapping each line ({@code String}) into an object of class T
	 * @return a stream of objects from class T, after converting each non-empty trimmed line of the specified file
	 */
	default  Stream readFileLines(String filename, Function f) {
		try {
			return Files.lines(Paths.get(filename)).map(s -> s.trim()).filter(s -> s.length() > 0).map(s -> f.apply(s));
		} catch (IOException e) {
			System.out.println("Problem with file " + filename + " (or the specified function)");
			System.exit(1);
			return null;
		}
	}

	/**
	 * Returns a stream composed of the non-empty trimmed lines ({@code String}) of the specified file
	 * 
	 * @param filename
	 *            the name of a file
	 * @return a stream composed of the non-empty trimmed lines ({@code String}) of the specified file
	 */
	default Stream readFileLines(String filename) {
		return readFileLines(filename, s -> s);
	}

	// ************************************************************************
	// ***** Auxiliary methods for handling Tuples and Automata
	// ************************************************************************

	/**
	 * Returns a tuple (array) of integers from the specified parameters.
	 * 
	 * @param value
	 *            an integer
	 * @param otherValues
	 *            a sequence of integers
	 * @return a 1-dimensional array of {@code int}
	 */
	default int[] tuple(int value, int... otherValues) {
		return IntStream.range(0, otherValues.length + 1).map(i -> i == 0 ? value : otherValues[i - 1]).toArray();
	}

	@Deprecated
	/**
	 * use {@code indexing} instead
	 */
	default int[][] number(int... t) {
		return indexing(t);
	}

	/**
	 * Builds and returns a 2-dimensional array of integers, obtained from the specified 1-dimensional array by replacing each value {@code v} at
	 * index {@code i} with a pair {@code (i,v)}. For example, indexing {@code [2,4,1]} yields {@code [[0,2],[1,4],[2,1]]}.
	 * 
	 * @param t
	 *            a 1-dimensional array of integers
	 * @return a 2-dimensional array of integers
	 */
	default int[][] indexing(int... t) {
		return IntStream.range(0, t.length).mapToObj(i -> tuple(i, t[i])).toArray(int[][]::new);
	}

	/**
	 * Builds and returns a 2-dimensional array of integers, obtained by replacing each value {@code v} at position {@code i} of the specified stream
	 * with a pair {@code (i,v)}. For example, indexing {@code [2,4,1]} from a stream yields {@code [[0,2],[1,4],[2,1]]}.
	 * 
	 * @param t
	 *            a stream of integer values
	 * @return A 2-dimensional array of integers
	 */
	default int[][] indexing(IntStream t) {
		return indexing(t.toArray());
	}

	/**
	 * Builds and returns a 2-dimensional array of integers, obtained from the specified 2-dimensional array by collecting triplets {@code (i,j,v)}
	 * where {@code v} is the value v at index {@code (i,j)} of the array. For example, indexing {@code [[1,2,1],[2,5,1]]} yields
	 * {@code [[0,0,1],[0,1,2],[0,2,1],[1,0,2],[1,1,5],[1,2,1]]}.
	 * 
	 * @param m
	 *            a 2-dimensional array of integers
	 * @return a 2-dimensional array of integers
	 */
	default int[][] indexing(int[]... m) {
		return IntStream.range(0, m.length).mapToObj(i -> IntStream.range(0, m[i].length).mapToObj(j -> tuple(i, j, m[i][j]))).flatMap(s -> s)
				.toArray(int[][]::new);
	}

	/**
	 * Builds and returns a 2-dimensional array of integers, obtained from the specified array by replacing each tuple {@code (v1,v2,...,vr)} at index
	 * {@code i} with a new tuple {@code (i,v1,v2,...,vr)}. For example, indexing {@code [[0,3,1],[2,4,1]]} yields {@code [[0,0,3,1],[1,2,4,1]]}.
	 * 
	 * @param tuples
	 *            a 2-dimensional array of integers
	 * @return a 2-dimensional array of integers
	 */
	default int[][] indexingTuples(int[]... tuples) {
		return IntStream.range(0, tuples.length).mapToObj(i -> tuple(i, tuples[i])).toArray(int[][]::new);
	}

	/**
	 * Builds and returns a 2-dimensional array of integers, obtained by replacing each tuple {@code (v1,v2,...,vr)} at position {@code i} of the
	 * specified stream with a new tuple {@code (i,v1,v2,...,vr)}. For example, indexing {@code [[0,3,1],[2,4,1]]} from a stream yields
	 * {@code [[0,0,3,1],[1,2,4,1]]}.
	 * 
	 * @param tuples
	 *            a stream of arrays of integers
	 * @return a 2-dimensional array of integers
	 */
	default int[][] indexingTuples(Stream tuples) {
		return indexingTuples(tuples.toArray(int[][]::new));
	}

	/**
	 * Builds an empty integer table that can be fed with tuples.
	 * 
	 * @return an object {@code TableInteger}
	 */
	default Table table() {
		return new Table();
	}

	/**
	 * Builds an empty integer table which is either positive (i.e, contains supports) or negative (i.e., contains conflicts) depending on the
	 * specified Boolean value.
	 * 
	 * @param positive
	 *            a Boolean value indicating if the created table is positive ({@code true}) or negative ({@code false})
	 * @return an empty integer table
	 */
	default Table table(boolean positive) {
		return new Table().positive(positive);
	}

	/**
	 * Builds an integer table containing the specified tuple.
	 * 
	 * @param value
	 *            an integer
	 * @param otherValues
	 *            a sequence of integers
	 * @return an integer table with one tuple
	 */
	default Table table(int value, int... otherValues) {
		return new Table().add(value, otherValues);
	}

	/**
	 * Builds an integer table containing the specified tuples.
	 * 
	 * @param tuples
	 *            a sequence of tuples
	 * @return an integer table with the specified tuples
	 */
	default Table table(int[]... tuples) {
		return new Table().add(tuples);
	}

	/**
	 * Builds an integer table containing the specified tuples.
	 * 
	 * @param stream
	 *            a stream of tuples
	 * @return an integer table with the specified tuples
	 */
	default Table table(Stream stream) {
		return new Table().add(stream);
	}

	/**
	 * Builds an integer table containing the specified tuples.
	 * 
	 * @param collection
	 *            a collection of tuples
	 * @return an integer table with the specified tuples
	 */
	default Table table(Collection collection) {
		return new Table().add(collection.stream());
	}

	/**
	 * Builds an integer table containing all tuples from the specified table.
	 * 
	 * @param table
	 *            an existing table
	 * @return an integer table with all tuples from the specified table.
	 */
	default Table table(Table table) {
		return new Table().add(table);
	}

	/**
	 * Returns a table corresponding to the intersection of the two specified tables
	 * 
	 * @param table1
	 *            a first integer table
	 * @param table2
	 *            a second integer table
	 * @return an integer table that represents the intersection of the two specified tables
	 */
	default Table tableIntersection(Table table1, Table table2) {
		return table1.intersectionWith(table2);
	}

	/**
	 * Returns a new integer table obtained after adding a new column at the specified table. The position of the new column is specified as well as
	 * the value that must be put in that column. For example, it can be useful for adding a column with '*' in tables.
	 * 
	 * @param table
	 *            an integer table
	 * @param position
	 *            the position of a new column where the value must be put
	 * @param value
	 *            the value that must be put in the column
	 * @return an integer table obtained after adding a new column at the specified table
	 */
	default Table tableWithNewColumn(Table table, int position, int value) {
		return table.addColumnWithValue(position, value);
	}

	/**
	 * Builds an integer table after parsing the specified string. The string is what can be expected in XCSP3, as for example {@code (1,2)(1,3)(2,3)}
	 * for an integer table.
	 * 
	 * @param tuples
	 *            a string representing a sequence of integer tuples.
	 * @return a table containing the parsed specified tuples
	 */
	default Table table(String tuples) {
		return new Table().add(tuples);
	}

	// /**
	// * Builds an integer table containing all tuples (supports) respecting the specified predicate
	// *
	// * @param tree
	// * a syntactic tree
	// * @return an integer table with all tuples respecting the specified predicate (tree)
	// */
	// default TableInteger table(XNodeParent tree) {
	// return (TableInteger) imp().tableFor(tree);
	// }

	/**
	 * Builds and returns an empty object {@code Transitions}. It is then possible to add transitions.
	 * 
	 * @return an object {@code Transitions}
	 */
	default Transitions transitions() {
		return new Transitions();
	}

	/**
	 * Builds and returns an object {@code Transitions} after parsing the specified string. The string is what can be expected in XCSP3, as for
	 * example {@code "(q0,0,q1)(q0,2,q2)(q1,0,q3)"}.
	 * 
	 * @param transitions
	 *            a string representing the transitions
	 * @return an object {@code Transitions}
	 */
	default Transitions transitions(String transitions) {
		return Transitions.parse(transitions);
	}

	/**
	 * Pure Syntactic Sugar: this method simply returns its argument. It can be useful to emphasize the set of final states when building an
	 * automaton.
	 * 
	 * @param finalStates
	 *            a sequence of {@code String}
	 * @return an array of {@code String}
	 */
	default String[] finalStates(String... finalStates) {
		return finalStates;
	}

	/**
	 * Pure Syntactic Sugar: this method simply returns its argument. It can be useful to emphasize the (unique) final state when building an
	 * automaton.
	 * 
	 * @param finalState
	 *            a {@code String}
	 * @return a {@code String}
	 */
	default String[] finalState(String finalState) {
		return finalStates(finalState);
	}

	/**
	 * Builds an {@code Automaton} from the specified transitions, start and final states.
	 * 
	 * @param startState
	 *            the start state
	 * @param transitions
	 *            the transitions of the automaton
	 * @param finalStates
	 *            the final states
	 * @return an automaton
	 */
	default Automaton automaton(String startState, Transition[] transitions, String... finalStates) {
		return new Automaton(startState, transitions, finalStates);
	}

	/**
	 * Builds an {@code Automaton} from the specified transitions, start and final states.
	 * 
	 * @param startState
	 *            the start state
	 * @param transitions
	 *            the object denoting the transitions
	 * @param finalStates
	 *            the final states
	 * @return an automaton
	 */
	default Automaton automaton(String startState, Transitions transitions, String... finalStates) {
		return automaton(startState, transitions.toArray(), finalStates);
	}

	/**
	 * Builds an {@code Automaton} from the specified transitions, start and final states.
	 * 
	 * @param startState
	 *            the start state
	 * @param transitions
	 *            the string denoting the transitions
	 * @param finalStates
	 *            the final states
	 * @return an automaton
	 */
	default Automaton automaton(String startState, String transitions, String... finalStates) {
		return automaton(startState, transitions(transitions), finalStates);
	}

	// ************************************************************************
	// ***** Auxiliary classes and methods for Constraints
	// ************************************************************************

	/**
	 * Class that is useful to represent objects wrapping indexing information. Basically, this is used as syntactic sugar.
	 */
	static class Index {

		public Var var;

		public TypeRank rank;

		public Index(Var var, TypeRank rank) {
			this.var = var;
			this.rank = rank;
		}

		public Index(Var var) {
			this(var, TypeRank.ANY);
		}

	}

	static interface Occurrences {

		static class OccurrencesInt implements Occurrences {
			public int occurs;

			public OccurrencesInt(int occurs) {
				this.occurs = occurs;
			}
		}

		static class OccurrencesIntRange implements Occurrences {
			public int occursMin;
			public int occursMax;

			public OccurrencesIntRange(int occursMin, int occursMax) {
				this.occursMin = occursMin;
				this.occursMax = occursMax;
			}
		}

		static class OccurrencesInt1D implements Occurrences {
			public int[] occurs;

			public OccurrencesInt1D(int[] occurs) {
				this.occurs = occurs;
			}
		}

		static class OccurrencesIntRange1D implements Occurrences {
			public int[] occursMin;
			public int[] occursMax;

			public OccurrencesIntRange1D(int[] occursMin, int[] occursMax) {
				this.occursMin = occursMin;
				this.occursMax = occursMax;
			}
		}

		static class OccurrencesVar1D implements Occurrences {
			public Var[] occurs;

			public OccurrencesVar1D(Var[] occurs) {
				this.occurs = occurs;
			}
		}
	}

	/**
	 * Returns an object {@code Occurrences} that represents the number of times each value of a given set in a certain context (when posting a
	 * constraint {@code cardinality}) must occur.
	 * 
	 * @param occurs
	 *            an integer
	 * @return an object {@code Occurrences} that can be used with constraint {@code cardinality}
	 */
	default Occurrences occursEachExactly(int occurs) {
		return new OccurrencesInt(occurs);
	}

	/**
	 * Returns an object {@code Occurrences} that represents the bounds about the number of times each value of a given set in a certain context (when
	 * posting a constraint {@code cardinality}) must occur each.
	 * 
	 * @param occursMin
	 *            the lower bound for the number of occurrences
	 * @param occursMax
	 *            the upper bound for the number of occurrences
	 * @return an object {@code Occurrences} that can be used with constraint {@code cardinality}
	 */
	default Occurrences occursEachBetween(int occursMin, int occursMax) {
		return new OccurrencesIntRange(occursMin, occursMax);
	}

	/**
	 * Returns an object {@code Occurrences} that represents the respective number of times each value of a given set in a certain context (when
	 * posting a constraint {@code cardinality}) must occur.
	 * 
	 * @param occurs
	 *            a 1-dimensional array of integers representing the respective numbers of occurrences
	 * @return an object {@code Occurrences} that can be used with constraint {@code cardinality}
	 */
	default Occurrences occurExactly(int... occurs) {
		return new OccurrencesInt1D(occurs);
	}

	@Deprecated
	/**
	 * Use {@code occurExactly} instead.
	 */
	default Occurrences occurrences(int... occurs) {
		return occurExactly(occurs);
	}

	/**
	 * Returns an object {@code Occurrences} that represents the respective bounds about the number of times each value of a given set in a certain
	 * context (when posting a constraint {@code cardinality}) must occur.
	 * 
	 * @param occursMin
	 *            the lower bounds for the number of occurrences
	 * @param occursMax
	 *            the upper bounds for the number of occurrences
	 * @return an object {@code Occurrences} that can be used with constraint {@code cardinality}
	 */
	default Occurrences occurBetween(int[] occursMin, int[] occursMax) {
		return new OccurrencesIntRange1D(occursMin, occursMax);
	}

	@Deprecated
	/**
	 * Use {@code occurBetween} instead.
	 */
	default Occurrences occursBetween(int[] occursMin, int[] occursMax) {
		return occurBetween(occursMin, occursMax);
	}

	/**
	 * Returns an object {@code Occurrences} that represents the respective numbers of times each value of a given set in a certain context (when
	 * posting a constraint {@code cardinality}) must occur.
	 * 
	 * @param occurs
	 *            a 1-dimensional array of integer variables
	 * @return an object {@code Occurrences} that can be used with constraint {@code cardinality}
	 */
	default Occurrences occurExactly(Var... occurs) {
		return new OccurrencesVar1D(occurs);
	}

	@Deprecated
	/**
	 * Use {@code occurExactly} instead.
	 */
	default Occurrences occurrences(Var... occurs) {
		return occurExactly(occurs);
	}

	/**
	 * Returns an object {@code Condition} composed of the specified relational operator and value (right operand). Such object can be used when
	 * posting constraints.
	 * 
	 * @param op
	 *            a relational operator
	 * @param limit
	 *            an integer
	 * @return an object {@code Condition} composed of the specified relational operator and value
	 */
	default Condition condition(TypeConditionOperatorRel op, long limit) {
		return new ConditionVal(op, limit);
	}

	/**
	 * Returns an object {@code Condition} composed of the specified relational operator and variable (right operand). Such object can be used when
	 * posting constraints.
	 * 
	 * @param op
	 *            a relational operator
	 * @param limit
	 *            an integer variable
	 * @return an object {@code Condition} composed of the specified relational operator and variable
	 */
	default Condition condition(TypeConditionOperatorRel op, Var limit) {
		return new ConditionVar(op, limit);
	}

	/**
	 * Returns an object {@code Condition} composed of the specified set operator and interval (defined from the two specified bounds). Such object
	 * can be used when posting constraints.
	 * 
	 * @param op
	 *            a set operator
	 * @param range
	 *            a range (interval) of values
	 * @return an object {@code Condition} composed of the specified set operator and interval
	 */
	default Condition condition(TypeConditionOperatorSet op, Range range) {
		control(range.step == 1 && range.length() >= 1, "Bad form of range");
		return new ConditionIntvl(op, range.start, range.stop - 1);
	}

	/**
	 * Returns an object {@code Condition} composed of the specified set operator and array of integers (right operand). Such object can be used when
	 * posting constraints.
	 * 
	 * @param op
	 *            a set operator
	 * @param values
	 *            an array of integers
	 * @return an object {@code Condition} composed of the specified set operator and array of integers
	 */
	default Condition condition(TypeConditionOperatorSet op, int[] values) {
		return new ConditionIntset(op, IntStream.of(Utilities.collectInt(values)).sorted().distinct().toArray()); // singleValuesIn(values));
	}

	/**
	 * Returns an object {@code Index} wrapping the specified variable (and the default value ANY). Such object can be used when posting constraints.
	 * 
	 * @param variable
	 *            an integer variable
	 * @return an object {@code Index} wrapping the specified variable
	 */
	default Index index(Var variable) {
		return new Index(variable);
	}

	/**
	 * Returns an object {@code Index} wrapping the specified variable and the specified rank type. In the context of looking for an object with a
	 * certain property P in a structure (typically, a variable with property P in a 1-dimensional array of variables), the value of {@code rank}
	 * indicates if {@code variable} must be:
	 * 
    *
  • the smallest valid index number (FIRST), meaning that {@code variable} must refer to the first object in the structure with property P
  • *
  • the greatest valid index number (LAST), meaning that {@code variable} must refer to the last variable in the structure with property P
  • *
  • or any valid index number (ANY), meaning that {@code variable} can refer to any variable in the structure with property P.
  • *
* * @param variable * an integer variable * @param rank * the way indexing search is considered (FIRST, LAST or ANY) * @return an object {@code Index} wrapping the specified variable and the specified rank type */ default Index index(Var variable, TypeRank rank) { return new Index(variable, rank); } /** * Pure Syntactic Sugar: this method simply returns its argument. It can be useful to emphasize the value used as starting index when posting some * constraints (e.g., {@code element}, {@code channel} or {@code minimum}). * * @param value * an integer * @return the same integer */ default int startIndex(int value) { return value; } /** * Pure Syntactic Sugar: this method simply returns its argument. It can be useful to emphasize a limitation for some constraints (e.g., * {@code instantiation}. * * @param p * a predicate * @return the same predicate */ default Intx2Predicate onlyOn(Intx2Predicate p) { return p; } /** * Pure Syntactic Sugar: this method simply returns its argument. It can be useful to emphasize a scalar product. * * @param coeffs * a 1-dimensional array (varargs) of integers * @return the same 1-dimensional array of integers */ default int[] weightedBy(int... coeffs) { return coeffs; } /** * Pure Syntactic Sugar: this method simply returns its argument. It can be useful to emphasize a scalar product. * * @param coeffs * a 1-dimensional array (varargs) of variables * @return the same 1-dimensional array of variables */ default Var[] weightedBy(Var... coeffs) { return coeffs; } /** * Pure Syntactic Sugar: this method simply returns its argument. It can be useful to emphasize a scalar product. * * @param coeffs * a 2-dimensional array (varargs) of integers * @return the same 2-dimensional array of integers */ default int[][] weightedBy(int[]... coeffs) { return coeffs; } /** * Pure Syntactic Sugar: this method simply returns its argument. It can be useful to emphasize a scalar product. * * @param coeffs * a 2-dimensional array (varargs) of variables * @return the same 2-dimensional array of variables */ default Var[][] weightedBy(Var[]... coeffs) { return coeffs; } /** * Pure Syntactic Sugar: this method simply returns its argument. It can be useful to emphasize the target when posting some constraints (e.g., * {@code count}, {@code element} or {@code instantiation}). * * @param value * an integer * @return the same integer */ default int takingValue(int value) { return value; } /** * Pure Syntactic Sugar: this method simply returns its argument. It can be useful to emphasize the target when posting some constraints (e.g., * {@code count}, {@code element} or {@code instantiation}). * * @param value * a variable * @return the same variable */ default Var takingValue(Var value) { return value; } /** * Pure Syntactic Sugar: this method simply returns its argument. It can be useful when posting constraints with an "exceptional" value to be * indicated. * * @param value * an integer * @return the same integer */ default int exceptValue(int value) { return value; } /** * Pure Syntactic Sugar: this method simply returns its argument. It can be useful when posting constraints with "exceptional" values to be * indicated. * * @param values * a 1-dimensional array (varargs) of integers * @return the same 1-dimensional array of integers */ default int[] exceptValues(int... values) { control(values.length >= 1); return values; } /** * Pure Syntactic Sugar: this method simply returns its argument. It can be useful to emphasize the target when posting some constraints (e.g., * {@code count}, {@code element} or {@code instantiation}). * * @param values * a 1-dimensional array (varargs) of integers * @return the same 1-dimensional array of integers */ default int[] takingValues(int... values) { return values; } /** * Syntactic Sugar: this method returns the 1-dimensional array of integers represented by the specified range. It can be useful to emphasize the * target when posting some constraints (e.g., {@code count}, {@code element} or {@code instantiation}). * * @param values * an object {@code Range} * @return the 1-dimensional array of integers, represented by the specified range */ default int[] takingValues(Range values) { return values.toArray(); } /** * Pure Syntactic Sugar: this method simply returns its argument. It can be useful to emphasize the target when posting some constraints (e.g., * {@code instantiation}). * * @param values * a 2-dimensional array (varargs) of integers * @return the same 2-dimensional array of integers */ default int[][] takingValues(int[]... values) { return values; } /** * Pure Syntactic Sugar: this method simply returns its argument. It can be useful to emphasize a specific variable when posting some constraints * (e.g., {@code element}). * * @param index * a variable * @return the same variable */ default Var at(Var index) { return index; } // ************************************************************************ // ***** Managing loops/groups (forall) and blocks // ************************************************************************ /** * Builds a block by executing the specified runnable object. For example: * *
	 * {@code 
	 * block(() -> { 
	 *    instantiation(x, t); 
	 *    lexMatrix(x, INCREASING);
	 * }).tag(SYMMETRY_BREAKING); }
	 * 
* * @param r * an object to run * @return an object {@code CtrArray} that wraps the built block and allows us to provide note and tags by method chaining */ default CtrArray block(Runnable r) { return imp().manageLoop(r); } /** * Builds a group of constraints by executing the specified consumer on each value of the * specified range. For example: * *
	 * {@code forall(range(n - 1), i -> equal(x[i], x[i + 1]));}
	 * 
* * @param range * a range of values * @param c * a consumer * @return an object {@code CtrArray} that wraps the built group and allows us to provide note and tags by method chaining */ default CtrArray forall(Range range, IntConsumer c) { return imp().forall(range, c); } /** Builds constraints by considering the specified ranges and soliciting the specified function. */ /** * Builds a group of constraints by executing the specified consumer on each double value of * the specified double range. For example: * *
	 * {@code forall(range(n).range(n), (i,j) -> lessThan(x[i], y[j]));}
	 * 
* * @param rangesx2 * a double range of values * @param c2 * a consumer that accepts two integers * @return an object {@code CtrArray} that wraps the built group and allows us to provide note and tags by method chaining */ default CtrArray forall(Rangesx2 rangesx2, Intx2Consumer c2) { return imp().forall(rangesx2, c2); } /** * Builds a group of constraints by executing the specified consumer on each triple value of * the specified triple range. For example: * *
	 * {@code forall(range(n).range(n).range(2), (i,j,k) -> lessThan(x[i], add(y[j],k)));}
	 * 
* * @param rangesx3 * a triple range of values * @param c3 * a consumer that accepts three integers * @return an object {@code CtrArray} that wraps the built group and allows us to provide note and tags by method chaining */ default CtrArray forall(Rangesx3 rangesx3, Intx3Consumer c3) { return imp().forall(rangesx3, c3); } /** * Builds a group of constraints by executing the specified consumer on each quadruple value * of the specified quadruple range. For example: * *
	 * {@code forall(range(n).range(n).range(2).range(2), (i,j,k,l) -> lessThan(add(x[i],l), add(y[j],k)));}
	 * 
* * @param rangesx4 * a quadruple range of values * @param c4 * a consumer that accepts four integers * @return an object {@code CtrArray} that wraps the built group and allows us to provide note and tags by method chaining */ default CtrArray forall(Rangesx4 rangesx4, Intx4Consumer c4) { return imp().forall(rangesx4, c4); } /** * Builds a group of constraints by executing the specified consumer on each quintuple value * of the specified quintuple range. For example: * *
	 * {@code forall(range(n).range(n).range(2).range(2).range(10), (i,j,k,l,m) -> lessThan(add(x[i],dist(l,m)), add(y[j],k)));}
	 * 
* * @param rangesx5 * a quintuple range of values * @param c5 * a consumer that accepts five integers * @return an object {@code CtrArray} that wraps the built group and allows us to provide note and tags by method chaining */ default CtrArray forall(Rangesx5 rangesx5, Intx5Consumer c5) { return imp().forall(rangesx5, c5); } /** * Builds a group of constraints by executing the specified consumer on each sixtuple value of * the specified sixtuple range. * * @param rangesx6 * a sixtuple range of values * @param c6 * a consumer that accepts six integers * @return an object {@code CtrArray} that wraps the built group and allows us to provide note and tags by method chaining */ default CtrArray forall(Rangesx6 rangesx6, Intx6Consumer c6) { return imp().forall(rangesx6, c6); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy