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

org.chocosolver.parser.xcsp.tools.XValues Maven / Gradle / Ivy

package org.chocosolver.parser.xcsp.tools;

import org.chocosolver.parser.xcsp.tools.XDomains.DomBasic;
import org.chocosolver.parser.xcsp.tools.XDomains.DomInteger;
import org.chocosolver.parser.xcsp.tools.XParser.ModifiableBoolean;
import org.chocosolver.parser.xcsp.tools.XVariables.TypeVar;
import org.chocosolver.parser.xcsp.tools.XVariables.Var;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

import static org.chocosolver.parser.xcsp.tools.XConstants.*;
import static org.chocosolver.parser.xcsp.tools.XUtility.safeLong;

public class XValues {

	/** The enum type describing the different types of primitives that can be used for representing arrays of integer tuples. */
	public static enum TypePrimitive {
		BYTE,
		SHORT,
		INT,
		LONG;

		/** Returns the smallest primitive that can be used for representing values lying within the specified bounds. */
		public static TypePrimitive whichPrimitiveFor(long inf, long sup) {
			if (MIN_SAFE_BYTE <= inf && sup <= MAX_SAFE_BYTE)
				return BYTE;
			if (MIN_SAFE_SHORT <= inf && sup <= MAX_SAFE_SHORT)
				return SHORT;
			if (MIN_SAFE_INT <= inf && sup <= MAX_SAFE_INT)
				return INT;
			// if (MIN_SAFE_LONG <= inf && sup <= MAX_SAFE_LONG)
			return LONG; // else return null;
		}

		/** Returns the smallest primitive that can be used for representing the specified value. */
		public static TypePrimitive whichPrimitiveFor(long val) {
			return whichPrimitiveFor(val, val);
		}

		/**
		 * Returns the smallest primitive that can be used for representing any value of the domains of the specified variables. If one variable is not integer,
		 * null is returned.
		 */
		public static TypePrimitive whichPrimitiveFor(Var[] vars) {
			if (Stream.of(vars).anyMatch(x -> x.type != TypeVar.integer))
				return null;
			return TypePrimitive.values()[Stream.of(vars).mapToInt(x -> ((DomInteger) x.dom).whichPrimitive().ordinal()).max()
					.orElse(TypePrimitive.LONG.ordinal())];
		}

		/**
		 * Returns the smallest primitive that can be used for representing any value of the domains of the specified variables. If one variable is not integer,
		 * null is returned.
		 */
		public static TypePrimitive whichPrimitiveFor(Var[][] varss) {
			if (whichPrimitiveFor(varss[0]) == null)
				return null;
			return TypePrimitive.values()[Stream.of(varss).mapToInt(t -> whichPrimitiveFor(t).ordinal()).max().orElse(TypePrimitive.LONG.ordinal())];
		}

		/** Returns true iff the primitive can represent the specified value. */
		private boolean canRepresent(long val) {
			return this.ordinal() >= whichPrimitiveFor(val).ordinal();
		}

		/**
		 * Parse the specified string that denotes a sequence of values. In case, we have at least one interval, we just return an array of IntegerEntity (as
		 * for integer domains), and no validity test on values is performed. Otherwise, we return an array of integer (either long[] or int[]). It is possible
		 * that some values are discarded because either they do not belong to the specified domain (test performed if this domain is not null), or they cannot
		 * be represented by the primitive.
		 */
		protected Object parseSeq(String s, DomInteger dom) {
			if (s.indexOf("..") != -1)
				return IntegerEntity.parseSeq(s);
			int nbDiscarded = 0;
			List list = new ArrayList<>();
			for (String tok : s.split("\\s+")) {
				assert !tok.equals("*") : "STAR not handled in unary lists";
				long l = XUtility.safeLong(tok);
				if (canRepresent(l) && (dom == null || dom.contains(l)))
					list.add(l);
				else
					nbDiscarded++;
			}
			if (nbDiscarded > 0)
				System.out.println(nbDiscarded + " discarded values in the unary list " + s);
			if (this == LONG)
				return list.stream().mapToLong(i -> i).toArray();
			else
				return list.stream().mapToInt(i -> i.intValue()).toArray();
			// TODO possible refinement for returning byte[] and short[]
		}

		/**
		 * Parse the specified string, and builds a tuple of (long) integers put in the specified array t. If the tuple is not valid wrt the specified domains
		 * or the primitive, false is returned, in which case, the tuple can be discarded. If * is encountered, the specified modifiable boolean is set to true.
		 */
		protected boolean parseTuple(String s, long[] t, DomBasic[] doms, ModifiableBoolean mb) {
			String[] toks = s.split("\\s*,\\s*");
			assert toks.length == t.length : toks.length + " " + t.length;
			for (int i = 0; i < toks.length; i++) {
				if (toks[i].equals("*")) {
					t[i] = this == BYTE ? XConstants.STAR_BYTE : this == SHORT ? XConstants.STAR_SHORT : this == INT ? XConstants.STAR_INT : XConstants.STAR;
					mb.value = true;
				} else {
					long l = XUtility.safeLong(toks[i]);
					if (canRepresent(l) && (doms == null || ((DomInteger) doms[i]).contains(l)))
						t[i] = l;
					else
						return false; // because the tuple can be discarded
				}
			}
			return true;
		}
	}

	/** An interface used to denote simple values, i.e., rational, decimal or integer values. */
	public static interface SimpleValue {
		/**
		 * Returns a simple value obtained by parsing the specified string. The specified boolean allows us to indicate if special values (such as +infinity)
		 * must be checked.
		 */
		public static SimpleValue parse(String s, boolean checkSpecialValues) {
			String[] t = s.split("/");
			if (t.length == 2)
				return new Rational(safeLong(t[0]), safeLong(t[1]));
			t = s.split("\\.");
			if (t.length == 2)
				return new Decimal(safeLong(t[0]), safeLong(t[1]));
			return new IntegerValue(safeLong(s, checkSpecialValues));
		}

		/** Returns a simple value obtained by parsing the specified string. */
		public static SimpleValue parse(String s) {
			return parse(s, false);
		}

		/** Returns an array of SimpleValue objects, obtained by parsing the specified string. */
		public static SimpleValue[] parseSeq(String seq) {
			return Stream.of(seq.split("\\s+")).map(s -> SimpleValue.parse(s)).toArray(SimpleValue[]::new);
		}
	}

	/**
	 * An interface used to denote integer entities, i.e., either integer values or integer intervals. These entities are present when defining integer domains
	 * or unary integer extensional constraints.
	 */
	public static interface IntegerEntity extends Comparable {
		/** Returns an integer entity (integer value or integer interval) obtained by parsing the specified string. */
		public static IntegerEntity parse(String s) {
			String[] t = s.split("\\.\\.");
			return t.length == 1 ? new IntegerValue(safeLong(t[0])) : new IntegerInterval(safeLong(t[0], true), safeLong(t[1], true));
		}

		/** Returns an array of integer entities (integer values or integer intervals) obtained by parsing the specified string. */
		public static IntegerEntity[] parseSeq(String seq) {
			return Stream.of(seq.split("\\s+")).map(tok -> IntegerEntity.parse(tok)).toArray(IntegerEntity[]::new);
		}

		@Override
		public default int compareTo(IntegerEntity p) {
			long l1 = this instanceof IntegerValue ? ((IntegerValue) this).v : ((IntegerInterval) this).inf;
			long l2 = p instanceof IntegerValue ? ((IntegerValue) p).v : ((IntegerInterval) p).inf;
			return l1 < l2 ? -1 : l1 > l2 ? 1 : 0; // correct because pieces do not overlap
		}

		/** Returns true iff the entity is an integer value or an integer interval containing only one value */
		public boolean isSingleton();

		/** Returns the smallest value of the entity (the value itself or the lower bound of the interval). */
		public long smallest();

		/** Returns the greatest value of the entity (the value itself or the upper bound of the interval). */
		public long greatest();

		/** Returns the number of values represented by the entity. */
		public long width();

		/**
		 * Returns 0 if the entity contains the specified value, -1 if the values of the entity are strictly smaller than the specified value, and +1 if the
		 * values of the entity are strictly greater than the specified value.
		 */
		public int compareContains(long l);

	}

	/** A class to represent an integer value. */
	public static final class IntegerValue implements IntegerEntity, SimpleValue {
		/** The value of the integer. */
		public final long v;

		/** Builds an IntegerValue object with the specified value. */
		protected IntegerValue(long v) {
			this.v = v;
		}

		@Override
		public boolean isSingleton() {
			return true;
		}

		@Override
		public long smallest() {
			return v;
		}

		@Override
		public long greatest() {
			return v;
		}

		@Override
		public long width() {
			return 1L;
		}

		@Override
		public int compareContains(long l) {
			return Long.compare(v, l);
		}

		@Override
		public String toString() {
			return v + "";
		}
	}

	/** A class to represent an integer interval. */
	public static final class IntegerInterval implements IntegerEntity {
		/** The bounds of the interval. */
		public final long inf, sup;

		/** Builds an IntegerInterval object with the specified bounds. */
		protected IntegerInterval(long inf, long sup) {
			this.inf = inf;
			this.sup = sup;
			assert inf <= sup : "Pb with an interval " + this;
		}

		@Override
		public boolean isSingleton() {
			return inf == sup;
		}

		@Override
		public long smallest() {
			return inf;
		}

		@Override
		public long greatest() {
			return sup;
		}

		@Override
		public long width() {
			return sup - inf + 1;
		}

		@Override
		public int compareContains(long l) {
			return sup < l ? -1 : inf > l ? 1 : 0;
		}

		@Override
		public String toString() {
			return inf + ".." + sup;
		}
	}

	/** A class to represent rational values. */
	static final class Rational implements SimpleValue {
		/** The numerator and the denominator of the rational. */
		public final long numerator, denominator;

		/** Builds a rational with the specified numerator and denominator. */
		protected Rational(long num, long den) {
			this.numerator = num;
			this.denominator = den;
			assert den != 0 : "Pb with rational " + this;
		}

		@Override
		public String toString() {
			return numerator + "/" + denominator;
		}
	}

	/** A class to represent decimal values. */
	static final class Decimal implements SimpleValue {
		/** The integer and decimal parts of the decimal value. */
		public final long integerPart, decimalPart;

		/** Builds a decimal with the specified integer and decimal parts. */
		protected Decimal(long integerPart, long decimalPart) {
			this.integerPart = integerPart;
			this.decimalPart = decimalPart;
		}

		@Override
		public String toString() {
			return integerPart + "." + decimalPart;
		}
	}

	/** A class to represent real intervals. */
	static final class RealInterval {
		/** Returns a real interval by parsing the specified string. */
		public static RealInterval parse(String s) {
			boolean infClosed = s.charAt(0) == '[', supClosed = s.charAt(s.length() - 1) == '[';
			String[] t = s.split(",");
			SimpleValue inf = SimpleValue.parse(t[0].substring(1), true), sup = SimpleValue.parse(t[1].substring(0, t[1].length() - 1), true);
			return new RealInterval(inf, sup, infClosed, supClosed);
		}

		/** Returns an array of real intervals by parsing the specified string. */
		public static RealInterval[] parseSeq(String seq) {
			return Stream.of(seq.split("\\s+")).map(tok -> RealInterval.parse(tok)).toArray(RealInterval[]::new);
		}

		/** The bounds of the interval. */
		public final SimpleValue inf, sup;

		/** The status (open/closed) of the bounds of the interval. */
		public final boolean infClosed, supClosed;

		/** Builds a real interval with the specified bounds together with their status. */
		protected RealInterval(SimpleValue inf, SimpleValue sup, boolean infClosed, boolean supClosed) {
			this.inf = inf;
			this.sup = sup;
			this.infClosed = infClosed;
			this.supClosed = supClosed;
		}

		@Override
		public String toString() {
			return (infClosed ? "[" : "]") + inf + "," + sup + (supClosed ? "[" : "]");
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy