public static Long safeLong(String s, boolean checkSpecialValues) {
	if (checkSpecialValues) {
		if (s.equals(PLUS_INFINITY_STRING))
			return PLUS_INFINITY;
		if (s.equals(MINUS_INFINITY_STRING))
			return MINUS_INFINITY;
	}
	if (s.length() > 18) { // 18 because MAX_LONG and MIN_LONG are composed of at most 19 characters
		BigInteger big = new BigInteger(s);
		control(big.compareTo(BIG_MIN_SAFE_LONG) >= 0 && big.compareTo(BIG_MAX_SAFE_LONG) <= 0, "Too small or big value for this parser : " + s);
		return big.longValue();
	} else
		return Long.parseLong(s);
} public class Types {

	public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) {
		try {
			return Enum.valueOf(enumType, enumType == TypeCtr.class || enumType == TypeChild.class || enumType == TypeAtt.class ? name : name.toUpperCase());
			// currently, the three enums mentioned above do not (systematically) use upper-case
		} catch (IllegalArgumentException e) {
			return null;
		}
	}

	/** The enum type specifying the different types of frameworks. */
	public static enum TypeFramework {
		CSP, MAXCSP, COP, UNKNOWN; // , WCSP, FCSP, QCSP, QCSP_PLUS, QCOP, QCOP_PLUS, SCSP, SCOP, QSTR, TCSP, NCSP,
									// NCOP, DisCSP, DisWCSP;
	}

	/**
	 * The enum type describing the different types of variables.
	 */
	public static enum TypeVar {
		integer, symbolic, real, stochastic, symbolic_stochastic, set, symbolic_set, undirected_graph, directed_graph, point, interval, region;

		/** Returns true if the constant corresponds to integer, symbolic, real or (symbolic) stochastic. */
		public boolean isBasic() {
			return this == integer || this == symbolic || this == real || isStochastic();
		}

		public boolean isStochastic() {
			return this == stochastic || this == symbolic_stochastic;
		}

		public boolean isSet() {
			return this == set || this == symbolic_set;
		}

		public boolean isGraph() {
			return this == undirected_graph || this == directed_graph;
		}

		public boolean isComplex() {
			return isSet() || isGraph();
		}

		public boolean isQualitative() {
			return this == point || this == interval || this == region;
		}
	}

	/**
	 * The enum type specifying the different types of constraints and meta-constraints. We use lower-case letters, so
	 * as to directly get the names of the elements (no need to define constants or make any transformations).
	 */
	public static enum TypeCtr {
		extension,
		intension,
		regular,
		grammar,
		mdd,
		allDifferent,
		allEqual,
		allDistant,
		ordered,
		lex,
		allIncomparable,
		sum,
		count,
		nValues,
		cardinality,
		balance,
		spread,
		deviation,
		sumCosts,
		stretch,
		noOverlap,
		cumulative,
		binPacking,
		knapsack,
		networkFlow,
		circuit,
		nCircuits,
		path,
		nPaths,
		tree,
		nTrees,
		arbo,
		nArbos,
		nCliques,
		clause,
		instantiation,
		allIntersecting,
		range,
		roots,
		partition,
		minimum,
		maximum,
		element,
		channel,
		permutation,
		precedence,
		and,
		or,
		not,
		iff, // future meta-constraint to be taken into account
		ifThen,
		ifThenElse,
		slide,
		seqbin,
		smart;

		/** Returns true if the element has a sliding nature. */
		public boolean isSliding() {
			return this == slide || this == seqbin;
		}

		/** Returns true if the element has a "direct" logical nature. */
		public boolean isLogical() {
			return this == and || this == or || this == not || this == iff;
		}

		/** Returns true if the element has a logical nature corresponding to an if-based control structure. */
		public boolean isControl() {
			return this == ifThen || this == ifThenElse;
		}

		/** Returns true if the element corresponds to a meta-constraint. */
		public boolean isMeta() {
			return isSliding() || isLogical() || isControl();
		}

		/**
		 * Returns {@code true} iff this type is one of the specified types.
		 * 
		 * @param types
		 *            a sequence of types
		 * @return {@code true} iff this type is one of the specified types
		 */
		public boolean oneOf(TypeCtr... types) {
			return Stream.of(types).anyMatch(t -> t == this);
		}
	}

	/**
	 * The enum type specifying the different types of child elements of constraints. We use lower-case letters, so as
	 * to directly get the names of the elements (except for FINAL that needs to be managed apart, because this is a
	 * keyword).
	 */
	public static enum TypeChild {
		list,
		set,
		mset,
		matrix,
		function,
		supports,
		conflicts,
		except,
		value,
		values,
		total,
		coeffs,
		condition,
		cost,
		operator,
		number,
		transitions,
		start,
		FINAL, // upper-cased because a keyword
		terminal,
		rules,
		index,
		mapping,
		occurs,
		rowOccurs,
		colOccurs,
		widths,
		patterns,
		origins,
		lengths,
		ends,
		heights,
		machines,
		conditions,
		sizes,
		weights,
		profits,
		limit,
		size,
		root,
		image,
		graph,
		row;
	}

	/**
	 * The enum type specifying the different types of attributes that may be encountered. We use lower-case letters, so
	 * as to directly get the names of the elements (except for CLASS, FOR and CASE that need to be managed apart,
	 * because they correspond to keywords).
	 */
	public static enum TypeAtt {
		format,
		type,
		id,
		CLASS, // upper-cased because a keyword
		note,
		as,
		size,
		violationMeasure,
		violationParameters,
		defaultCost,
		violationCost,
		cost,
		reifiedBy,
		hreifiedFrom,
		hreifiedTo,
		closed,
		FOR, // upper-cased because a keyword
		restriction,
		rank,
		startIndex,
		startRowIndex,
		startColIndex,
		zeroIgnored,
		CASE, // upper-cased because a keyword
		order,
		circular,
		offset,
		collect,
		covered,
		violable,
		lb,
		ub,
		combination;
		// unclean, // used for tuples of table constraints
		// starred; // used for tuples of table constraints

		/**
		 * Returns true iff the element has a (full or half) reification nature.
		 */
		public boolean isReifying() {
			return this == reifiedBy || this == hreifiedFrom || this == hreifiedTo;
		}

		/**
		 * Returns the constant that corresponds to the specified string (we need this method to manage the special
		 * constants FOR and CASE).
		 */
		public static TypeAtt valOf(String s) {
			return s.equals("class") ? CLASS : s.equals("for") ? FOR : s.equals("case") ? TypeAtt.CASE : valueOf(s);
		}
	}

	/**
	 * The enum type specifying the different flags that may be associated with some elements (e.g., constraints).
	 */
	public static enum TypeFlag {
		STARRED_TUPLES, UNCLEAN_TUPLES, SMART_TUPLES;
	}

	/** The enum type specifying the different types of reification. */
	public static enum TypeReification {
		FULL, HALF_FROM, HALF_TO;
	}

	/** The enum type specifying the different types of lifting operations (except matrix). */
	public static enum TypeLifting {
		LIST, SET, MSET;
	}

	/**
	 * The enum type specifying the different types of operators that can be used in conditions.
	 */
	public static enum TypeConditionOperator {
		LT, LE, GE, GT, NE, EQ, IN, NOTIN;

		/**
		 * Returns the corresponding specialized TypeConditionOperatorRel for this constant, or null if this constant is
		 * a set operator.
		 */
		public TypeConditionOperatorRel toRel() {
			return isSet() ? null
					: this == LT ? TypeConditionOperatorRel.LT
							: this == LE ? TypeConditionOperatorRel.LE
									: this == GE ? TypeConditionOperatorRel.GE
											: this == GT ? TypeConditionOperatorRel.GT : this == NE ? TypeConditionOperatorRel.NE : TypeConditionOperatorRel.EQ;
		}

		/**
		 * Returns the corresponding specialized TypeConditionOperatorSet for this constant, or null if this constant is
		 * a relational operator.
		 */
		public TypeConditionOperatorSet toSet() {
			return !isSet() ? null : this == IN ? TypeConditionOperatorSet.IN : TypeConditionOperatorSet.NOTIN;
		}

		/** Returns true iff this constant corresponds to a set operator. */
		public boolean isSet() {
			return this == IN || this == NOTIN;
		}
	}

	/**
	 * The enum type specifying the different types of relational operators that can be used in conditions.
	 */
	public static enum TypeConditionOperatorRel {
		LT, LE, GE, GT, NE, EQ;

		/**
		 * Returns the operator that is the reverse operator of this operator (no change for NE and EQ).
		 */
		public TypeConditionOperatorRel arithmeticInversion() {
			return this == LT ? GT : this == LE ? GE : this == GE ? LE : this == GT ? LT : this; // no change for NE and
																									// EQ
		}

		/**
		 * Returns true iff this operator evaluates to true when given the two specified operands.
		 */
		public boolean isValidFor(long v1, long v2) {
			return this == LT ? v1 < v2 : this == LE ? v1 <= v2 : this == GE ? v1 >= v2 : this == GT ? v1 > v2 : this == NE ? v1 != v2 : v1 == v2;
		}

		public static TypeConditionOperatorRel valueFor(String s) {
			Utilities.control(s.equals("<") || s.equals("<=") || s.equals(">") || s.equals(">=") || s.equals("=") || s.equals("!="), "bad argument");
			return s.equals("<") ? LT : s.equals("<=") ? LE : s.equals(">") ? GT : s.equals(">=") ? GE : s.equals("=") ? EQ : NE;
		}

		public boolean oneOf(TypeConditionOperatorRel... types) {
			return Stream.of(types).anyMatch(t -> t == this);
		}

		/**
		 * The type from {@code TypeExpr} with the same name as this type, if it exists, {@code null} otherwise.
		 * 
		 * @return The type from {@code TypeExpr} with the same name as this type, if it exists, {@code null} otherwise
		 */
		public TypeExpr toExpr() {
			return this == LT ? TypeExpr.LT
					: this == LE ? TypeExpr.LE
							: this == GE ? TypeExpr.GE : this == GT ? TypeExpr.GT : this == EQ ? TypeExpr.EQ : this == NE ? TypeExpr.NE : null;
		}

	}

	/**
	 * The enum type specifying the different types of set operators that can be used in conditions.
	 */
	public static enum TypeConditionOperatorSet {
		IN, NOTIN;

		/**
		 * Returns true iff this operator evaluates to true when given the specified value and the two specified bounds
		 * of an interval.
		 */
		public boolean isValidFor(int v, long min, long max) {
			return this == IN ? min <= v && v <= max : v < min || v > max;
		}

		/**
		 * Returns true iff this operator evaluates to true when given the sepcified value and the specified set of
		 * values.
		 */
		public boolean isValidFor(int v, int[] t) {
			return (this == IN) == (IntStream.of(t).anyMatch(w -> v == w));
		}

		/**
		 * The type from {@code TypeExpr} with the same name as this type, if it exists, {@code null} otherwise.
		 * 
		 * @return The type from {@code TypeExpr} with the same name as this type, if it exists, {@code null} otherwise
		 */
		public TypeExpr toExpr() {
			return this == IN ? TypeExpr.IN : this == NOTIN ? TypeExpr.NOTIN : null;
		}
	}

	/**
	 * The enum type specifying the different types of operators that can be used in elements <operator>.
	 */
	public static enum TypeOperator {
		LT, LE, GE, GT, SUBSET, SUBSEQ, SUPSEQ, SUPSET;

		public static TypeOperator valOf(String s) {
			return TypeOperator.valueOf(s.trim().toUpperCase());
		}

		/**
		 * Returns the corresponding specialized TypeOperatorRel for this constant, or null if this constant is a set
		 * operator,.
		 */
		public TypeOperatorRel toRel() {
			return isSet() ? null : this == LT ? TypeOperatorRel.LT : this == LE ? TypeOperatorRel.LE : this == GE ? TypeOperatorRel.GE : TypeOperatorRel.GT;
		}

		/** Returns true iff the constant corresponds to a set operator. */
		public boolean isSet() {
			return this == SUBSET || this == SUBSEQ || this == SUPSEQ || this == SUPSET;
		}

	}

	/**
	 * The different operators that can be used in elements <operator>, when a relational operator is expected.
	 */
	public static enum TypeOperatorRel {
		LT, LE, GE, GT;

		/**
		 * Returns the operator that is the reverse operator of this operator (no change for NE and EQ).
		 */
		public TypeOperatorRel arithmeticInversion() {
			return this == LT ? GT : this == LE ? GE : this == GE ? LE : LT;
		}

		/**
		 * Returns true iff this operator evaluates to true when given the two specified operands.
		 */
		public boolean isValidFor(long v1, long v2) {
			return this == LT ? v1 < v2 : this == LE ? v1 <= v2 : this == GE ? v1 >= v2 : v1 > v2;
		}

		/**
		 * The type from {@code TypeExpr} with the same name as this type.
		 * 
		 * @return The type from {@code TypeExpr} with the same name as this type
		 */
		public TypeExpr toExpr() {
			return this == LT ? TypeExpr.LT : this == LE ? TypeExpr.LE : this == GE ? TypeExpr.GE : TypeExpr.GT;
		}

		public TypeConditionOperatorRel toConditionOperator() {
			return this == LT ? TypeConditionOperatorRel.LT
					: this == LE ? TypeConditionOperatorRel.LE : this == GE ? TypeConditionOperatorRel.GE : TypeConditionOperatorRel.GT;
		}
	}

	/**
	 * The different operators that can be used in elements <operator>, when a set operator is expected.
	 */
	public static enum TypeOperatorSet {
		SUBSET, SUBSEQ, SUPSEQ, SUPSET;
	}

	/**
	 * The enum type specifying the different types of operators that can be used in elements <operator>.
	 */
	public static enum TypeArithmeticOperator {
		ADD, SUB, MUL, DIV, MOD, DIST, POW;

		/**
		 * The type from {@code TypeExpr} with the same name as this type, if it exists, {@code null} otherwise.
		 * 
		 * @return The type from {@code TypeExpr} with the same name as this type, if it exists, {@code null} otherwise
		 */
		public TypeExpr toExpr() {
			return this == ADD ? TypeExpr.ADD
					: this == SUB ? TypeExpr.SUB
							: this == MUL ? TypeExpr.MUL
									: this == DIV ? TypeExpr.DIV : this == MOD ? TypeExpr.MOD : this == POW ? TypeExpr.POW : this == DIST ? TypeExpr.DIV : null;
		}
	}

	/**
	 * The enum type specifying the different types of basic unary arithmetic (and logic) operators.
	 */
	public static enum TypeUnaryArithmeticOperator {
		ABS, NEG, SQR, NOT;
	}

	/**
	 * The enum type specifying the different types of (non unary) logic operators.
	 */
	public static enum TypeLogicalOperator {
		AND, OR, XOR, IFF, IMP;
	}

	/**
	 * The enum type specifying the two relational operators EQ and NE.
	 */
	public static enum TypeEqNeOperator {
		EQ, NE;
	}

	/**
	 * The enum type specifying the different types of nodes that can be found in syntactic trees (built for intensional
	 * expressions).
	 */
	public static enum TypeExpr {
		NEG(1),
		ABS(1),
		SQR(1),
		ADD(2, Integer.MAX_VALUE),
		SUB(2),
		MUL(2, Integer.MAX_VALUE),
		DIV(2),
		MOD(2),
		POW(2),
		DIST(2),
		MIN(2, Integer.MAX_VALUE),
		MAX(2, Integer.MAX_VALUE),
		LT(2),
		LE(2),
		GE(2),
		GT(2),
		NE(2, Integer.MAX_VALUE),
		EQ(2, Integer.MAX_VALUE),
		SET(0, Integer.MAX_VALUE),
		IN(2),
		NOTIN(2),
		NOT(1),
		AND(2, Integer.MAX_VALUE),
		OR(2, Integer.MAX_VALUE),
		XOR(2, Integer.MAX_VALUE),
		IFF(2, Integer.MAX_VALUE),
		IMP(2),
		IF(3),
		CARD(1),
		UNION(2, Integer.MAX_VALUE),
		INTER(2, Integer.MAX_VALUE),
		DIFF(2),
		SDIFF(2, Integer.MAX_VALUE),
		HULL(1),
		DJOINT(2),
		SUBSET(2),
		SUBSEQ(2),
		SUPSEQ(2),
		SUPSET(2),
		CONVEX(1),
		FDIV(2),
		FMOD(2),
		SQRT(1),
		NROOT(2),
		EXP(1),
		LN(1),
		LOG(2),
		SIN(1),
		COS(1),
		TAN(1),
		ASIN(1),
		ACOS(1),
		ATAN(1),
		SINH(1),
		COSH(1),
		TANH(1),
		VAR(0),
		PAR(0),
		LONG(0),
		RATIONAL(0),
		DECIMAL(0),
		SYMBOL(0),
		SPECIAL(0, Integer.MAX_VALUE); // SPECIAL is a virtual type, useful when managing abstract trees

		/**
		 * The name of this type in lower-case.
		 */
		public final String lcname;

		/**
		 * The minimum arity (number of sons) for a node of this type.
		 */
		public final int arityMin;

		/**
		 * The maximum arity (number of sons) for a node of this type.
		 */
		public final int arityMax;

		/** Builds a constant, while specifying its minimum and maximum arity (number of sons). */
		private TypeExpr(int arityMin, int arityMax) {
			this.arityMin = arityMin;
			this.arityMax = arityMax;
			this.lcname = name().toLowerCase();
		}

		/** Builds a constant, while specifying its arity (number of sons). */
		private TypeExpr(int arity) {
			this(arity, arity);
		}

		/**
		 * Returns {@code true} iff this type is one of the specified types.
		 * 
		 * @param types
		 *            a sequence of types
		 * @return {@code true} iff this type is one of the specified types
		 */
		public boolean oneOf(TypeExpr... types) {
			return Stream.of(types).anyMatch(t -> t == this);
		}

		/**
		 * Returns {@code true} iff this type is not one of the specified types.
		 * 
		 * @param types
		 *            a sequence of types
		 * @return {@code true} iff this type is not one of the specified types
		 */
		public boolean notOneOf(TypeExpr... types) {
			return Stream.of(types).noneMatch(t -> t == this);
		}

		/**
		 * Returns {@code true} iff this type denotes an operator that is commutative (and also associative when it is a
		 * non-binary operator).
		 * 
		 * @return {@code true} iff this type denotes an operator that is symmetric
		 */
		public boolean isSymmetricOperator() {
			return oneOf(ADD, MUL, MIN, MAX, DIST, NE, EQ, SET, AND, OR, XOR, IFF, UNION, INTER, DJOINT);
		}

		/**
		 * Returns {@code true} iff this type denotes a binary non-symmetric relational operator (i.e.,
		 * {@code LT, LE, GE and GT}).
		 * 
		 * @return {@code true} iff this type denotes a binary non-symmetric relational
		 */
		public boolean isUnsymmetricRelationalOperator() {
			return oneOf(LT, LE, GE, GT);
		}

		/**
		 * Returns {@code true} iff this type denotes a relational operator (i.e., {@code LT, LE, GE, GT, EQ and NE}).
		 * 
		 * @return {@code true} iff this type denotes a relational operator
		 */
		public boolean isRelationalOperator() {
			return isUnsymmetricRelationalOperator() || oneOf(NE, EQ);
		}

		/**
		 * Returns {@code true} iff this type denotes a unary arithmetic or logic operator (i.e.,
		 * {@code ABS, NEG, SQR, and NOT}).
		 * 
		 * @return {@code true} iff this type denotes a unary arithmetic or logic operator
		 */
		public boolean isUnaryArithmeticOrLogicOperator() {
			return oneOf(ABS, NEG, SQR, NOT);
		}

		/**
		 * Returns {@code true} iff this type denotes a (non-unary) arithmetic operator (i.e.,
		 * {@code ADD, SUB, MUL, DIV, MOD, POW and DIST}).
		 * 
		 * @return {@code true} iff this type denotes a (non-unary) arithmetic operator
		 */
		public boolean isArithmeticOperator() {
			return oneOf(ADD, SUB, MUL, DIV, MOD, POW, DIST);
		}

		/**
		 * Returns {@code true} iff this type denotes a (non-unary) logical operator (i.e.,
		 * {@code AND, OR, XOR, IFF, and IMP}).
		 * 
		 * @return {@code true} iff this type denotes a (non-unary) logical operator
		 */
		public boolean isLogicalOperator() {
			return oneOf(AND, OR, XOR, IFF, IMP);
		}

		/**
		 * Returns {@code true} iff this type denotes an operator that evaluates to 0/1 (false/true).
		 * 
		 * @return {@code true} iff this type denotes an operator that evaluates to 0/1 (false/true)
		 */
		public boolean isPredicateOperator() {
			return isRelationalOperator() || isLogicalOperator() || oneOf(NOT, IN, NOTIN);
		}

		/**
		 * Returns {@code true} iff this type denotes an operator that behaves like identity if only one operand was
		 * given.
		 * 
		 * @return @code true} iff this type denotes an operator that behaves like identity for only one operand
		 */
		public boolean isIdentityWhenOneOperand() {
			return oneOf(ADD, MUL, MIN, MAX, EQ, AND, OR, XOR, IFF);
		}

		/**
		 * Returns the type denoting the arithmetic inversion of this type, if this type denotes a relational operator,
		 * {@code null} otherwise. The arithmetic inversion is not obtained by applying a logical negation but a
		 * multiplication by -1. For example, the arithmetic inversion of {@code LT} is {@code GT} (and not {@code GE}).
		 * Also, the arithmetic inversion of {@code EQ} is {@code EQ}.
		 * 
		 * @return the type denoting the arithmetic inversion of this type, if this type denotes a relational operator,
		 *         {@code null} otherwise
		 */
		public TypeExpr arithmeticInversion() {
			return this == LT ? GT : this == LE ? GE : this == GE ? LE : this == GT ? LT : this == NE ? NE : this == EQ ? EQ : null;
		}

		/**
		 * Returns the type denoting the logical inversion of this type, if this type denotes a a Boolean operator (that
		 * can be inverted when considering the current pool of constants), {@code null} otherwise. The logical
		 * inversion is different from the arithmetic inversion. For example, the logical inversion of {@code LT} is
		 * {@code GE} (and not {@code GT}). Also, the logical inversion of {@code EQ} is {@code NE}.
		 * 
		 * @return the type denoting the logical inversion of this type, if this type denotes a a Boolean operator that
		 *         can be inverted, {@code null} otherwise
		 */
		public TypeExpr logicalInversion() {
			return this == LT ? GE
					: this == LE ? GT
							: this == GE ? LT
									: this == GT ? LE
											: this == NE ? EQ
													: this == EQ ? NE
															: this == IN ? NOTIN
																	: this == NOTIN ? IN
																			: this == SUBSET ? SUPSEQ
																					: this == SUBSEQ ? SUPSET
																							: this == SUPSEQ ? SUBSET : this == SUPSET ? SUBSEQ : null;
		}

		/**
		 * Returns {@code true} iff this type denotes an operator that can be logically inverted, {@code null}
		 * otherwise.
		 * 
		 * @return {@code true} iff this type denotes an operator that can be logically inverted, {@code null} otherwise
		 */
		public boolean isLogicallyInvertible() {
			return logicalInversion() != null;
		}

		/**
		 * The type from {@code TypeConditionOperatorRel} with the same name as this type, if it exists, {@code null}
		 * otherwise.
		 * 
		 * @return The type from {@code TypeConditionOperatorRel} with the same name as this type, if it exists,
		 *         {@code null} otherwise
		 */
		public TypeConditionOperatorRel toRelop() {
			return this == LT ? TypeConditionOperatorRel.LT
					: this == LE ? TypeConditionOperatorRel.LE
							: this == GE ? TypeConditionOperatorRel.GE
									: this == GT ? TypeConditionOperatorRel.GT
											: this == EQ ? TypeConditionOperatorRel.EQ : this == NE ? TypeConditionOperatorRel.NE : null;
		}

		/**
		 * The type from {@code TypeConditionOperatorSet} with the same name as this type, if it exists, {@code null}
		 * otherwise.
		 * 
		 * @return The type from {@code TypeConditionOperatorSet} with the same name as this type, if it exists,
		 *         {@code null} otherwise
		 */
		public TypeConditionOperatorSet toSetop() {
			return this == IN ? TypeConditionOperatorSet.IN : this == NOTIN ? TypeConditionOperatorSet.NOTIN : null;
		}

		/**
		 * The type from {@code TypeArithmeticOperator} with the same name as this type, if it exists, {@code null}
		 * otherwise.
		 * 
		 * @return The type from {@code TypeArithmeticOperator} with the same name as this type, if it exists,
		 *         {@code null} otherwise
		 */
		public TypeArithmeticOperator toAriop() {
			return this == ADD ? TypeArithmeticOperator.ADD
					: this == SUB ? TypeArithmeticOperator.SUB
							: this == MUL ? TypeArithmeticOperator.MUL
									: this == DIV ? TypeArithmeticOperator.DIV
											: this == MOD ? TypeArithmeticOperator.MOD
													: this == POW ? TypeArithmeticOperator.POW : this == DIST ? TypeArithmeticOperator.DIST : null;
		}

		/**
		 * The type from {@code TypeUnaryArithmeticOperator} with the same name as this type, if it exists, {@code null}
		 * otherwise.
		 * 
		 * @return The type from {@code TypeUnaryArithmeticOperator} with the same name as this type, if it exists,
		 *         {@code null} otherwise
		 */
		public TypeUnaryArithmeticOperator toUnalop() {
			return this == ABS ? TypeUnaryArithmeticOperator.ABS
					: this == NEG ? TypeUnaryArithmeticOperator.NEG
							: this == SQR ? TypeUnaryArithmeticOperator.SQR : this == NOT ? TypeUnaryArithmeticOperator.NOT : null;
		}

		/**
		 * The type from {@code TypeLogicalOperator} with the same name as this type, if it exists, {@code null}
		 * otherwise.
		 * 
		 * @return The type from {@code TypeLogicalOperator} with the same name as this type, if it exists, {@code null}
		 *         otherwise
		 */
		public TypeLogicalOperator toLogop() {
			return this == AND ? TypeLogicalOperator.AND
					: this == OR ? TypeLogicalOperator.OR
							: this == XOR ? TypeLogicalOperator.XOR : this == IFF ? TypeLogicalOperator.IFF : this == IMP ? TypeLogicalOperator.IMP : null;
		}

	}

	/**
	 * The enum type specifying the different types of measures used by elements <cost>.
	 */
	public static enum TypeMeasure {
		VAR, DEC, VAL, EDIT;
	}

	/** The enum type specifying the different types of objectives. */
	public static enum TypeObjective {
		EXPRESSION, SUM, PRODUCT, MINIMUM, MAXIMUM, NVALUES, LEX;

		public boolean generalizable() {
			return this == SUM || this == MINIMUM || this == MAXIMUM || this == NVALUES;
		}
	}

	/**
	 * The enum type specifying the different types of combination of objectives.
	 */
	public static enum TypeCombination {
		LEXICO, PARETO;
	}

	/**
	 * The enum type specifying the two directions 'Up' and 'Down'
	 */
	public static enum TypeUpDown {
		UP, DOWN;
	}

	/**
	 * The enum type specifying the different types of ranking used by constraints <maximum>, <minimum>, <element>.
	 */
	public static enum TypeRank {
		FIRST, LAST, ANY;
	}

	/**
	 * The enum type specifying the different types of optimization (used for annotations).
	 */
	public static enum TypeOptimization {
		MINIMIZE, MAXIMIZE;

		public String shortName() {
			return this == MINIMIZE ? "min" : "max";
		}
	}

	/**
	 * The interface that denotes a class (XML/HTML meaning) that can be associated with any XCSP3 element
	 */
	public interface TypeClass {

		/**
		 * Returns the camel case name of this constant (for example, clues, or symmetryBreaking)
		 */
		public String ccname();

		/** Transforms String objects into TypeClass objects. */
		public static TypeClass[] classesFor(String... classes) {
			return Stream.of(classes).map(
					s -> Stream.of(StandardClass.values()).map(c -> (TypeClass) c).filter(c -> c.ccname().equals(s)).findFirst().orElse(new SpecialClass(s)))
					.toArray(TypeClass[]::new);
		}

		/** Determines if the two specified arrays of TypeClass objects intersect or not. */
		public static boolean intersect(TypeClass[] t1, TypeClass[] t2) {
			return t1 != null && t2 != null && Stream.of(t1).anyMatch(c1 -> Stream.of(t2).anyMatch(c2 -> c1.ccname().equals(c2.ccname())));
		}

		/**
		 * Determines if the two specified arrays of TypeClass objects are equivalent or not.
		 */
		public static boolean equivalent(Set<TypeClass> s1, Set<TypeClass> s2) {
			return (s1 == null && s2 == null) || (s1 != null && s2 != null && s1.size() == s2.size()
					&& s1.stream().allMatch(c1 -> s2.stream().anyMatch(c2 -> c1.ccname().equals(c2.ccname()))));
		}
	}

	/**
	 * The enum type describing the different standard classes that can be associated with XCSP3 elements.
	 */
	public static enum StandardClass implements TypeClass {
		CHANNELING, CLUES, ROWS, COLUMNS, BLOCKS, DIAGONALS, SYMMETRY_BREAKING, REDUNDANT_CONSTRAINTS, NOGOODS;

		private final String ccname;

		@Override
		public String ccname() {
			return ccname;
		}

		private StandardClass() {
			ccname = Utilities.toKebabCase(super.name()); // toCamelCase(super.name());
		}

	}

	/** The class that allows the user to define his own classes */
	public static class SpecialClass implements TypeClass {
		private final String ccname;

		public SpecialClass(String name) {
			this.ccname = name;
		}

		@Override
		public String ccname() {
			return ccname;
		}

		@Override
		public boolean equals(Object o) {
			return o instanceof SpecialClass && ((SpecialClass) o).ccname.equals(this.ccname);
		}

		@Override
		public int hashCode() {
			return ccname.hashCode();
		}
	}
} public static enum TypeAtt {
	format,
	type,
	id,
	CLASS, // upper-cased because a keyword
	note,
	as,
	size,
	violationMeasure,
	violationParameters,
	defaultCost,
	violationCost,
	cost,
	reifiedBy,
	hreifiedFrom,
	hreifiedTo,
	closed,
	FOR, // upper-cased because a keyword
	restriction,
	rank,
	startIndex,
	startRowIndex,
	startColIndex,
	zeroIgnored,
	CASE, // upper-cased because a keyword
	order,
	circular,
	offset,
	collect,
	covered,
	violable,
	lb,
	ub,
	combination;
	// unclean, // used for tuples of table constraints
	// starred; // used for tuples of table constraints

	/**
	 * Returns true iff the element has a (full or half) reification nature.
	 */
	public boolean isReifying() {
		return this == reifiedBy || this == hreifiedFrom || this == hreifiedTo;
	}

	/**
	 * Returns the constant that corresponds to the specified string (we need this method to manage the special
	 * constants FOR and CASE).
	 */
	public static TypeAtt valOf(String s) {
		return s.equals("class") ? CLASS : s.equals("for") ? FOR : s.equals("case") ? TypeAtt.CASE : valueOf(s);
	}
} public interface TypeClass {

	/**
	 * Returns the camel case name of this constant (for example, clues, or symmetryBreaking)
	 */
	public String ccname();

	/** Transforms String objects into TypeClass objects. */
	public static TypeClass[] classesFor(String... classes) {
		return Stream.of(classes).map(
				s -> Stream.of(StandardClass.values()).map(c -> (TypeClass) c).filter(c -> c.ccname().equals(s)).findFirst().orElse(new SpecialClass(s)))
				.toArray(TypeClass[]::new);
	}

	/** Determines if the two specified arrays of TypeClass objects intersect or not. */
	public static boolean intersect(TypeClass[] t1, TypeClass[] t2) {
		return t1 != null && t2 != null && Stream.of(t1).anyMatch(c1 -> Stream.of(t2).anyMatch(c2 -> c1.ccname().equals(c2.ccname())));
	}

	/**
	 * Determines if the two specified arrays of TypeClass objects are equivalent or not.
	 */
	public static boolean equivalent(Set<TypeClass> s1, Set<TypeClass> s2) {
		return (s1 == null && s2 == null) || (s1 != null && s2 != null && s1.size() == s2.size()
				&& s1.stream().allMatch(c1 -> s2.stream().anyMatch(c2 -> c1.ccname().equals(c2.ccname()))));
	}
} public static enum TypeFlag {
	STARRED_TUPLES, UNCLEAN_TUPLES, SMART_TUPLES;
} public static enum TypeObjective {
	EXPRESSION, SUM, PRODUCT, MINIMUM, MAXIMUM, NVALUES, LEX;

	public boolean generalizable() {
		return this == SUM || this == MINIMUM || this == MAXIMUM || this == NVALUES;
	}
} public static enum TypeVar {
	integer, symbolic, real, stochastic, symbolic_stochastic, set, symbolic_set, undirected_graph, directed_graph, point, interval, region;

	/** Returns true if the constant corresponds to integer, symbolic, real or (symbolic) stochastic. */
	public boolean isBasic() {
		return this == integer || this == symbolic || this == real || isStochastic();
	}

	public boolean isStochastic() {
		return this == stochastic || this == symbolic_stochastic;
	}

	public boolean isSet() {
		return this == set || this == symbolic_set;
	}

	public boolean isGraph() {
		return this == undirected_graph || this == directed_graph;
	}

	public boolean isComplex() {
		return isSet() || isGraph();
	}

	public boolean isQualitative() {
		return this == point || this == interval || this == region;
	}
} public class Utilities {

	public static final Comparator<int[]> lexComparatorInt = (t1, t2) -> {
		for (int i = 0; i < t1.length; i++)
			if (t1[i] < t2[i])
				return -1;
			else if (t1[i] > t2[i])
				return +1;
		return 0;
	};

	public static final Comparator<String[]> lexComparatorString = (t1, t2) -> {
		for (int i = 0; i < t1.length; i++) {
			int res = t1[i].compareTo(t2[i]);
			if (res != 0)
				return res;
		}
		return 0;
	};

	public static <T> T[] buildArray(Class<?> cl, int length) {
		return (T[]) Array.newInstance(cl, length);
	}

	public static <T> T[][] buildArray(Class<?> cl, int length1, int length2) {
		return (T[][]) Array.newInstance(cl, length1, length2);
	}

	public static Object firstNonNull(Object array) {
		if (array != null && array.getClass().isArray())
			return IntStream.range(0, Array.getLength(array)).mapToObj(i -> firstNonNull(Array.get(array, i))).filter(o -> o != null).findFirst().orElse(null);
		return array;
	}

	/**
	 * Builds a one-dimensional array of T with the objects of the specified list. If the list does not contain any
	 * object other than null, null is returned.
	 */
	public static <T> T[] convert(Collection<T> list) {
		Object firstObject = list.stream().filter(o -> o != null).findFirst().orElse(null);
		if (firstObject == null)
			return null;
		T[] ts = buildArray(firstObject.getClass(), list.size());
		int i = 0;
		for (T x : list)
			ts[i++] = x;
		return ts;
	}

	/**
	 * Builds a one-dimensional array of T with the objects of the specified stream. If the stream does not contain any
	 * object other than null, null is returned.
	 */
	public static <T> T[] convert(Stream<T> stream) {
		return convert(stream.collect(Collectors.toList()));
	}

	public static <T> T[] convert(Object[] t) {
		Object firstObject = Stream.of(t).filter(o -> o != null).findFirst().orElse(null);
		Class<?> clazz = firstObject == null ? null
				: Stream.of(t).noneMatch(o -> o != null && o.getClass() != firstObject.getClass()) ? firstObject.getClass() : null;
		if (clazz == null)
			return null; // null is returned if the array has only null or elements of several types
		T[] ts = buildArray(firstObject.getClass(), t.length);
		int i = 0;
		for (Object x : t)
			ts[i++] = (T) x;
		return ts;
	}

	public static <T> T[][] convert(Object[][] t) {
		control(isRegular(t), " pb");
		// other controls to add
		T[][] m = buildArray(t[0][0].getClass(), t.length, t[0].length);
		for (int i = 0; i < t.length; i++)
			for (int j = 0; j < t[i].length; j++)
				m[i][j] = (T) t[i][j];
		return m;
	}

	public static Object[] specificArrayFrom(List<Object> list) {
		Object firstObject = list.stream().filter(o -> o != null).findFirst().orElse(null);
		Class<?> clazz = firstObject == null ? null
				: list.stream().noneMatch(o -> o != null && o.getClass() != firstObject.getClass()) ? firstObject.getClass() : null;
		return clazz == null ? list.toArray() : list.toArray((Object[]) Array.newInstance(clazz, list.size()));
	}

	public static Object[][] specificArray2DFrom(List<Object[]> list) {
		Class<?> clazz = list.stream().noneMatch(o -> o.getClass() != list.get(0).getClass()) ? list.get(0).getClass() : null;
		return clazz == null ? list.toArray(new Object[0][]) : list.toArray((Object[][]) Array.newInstance(clazz, list.size()));
	}

	private static <T> List<T> collectRec(Class<T> clazz, List<T> list, Object src) {
		if (src != null) {
			if (src instanceof Collection)
				collectRec(clazz, list, ((Collection<?>) src).stream());
			else if (src instanceof Stream)
				((Stream<?>) src).forEach(o -> collectRec(clazz, list, o));
			else if (src.getClass().isArray())
				IntStream.range(0, Array.getLength(src)).forEach(i -> collectRec(clazz, list, Array.get(src, i)));
			else if (clazz.isAssignableFrom(src.getClass()))
				list.add(clazz.cast(src));
			else if (src instanceof IntStream)
				((IntStream) src).forEach(o -> collectRec(clazz, list, o));
			else if (src.getClass() == Range.class)
				collectRec(clazz, list, ((Range) src).toArray()); // in order to deal with clazz being Integer.class
		}
		return list;
	}

	/**
	 * Returns a 1-dimensional array of objects of the specified type after collecting any object of this type being
	 * present in the specified objects. The specified objects can be stream (and IntStream), collections and arrays.
	 * The collecting process is made recursively.
	 * 
	 * @param clazz
	 *            the class of the objects to be collected
	 * @param src
	 *            the objects where to collect the objects
	 * @return a 1-dimensional array of objects of the specified type after collecting any object of this type being
	 *         present in the specified objects
	 */
	public static <T> T[] collect(Class<T> clazz, Object... src) {
		List<T> list = new ArrayList<>();
		Stream.of(src).forEach(o -> collectRec(clazz, list, o));
		return convert(list.stream().collect(Collectors.toList()));
	}

	/**
	 * Builds a 1-dimensional array of integers (int) from the specified sequence of parameters. Each parameter can be
	 * an integer, a Range, an array, a stream, a collection, etc. All integers are collected and concatenated to form a
	 * 1-dimensional array.
	 *
	 * @param src
	 *            the objects where to collect the integers
	 * @return a 1-dimensional array of integers after collecting any encountered integer in the specified objects
	 */
	public static int[] collectInt(Object... src) {
		Integer[] t = collect(Integer.class, src);
		return t == null ? new int[0] : Stream.of(t).filter(i -> i != null).mapToInt(i -> i).toArray();
	}

	public static boolean isNumeric(String token) {
		return token.matches("-?\\d+(\\.\\d+)?"); // match a number with optional '-' and decimal.
	}

	public static boolean isNumericInterval(String token) {
		return token.matches("-?\\d+\\.\\.-?\\d+");
	}

	public static int[] splitToInts(String s, String regex) {
		return Arrays.stream(s.trim().split(regex)).filter(tok -> tok.length() > 0).mapToInt(tok -> Integer.parseInt(tok)).toArray();
	}

	public static int[] splitToInts(String s) {
		return splitToInts(s, Constants.REG_WS);
	}

	public static int splitToInt(String s, String regex) {
		int[] t = splitToInts(s, regex);
		control(t.length > 0, "Not possible to extract an int from this call");
		return t[0];
	}

	public static int[] wordAsIntArray(String s) {
		assert s.chars().allMatch(c -> ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'));
		int[] t = new int[s.length()]; // We don't use streams here for efficiency reasons (when dealing with large sets
										// of words)
		for (int i = 0; i < s.length(); i++)
			t[i] = s.charAt(i) - (Character.isUpperCase(s.charAt(i)) ? 'A' : 'a');
		return t;
	}

	public static Boolean toBoolean(String s) {
		s = s.toLowerCase();
		if (s.equals("yes") || s.equals("y") || s.equals("true") || s.equals("t") || s.equals("1"))
			return Boolean.TRUE;
		if (s.equals("no") || s.equals("n") || s.equals("false") || s.equals("f") || s.equals("0"))
			return Boolean.FALSE;
		return null;
	}

	public static boolean isInteger(String token) {
		try {
			Integer.parseInt(token);
			return true;
		} catch (NumberFormatException e) {
			return false;
		}
	}

	public static boolean isLong(String token) {
		try {
			Long.parseLong(token);
			return true;
		} catch (NumberFormatException e) {
			return false;
		}
	}

	public static Integer toInteger(String token, Predicate<Integer> p) {
		try {
			Integer i = Integer.parseInt(token);
			Utilities.control(p == null || p.test(i), "Value " + i + " not accepted by " + p);
			return i;
		} catch (RuntimeException e) {
			return null;
		}
	}

	public static Integer toInteger(String token) {
		return toInteger(token, null);
	}

	public static int[] toIntegers(String[] tokens) {
		if (tokens == null || tokens.length == 0)
			return null;
		return Stream.of(tokens).map(tok -> toInteger(tok)).mapToInt(i -> i).toArray();
	}

	public static Double toDouble(String token, Predicate<Double> p) {
		try {
			Double d = Double.parseDouble(token);
			Utilities.control(p == null || p.test(d), "Value " + d + " not accepted by " + p);
			return d;
		} catch (RuntimeException e) {
			return null;
		}
	}

	public static double toDouble(String token) {
		return toDouble(token, null);
	}

	public static BigInteger powerBig(long a, int b) {
		return BigInteger.valueOf(a).pow(b);
	}

	public static int power(long a, int b) {
		return powerBig(a, b).intValueExact();
	}

	private static BigInteger recursiveFactorial(long start, long n) {
		long i;
		if (n <= 16) {
			BigInteger r = BigInteger.valueOf(start);
			for (i = start + 1; i < start + n; i++)
				r = r.multiply(BigInteger.valueOf(i));
			return r;
		}
		i = n / 2;
		return recursiveFactorial(start, i).multiply(recursiveFactorial(start + i, n - i));
	}

	public static BigInteger factorialBig(int n) {
		return recursiveFactorial(1, n);
	}

	public static int factorial(int n) {
		return factorialBig(n).intValueExact();
	}

	public static BigInteger binomialBig(int n, int k) {
		if (k < 0 || n < k)
			return BigInteger.ZERO;
		if (k > n - k)
			k = n - k;
		BigInteger i = BigInteger.ONE;
		for (int v = 0; v < k; v++)
			i = i.multiply(BigInteger.valueOf(n - v)).divide(BigInteger.valueOf(v + 1));
		return i;
	}

	public static int binomial(int n, int k) {
		return binomialBig(n, k).intValueExact();
	}

	public static BigInteger nArrangementsFor(int[] nValues) {
		return IntStream.of(nValues).mapToObj(v -> BigInteger.valueOf(v)).reduce(BigInteger.ONE, (acc, v) -> acc.multiply(v));
	}

	public static boolean contains(int[] tab, int v, int from, int to) {
		return IntStream.rangeClosed(from, to).anyMatch(i -> tab[i] == v);
	}

	public static boolean contains(int[] tab, int v) {
		return contains(tab, v, 0, tab.length - 1);
	}

	public static int indexOf(String s, String... t) {
		return IntStream.range(0, t.length).filter(i -> t[i].equals(s)).findFirst().orElse(-1);
	}

	public static int indexOf(String s, List<Object> list) {
		return IntStream.range(0, list.size()).filter(i -> list.get(i).equals(s)).findFirst().orElse(-1);
	}

	public static int indexOf(int value, int[] t) {
		for (int i = 0; i < t.length; i++)
			if (value == t[i])
				return i;
		return -1;
		// return IntStream.range(0, t.length).filter(i -> t[i] == value).findFirst().orElse(-1);
	}

	public static int indexOf(Object value, Object[] t) {
		return IntStream.range(0, t.length).filter(i -> t[i] == value).findFirst().orElse(-1);
	}

	/**
	 * Returns true is the array is regular and matches exactly the specified size. For example, if size is [5,4] then
	 * the specified array must be a 2-dimensional array of 5 x 4 squares.
	 */
	public static boolean hasSize(Object array, int... size) {
		boolean b1 = array != null && array.getClass().isArray(), b2 = size.length > 0;
		if (!b1 && !b2)
			return true;
		if (b1 && !b2 || !b1 && b2 || Array.getLength(array) != size[0])
			return false;
		return IntStream.range(0, size[0]).noneMatch(i -> !hasSize(Array.get(array, i), Arrays.stream(size).skip(1).toArray()));
	}

	/**
	 * Returns true is the array is regular, that is to say has the form of a rectangle for a 2-dimensional array, a
	 * cube for a 3-dimensional array... For example, if the specified array is a 2-dimensional array of 5 x 4 squares,
	 * then it is regular. But it has 3 squares for the first row, and 4 squares for the second row, then it is not
	 * regular.
	 */
	public static boolean isRegular(Object array) {
		List<Integer> list = new ArrayList<>();
		for (Object a = array; a != null && a.getClass().isArray(); a = Array.getLength(a) == 0 ? null : Array.get(a, 0))
			list.add(Array.getLength(a));
		return hasSize(array, list.stream().mapToInt(i -> i).toArray());
	}

	/**
	 * Method that controls that the specified condition is verified. If it is not the case, a message is displayed and
	 * the program is stopped.
	 */
	public static Object control(boolean condition, String message) {
		if (!condition) {
			System.out.println("\n\nFatal Error: " + message);
			throw new RuntimeException();
			// System.exit(1);
		}
		return null;
	}

	public static Object exit(String message) {
		return control(false, message);
	}

	/**
	 * Checks if the specified {@code Runnable} object raises an {@code ArithmeticException} object, when run. The value
	 * {@code true} is returned iff no such exception is raised.
	 * 
	 * @param r
	 *            a {@code Runnable} object to be run
	 * @return {@code true} iff no {@code ArithmeticException} is raised when running the specified code
	 */
	public static boolean checkSafeArithmeticOperation(Runnable r) {
		try {
			r.run();
			return true;
		} catch (ArithmeticException e) {
			return false;
		}
	}

	/**
	 * Method that parses the specified string as a long integer. If the value is too small or too big, an exception is
	 * raised. The specified boolean allows us to indicate if some special values (such as +infinity) must be checked.
	 */
	public static Long safeLong(String s, boolean checkSpecialValues) {
		if (checkSpecialValues) {
			if (s.equals(PLUS_INFINITY_STRING))
				return PLUS_INFINITY;
			if (s.equals(MINUS_INFINITY_STRING))
				return MINUS_INFINITY;
		}
		if (s.length() > 18) { // 18 because MAX_LONG and MIN_LONG are composed of at most 19 characters
			BigInteger big = new BigInteger(s);
			control(big.compareTo(BIG_MIN_SAFE_LONG) >= 0 && big.compareTo(BIG_MAX_SAFE_LONG) <= 0, "Too small or big value for this parser : " + s);
			return big.longValue();
		} else
			return Long.parseLong(s);
	}

	/**
	 * Method that parses the specified string as a long integer. If the value is too small or too big, an exception is
	 * raised.
	 */
	public static Long safeLong(String s) {
		return safeLong(s, false);
	}

	public static boolean isSafeInt(long l, boolean useMargin) {
		return (useMargin ? Constants.MIN_SAFE_INT : Integer.MIN_VALUE) <= l && l <= (useMargin ? Constants.MAX_SAFE_INT : Integer.MAX_VALUE);
	}

	public static boolean isSafeInt(long l) {
		return isSafeInt(l, true);
	}

	/**
	 * Converts the specified long number to int if it is safe to do it. When the specified boolean is set to true, we
	 * control that it is safe according to the constants MIN_SAFE_INT and MAX_SAFE_INT.
	 */
	public static int safeInt(Long l, boolean useMargin) {
		control(isSafeInt(l, useMargin), "Too big integer value " + l);
		return l.intValue();
		// return safeLong2Int(number.longValue(), useMargin);
	}

	/**
	 * Converts the specified long to int if it is safe to do it. We control that it is safe according to the constants
	 * MIN_SAFE_INT and MAX_SAFE_INT.
	 */
	public static int safeInt(Long l) {
		return safeInt(l, true);
	}

	/**
	 * Converts the specified long to int if it is safe to do it. Note that VAL_MINUS_INFINITY will be translated to
	 * VAL_MINUS_INFINITY_INT and that VAL_PLUS_INFINITY will be translated to VAL_PLUS_INFINITY_INT . We control that
	 * it is safe according to the constants MIN_SAFE_INT and MAX_SAFE_INT.
	 */
	public static int safeIntWhileHandlingInfinity(long l) {
		if (l == Constants.MINUS_INFINITY)
			return Constants.MINUS_INFINITY_INT;
		if (l == Constants.PLUS_INFINITY)
			return Constants.PLUS_INFINITY_INT;
		return safeInt(l);
	}

	public static <T> T[] swap(T[] t, int i, int j) {
		T tmp = t[i];
		t[i] = t[j];
		t[j] = tmp;
		return t;
	}

	/** Method that joins the elements of the specified array, using the specified delimiter to separate them. */
	public static String join(Object array, String delimiter) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0, length = Array.getLength(array); i < length; i++) {
			Object item = Array.get(array, i);
			if (item != null && item.getClass().isArray())
				sb.append("[").append(join(item, delimiter)).append("]");
			else
				sb.append(item != null ? item.toString() : "null").append(i < length - 1 ? delimiter : "");
		}
		return sb.toString();
	}

	/** Method that joins the elements of the specified array, using a white-space as delimiter. */
	public static String join(Object array) {
		return join(array, " ");
	}

	public static String join(Collection<? extends Object> c) {
		return join(c.toArray());
	}

	/** Method that joins the elements of the specified map, using the specified separator and delimiter. */
	public static <K, V> String join(Map<K, V> m, String separator, String delimiter) {
		return m.entrySet().stream().map(e -> e.getKey() + separator + e.getValue()).reduce("", (n, p) -> n + (n.length() == 0 ? "" : delimiter) + p);
	}

	/**
	 * Method that joins the elements of the specified two-dimensional array, using the specified separator and
	 * delimiter.
	 */
	public static String join(Object[][] m, String separator, String delimiter) {
		return Arrays.stream(m).map(t -> join(t, delimiter)).reduce("", (n, p) -> n + (n.length() == 0 ? "" : separator) + p);
	}

	public static String join(int[][] m, String separator, String delimiter) {
		return Arrays.stream(m).map(t -> join(t, delimiter)).reduce("", (n, p) -> n + (n.length() == 0 ? "" : separator) + p);
	}

	/**
	 * Returns the specified string in camel case form (with the first letter of the first word in lower case).
	 */
	public static String toCamelCase(String s) {
		String[] words = s.split("_");
		return IntStream.range(0, words.length)
				.mapToObj(i -> i == 0 ? words[i].toLowerCase() : words[i].substring(0, 1).toUpperCase() + words[i].substring(1).toLowerCase())
				.collect(Collectors.joining());
	}

	/**
	 * Returns the specified string in kebab case form.
	 */
	public static String toKebabCase(String s) {
		String[] words = s.split("_");
		return Stream.of(words).map(w -> w.toLowerCase()).collect(Collectors.joining("-"));
	}

	/** Method for converting an array into a string. */
	public static String arrayToString(Object array, final char LEFT, final char RIGHT, final String SEP) {
		assert array.getClass().isArray();

		if (array instanceof boolean[])
			return Arrays.toString((boolean[]) array);
		if (array instanceof byte[])
			return Arrays.toString((byte[]) array);
		if (array instanceof short[])
			return Arrays.toString((short[]) array);
		if (array instanceof int[])
			return Arrays.toString((int[]) array);
		if (array instanceof long[])
			return Arrays.toString((long[]) array);
		if (array instanceof String[])
			return LEFT + String.join(SEP, (String[]) array) + RIGHT;
		if (array instanceof IVar[])
			return LEFT + String.join(SEP, Stream.of((IVar[]) array).map(x -> x.toString()).toArray(String[]::new)) + RIGHT;

		if (array instanceof boolean[][])
			return LEFT + String.join(SEP, Stream.of((boolean[][]) array).map(t -> arrayToString(t, LEFT, RIGHT, SEP)).toArray(String[]::new)) + RIGHT;
		if (array instanceof byte[][])
			return LEFT + String.join(SEP, Stream.of((byte[][]) array).map(t -> arrayToString(t, LEFT, RIGHT, SEP)).toArray(String[]::new)) + RIGHT;
		if (array instanceof short[][])
			return LEFT + String.join(SEP, Stream.of((short[][]) array).map(t -> arrayToString(t, LEFT, RIGHT, SEP)).toArray(String[]::new)) + RIGHT;
		if (array instanceof int[][])
			return LEFT + String.join(SEP, Stream.of((int[][]) array).map(t -> arrayToString(t, LEFT, RIGHT, SEP)).toArray(String[]::new)) + RIGHT;
		if (array instanceof long[][])
			return LEFT + String.join(SEP, Stream.of((long[][]) array).map(t -> arrayToString(t, LEFT, RIGHT, SEP)).toArray(String[]::new)) + RIGHT;
		if (array instanceof String[][])
			return LEFT + String.join(SEP, Stream.of((String[][]) array).map(t -> arrayToString(t, LEFT, RIGHT, SEP)).toArray(String[]::new)) + RIGHT;

		if (array instanceof boolean[][][])
			return LEFT + String.join(SEP, Stream.of((boolean[][][]) array).map(t -> arrayToString(t, LEFT, RIGHT, SEP)).toArray(String[]::new)) + RIGHT;
		if (array instanceof byte[][][])
			return LEFT + String.join(SEP, Stream.of((byte[][][]) array).map(t -> arrayToString(t, LEFT, RIGHT, SEP)).toArray(String[]::new)) + RIGHT;
		if (array instanceof short[][][])
			return LEFT + String.join(SEP, Stream.of((short[][][]) array).map(t -> arrayToString(t, LEFT, RIGHT, SEP)).toArray(String[]::new)) + RIGHT;
		if (array instanceof int[][][])
			return LEFT + String.join(SEP, Stream.of((int[][][]) array).map(t -> arrayToString(t, LEFT, RIGHT, SEP)).toArray(String[]::new)) + RIGHT;
		if (array instanceof long[][][])
			return LEFT + String.join(SEP, Stream.of((long[][][]) array).map(t -> arrayToString(t, LEFT, RIGHT, SEP)).toArray(String[]::new)) + RIGHT;
		if (array instanceof String[][][])
			return LEFT + String.join(SEP, Stream.of((String[][][]) array).map(t -> arrayToString(t, LEFT, RIGHT, SEP)).toArray(String[]::new)) + RIGHT;

		if (array instanceof Long[][])
			return LEFT + String.join(SEP, Stream.of((Long[][]) array).map(t -> arrayToString(t, LEFT, RIGHT, SEP)).toArray(String[]::new)) + RIGHT;

		if (array instanceof IVar[][])
			return LEFT + String.join(SEP, Stream.of((IVar[][]) array).map(t -> arrayToString(t, LEFT, RIGHT, SEP)).toArray(String[]::new)) + RIGHT;

		if (array instanceof Object[][])
			return LEFT + String.join(SEP, Stream.of((Object[][]) array).map(t -> arrayToString(t)).toArray(String[]::new)) + RIGHT;
		// return "(" + String.join(")(", Stream.of((Object[][]) array).map(t ->
		// simplify(Arrays.toString(t))).toArray(String[]::new)) +
		// ")";
		if (array instanceof Object[])
			return String.join(SEP,
					Stream.of((Object[]) array).map(t -> t.getClass().isArray() ? LEFT + arrayToString(t) + RIGHT : t.toString()).toArray(String[]::new));
		return null;
	}

	/** Method for converting an array into a string. */
	public static String arrayToString(Object array) {
		return arrayToString(array, '[', ']', ", ");
	}

	/**
	 * Returns true if inside the specified object, there is an element that checks the predicate. If syntactic trees
	 * are encountered, we check the leaves only.
	 */
	public static boolean check(Object obj, Predicate<Object> p) {
		if (obj instanceof Object[])
			return IntStream.range(0, Array.getLength(obj)).anyMatch(i -> check(Array.get(obj, i), p));
		if (obj instanceof XNode)
			return ((XNode<?>) obj).firstNodeSuchThat(n -> n instanceof XNodeLeaf && p.test(((XNodeLeaf<?>) n).value)) != null;
		// if (obj instanceof XNode)
		// return ((XNode<?>) obj).containsLeafSuchThat(leaf -> p.test(leaf.value));
		return p.test(obj);
	}

	public static class ModifiableBoolean {
		public Boolean value;

		public ModifiableBoolean(Boolean value) {
			this.value = value;
		}
	}

	// ************************************************************************
	// ***** Methods for XML
	// ************************************************************************

	/** Method that loads an XML document, using the specified file name. */
	public static Document loadDocument(String fileName) throws Exception {
		Utilities.control(new File(fileName).exists(), "Filename " + fileName + " not found\n");
		if (fileName.endsWith("xml.bz2") || fileName.endsWith("xml.lzma")) {
			Process p = Runtime.getRuntime().exec((fileName.endsWith("xml.bz2") ? "bunzip2 -c " : "lzma -c -d ") + fileName);
			Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(p.getInputStream());
			p.waitFor();
			return document;
		} else
			return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new FileInputStream(new File(fileName)));
	}

	public static void save(Document document, PrintWriter out) {
		try {
			Transformer transformer = TransformerFactory.newInstance().newTransformer();
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
			transformer.transform(new DOMSource(document), new StreamResult(out));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static String save(Document document, String fileName) {
		try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(fileName)))) {
			save(document, out);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return fileName;
	}

	/** Method that returns an array with the child elements of the specified element. */
	public static Element[] childElementsOf(Element element) {
		NodeList childs = element.getChildNodes();
		return IntStream.range(0, childs.getLength()).mapToObj(i -> childs.item(i)).filter(e -> e.getNodeType() == Node.ELEMENT_NODE).toArray(Element[]::new);
	}

	/** Determines whether the specified element has the specified type as tag name. */
	public static boolean isTag(Element elt, TypeChild type) {
		return elt.getTagName().equals(type.name());
	}

	public static Element element(Document doc, String tag, List<Element> sons) {
		Element elt = doc.createElement(tag);
		sons.stream().forEach(c -> elt.appendChild(c));
		return elt;
	}

	public static Element element(Document doc, String tag, Element son) {
		return element(doc, tag, Arrays.asList(son));
	}

	public static Element element(Document doc, String tag, Element son, Element... otherSons) {
		return element(doc, tag, IntStream.range(0, 1 + otherSons.length).mapToObj(i -> i == 0 ? son : otherSons[i - 1]).collect(Collectors.toList()));
	}

	public static Element element(Document doc, String tag, Element son, Stream<Element> otherSons) {
		return element(doc, tag, Stream.concat(Stream.of(son), otherSons).collect(Collectors.toList()));
	}

	public static Element element(Document doc, String tag, Object textContent) {
		Element elt = doc.createElement(tag);
		elt.setTextContent(" " + textContent + " ");
		return elt;
	}

	public static Element element(Document doc, String tag, String attName, String attValue, Object textContent) {
		Element elt = element(doc, tag, textContent);
		elt.setAttribute(attName, attValue);
		return elt;
	}

	public static Element element(Document doc, String tag, String attName, String attValue) {
		Element elt = doc.createElement(tag);
		elt.setAttribute(attName, attValue);
		return elt;
	}

	public static Element element(Document doc, String tag, String attName1, String attValue1, String attName2, String attValue2) {
		Element elt = doc.createElement(tag);
		elt.setAttribute(attName1, attValue1);
		elt.setAttribute(attName2, attValue2);
		return elt;
	}

	public static Element element(Document doc, String tag, Stream<Entry<String, Object>> attributes) {
		Element elt = doc.createElement(tag);
		if (attributes != null)
			attributes.forEach(e -> elt.setAttribute(e.getKey(), e.getValue().toString()));
		return elt;
	}

	public static Element element(Document doc, String tag, Collection<Entry<String, Object>> attributes) {
		return element(doc, tag, attributes != null ? attributes.stream() : null);
	}

} public static class XCtr extends CEntryReifiable {
	/** The type of the constraint. For example, it may be intension, extension, or regular. */
	public final TypeCtr type;

	/** Returns the type of the constraint. For example, it may be intension, extension, or regular. We need an accessor for Scala. **/
	public final TypeCtr getType() {
		return type;
	}

	/**
	 * The child elements of the constraint. For example, we have a first child for <list> and a second child for <transitions> if the constraint is <mdd>.
	 */
	public final CChild[] 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 XAbstraction abstraction;

	/** Build an object representing a stand-alone constraint (template). */
	public XCtr(TypeCtr type, CChild... childs) {
		this.type = type;
		this.childs = childs;
		int[] abstractChildsPositions = IntStream.range(0, childs.length).filter(i -> childs[i].subjectToAbstraction()).toArray();
		if (abstractChildsPositions.length > 0) {
			Utilities.control(
					IntStream.of(abstractChildsPositions).mapToObj(i -> childs[i])
							.allMatch(child -> child.type == TypeChild.function || child.isTotallyAbstract() || child.value instanceof ConditionPar),
					"Abstraction Form not handled");
			abstraction = new XAbstraction(IntStream.of(abstractChildsPositions).mapToObj(i -> childs[i]).toArray(CChild[]::new));
		}
	}

	@Override
	public LinkedHashSet<XVar> collectVars(LinkedHashSet<XVar> set) {
		Stream.of(childs).filter(child -> child.type != TypeChild.supports && child.type != TypeChild.conflicts).forEach(child -> child.collectVars(set));
		return super.collectVars(set);
	}

	@Override
	public boolean subjectToAbstraction() {
		return abstraction != null;
	}

	@Override
	public String toString() {
		return type + super.toString() + "\n\t" + Utilities.join(childs, "\n\t");
	}
} public static abstract class XVar extends VEntry implements IVar {

	/** Builds a variable with the specified id, type and domain. */
	public static final XVar build(String id, TypeVar type, IDom dom) {
		switch (type) {
		case integer:
			return new XVarInteger(id, type, dom);
		case symbolic:
			return new XVarSymbolic(id, type, dom);
		case stochastic:
			return new XVarStochastic(id, type, dom);
		case real:
			return new XVarReal(id, type, dom);
		case set:
			return new XVarSet(id, type, dom);
		default:
			throw new RuntimeException("Unimplemented case ");
		}
	}

	/** Builds a variable from an array with the specified id (combined with the specified indexes), type and domain. */
	public static final XVar build(String idArray, TypeVar type, IDom dom, int[] indexes) {
		return build(idArray + "[" + Utilities.join(indexes, "][") + "]", type, dom);
	}

	/** The domain of the variable. It is null if the variable is qualitative. */
	public final IDom dom;

	/** The degree of the variable. This is automatically computed after all constraints have been parsed. */
	public int degree;

	/** Builds a variable with the specified id, type and domain. */
	protected XVar(String id, TypeVar type, IDom dom) {
		super(id, type);
		this.dom = dom;
	}

	// /** Builds a variable from an array with the specified id (combined with the specified indexes), type and domain. */
	// protected VVar(String idArray, TypeVar type, DDom dom, int[] indexes) {
	// this(idArray + "[" + XUtility.join(indexes, "][") + "]", type, dom);
	// }

	@Override
	public String id() {
		return id;
	}

	@Override
	public String toString() {
		return id; // + " :" + type + " of " + dom;
	}
}
import static org.xcsp.common.Utilities.safeLong;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.IntStream;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.xcsp.common.Types;
import org.xcsp.common.Types.TypeAtt;
import org.xcsp.common.Types.TypeClass;
import org.xcsp.common.Types.TypeFlag;
import org.xcsp.common.Types.TypeObjective;
import org.xcsp.common.Types.TypeVar;
import org.xcsp.common.Utilities;
import org.xcsp.parser.entries.XConstraints.XCtr;
import org.xcsp.parser.entries.XVariables.XVar;
package org.xcsp.parser.entries;




/** The class root of any entry in variables, constraints and objectives. The basic attributes id, class and note are managed here. */
public abstract class ParsingEntry {
	/** The id (unique identifier) of the entry. */
	public String id;

	/** The classes associated with the entry. */
	public TypeClass[] classes;

	/** The note (short comment) associated with the entry. */
	public String note;

	/**
	 * The attributes that are associated with the element. Useful for storing all attributes by a simple copy. It is mainly used when dealing with
	 * special parameters of constraints (startIndex, circular, ...).
	 */
	public final Map<TypeAtt, String> attributes = new HashMap<>();

	/** The flags associated with the entry. Currently, used only for table constraints. */
	public final Set<TypeFlag> flags = new HashSet<>();

	/** Returns the Boolean value of the specified attribute, if it exists, the specified default value otherwise. */
	public final boolean getAttributeValue(TypeAtt att, boolean defaultValue) {
		return attributes.get(att) == null ? defaultValue : attributes.get(att).toLowerCase().equals("true");
	}

	/** Returns the int value of the specified attribute, if it exists, the specified default value otherwise. */
	public final int getAttributeValue(TypeAtt att, int defaultValue) {
		return attributes.get(att) == null ? defaultValue : Utilities.safeInt(safeLong(attributes.get(att)));
	}

	/** Returns the value of the specified attribute, if it exists, the specified default value otherwise. */
	public final <T extends Enum<T>> T getAttributeValue(TypeAtt att, Class<T> clazz, T defaultValue) {
		return attributes.get(att) == null ? defaultValue : Types.valueOf(clazz, attributes.get(att));
	}

	/** 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()));
		if (id == null && attributes.containsKey(TypeAtt.id))
			id = attributes.get(TypeAtt.id);
		if (attributes.containsKey(TypeAtt.CLASS))
			classes = TypeClass.classesFor(attributes.get(TypeAtt.CLASS).split("\\s+"));
		if (attributes.containsKey(TypeAtt.note))
			note = attributes.get(TypeAtt.note);
	}

	protected ParsingEntry() {}

	protected ParsingEntry(String id) {
		this.id = id;
		Utilities.control(id.matches("[a-zA-Z][_a-zA-Z0-9\\[\\]]*"), "Badly formed id : " + id + ". This does not match [a-zA-Z][_a-zA-Z0-9\\\\[\\\\]]* \n");
	}

	/** The root class used for Var and Array objects. */
	public static abstract class VEntry extends ParsingEntry {
		/** The type of the entry. */
		public final TypeVar type;

		/** Returns the type of the entry. We need an accessor for Scala. */
		public final TypeVar getType() {
			return type;
		}

		/** Builds an entry with the specified id and type. */
		protected VEntry(String id, TypeVar type) {
			super(id);
			this.type = type;
		}

		@Override
		public String toString() {
			return id + ":" + type;
		}
	}

	/**
	 * The root class of any element that is a (direct or indirect) entry in <constraints>. Also used for child elements of constraints (and
	 * constraint templates).
	 */
	public static abstract class CEntry extends ParsingEntry {

		/** The set of variables involved in this element. This is used as a cache (lazy initialization, as seen in method vars()). */
		private XVar[] vars;