1 /*
2  * CardAeqX.java
3  * This file is part of JaCoP.
4  * <p>
5  * JaCoP is a Java Constraint Programming solver.
6  * <p>
7  * Copyright (C) 2000-2008 Krzysztof Kuchcinski and Radoslaw Szymanek
8  * <p>
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU Affero General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  * <p>
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Affero General Public License for more details.
18  * <p>
19  * Notwithstanding any other provision of this License, the copyright
20  * owners of this work supplement the terms of this License with terms
21  * prohibiting misrepresentation of the origin of this work and requiring
22  * that modified versions of this work be marked in reasonable ways as
23  * different from the original version. This supplement of the license
24  * terms is in accordance with Section 7 of GNU Affero General Public
25  * License version 3.
26  * <p>
27  * You should have received a copy of the GNU Affero General Public License
28  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
29  */
30 
31 package org.jacop.set.constraints;
32 
33 import org.jacop.api.SatisfiedPresent;
34 import org.jacop.constraints.Constraint;
35 import org.jacop.core.IntDomain;
36 import org.jacop.core.IntVar;
37 import org.jacop.core.Store;
38 import org.jacop.core.Var;
39 import org.jacop.set.core.SetDomain;
40 import org.jacop.set.core.SetVar;
41 
42 import java.util.concurrent.atomic.AtomicInteger;
43 
44 /**
45  * The set cardinality constraint.
46  *
47  * @author Radoslaw Szymanek and Krzysztof Kuchcinski
48  * @version 3.1
49  */
50 
51 public class CardAeqX extends Constraint implements SatisfiedPresent {
52 
53     static AtomicInteger idNumber = new AtomicInteger(0);
54 
55     /**
56      * It specifies set variable a which is being restricted.
57      */
58     public SetVar a;
59 
60     /**
61      * It specifies integer variable c specifying the possible cardinality of set variable a.
62      */
63     public IntVar cardinality;
64 
65     /**
66      * It constructs a cardinality constraint to restrict the number of elements
67      * in the set assigned to set variable a.
68      *
69      * @param a           variable that is restricted to have the cardinality c.
70      * @param cardinality the variable specifying the possible values for cardinality of set variable a.
71      */
CardAeqX(SetVar a, IntVar cardinality)72     public CardAeqX(SetVar a, IntVar cardinality) {
73 
74         checkInputForNullness(new String[] {"a", "cardinality"}, new Object[] {a, cardinality});
75 
76         this.numberId = idNumber.incrementAndGet();
77         this.a = a;
78         this.cardinality = cardinality;
79 
80         setScope(a, cardinality);
81 
82     }
83 
consistency(Store store)84     @Override public void consistency(Store store) {
85 
86         /**
87          * It computes the consistency of the constraint.
88          *
89          * #A = B
90          *
91          * Cardinality of set variable A is equal to int variable B.
92          *
93          * B.in(#glbA, #lubA).
94          *
95          * If #glbA is already equal to maximum allowed cardinality then set is specified by glbA.
96          * if (#glbA == B.max()) then A = glbA
97          * If #lubA is already equal to minimum allowed cardinality then set is specified by lubA.
98          * if (#lubA == B.min()) then A = lubA
99          *
100          *
101          */
102 
103         SetDomain aDom = a.domain;
104         IntDomain card = cardinality.domain;
105 
106         //T12
107         int min = Math.max(aDom.glb().getSize(), card.min());
108         int max = Math.min(aDom.lub().getSize(), card.max());
109 
110         if (min > max)
111             throw Store.failException;
112 
113         cardinality.domain.in(store.level, cardinality, min, max);
114 
115         //T13 else //T14
116         if (aDom.glb().getSize() == card.max())
117             a.domain.inLUB(store.level, a, aDom.glb());
118         else if (aDom.lub().getSize() == card.min())
119             a.domain.inGLB(store.level, a, aDom.lub());
120 
121     }
122 
getConsistencyPruningEvent(Var var)123     @Override public int getConsistencyPruningEvent(Var var) {
124 
125         // If consistency function mode
126         if (consistencyPruningEvents != null) {
127             Integer possibleEvent = consistencyPruningEvents.get(var);
128             if (possibleEvent != null)
129                 return possibleEvent;
130         }
131 
132         if (var == cardinality)
133             return IntDomain.ANY;
134         else
135             return SetDomain.ANY;
136     }
137 
getDefaultConsistencyPruningEvent()138     @Override public int getDefaultConsistencyPruningEvent() {
139         throw new IllegalStateException("Not implemented as more precise variant exists.");
140     }
141 
satisfied()142     @Override public boolean satisfied() {
143         return (grounded() && a.domain.card().eq(cardinality.dom()));
144     }
145 
toString()146     @Override public String toString() {
147         return id() + " : card(" + a + ", " + cardinality + " )";
148     }
149 
150 }
151