001package org.clafer.choco.constraint;
002
003import java.util.ArrayList;
004import java.util.List;
005import org.clafer.choco.constraint.propagator.PropAcyclic;
006import org.clafer.choco.constraint.propagator.PropAnd;
007import org.clafer.choco.constraint.propagator.PropArrayToSet;
008import org.clafer.choco.constraint.propagator.PropArrayToSetCard;
009import org.clafer.choco.constraint.propagator.PropFilterString;
010import org.clafer.choco.constraint.propagator.PropIfThenElse;
011import org.clafer.choco.constraint.propagator.PropIntChannel;
012import org.clafer.choco.constraint.propagator.PropIntNotMemberSet;
013import org.clafer.choco.constraint.propagator.PropJoinFunction;
014import org.clafer.choco.constraint.propagator.PropJoinFunctionCard;
015import org.clafer.choco.constraint.propagator.PropJoinInjectiveRelationCard;
016import org.clafer.choco.constraint.propagator.PropJoinRelation;
017import org.clafer.choco.constraint.propagator.PropLexChainChannel;
018import org.clafer.choco.constraint.propagator.PropLone;
019import org.clafer.choco.constraint.propagator.PropMask;
020import org.clafer.choco.constraint.propagator.PropOne;
021import org.clafer.choco.constraint.propagator.PropOr;
022import org.clafer.choco.constraint.propagator.PropSelectN;
023import org.clafer.choco.constraint.propagator.PropSetDifference;
024import org.clafer.choco.constraint.propagator.PropSetNotEqualC;
025import org.clafer.choco.constraint.propagator.PropSetSum;
026import org.clafer.choco.constraint.propagator.PropSetUnion;
027import org.clafer.choco.constraint.propagator.PropSetUnionCard;
028import org.clafer.choco.constraint.propagator.PropSingleton;
029import org.clafer.choco.constraint.propagator.PropSortedSets;
030import org.clafer.choco.constraint.propagator.PropSortedSetsCard;
031import org.clafer.choco.constraint.propagator.PropUnreachable;
032import org.clafer.common.Util;
033import solver.constraints.Constraint;
034import solver.constraints.Propagator;
035import solver.constraints.binary.PropEqualXY_C;
036import solver.constraints.binary.PropEqualX_Y;
037import solver.constraints.binary.PropEqualX_YC;
038import solver.constraints.binary.PropGreaterOrEqualX_Y;
039import solver.constraints.nary.sum.PropSumEq;
040import solver.constraints.set.PropIntersection;
041import solver.constraints.set.PropSubsetEq;
042import solver.constraints.unary.PropEqualXC;
043import solver.constraints.unary.PropGreaterOrEqualXC;
044import solver.constraints.unary.PropLessOrEqualXC;
045import solver.variables.BoolVar;
046import solver.variables.IntVar;
047import solver.variables.SetVar;
048import solver.variables.VF;
049import solver.variables.Variable;
050
051/**
052 * Custom Choco constraints. Designed for Clafer. Note that these constraints
053 * requires that the envelope and kernel to be in sorted order from lowest to
054 * highest, which is not explicitly enforced by Choco.
055 *
056 * @author jimmy
057 */
058public class Constraints {
059
060    private Constraints() {
061    }
062
063    private static Propagator<IntVar> lessThanEq(IntVar l, IntVar g) {
064        if (l.instantiated()) {
065            return new PropGreaterOrEqualXC(g, l.getValue());
066        }
067        if (g.instantiated()) {
068            return new PropLessOrEqualXC(l, g.getValue());
069        }
070        return new PropGreaterOrEqualX_Y(new IntVar[]{g, l});
071    }
072
073    private static Propagator<IntVar> greaterThanEq(IntVar g, IntVar l) {
074        return lessThanEq(l, g);
075    }
076
077    private static Propagator<IntVar> sumEq(IntVar[] ints, IntVar sum) {
078        List<IntVar> filter = new ArrayList<>(ints.length);
079        int constant = 0;
080        for (IntVar var : ints) {
081            if (var.instantiated()) {
082                constant += var.getValue();
083            } else {
084                filter.add(var);
085            }
086        }
087        IntVar[] filtered =
088                filter.size() == ints.length
089                ? ints
090                : filter.toArray(new IntVar[filter.size()]);
091        switch (filtered.length) {
092            case 0:
093                return new PropEqualXC(sum, constant);
094            case 1:
095                if (sum.instantiated()) {
096                    return new PropEqualXC(filtered[0], sum.getValue() - constant);
097                }
098                return constant == 0
099                        ? new PropEqualX_Y(filtered[0], sum)
100                        : new PropEqualX_YC(new IntVar[]{filtered[0], sum}, -constant);
101            case 2:
102                if (sum.instantiated()) {
103                    return new PropEqualXY_C(filtered, sum.getValue() - constant);
104                }
105            // fallthrough
106            default:
107                return new PropSumEq(Util.cons(VF.fixed(constant, sum.getSolver()), filtered), sum);
108        }
109    }
110
111    /**
112     *******************
113     *
114     * Boolean. When using boolean constraints, beware of the cases where the
115     * documentation states that certain cardinality constraints are to be
116     * enforced elsewhere. The only reason is for efficiency.
117     *
118     *******************
119     */
120    /**
121     * A constraint enforcing
122     * {@code operands[0] ∧ operands[1] ∧ ... ∧ operands[n]}.
123     *
124     * @param operands the operands
125     * @return constraint {@code operands[0] ∧ operands[1] ∧ ... ∧ operands[n]}
126     */
127    public static Constraint and(BoolVar... operands) {
128        Constraint<BoolVar, PropAnd> constraint = new Constraint<>(operands, operands[0].getSolver());
129        constraint.setPropagators(new PropAnd(operands));
130        return constraint;
131    }
132
133    /**
134     * A constraint enforcing
135     * {@code operands[0] + operands[1] + ... + operands[n] ≤ 1}.
136     *
137     * @param operands the operands
138     * @return constraint
139     * {@code operands[0] + operands[1] + ... + operands[n] ≤ 1}
140     */
141    public static Constraint lone(BoolVar... operands) {
142        Constraint<BoolVar, PropLone> constraint = new Constraint<>(operands, operands[0].getSolver());
143        constraint.setPropagators(new PropLone(operands));
144        return constraint;
145    }
146
147    /**
148     * A constraint enforcing
149     * {@code operands[0] + operands[1] + ... + operands[n] = 1}.
150     *
151     * @param operands the operands
152     * @return constraint
153     * {@code operands[0] + operands[1] + ... + operands[n] = 1}
154     */
155    public static Constraint one(BoolVar... operands) {
156        Constraint<BoolVar, PropOne> constraint = new Constraint<>(operands, operands[0].getSolver());
157        constraint.setPropagators(new PropOne(operands));
158        return constraint;
159    }
160
161    /**
162     * A constraint enforcing
163     * {@code operands[0] ∨ operands[1] ∨ ... ∨ operands[n]}.
164     *
165     * @param operands the operands
166     * @return constraint {@code operands[0] ∨ operands[1] ∨ ... ∨ operands[n]}
167     */
168    public static Constraint or(BoolVar... operands) {
169        Constraint<BoolVar, PropOr> constraint = new Constraint<>(operands, operands[0].getSolver());
170        constraint.setPropagators(new PropOr(operands));
171        return constraint;
172    }
173
174    /**
175     * A constraint enforcing
176     * {@code constraints[0] ∨ constraints[1] ∨ ... ∨ constraints[n]}. The
177     * reason this constraint is useful is because it does not require
178     * introducing new reified variables to the solver thus can be added
179     * dynamically while the solver is in progress.
180     *
181     * @param constraints the constraints
182     * @return constraint
183     * {@code constraints[0] ∨ constraints[1] ∨ ... ∨ constraints[n]}
184     */
185    public static Constraint or(Constraint... constraints) {
186        return new OrConstraint(constraints);
187    }
188
189    /**
190     * A constraint enforcing
191     * {@code antecedent => consequent && !antecedent => alternative}.
192     *
193     * @param antecedent the antecedent
194     * @param consequent the consequent
195     * @param alternative the alternative
196     * @return constraint
197     * {@code antecedent => consequent && !antecedent => alternative}
198     */
199    public static Constraint ifThenElse(BoolVar antecedent, BoolVar consequent, BoolVar alternative) {
200        Constraint<BoolVar, PropIfThenElse> constraint =
201                new Constraint<>(new BoolVar[]{antecedent, consequent, alternative}, antecedent.getSolver());
202        constraint.setPropagators(new PropIfThenElse(antecedent, consequent, alternative));
203        return constraint;
204    }
205
206    /**
207     * A constraint enforcing {@code reify <=> (variable = constant)}.
208     *
209     * @param reify the reified constraint
210     * @param variable the variable
211     * @param constant the constant
212     * @return constraint {@code reify <=> (variable = constant)}
213     */
214    public static Constraint reifyEqual(BoolVar reify, IntVar variable, int constant) {
215        return new ReifyEqualXC(reify, true, variable, constant);
216    }
217
218    /**
219     * A constraint enforcing {@code reify <=> (v1 = v2)}.
220     *
221     * @param reify the reified constraint
222     * @param v1 the first variable
223     * @param v2 the second variable
224     * @return constraint {@code reify <=> (v1 = v2)}
225     */
226    public static Constraint reifyEqual(BoolVar reify, IntVar v1, IntVar v2) {
227        return new ReifyEqualXY(reify, true, v1, v2);
228    }
229
230    /**
231     * A constraint enforcing {@code reify <=> (variable ≠ constant)}.
232     *
233     * @param reify the reified constraint
234     * @param variable the variable
235     * @param constant the constant
236     * @return constraint {@code reify <=> (variable ≠ constant)}
237     */
238    public static Constraint reifyNotEqual(BoolVar reify, IntVar variable, int constant) {
239        return new ReifyEqualXC(reify, false, variable, constant);
240    }
241
242    /**
243     * A constraint enforcing {@code reify <=> (v1 ≠ v2)}.
244     *
245     * @param reify the reified constraint
246     * @param v1 the first variable
247     * @param v2 the second variable
248     * @return constraint {@code reify <=> (v1 ≠ v2)}
249     */
250    public static Constraint reifyNotEqual(BoolVar reify, IntVar v1, IntVar v2) {
251        return new ReifyEqualXY(reify, false, v1, v2);
252    }
253
254    /**
255     * A constraint enforcing {@code set1 = set2}. Does not enforce that
256     * {@code set1Card = |set1Card|} nor {@code set2Card = |set2Card|} because
257     * of how the compilation works, it is already enforced elsewhere.
258     *
259     * @param set1 the left set
260     * @param set1Card the cardinality of {@code set1}
261     * @param set2 the right set
262     * @param set2Card the cardinality of {@code set2}
263     * @return constraint {@code set1 = set2}
264     */
265    public static Constraint equal(SetVar set1, IntVar set1Card, SetVar set2, IntVar set2Card) {
266        return new SetEquality(set1, set1Card, true, set2, set2Card);
267    }
268
269    /**
270     * A constraint enforcing {@code set1 ≠ set2}.
271     *
272     * @param set1 the left set
273     * @param set1Card the cardinality of {@code set1}
274     * @param set2 the right set
275     * @param set2Card the cardinality of {@code set2}
276     * @return constraint {@code set1 ≠ set2}
277     */
278    public static Constraint notEqual(SetVar set1, IntVar set1Card, SetVar set2, IntVar set2Card) {
279        return new SetEquality(set1, set1Card, false, set2, set2Card);
280    }
281
282    /**
283     * A constraint enforcing {@code set ≠ {constant}}.
284     *
285     * @param set the set
286     * @param constant the constant
287     * @return constraint {@code set1 ≠ set2}
288     */
289    public static Constraint notEqual(SetVar set, int[] constant) {
290        Constraint<SetVar, PropSetNotEqualC> constraint =
291                new Constraint<>(new SetVar[]{set}, set.getSolver());
292        constraint.setPropagators(new PropSetNotEqualC(set, constant));
293        return constraint;
294    }
295
296    /**
297     * A constraint enforcing {@code element ∉ set}.
298     *
299     * @param element the element
300     * @param set the set
301     * @return constraint {@code element ∉ set}.
302     */
303    public static Constraint notMember(IntVar element, SetVar set) {
304        Constraint<Variable, PropIntNotMemberSet> constraint =
305                new Constraint<>(new Variable[]{element, set}, element.getSolver());
306        constraint.setPropagators(new PropIntNotMemberSet(element, set));
307        return constraint;
308    }
309
310    /**
311     * A constraint enforcing {@code sub ⊆ sup}. Does not enforce that
312     * {@code subCard = |sub|} nor {@code supCard = |sup|} because of how the
313     * compilation works, it is already enforced elsewhere.
314     *
315     * @param sub the subset
316     * @param subCard the cardinality of {@code sub}
317     * @param sup the superset
318     * @param supCard the cardinality of {@code sup}
319     * @return constraint {@code sub ⊆ sup}
320     */
321    public static Constraint subsetEq(SetVar sub, IntVar subCard, SetVar sup, IntVar supCard) {
322        @SuppressWarnings("unchecked")
323        Constraint<? extends Variable, Propagator<? extends Variable>> constraint =
324                new Constraint(new Variable[]{sub, subCard, sup, supCard}, sub.getSolver());
325
326        @SuppressWarnings("unchecked")
327        Propagator<? extends Variable>[] propagators = new Propagator[]{
328            new PropSubsetEq(sub, sup),
329            // Simple cardinality propagation.
330            lessThanEq(subCard, supCard)
331        };
332        constraint.setPropagators(propagators);
333
334        return constraint;
335    }
336
337    /**
338     * A constraint enforcing {@code x ∈ sets[i] <=> ints[x] = i}.
339     *
340     * @param sets the sets
341     * @param ints the integers
342     * @return constraint {@code x ∈ sets[i] <=> ints[x] = i}
343     */
344    public static Constraint intChannel(SetVar[] sets, IntVar[] ints) {
345        /* 
346         * TODO: Take cardinalities of the sets into account?
347         * For example if card(sets[0]) <= 3, then if at least 3 of the integers
348         * are instantiated to 0, then remove 0 from the domains of the other integers.
349         * If card(sets[0]) >= 2 and only 2 ints contain 0 in their domain, then
350         * set those ints to 0.
351         */
352        Variable[] variables = new Variable[sets.length + ints.length];
353        System.arraycopy(sets, 0, variables, 0, sets.length);
354        System.arraycopy(ints, 0, variables, sets.length, ints.length);
355
356        Constraint<Variable, PropIntChannel> constraint =
357                new Constraint<>(variables, sets[0].getSolver());
358        constraint.setPropagators(new PropIntChannel(sets, ints));
359
360        return constraint;
361    }
362
363    /**
364     * A constraint enforcing
365     * {@code array(sets[0]) ++ array(sets[1]) ++ ... ++ array(sets[n]) ∈ N}
366     * where {@code array} is the sorted array representation of the set,
367     * {@code ++} is append, and {@code N = {[0,1,...,i] | i ≥ 0}}.
368     *
369     * @param sets the sets
370     * @param setCards the cardinalities of {@code sets}
371     * @return constraint
372     * {@code array(sets[0]) ++ array(sets[1]) ++ ... ++ array(sets[n]) ∈ N}
373     */
374    public static Constraint sortedSets(SetVar[] sets, IntVar[] setCards) {
375        if (sets.length != setCards.length) {
376            throw new IllegalArgumentException();
377        }
378
379        Variable[] variables = new Variable[sets.length + setCards.length];
380        System.arraycopy(sets, 0, variables, 0, sets.length);
381        System.arraycopy(setCards, 0, variables, sets.length, setCards.length);
382
383        @SuppressWarnings("unchecked")
384        Constraint<? extends Variable, Propagator<? extends Variable>> constraint =
385                new Constraint(variables, sets[0].getSolver());
386
387        @SuppressWarnings("unchecked")
388        Propagator<? extends Variable>[] propagators = new Propagator[]{
389            new PropSortedSets(sets),
390            new PropSortedSetsCard(sets, setCards)
391        };
392        constraint.setPropagators(propagators);
393
394        return constraint;
395    }
396
397    /**
398     * A constraint enforcing
399     * {@code strings[i] ≤ strings[j] <=> ints[i] ≤ ints[j]} and
400     * {@code strings[i] = strings[j] <=> ints[i] = ints[j]}.
401     *
402     * @param strings the strings
403     * @param ints the integers
404     * @return constraint {@code strings[i] ≤ strings[j] <=> ints[i] ≤ ints[j]}
405     * and {@code strings[i] = strings[j] <=> ints[i] = ints[j]}
406     */
407    public static Constraint lexChainChannel(IntVar[][] strings, IntVar[] ints) {
408        if (strings.length != ints.length) {
409            throw new IllegalArgumentException();
410        }
411
412        IntVar[] variables = new IntVar[strings.length * strings[0].length + ints.length];
413        System.arraycopy(ints, 0, variables, 0, ints.length);
414        int i = ints.length;
415        for (IntVar[] string : strings) {
416            System.arraycopy(string, 0, variables, i, string.length);
417            i += string.length;
418        }
419        assert i == variables.length;
420
421        Constraint<IntVar, PropLexChainChannel> constraint =
422                new Constraint<>(variables, variables[0].getSolver());
423        constraint.setPropagators(new PropLexChainChannel(strings, ints));
424
425        return constraint;
426    }
427
428    /**
429     * A constraint enforcing that {@code bools[i] <=> i < n}.
430     *
431     * @param bools the booleans
432     * @param n the number of true booleans
433     * @return constraint {@code bools[i] <=> i < n}
434     */
435    public static Constraint selectN(BoolVar[] bools, IntVar n) {
436        IntVar[] variables = new IntVar[bools.length + 1];
437        System.arraycopy(bools, 0, variables, 0, bools.length);
438        variables[bools.length] = n;
439
440        Constraint<IntVar, PropSelectN> constraint =
441                new Constraint<>(variables, n.getSolver());
442        constraint.setPropagators(new PropSelectN(bools, n));
443
444        return constraint;
445    }
446
447    /**
448     * A constraint enforcing no cycles. {@code edges[i] = j} implies that there
449     * is a directed edge from node i to node j. {@code edges[i] = edges.length}
450     * implies that there are no direct edges from node i.
451     *
452     * @param edges the edges of the graph
453     * @return constraint enforcing no cycles
454     */
455    public static Constraint acyclic(IntVar... edges) {
456        Constraint<IntVar, PropAcyclic> constraint = new Constraint<>(edges, edges[0].getSolver());
457        constraint.setPropagators(new PropAcyclic(edges));
458        return constraint;
459    }
460
461    /**
462     * A constraint enforcing no path from one node to another.
463     * {@code edges[i] = j} implies that there is a directed edge from node i to
464     * node j. {@code edges[i] ≥ edges.length} implies that there are no direct
465     * edges from node i.
466     *
467     * @param edges the edges of the graph
468     * @return constraint enforcing no path from one node to another
469     */
470    public static Constraint unreachable(IntVar[] edges, int from, int to) {
471        Constraint<IntVar, PropUnreachable> constraint = new Constraint<>(edges, edges[0].getSolver());
472        constraint.setPropagators(new PropUnreachable(edges, from, to));
473        return constraint;
474    }
475
476    /**
477     * A constraint enforcing
478     * {@code result[i] = if i \u003c array(set).length then string[array(set)[i] - offset] else -1}
479     * where {@code array} is the sorted array representation of the set. Does
480     * not enforce that {@code setCard = |setCard|} because of how the
481     * compilation works, it is already enforced elsewhere.
482     *
483     * @param set the set
484     * @param setCard the cardinality of {@code set}
485     * @param offset the offset
486     * @param string the string
487     * @param result the result
488     * @return constraint
489     * {@code result[i] = if i \u003c array(set).length then string[array(set)[i] - offset] else -1}
490     */
491    public static Constraint filterString(SetVar set, IntVar setCard, int offset, IntVar[] string, IntVar[] result) {
492        Constraint<Variable, PropFilterString> constraint =
493                new Constraint<>(PropFilterString.buildArray(set, setCard, string, result), set.getSolver());
494        constraint.setPropagators(new PropFilterString(set, setCard, offset, string, result));
495        return constraint;
496    }
497
498    /**
499     *******************
500     *
501     * Integer. When using integer constraints, beware of the cases where the
502     * documentation states that certain cardinality constraints are to be
503     * enforced elsewhere. The only reason is for efficiency.
504     *
505     *******************
506     */
507    /**
508     * <p>
509     * A constraint enforcing {@code Σ set= sum}. Does not enforce that
510     * {@code sumCard = |sum|} because of how the compilation works, it is
511     * already enforced elsewhere.
512     * </p>
513     * <p>
514     * More * efficient than the standard operation in the Choco library when
515     * the cardinality is bounded to be relatively small.
516     * </p>
517     * <p>
518     * For example:
519     * <pre>
520     *   Animal 2
521     *     Age -> integer
522     *   [Animal.Age = 1000]
523     * </pre>
524     * </p>
525     * <p> {@code Animal.Age} is a set with a very large envelope. However, due
526     * to static analysis of the model, it is easy to see that the cardinality
527     * must be 2. In general, the cardinality is bounded by the scope of Age,
528     * although often times the analysis will find a tighter bound. Once the
529     * first integer x is selected for the set, the second integer 1000 - x is
530     * already determined due to cardinality = 2. Since the Choco library's
531     * setSum constraint is not given the cardinality, it cannot make this
532     * deduction.
533     * </p>
534     *
535     * @param set the set of integers
536     * @param setCard the cardinality of {@code set}
537     * @param sum the sum of the set
538     * @return constraint {@code Σ set= sum}
539     */
540    public static Constraint setSum(SetVar set, IntVar setCard, IntVar sum) {
541        Constraint<Variable, PropSetSum> constraint =
542                new Constraint<>(new Variable[]{set, setCard, sum}, set.getSolver());
543        constraint.setPropagators(new PropSetSum(set, setCard, sum));
544        return constraint;
545    }
546
547    /**
548     *******************
549     *
550     * Set. When using set constraints, beware of the cases where the
551     * documentation states that certain cardinality constraints are to be
552     * enforced elsewhere. The only reason is for efficiency.
553     *
554     *******************
555     */
556    /**
557     * A constraint enforcing {@code {ivar} = svar}.
558     *
559     * @param ivar the integer
560     * @param svar the singleton set
561     * @return constraint {@code {ivar} = svar}
562     */
563    public static Constraint singleton(IntVar ivar, SetVar svar) {
564        Constraint<Variable, PropSingleton> constraint =
565                new Constraint<>(new Variable[]{ivar, svar}, ivar.getSolver());
566        constraint.setPropagators(new PropSingleton(ivar, svar));
567        return constraint;
568    }
569
570    /**
571     * A constraint enforcing {@code {ivar} = svar} and {@code svarCard = 1}.
572     * Does not enforce that {@code svarCard = |svarCard|} because of how the
573     * compilation works, it is already enforced elsewhere.
574     *
575     * @param ivar the integer
576     * @param svar the singleton set
577     * @param svarCard the cardinality of {@code svar}
578     * @return constraint {@code {ivar} = svar}
579     */
580    public static Constraint singleton(IntVar ivar, SetVar svar, IntVar svarCard) {
581        @SuppressWarnings("unchecked")
582        Constraint<? extends Variable, Propagator<? extends Variable>> constraint =
583                new Constraint(new Variable[]{ivar, svar, svarCard}, ivar.getSolver());
584
585        @SuppressWarnings("unchecked")
586        Propagator<? extends Variable>[] propagators = new Propagator[]{
587            new PropSingleton(ivar, svar),
588            new PropEqualXC(svarCard, 1)
589        };
590        constraint.setPropagators(propagators);
591
592        return constraint;
593    }
594
595    /**
596     * A constraint enforcing {@code {ivar[0], ivar[1], ..., ivar[n]} = svar}.
597     *
598     * @param ivars the array
599     * @param svar the set
600     * @param svarCard the cardinality of {@code svar}
601     * @return constraint {@code {ivar[0], ivar[1], ..., ivar[n]} = svar}
602     */
603    public static Constraint arrayToSet(IntVar[] ivars, SetVar svar, IntVar svarCard) {
604        return arrayToSet(ivars, svar, svarCard, null);
605    }
606
607    /**
608     * A constraint enforcing {@code {ivar[0], ivar[1], ..., ivar[n]} = svar}
609     * and {@code for all constant k, |{i | ivar[i] = k}| ≤ globalCardinality}.
610     * Does not enforce that {@code svarCard = |svar|} because of how the
611     * compilation works, it is already enforced elsewhere.
612     *
613     * @param ivars the array
614     * @param svar the set
615     * @param svarCard the cardinality of {@code svar}
616     * @param globalCardinality the global cardinality of the array elements
617     * @return constraint {@code {ivar[0], ivar[1], ..., ivar[n]} = svar} and
618     * {@code for all constant k |{i | ivar[i] = k}| ≤ globalCardinality}
619     */
620    public static Constraint arrayToSet(IntVar[] ivars, SetVar svar, IntVar svarCard, Integer globalCardinality) {
621        Variable[] variables = new Variable[ivars.length + 2];
622        variables[0] = svar;
623        variables[1] = svarCard;
624        System.arraycopy(ivars, 0, variables, 2, ivars.length);
625
626        @SuppressWarnings("unchecked")
627        Constraint<? extends Variable, Propagator<? extends Variable>> constraint =
628                new Constraint(variables, svar.getSolver());
629
630        @SuppressWarnings("unchecked")
631        Propagator<? extends Variable>[] propagators = new Propagator[]{
632            new PropArrayToSet(ivars, svar),
633            new PropArrayToSetCard(ivars, svarCard, globalCardinality)
634        };
635        constraint.setPropagators(propagators);
636
637        return constraint;
638    }
639
640    @Deprecated // Every join relation in Clafer is injective.
641    public static Constraint joinRelation(SetVar take, SetVar[] children, SetVar to) {
642        SetVar[] variables = new SetVar[children.length + 2];
643        variables[0] = take;
644        variables[1] = to;
645        System.arraycopy(children, 0, variables, 2, children.length);
646
647        Constraint<SetVar, PropJoinRelation> constraint = new Constraint<>(variables, take.getSolver());
648        constraint.setPropagators(new PropJoinRelation(take, children, to));
649
650        return constraint;
651    }
652
653    /**
654     * A constraint enforcing {@code take.children = to} where children is an
655     * injective relation. The representation of the relation is explained in
656     * {@link PropJoinRelation}. Does not enforce that the children relation is
657     * injective nor {@code takeCard = |take|} nor
658     * {@code childrenCards[i] = |children[i]|} nor {@code toCard = |to|}
659     * because of how the compilation works, it is already enforced elsewhere.
660     *
661     * @param take the left-hand side set
662     * @param takeCard the cardinality of {@code take}
663     * @param children the set representation of a injective binary relation
664     * @param childrenCards the cardinalities of {@code children}
665     * @param to the right-hand side set
666     * @param toCard the cardinality of {@code to}
667     * @return constraint {@code take.children = to}
668     * @see PropJoinFunction
669     */
670    public static Constraint joinInjectiveRelation(SetVar take, IntVar takeCard, SetVar[] children, IntVar[] childrenCards, SetVar to, IntVar toCard) {
671        if (children.length != childrenCards.length) {
672            throw new IllegalArgumentException();
673        }
674
675        Variable[] variables = new Variable[children.length * 2 + 4];
676        variables[0] = take;
677        variables[1] = takeCard;
678        variables[2] = to;
679        variables[3] = toCard;
680        System.arraycopy(children, 0, variables, 4, children.length);
681        System.arraycopy(childrenCards, 0, variables, 4 + children.length, childrenCards.length);
682
683        @SuppressWarnings("unchecked")
684        Constraint<? extends Variable, Propagator<? extends Variable>> constraint =
685                new Constraint(variables, take.getSolver());
686
687        @SuppressWarnings("unchecked")
688        Propagator<? extends Variable>[] propagators = new Propagator[]{
689            new PropJoinRelation(take, children, to),
690            new PropJoinInjectiveRelationCard(take, takeCard, childrenCards, toCard)
691        };
692        constraint.setPropagators(propagators);
693
694        return constraint;
695    }
696
697    /**
698     * A constraint enforcing {@code take.refs = to} where refs is a function.
699     * The representation of the function is explained in
700     * {@link PropJoinFunction}. Does not enforce that {@code takeCard = |take|}
701     * nor {@code toCard = |to|} because of how the compilation works, it is
702     * already enforced elsewhere.
703     *
704     * @param take the left-hand side set
705     * @param takeCard the cardinality of {@code take}
706     * @param refs the integer representation of a binary function
707     * @param to the right-hand side set
708     * @param toCard the cardinality of {@code to}
709     * @return constraint {@code take.refs = to}
710     * @see PropJoinFunction
711     */
712    public static Constraint joinFunction(SetVar take, IntVar takeCard, IntVar[] refs, SetVar to, IntVar toCard) {
713        return joinFunction(take, takeCard, refs, to, toCard, null);
714    }
715
716    /**
717     * A constraint enforcing {@code take.refs = to} where refs is a function
718     * and {@code for all k in take, |{i | refs[i] = k}| ≤ globalCardinality}.
719     * The representation of the function is explained in
720     * {@link PropJoinFunction}. Does not enforce that {@code takeCard = |take|}
721     * nor {@code toCard = |to|} because of how the compilation works, it is
722     * already enforced elsewhere.
723     *
724     * @param take the left-hand side set
725     * @param takeCard the cardinality of {@code take}
726     * @param refs the integer representation of a binary function
727     * @param to the right-hand side set
728     * @param toCard the cardinality of {@code to}
729     * @param globalCardinality the global cardinality of the {@code refs}
730     * function for the domain of {@code take}
731     * @return constraint {@code take.refs = to} and
732     * {@code for all k in take, |{i | refs[i] = k}| ≤ globalCardinality}
733     * @see PropJoinFunction
734     */
735    public static Constraint joinFunction(SetVar take, IntVar takeCard, IntVar[] refs, SetVar to, IntVar toCard, Integer globalCardinality) {
736        Variable[] variables = new Variable[refs.length + 4];
737        variables[0] = take;
738        variables[1] = takeCard;
739        variables[2] = to;
740        variables[3] = toCard;
741        // Assumes take card is already constrained for maximum efficiency.
742        System.arraycopy(refs, 0, variables, 4, refs.length);
743
744        @SuppressWarnings("unchecked")
745        Constraint<? extends Variable, Propagator<? extends Variable>> constraint =
746                new Constraint(variables, take.getSolver());
747
748        @SuppressWarnings("unchecked")
749        Propagator<? extends Variable>[] propagators = new Propagator[]{
750            new PropJoinFunction(take, refs, to),
751            new PropJoinFunctionCard(take, takeCard, refs, toCard, globalCardinality)
752        };
753        constraint.setPropagators(propagators);
754
755        return constraint;
756    }
757
758    /**
759     * A constraint enforcing {@code minuend - subtrahend = difference}. Does
760     * not enforce that {@code minuendCard = |minuend|} nor
761     * {@code subtrahendCard = |subtrahend|} nor
762     * {@code differenceCard = |difference|} because of how the compilation
763     * works, it is already enforced elsewhere.
764     *
765     * @param minuend the minuend
766     * @param minuendCard the cardinality of {@code minuend}
767     * @param subtrahend the subtrahend
768     * @param subtrahendCard the cardinality of {@code subtrahend}
769     * @param difference the difference
770     * @param differenceCard the cardinality of {@code difference}
771     * @return constraint {@code minuend - subtrahend = difference}
772     */
773    public static Constraint difference(
774            SetVar minuend, IntVar minuendCard,
775            SetVar subtrahend, IntVar subtrahendCard,
776            SetVar difference, IntVar differenceCard) {
777        Variable[] variables = new Variable[]{
778            minuend, minuendCard, subtrahend, subtrahendCard, difference, differenceCard
779        };
780
781        @SuppressWarnings("unchecked")
782        Constraint<? extends Variable, Propagator<? extends Variable>> constraint =
783                new Constraint(variables, difference.getSolver());
784
785        @SuppressWarnings("unchecked")
786        Propagator<? extends Variable>[] propagators = new Propagator[]{
787            new PropSetDifference(minuend, subtrahend, difference),
788            // Simple cardinality propagation.
789            greaterThanEq(minuendCard, differenceCard)
790        };
791        constraint.setPropagators(propagators);
792
793        return constraint;
794    }
795
796    /**
797     * A constraint enforcing
798     * {@code operands[0] ∩ operands[1] ∩ ... ∩ operands[n] = intersection}.
799     * Does not enforce that {@code operandCards[i] = |operands[i]|} nor
800     * {@code intersectionCard = |intersection|} because of how the compilation
801     * works, it is already enforced elsewhere.
802     *
803     * @param operands the operands
804     * @param operandCards the cardinalities of {@code operands}
805     * @param intersection the intersection
806     * @param intersectionCard the cardinality of {@code intersection}
807     * @return constraint
808     * {@code operands[0] ∩ operands[1] ∩ ... ∩ operands[n] = intersection}
809     */
810    public static Constraint intersection(
811            SetVar[] operands, IntVar[] operandCards,
812            SetVar intersection, IntVar intersectionCard) {
813        if (operands.length != operandCards.length) {
814            throw new IllegalArgumentException();
815        }
816
817        Variable[] variables = new Variable[operands.length + operandCards.length + 2];
818        System.arraycopy(operands, 0, variables, 0, operands.length);
819        System.arraycopy(operandCards, 0, variables, operands.length, operandCards.length);
820        variables[operands.length + operandCards.length] = intersection;
821        variables[operands.length + operandCards.length + 1] = intersectionCard;
822
823        @SuppressWarnings("unchecked")
824        Constraint<? extends Variable, Propagator<? extends Variable>> constraint =
825                new Constraint(variables, intersection.getSolver());
826
827        @SuppressWarnings("unchecked")
828        Propagator<? extends Variable>[] propagators = new Propagator[operandCards.length + 2];
829        // See SCF.intersection(operands, intersection);
830        // TODO: Needs to add the same propagator twice because the implementation
831        // is not guaranteed to be idempotent. If it ever becomes idempotent, then
832        // follow their implementation.
833        propagators[0] = new PropIntersection(operands, intersection);
834        propagators[1] = new PropIntersection(operands, intersection);
835        for (int i = 0; i < operandCards.length; i++) {
836            // Simple cardinality propagation.
837            propagators[i + 2] = greaterThanEq(operandCards[i], intersectionCard);
838        }
839        constraint.setPropagators(propagators);
840
841        return constraint;
842    }
843
844    /**
845     * A constraint enforcing
846     * {@code operands[0] ∪ operands[1] ∪ ... ∪ operands[n] = union}. Does not
847     * enforce that {@code operandCards[i] = |operands[i]|} nor
848     * {@code unionCard = |union|} because of how the compilation works, it is
849     * already enforced elsewhere.
850     *
851     * @param operands the operands
852     * @param operandCards the cardinalities of {@code operands}
853     * @param union the union
854     * @param unionCard the cardinality of {@code union}
855     * @param disjoint the sets are disjoint
856     * @return constraint
857     * {@code operands[0] ∪ operands[1] ∪ ... ∪ operands[n] = union}
858     */
859    public static Constraint union(
860            SetVar[] operands, IntVar[] operandCards,
861            SetVar union, IntVar unionCard,
862            boolean disjoint) {
863        if (operands.length != operandCards.length) {
864            throw new IllegalArgumentException();
865        }
866
867        Variable[] variables = new Variable[operands.length + operandCards.length + 2];
868        System.arraycopy(operands, 0, variables, 0, operands.length);
869        System.arraycopy(operandCards, 0, variables, operands.length, operandCards.length);
870        variables[operands.length + operandCards.length] = union;
871        variables[operands.length + operandCards.length + 1] = unionCard;
872
873        @SuppressWarnings("unchecked")
874        Constraint<? extends Variable, Propagator<? extends Variable>> constraint =
875                new Constraint(variables, union.getSolver());
876
877        @SuppressWarnings("unchecked")
878        Propagator<? extends Variable>[] propagators = new Propagator[]{
879            new PropSetUnion(operands, union),
880            disjoint
881            ? sumEq(operandCards, unionCard)
882            : new PropSetUnionCard(operandCards, unionCard)
883        };
884        constraint.setPropagators(propagators);
885
886        return constraint;
887    }
888
889    /**
890     * A constraint enforcing
891     * {@code {i + from | i ∈ member} = set ∩ {from, from + 1, ..., to - 1}}.
892     * Does not enforce that {@code setCard = |set|} nor
893     * {@code maskedCard = |masked|} because of how the compilation works, it is
894     * already enforced elsewhere.
895     *
896     * @param set the set
897     * @param setCard the cardinality of {@code set}
898     * @param masked the masked set
899     * @param maskedCard the cardinality of {@code masked}
900     * @param from the inclusive start of the mask
901     * @param to the exclusive end of the mask
902     * @return constraint
903     * {@code {i + from | i ∈ member} = set ∩ {from, from + 1, ..., to - 1}}
904     */
905    public static Constraint mask(
906            SetVar set, IntVar setCard,
907            SetVar masked, IntVar maskedCard,
908            int from, int to) {
909        @SuppressWarnings("unchecked")
910        Constraint<? extends Variable, Propagator<? extends Variable>> constraint =
911                new Constraint(new Variable[]{set, setCard, masked, maskedCard}, set.getSolver());
912
913        @SuppressWarnings("unchecked")
914        Propagator<? extends Variable>[] propagators = new Propagator[]{
915            new PropMask(set, masked, from, to),
916            // Simple cardinality propagation.
917            greaterThanEq(setCard, maskedCard)
918        };
919        constraint.setPropagators(propagators);
920
921        return constraint;
922    }
923}