1 /*
2  * BoolClause.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.constraints;
32 
33 import org.jacop.core.IntDomain;
34 import org.jacop.core.IntVar;
35 import org.jacop.core.Store;
36 import org.jacop.core.TimeStamp;
37 
38 import java.util.Arrays;
39 import java.util.List;
40 import java.util.concurrent.atomic.AtomicInteger;
41 import java.util.stream.Stream;
42 
43 /**
44  * I defines a boolean clause for 0/1 variables x_i and y_i.
45  * The clause is fulfilled if at least one varibale x_i = 1 or at least one varibale y_i = 0,
46  * that is it defines (x_1 \/ x_2 \/ ... x_n) \/ (not y_1 \/ not y_2 \/ ... not y_n)
47  * It restricts the domain of all x as well as result to be between 0 and 1.
48  *
49  * @author Krzysztof Kuchcinski and Radoslaw Szymanek
50  * @version 4.8
51  */
52 
53 public class BoolClause extends PrimitiveConstraint {
54 
55     final static AtomicInteger idNumber = new AtomicInteger(0);
56 
57     /**
58      * It specifies lists of variables for the constraint.
59      */
60     final public IntVar[] x;
61     final public IntVar[] y;
62 
63     /**
64      * It specifies length of lists x and y respectively.
65      */
66     private final int lx, ly;
67 
68     /**
69      * Defines first position of the variable that is not ground to 0 (positionX) or 0 (positionY).
70      */
71     private TimeStamp<Integer> positionX;
72     private TimeStamp<Integer> positionY;
73 
74     /**
75      * It constructs BoolClause.
76      *
77      * @param x list of positive arguments x's.
78      * @param y list of negative arguments y's.
79      */
BoolClause(IntVar[] x, IntVar[] y)80     public BoolClause(IntVar[] x, IntVar[] y) {
81 
82         checkInputForNullness(new String[] {"x", "y"}, x, y);
83 
84         this.numberId = idNumber.incrementAndGet();
85         this.lx = x.length;
86         this.ly = y.length;
87 
88         this.x = Arrays.copyOf(x, x.length);
89         this.y = Arrays.copyOf(y, y.length);
90 
91         assert (checkInvariants() == null) : checkInvariants();
92 
93         if (lx + ly > 4)
94             queueIndex = 1;
95         else
96             queueIndex = 0;
97 
98         setScope(Stream.concat(Arrays.stream(x), Arrays.stream(y)));
99     }
100 
101     /**
102      * It constructs BoolClause.
103      *
104      * @param x list of positive arguments x's.
105      * @param y list of negative arguments y's.
106      */
BoolClause(List<IntVar> x, List<IntVar> y)107     public BoolClause(List<IntVar> x, List<IntVar> y) {
108         this(x.toArray(new IntVar[x.size()]), y.toArray(new IntVar[y.size()]));
109     }
110 
111     /**
112      * It checks invariants required by the constraint. Namely that
113      * boolean variables have boolean domain.
114      *
115      * @return the string describing the violation of the invariant, null otherwise.
116      */
checkInvariants()117     public String checkInvariants() {
118 
119         for (IntVar var : x)
120             if (var.min() < 0 || var.max() > 1)
121                 return "Variable " + var + " does not have boolean domain";
122 
123         for (IntVar var : y)
124             if (var.min() < 0 || var.max() > 1)
125                 return "Variable " + var + " does not have boolean domain";
126 
127         return null;
128     }
129 
getDefaultNestedConsistencyPruningEvent()130     @Override protected int getDefaultNestedConsistencyPruningEvent() {
131         return IntDomain.ANY;
132     }
133 
getDefaultNestedNotConsistencyPruningEvent()134     @Override protected int getDefaultNestedNotConsistencyPruningEvent() {
135         return IntDomain.GROUND;
136     }
137 
getDefaultConsistencyPruningEvent()138     @Override public int getDefaultConsistencyPruningEvent() {
139         return IntDomain.BOUND;
140     }
141 
getDefaultNotConsistencyPruningEvent()142     @Override protected int getDefaultNotConsistencyPruningEvent() {
143         return IntDomain.GROUND;
144     }
145 
include(Store store)146     @Override public void include(Store store) {
147         positionX = new TimeStamp<>(store, 0);
148         positionY = new TimeStamp<>(store, 0);
149     }
150 
151     /**
152      * computes consistency for x_0 \/ ... \/ x_n \/ not y_0 \/ ... \/ not y_n
153      */
consistency(Store store)154     @Override public void consistency(Store store) {
155 
156         int startX = positionX.value();
157         int startY = positionY.value();
158 
159         for (int i = startX; i < lx; i++) {
160             if (x[i].max() == 0) {
161                 swap(x, startX, i);
162                 startX++;
163             } else if (x[i].min() == 1) {
164                 removeConstraint();
165                 return;
166             }
167         }
168 	positionX.update(startX);
169 
170         for (int i = startY; i < ly; i++) {
171             if (y[i].min() == 1) {
172                 swap(y, startY, i);
173                 startY++;
174             } else if (y[i].max() == 0) {
175                 removeConstraint();
176                 return;
177             }
178         }
179 	positionY.update(startY);
180 
181         // all x = 0 and all y = 1 => FAIL
182         if (startX == lx && startY == ly)
183             throw Store.failException;
184             // last x must be 1
185         else if (startX == lx - 1 && startY == ly)
186             x[lx - 1].domain.in(store.level, x[lx - 1], 1, 1);
187             // last y must be 0
188         else if (startX == lx && startY == ly - 1)
189             y[ly - 1].domain.in(store.level, y[ly - 1], 0, 0);
190 
191         if (lx - startX + ly + startY < 5)
192             queueIndex = 0;
193     }
194 
swap(IntVar[] p, int i, int j)195     private void swap(IntVar[] p, int i, int j) {
196         if (i != j) {
197             IntVar tmp = p[i];
198             p[i] = p[j];
199             p[j] = tmp;
200         }
201     }
202 
203 
204     /**
205      * computes consistency for not (x_0 \/ ... \/ x_n \/ not y_0 \/ ... \/ not y_n)
206      * implies
207      * not x_0 /\ ... /\ not x_n /\ y_0 /\ ... /\ y_n
208      * taht is all x_i = 0 /\ all y_i = 1
209      */
notConsistency(Store store)210     @Override public void notConsistency(Store store) {
211 
212         for (int i = 0; i < lx; i++)
213             x[i].domain.in(store.level, x[i], 0, 0);
214         for (int i = 0; i < ly; i++)
215             y[i].domain.in(store.level, y[i], 1, 1);
216 
217         removeConstraint();
218 
219     }
220 
satisfied()221     @Override public boolean satisfied() {
222 
223         int startX = positionX.value();
224         int startY = positionY.value();
225 
226         for (int i = startX; i < lx; i++)
227             if (x[i].min() == 1)
228                 return true;
229             else if (x[i].max() == 0) {
230                 swap(x, startX, i);
231                 startX++;
232             }
233 	positionX.update(startX);
234 
235         for (int i = startY; i < ly; i++)
236             if (y[i].max() == 0)
237                 return true;
238             else if (y[i].min() == 1) {
239                 swap(y, startY, i);
240                 startY++;
241             }
242 	positionY.update(startY);
243 
244         return false;
245 
246     }
247 
notSatisfied()248     @Override public boolean notSatisfied() {
249 
250         int startX = positionX.value();
251         int startY = positionY.value();
252 
253         for (int i = startX; i < lx; i++)
254             if (x[i].max() == 0) {
255                 swap(x, startX, i);
256                 startX++;
257             } else
258                 return false;
259 	positionX.update(startX);
260 
261         for (int i = startY; i < ly; i++)
262             if (y[i].min() == 1) {
263                 swap(y, startY, i);
264                 startY++;
265             } else
266                 return false;
267 	positionY.update(startY);
268 
269         return startX == lx && startY == ly;
270     }
271 
toString()272     @Override public String toString() {
273 
274         StringBuilder resultString = new StringBuilder(id());
275 
276         resultString.append(" : BoolClause([ ");
277         for (int i = 0; i < lx; i++) {
278             resultString.append(x[i]);
279             if (i < lx - 1)
280                 resultString.append(", ");
281         }
282         resultString.append("], [");
283 
284         for (int i = 0; i < ly; i++) {
285             resultString.append(y[i]);
286             if (i < ly - 1)
287                 resultString.append(", ");
288         }
289         resultString.append("])");
290         return resultString.toString();
291     }
292 
293 }
294