
org.xcsp.common.domains.Domains Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xcsp3-tools Show documentation
Show all versions of xcsp3-tools Show documentation
Java Tools for parsing XCSP3 instances, compiling JvCSP3 models, and checking solutions. For more information about XCSP3, follow www.xcsp.org
The newest version!
/*
* Copyright (c) 2016 XCSP3 Team ([email protected])
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.xcsp.common.domains;
import java.util.Arrays;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.xcsp.common.Constants;
import org.xcsp.common.Range;
import org.xcsp.common.Types.TypeVar;
import org.xcsp.common.Utilities;
import org.xcsp.common.domains.Values.IntegerEntity;
import org.xcsp.common.domains.Values.IntegerInterval;
import org.xcsp.common.domains.Values.IntegerValue;
import org.xcsp.common.domains.Values.RealInterval;
import org.xcsp.common.domains.Values.SimpleValue;
/**
* In this class, we find intern classes for managing all types of domains.
*
* @author Christophe Lecoutre
*/
public class Domains {
/** The root interface to tag domain objects. */
public static interface IDom {
}
/** A class for representing basic domains, i.e. domains for integer, symbolic, real and stochastic variables. */
public static class DomBasic implements IDom {
/** Returns the basic domain obtained by parsing the specified string, according to the value of the specified type. */
public static DomBasic parse(String s, TypeVar type) {
return type == TypeVar.integer ? new Dom(s)
: type == TypeVar.symbolic ? new DomSymbolic(s) : type == TypeVar.real ? new DomReal(s) : DomStochastic.parse(s, type);
}
/**
* The values of the domain: for an integer domain, values are IntegerEntity, for a symbolic domain, values are String, and for a float
* domain, values are RealInterval.
*/
public final Object[] values;
/** Builds a basic domain, with the specified values. */
protected DomBasic(Object[] values) {
this.values = values;
}
@Override
public String toString() {
return values.length == 2 ? values[0] + " " + values[1] : Utilities.join(values);
}
}
/** The class for representing the domain of an integer variable. */
public static final class Dom extends DomBasic {
public static String compactFormOf(int[] values) {
StringBuilder sb = new StringBuilder();
if (values.length == 2)
return values[0] + " " + values[1];
int prevVal = values[0], startInterval = prevVal;
for (int i = 1; i < values.length; i++) {
int currVal = values[i];
if (currVal != prevVal + 1) {
sb.append(prevVal == startInterval ? prevVal : startInterval + (prevVal == startInterval + 1 ? " " : "..") + prevVal).append(" ");
// when only two values, no need for an interval
startInterval = currVal;
}
prevVal = currVal;
}
return sb.append(prevVal == startInterval ? prevVal : startInterval + (prevVal == startInterval + 1 ? " " : "..") + prevVal).toString();
}
/**
* Builds an integer domain, with the integer values (entities that are either integers or integer intervals) obtained by parsing the
* specified string.
*/
protected Dom(String seq) {
super(IntegerEntity.parseSeq(seq)); // must be already sorted.
}
/** Builds an integer domain, with the specified integer values. */
public Dom(int[] values) {
super(IntStream.of(values).mapToObj(v -> new IntegerValue(v)).toArray(IntegerEntity[]::new));
}
/** Builds an integer domain, with the specified integer interval. */
public Dom(int min, int max) {
super(new IntegerEntity[] { new IntegerInterval(min, max) });
}
/** Returns the first (smallest) value of the domain. It may be VAL_M_INFINITY for -infinity. */
public long firstValue() {
return ((IntegerEntity) values[0]).smallest();
}
/** Returns the last (greatest) value of the domain. It may be VAL_P_INFINITY for +infinity. */
public long lastValue() {
return ((IntegerEntity) values[values.length - 1]).greatest();
}
/** Returns true iff the domain contains the specified value. */
public boolean contains(long v) {
for (int left = 0, right = values.length - 1; left <= right;) {
int center = (left + right) / 2;
int res = ((IntegerEntity) values[center]).compareContains(v);
if (res == 0)
return true;
if (res == -1)
left = center + 1;
else
right = center - 1;
}
return false;
}
private Object cacheAllValues; // cache for lazy initialization
/** Returns the number of values in the domain, if the domain is finite. Returns -1 otherwise. */
public long nValues() {
if (cacheAllValues == null)
cacheAllValues = allValues();
return cacheAllValues == null ? -1 : cacheAllValues instanceof Range ? ((Range) cacheAllValues).length() : ((int[]) cacheAllValues).length;
}
/**
* Returns the values of the integer domain, either as an object Range or as an array of integers. Returns null if the domain is infinite (or
* too large).
**/
public Object allValues() {
if (cacheAllValues == null) {
IntegerEntity[] vs = (IntegerEntity[]) values;
if (values.length == 1 && values[0] instanceof IntegerInterval) {
IntegerInterval ii = (IntegerInterval) values[0];
cacheAllValues = ii.width() == -1 ? null : new Range(ii);
} else
cacheAllValues = IntegerEntity.toIntArray(vs, Integer.MAX_VALUE);
}
assert !(cacheAllValues instanceof int[])
|| IntStream.range(0, ((int[]) cacheAllValues).length - 1).allMatch(i -> ((int[]) cacheAllValues)[i] < ((int[]) cacheAllValues)[i + 1]);
return cacheAllValues;
}
/**
* Returns this object if the condition is evaluated to {@code true}, {@code null} otherwise.
*
* @param condition
* a Boolean expression
* @return this object if the condition is evaluated to {@code true}, {@code null} otherwise
*/
public Dom when(boolean condition) {
return condition ? this : null;
}
}
/** The class for representing the domain of a symbolic variable. */
public static final class DomSymbolic extends DomBasic {
/** Builds a symbolic domain, with the symbols obtained by parsing the specified string. */
protected DomSymbolic(String seq) {
super(Stream.of(seq.split("\\s+")).sorted().toArray(String[]::new));
}
/** Builds a symbolic domain, with the specified symbols. */
public DomSymbolic(String[] values) {
super(values);
}
/** Returns true iff the domain contains the specified value. */
public boolean contains(String s) {
return Arrays.binarySearch(values, s) >= 0;
}
}
/** The class for representing the domain of a real variable. */
public static class DomReal extends DomBasic {
/** Builds a real domain, with the intervals obtained by parsing the specified string. */
protected DomReal(String seq) {
super(RealInterval.parseSeq(seq));
}
}
/** The class for representing the domain of a stochastic variable. */
public static final class DomStochastic extends DomBasic {
/** Returns the stochastic domain obtained by parsing the specified string, according to the specified type. */
public static DomStochastic parse(String s, TypeVar type) {
String[] toks = s.split("\\s+");
Object[] values = new Object[toks.length];
SimpleValue[] probas = new SimpleValue[toks.length];
for (int i = 0; i < toks.length; i++) {
String[] t = toks[i].split(":");
values[i] = type == TypeVar.symbolic_stochastic ? t[0] : IntegerEntity.parse(t[0]);
probas[i] = SimpleValue.parse(t[1]);
}
return new DomStochastic(values, probas);
}
/**
* The probabilities associated with the values of the domain: probas[i] is the probability of values[i]. Probabilities can be given as
* rational, decimal, or integer values (only, 0 and 1 for integer).
*/
public final SimpleValue[] probas;
/** Builds a stochastic domain, with the specified values and the specified probabilities. */
protected DomStochastic(Object[] values, SimpleValue[] probas) {
super(values);
this.probas = probas;
assert values.length == probas.length;
}
@Override
public String toString() {
return super.toString() + " Probas: " + Utilities.join(probas);
}
}
/** The interface to tag complex domains, i.e. domains for set or graph variables. */
public static interface DomComplex extends IDom {
}
/** The class for representing the domain of a set variable. */
public static final class DomSet implements DomComplex {
/** Returns the set domain obtained by parsing the specified strings, according to the specified type. */
public static DomSet parse(String req, String pos, TypeVar type) {
return type == TypeVar.set ? new DomSet(IntegerEntity.parseSeq(req), IntegerEntity.parseSeq(pos))
: new DomSet(req.split("\\s+"), pos.split("\\s+"));
}
/**
* The required and possible values. For an integer set domain, values are IntegerEntity. For a symbolic set domain, values are String.
*/
public final Object[] required, possible;
/** Builds a set domain, with the specified required and possible values. */
protected DomSet(Object[] required, Object[] possible) {
this.required = required;
this.possible = possible;
}
@Override
public String toString() {
return "[{" + Utilities.join(required) + "},{" + Utilities.join(possible) + "}]";
}
}
/** The class for representing the domain of a graph variable. */
public static final class DomGraph implements DomComplex {
/** Returns the graph domain obtained by parsing the specified strings, according to the specified type. */
public static DomGraph parse(String reqV, String reqE, String posV, String posE, TypeVar type) {
String[] rV = reqV.split("\\s+"), pV = posV.split("\\s+");
String[][] rE = Stream.of(reqE.split(Constants.DELIMITER_LISTS)).skip(1).map(tok -> tok.split("\\s*,\\s*")).toArray(String[][]::new);
String[][] pE = Stream.of(posE.split(Constants.DELIMITER_LISTS)).skip(1).map(tok -> tok.split("\\s*,\\s*")).toArray(String[][]::new);
return new DomGraph(rV, pV, rE, pE);
}
/** The required and possible nodes (vertices). */
public final String[] requiredV, possibleV;
/** The required and possible edges or arcs. */
public final String[][] requiredE, possibleE;
/** Builds a graph domain, with the specified required and possible values (nodes and edges/arcs). */
protected DomGraph(String[] requiredV, String[] possibleV, String[][] requiredE, String[][] possibleE) {
this.requiredV = requiredV;
this.possibleV = possibleV;
this.requiredE = requiredE;
this.possibleE = possibleE;
}
@Override
public String toString() {
return "[{" + Utilities.join(requiredV) + "-" + Utilities.join(requiredE) + "},{" + Utilities.join(possibleV) + "-" + Utilities.join(possibleE)
+ "}]";
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy