001package org.clafer.choco.constraint.propagator;
002
003import gnu.trove.set.TIntSet;
004import solver.ICause;
005import solver.exception.ContradictionException;
006import solver.variables.IntVar;
007import solver.variables.SetVar;
008import solver.variables.delta.IIntDeltaMonitor;
009import solver.variables.delta.monitor.SetDeltaMonitor;
010
011/**
012 * Various static utility functions for writing Choco propagators.
013 *
014 * @author jimmy
015 */
016public class PropUtil {
017
018    private PropUtil() {
019    }
020
021    /**
022     * Monitor the deltas for all the variables.
023     *
024     * @param vars the variables
025     * @param propagator the propagator
026     * @return the variables delta monitors
027     */
028    public static IIntDeltaMonitor[] monitorDeltas(IntVar[] vars, ICause propagator) {
029        IIntDeltaMonitor[] deltas = new IIntDeltaMonitor[vars.length];
030        for (int i = 0; i < vars.length; i++) {
031            deltas[i] = vars[i].monitorDelta(propagator);
032        }
033        return deltas;
034    }
035
036    /**
037     * Monitor the deltas for all the variables.
038     *
039     * @param vars the variables
040     * @param propagator the propagator
041     * @return the variables delta monitors
042     */
043    public static SetDeltaMonitor[] monitorDeltas(SetVar[] vars, ICause propagator) {
044        SetDeltaMonitor[] deltas = new SetDeltaMonitor[vars.length];
045        for (int i = 0; i < vars.length; i++) {
046            deltas[i] = vars[i].monitorDelta(propagator);
047        }
048        return deltas;
049    }
050
051    /**
052     * Enumerate the domain of a integer variable.
053     *
054     * @param ivar the integer variable
055     * @return {@code dom(int)}
056     */
057    public static int[] iterateDom(IntVar ivar) {
058        int[] iterate = new int[ivar.getDomainSize()];
059        int count = 0;
060        int ub = ivar.getUB();
061        for (int i = ivar.getLB(); i <= ub; i = ivar.nextValue(i)) {
062            iterate[count++] = i;
063        }
064        assert count == iterate.length;
065        return iterate;
066    }
067
068    /**
069     * Enumerate the envelope of a set variable.
070     *
071     * @param set the set variable
072     * @return {@code env(set)}
073     */
074    public static int[] iterateEnv(SetVar set) {
075        int[] iterate = new int[set.getEnvelopeSize()];
076        int count = 0;
077        for (int i = set.getEnvelopeFirst(); i != SetVar.END; i = set.getEnvelopeNext()) {
078            iterate[count++] = i;
079        }
080        assert count == iterate.length;
081        return iterate;
082    }
083
084    /**
085     * Enumerate the kernel of a set variable.
086     *
087     * @param set the set variable
088     * @return {@code ker(set)}
089     */
090    public static int[] iterateKer(SetVar set) {
091        int[] iterate = new int[set.getKernelSize()];
092        int count = 0;
093        for (int i = set.getKernelFirst(); i != SetVar.END; i = set.getKernelNext()) {
094            iterate[count++] = i;
095        }
096        assert count == iterate.length;
097        return iterate;
098    }
099
100    /**
101     * Checks if at least one of the integer's domain contains a value.
102     *
103     * @param union the integers
104     * @param value the value
105     * @return {@code true} if
106     * {@code value ∈ dom(union[i]) for some i}, {@code false} otherwise
107     */
108    public static boolean domsContain(IntVar[] union, int value) {
109        for (IntVar var : union) {
110            if (var.contains(value)) {
111                return true;
112            }
113        }
114        return false;
115    }
116
117    /**
118     * Checks if at least one of the set's envelope contains a value.
119     *
120     * @param union the sets
121     * @param value the value
122     * @return {@code true} if
123     * {@code value ∈ env(union[i]) for some i}, {@code false} otherwise
124     */
125    public static boolean envsContain(SetVar[] union, int value) {
126        for (SetVar var : union) {
127            if (var.envelopeContains(value)) {
128                return true;
129            }
130        }
131        return false;
132    }
133
134    /**
135     * Checks if at least one of the set's kernel contains a value.
136     *
137     * @param union the sets
138     * @param value the value
139     * @return {@code true} if
140     * {@code value ∈ kernel(union[i]) for some i}, {@code false} otherwise
141     */
142    public static boolean kersContain(SetVar[] union, int value) {
143        for (SetVar var : union) {
144            if (var.kernelContains(value)) {
145                return true;
146            }
147        }
148        return false;
149    }
150
151    /**
152     * Checks if an integer's domain is contained entirely in the other
153     * integer's domain.
154     *
155     * @param i1 the first operand
156     * @param i2 the second operand
157     * @return {@code true} if {@code dom(i1) ⋂ dom(i2) ≠ {}}, {@code false}
158     * otherwise
159     */
160    public static boolean isDomIntersectDom(IntVar i1, IntVar i2) {
161        int s1 = i1.getDomainSize();
162        int s2 = i2.getDomainSize();
163        IntVar small = i1;
164        IntVar large = i2;
165        int s = s1;
166        if (s1 > s2) {
167            small = i2;
168            large = i1;
169            s = s2;
170        }
171        if (s == 1) {
172            return large.contains(small.getLB());
173        }
174        int lb = small.getLB();
175        int largeLb = large.getLB();
176        if (largeLb > lb) {
177            lb = small.nextValue(largeLb - 1);
178        }
179        int ub = Math.min(small.getUB(), large.getUB());
180        for (int i = lb; i <= ub; i = small.nextValue(i)) {
181            if (large.contains(i)) {
182                return true;
183            }
184        }
185        return false;
186    }
187
188    /**
189     * Checks if an integer's domain is contained entirely in the set's
190     * envelope.
191     *
192     * @param i1 the first operand
193     * @param i2 the second operand
194     * @return {@code true} if {@code dom(i1) ⋂ env(i2) ≠ {}}, {@code false}
195     * otherwise
196     */
197    public static boolean isDomIntersectEnv(IntVar i1, SetVar i2) {
198        if (i1.getDomainSize() < i2.getEnvelopeSize()) {
199            int i = i1.getLB();
200            int envFirst = i2.getEnvelopeFirst();
201            if (envFirst >= i) {
202                if (envFirst == i || i1.contains(envFirst)) {
203                    return true;
204                }
205                i = i1.nextValue(envFirst);
206            }
207            int ub = i1.getUB();
208            for (; i <= ub; i = i1.nextValue(i)) {
209                if (i2.envelopeContains(i)) {
210                    return true;
211                }
212            }
213        } else {
214            for (int i = i2.getEnvelopeFirst(); i != SetVar.END;) {
215                int next = i1.nextValue(i - 1);
216                while (i < next && i != SetVar.END) {
217                    i = i2.getEnvelopeNext();
218                }
219                if (i == next) {
220                    return true;
221                }
222            }
223        }
224        return false;
225    }
226
227    /**
228     * Checks if an integer's domain is contained entirely in the set's kernel.
229     *
230     * @param i1 the first operand
231     * @param i2 the second operand
232     * @return {@code true} if {@code dom(i1) ⋂ ker(i2) ≠ {}}, {@code false}
233     * otherwise
234     */
235    public static boolean isDomIntersectKer(IntVar i1, SetVar i2) {
236        if (i1.getDomainSize() < i2.getKernelSize()) {
237            int i = i1.getLB();
238            int envFirst = i2.getKernelFirst();
239            if (envFirst >= i) {
240                if (envFirst == i || i1.contains(envFirst)) {
241                    return true;
242                }
243                i = i1.nextValue(envFirst);
244            }
245            int ub = i1.getUB();
246            for (; i <= ub; i = i1.nextValue(i)) {
247                if (i2.kernelContains(i)) {
248                    return true;
249                }
250            }
251        } else {
252            for (int i = i2.getKernelFirst(); i != SetVar.END;) {
253                int next = i1.nextValue(i - 1);
254                while (i < next && i != SetVar.END) {
255                    i = i2.getKernelNext();
256                }
257                if (i == next) {
258                    return true;
259                }
260            }
261        }
262        return false;
263    }
264
265    /**
266     * Checks if a set's envelope is contained entirely in the other set's
267     * envelope.
268     *
269     * @param i1 the first operand
270     * @param i2 the second operand
271     * @return {@code true} if {@code env(i1) ⋂ env(i2) ≠ {}}, {@code false}
272     * otherwise
273     */
274    public static boolean isEnvIntersectEnv(SetVar i1, SetVar i2) {
275        SetVar small = i1;
276        SetVar large = i2;
277        if (i1.getEnvelopeSize() > i2.getEnvelopeSize()) {
278            small = i2;
279            large = i1;
280        }
281        for (int i = small.getEnvelopeFirst(); i != SetVar.END; i = small.getEnvelopeNext()) {
282            if (large.envelopeContains(i)) {
283                return true;
284            }
285        }
286        return false;
287    }
288
289    /**
290     * Checks if a set's envelope is contained entirely in the set's kernel.
291     *
292     * @param i1 the first operand
293     * @param i2 the second operand
294     * @return {@code true} if {@code env(i1) ⋂ ker(i2) ≠ {}}, {@code false}
295     * otherwise
296     */
297    public static boolean isEnvIntersectKer(SetVar i1, SetVar i2) {
298        if (i1.getEnvelopeSize() < i2.getEnvelopeSize()) {
299            for (int i = i1.getEnvelopeFirst(); i != SetVar.END; i = i1.getEnvelopeNext()) {
300                if (i2.kernelContains(i)) {
301                    return true;
302                }
303            }
304        } else {
305            for (int i = i2.getKernelFirst(); i != SetVar.END; i = i2.getKernelNext()) {
306                if (i1.envelopeContains(i)) {
307                    return true;
308                }
309            }
310        }
311
312        return false;
313    }
314
315    /**
316     * Checks if a set's kernel is contained entirely in the other set's kernel.
317     *
318     * @param i1 the first operand
319     * @param i2 the second operand
320     * @return {@code true} if {@code ker(i1) ⋂ ker(i2) ≠ {}}, {@code false}
321     * otherwise
322     */
323    public static boolean isKerIntersectKer(SetVar i1, SetVar i2) {
324        SetVar small = i1;
325        SetVar large = i2;
326        if (i1.getKernelSize() > i2.getKernelSize()) {
327            small = i2;
328            large = i1;
329        }
330        for (int i = small.getKernelFirst(); i != SetVar.END; i = small.getKernelNext()) {
331            if (large.kernelContains(i)) {
332                return true;
333            }
334        }
335        return false;
336    }
337
338    /**
339     * Checks if an integer's domain is contained entirely in the other
340     * integer's domain.
341     *
342     * @param sub the subset
343     * @param sup the superset
344     * @return {@code true} if {@code dom(sub) ⊆ dom(sup)}, {@code false}
345     * otherwise
346     */
347    public static boolean isDomSubsetDom(IntVar sub, IntVar sup) {
348        if (sub.getDomainSize() > sup.getDomainSize()) {
349            return false;
350        }
351        int ub = sub.getUB();
352        for (int i = sub.getLB(); i <= ub; i = sub.nextValue(i)) {
353            if (!sup.contains(i)) {
354                return false;
355            }
356        }
357        return true;
358    }
359
360    /**
361     * Checks if an integer's domain is contained entirely in the set's
362     * envelope.
363     *
364     * @param sub the subset
365     * @param sup the superset
366     * @return {@code true} if {@code dom(sub) ⊆ env(sup)}, {@code false}
367     * otherwise
368     */
369    public static boolean isDomSubsetEnv(IntVar sub, SetVar sup) {
370        if (sub.getDomainSize() > sup.getEnvelopeSize()) {
371            return false;
372        }
373        int ub = sub.getUB();
374        for (int i = sub.getLB(); i <= ub; i = sub.nextValue(i)) {
375            if (!sup.envelopeContains(i)) {
376                return false;
377            }
378        }
379        return true;
380    }
381
382    /**
383     * Checks if an integer's domain is contained entirely in the set's kernel.
384     *
385     * @param sub the subset
386     * @param sup the superset
387     * @return {@code true} if {@code dom(sub) ⊆ ker(sup)}, {@code false}
388     * otherwise
389     */
390    public static boolean isDomSubsetKer(IntVar sub, SetVar sup) {
391        if (sub.getDomainSize() > sup.getKernelSize()) {
392            return false;
393        }
394        int ub = sub.getUB();
395        for (int i = sub.getLB(); i <= ub; i = sub.nextValue(i)) {
396            if (!sup.kernelContains(i)) {
397                return false;
398            }
399        }
400        return true;
401    }
402
403    /**
404     * Checks if a set's envelope is contained entirely in the integer's domain.
405     *
406     * @param sub the subset
407     * @param sup the superset
408     * @return {@code true} if {@code env(sub) ⊆ dom(sup)}, {@code false}
409     * otherwise
410     */
411    public static boolean isEnvSubsetDom(SetVar sub, IntVar sup) {
412        if (sub.getEnvelopeSize() > sup.getDomainSize()) {
413            return false;
414        }
415        for (int i = sub.getEnvelopeFirst(); i != SetVar.END; i = sub.getEnvelopeNext()) {
416            if (!sup.contains(i)) {
417                return false;
418            }
419        }
420        return true;
421    }
422
423    /**
424     * Checks if a set's envelope is contained entirely in the other set's
425     * envelope.
426     *
427     * @param sub the subset
428     * @param sup the superset
429     * @return {@code true} if {@code env(sub) ⊆ env(sup)}, {@code false}
430     * otherwise
431     */
432    public static boolean isEnvSubsetEnv(SetVar sub, SetVar sup) {
433        if (sub.getEnvelopeSize() > sup.getEnvelopeSize()) {
434            return false;
435        }
436        for (int i = sub.getEnvelopeFirst(); i != SetVar.END; i = sub.getEnvelopeNext()) {
437            if (!sup.envelopeContains(i)) {
438                return false;
439            }
440        }
441        return true;
442    }
443
444    /**
445     * Checks if a set's envelope is contained entirely in the set's kernel.
446     *
447     * @param sub the subset
448     * @param sup the superset
449     * @return {@code true} if {@code env(sub) ⊆ ker(sup)}, {@code false}
450     * otherwise
451     */
452    public static boolean isEnvSubsetKer(SetVar sub, SetVar sup) {
453        if (sub.getEnvelopeSize() > sup.getKernelSize()) {
454            return false;
455        }
456        for (int i = sub.getEnvelopeFirst(); i != SetVar.END; i = sub.getEnvelopeNext()) {
457            if (!sup.kernelContains(i)) {
458                return false;
459            }
460        }
461        return true;
462    }
463
464    /**
465     * Checks if a set's kernel is contained entirely in the integer's domain.
466     *
467     * @param sub the subset
468     * @param sup the superset
469     * @return {@code true} if {@code ker(sub) ⊆ dom(sup)}, {@code false}
470     * otherwise
471     */
472    public static boolean isKerSubsetDom(SetVar sub, IntVar sup) {
473        for (int i = sub.getKernelFirst(); i != SetVar.END; i = sub.getKernelNext()) {
474            if (!sup.contains(i)) {
475                return false;
476            }
477        }
478        return true;
479    }
480
481    /**
482     * Checks if a set's kernel is contained entirely in the set's envelope.
483     *
484     * @param sub the subset
485     * @param sup the superset
486     * @return {@code true} if {@code ker(sub) ⊆ env(sup)}, {@code false}
487     * otherwise
488     */
489    public static boolean isKerSubsetEnv(SetVar sub, SetVar sup) {
490        for (int i = sub.getKernelFirst(); i != SetVar.END; i = sub.getKernelNext()) {
491            if (!sup.envelopeContains(i)) {
492                return false;
493            }
494        }
495        return true;
496    }
497
498    /**
499     * Checks if a set's kernel is contained entirely in the other set's kernel.
500     *
501     * @param sub the subset
502     * @param sup the superset
503     * @return {@code true} if {@code ker(sub) ⊆ ker(sup)}, {@code false}
504     * otherwise
505     */
506    public static boolean isKerSubsetKer(SetVar sub, SetVar sup) {
507
508        for (int i = sub.getKernelFirst(); i != SetVar.END; i = sub.getKernelNext()) {
509            if (!sup.kernelContains(i)) {
510                return false;
511            }
512        }
513        return true;
514    }
515
516    /**
517     * Removes every element in an integer's domain that is not in the set.
518     *
519     * @param sub the subset
520     * @param sup the superset
521     * @param propagator the propagator
522     * @throws ContradictionException
523     * @return {@code true} if a variable has been changed, {@code false}
524     * otherwise
525     */
526    public static boolean domSubsetSet(IntVar sub, TIntSet sup, ICause propagator) throws ContradictionException {
527        boolean changed = false;
528        int left = Integer.MIN_VALUE;
529        int right = left;
530        int ub = sub.getUB();
531        for (int val = sub.getLB(); val <= ub; val = sub.nextValue(val)) {
532            if (!sup.contains(val)) {
533                if (val == right + 1) {
534                    right = val;
535                } else {
536                    changed |= sub.removeInterval(left, right, propagator);
537                    left = val;
538                    right = val;
539                }
540            }
541        }
542        changed |= sub.removeInterval(left, right, propagator);
543        return changed;
544    }
545
546    /**
547     * Removes every element in an integer's domain that is not in the other
548     * integer's domain.
549     *
550     * @param sub the subset
551     * @param sup the superset
552     * @param propagator the propagator
553     * @throws ContradictionException
554     * @return {@code true} if a variable has been changed, {@code false}
555     * otherwise
556     */
557    public static boolean domSubsetDom(IntVar sub, IntVar sup, ICause propagator) throws ContradictionException {
558        boolean changed = false;
559        changed |= sub.updateLowerBound(sup.getLB(), propagator);
560        changed |= sub.updateUpperBound(sup.getUB(), propagator);
561        int left = Integer.MIN_VALUE;
562        int right = left;
563        int ub = sub.getUB();
564        for (int val = sub.getLB(); val <= ub; val = sub.nextValue(val)) {
565            if (!sup.contains(val)) {
566                if (val == right + 1) {
567                    right = val;
568                } else {
569                    changed |= sub.removeInterval(left, right, propagator);
570                    left = val;
571                    right = val;
572                }
573            }
574        }
575        changed |= sub.removeInterval(left, right, propagator);
576        return changed;
577    }
578
579    /**
580     * Removes every element in an integer's domain that is not in the set's
581     * envelope.
582     *
583     * @param sub the subset
584     * @param sup the superset
585     * @param propagator the propagator
586     * @throws ContradictionException
587     * @return {@code true} if a variable has been changed, {@code false}
588     * otherwise
589     */
590    public static boolean domSubsetEnv(IntVar sub, SetVar sup, ICause propagator) throws ContradictionException {
591        boolean changed = false;
592        int left = Integer.MIN_VALUE;
593        int right = left;
594        int ub = sub.getUB();
595        for (int val = sub.getLB(); val <= ub; val = sub.nextValue(val)) {
596            if (!sup.envelopeContains(val)) {
597                if (val == right + 1) {
598                    right = val;
599                } else {
600                    changed |= sub.removeInterval(left, right, propagator);
601                    left = val;
602                    right = val;
603                }
604            }
605        }
606        changed |= sub.removeInterval(left, right, propagator);
607        return changed;
608    }
609
610    /**
611     * Removes every element in an integer's domain that is not in the set's
612     * kernel.
613     *
614     * @param sub the subset
615     * @param sup the superset
616     * @param propagator the propagator
617     * @throws ContradictionException
618     * @return {@code true} if a variable has been changed, {@code false}
619     * otherwise
620     */
621    public static boolean domSubsetKer(IntVar sub, SetVar sup, ICause propagator) throws ContradictionException {
622        boolean changed = false;
623        int left = Integer.MIN_VALUE;
624        int right = left;
625        int ub = sub.getUB();
626        for (int val = sub.getLB(); val <= ub; val = sub.nextValue(val)) {
627            if (!sup.kernelContains(val)) {
628                if (val == right + 1) {
629                    right = val;
630                } else {
631                    changed |= sub.removeInterval(left, right, propagator);
632                    left = val;
633                    right = val;
634                }
635            }
636        }
637        changed |= sub.removeInterval(left, right, propagator);
638        return changed;
639    }
640
641    /**
642     * Removes every element in a set's envelope that is not in the set.
643     *
644     * @param sub the subset
645     * @param sup the superset
646     * @param propagator the propagator
647     * @throws ContradictionException
648     * @return {@code true} if a variable has been changed, {@code false}
649     * otherwise
650     */
651    public static boolean envSubsetSet(SetVar sub, TIntSet sup, ICause propagator) throws ContradictionException {
652        boolean changed = false;
653        for (int val = sub.getEnvelopeFirst(); val != SetVar.END; val = sub.getEnvelopeNext()) {
654            if (!sup.contains(val)) {
655                changed |= sub.removeFromEnvelope(val, propagator);
656            }
657        }
658        return changed;
659    }
660
661    /**
662     * Removes every element in a set's envelope that is not in the integer's
663     * domain.
664     *
665     * @param sub the subset
666     * @param sup the superset
667     * @param propagator the propagator
668     * @throws ContradictionException
669     * @return {@code true} if a variable has been changed, {@code false}
670     * otherwise
671     */
672    public static boolean envSubsetDom(SetVar sub, IntVar sup, ICause propagator) throws ContradictionException {
673        boolean changed = false;
674        for (int val = sub.getEnvelopeFirst(); val != SetVar.END; val = sub.getEnvelopeNext()) {
675            if (!sup.contains(val)) {
676                changed |= sub.removeFromEnvelope(val, propagator);
677            }
678        }
679        return changed;
680    }
681
682    /**
683     * Removes every element in a set's envelope that is not in the other set's
684     * envelope.
685     *
686     * @param sub the subset
687     * @param sup the superset
688     * @param propagator the propagator
689     * @throws ContradictionException
690     * @return {@code true} if a variable has been changed, {@code false}
691     * otherwise
692     */
693    public static boolean envSubsetEnv(SetVar sub, SetVar sup, ICause propagator) throws ContradictionException {
694        boolean changed = false;
695        for (int i = sub.getEnvelopeFirst(); i != SetVar.END; i = sub.getEnvelopeNext()) {
696            if (!sup.envelopeContains(i)) {
697                changed |= sub.removeFromEnvelope(i, propagator);
698            }
699        }
700        return changed;
701    }
702
703    /**
704     * Removes every element in a set's envelope that is not in the set's
705     * kernel.
706     *
707     * @param sub the subset
708     * @param sup the superset
709     * @param propagator the propagator
710     * @throws ContradictionException
711     * @return {@code true} if a variable has been changed, {@code false}
712     * otherwise
713     */
714    public static boolean envSubsetKer(SetVar sub, SetVar sup, ICause propagator) throws ContradictionException {
715        boolean changed = false;
716        for (int i = sub.getEnvelopeFirst(); i != SetVar.END; i = sub.getEnvelopeNext()) {
717            if (!sup.kernelContains(i)) {
718                changed |= sub.removeFromEnvelope(i, propagator);
719            }
720        }
721        return changed;
722    }
723
724    /**
725     * Adds every element in a set's kernel to the other set's kernel.
726     *
727     * @param sub the subset
728     * @param sup the superset
729     * @param propagator the propagator
730     * @throws ContradictionException
731     * @return {@code true} if a variable has been changed, {@code false}
732     * otherwise
733     */
734    public static boolean kerSubsetKer(SetVar sub, SetVar sup, ICause propagator) throws ContradictionException {
735        boolean changed = false;
736        for (int i = sub.getKernelFirst(); i != SetVar.END; i = sub.getKernelNext()) {
737            changed |= sup.addToKernel(i, propagator);
738        }
739        return changed;
740    }
741}