1 /*
2  * And.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.api.UsesQueueVariable;
34 import org.jacop.core.Store;
35 import org.jacop.core.Var;
36 import org.jacop.util.QueueForward;
37 
38 import java.util.Arrays;
39 import java.util.List;
40 import java.util.concurrent.atomic.AtomicInteger;
41 
42 /**
43  * Constraint c1 /\ c2 ... /\ cn
44  *
45  * @author Krzysztof Kuchcinski and Radoslaw Szymanek
46  * @version 4.8
47  */
48 public class And extends PrimitiveConstraint implements UsesQueueVariable {
49 
50     final static AtomicInteger idNumber = new AtomicInteger(0);
51 
52     /**
53      * It specifies a list of constraints which must be satisfied to keep And constraint satisfied.
54      */
55     protected final PrimitiveConstraint listOfC[];
56 
57     private final QueueForward<PrimitiveConstraint> queueForward;
58 
59     /**
60      * It constructs an And constraint based on primitive constraints. The
61      * constraint is satisfied if all constraints are satisfied.
62      *
63      * @param listOfC arraylist of constraints
64      */
And(List<PrimitiveConstraint> listOfC)65     public And(List<PrimitiveConstraint> listOfC) {
66         this(listOfC.toArray(new PrimitiveConstraint[listOfC.size()]));
67     }
68 
69     /**
70      * It constructs a simple And constraint based on two primitive constraints.
71      *
72      * @param c1 the first primitive constraint
73      * @param c2 the second primitive constraint
74      */
And(PrimitiveConstraint c1, PrimitiveConstraint c2)75     public And(PrimitiveConstraint c1, PrimitiveConstraint c2) {
76         this(new PrimitiveConstraint[] {c1, c2});
77     }
78 
79     /**
80      * It constructs an And constraint over an array of primitive constraints.
81      *
82      * @param c an array of primitive constraints constituting the And constraint.
83      */
And(PrimitiveConstraint[] c)84     public And(PrimitiveConstraint[] c) {
85 
86         checkInputForNullness("c", c);
87         this.queueIndex = 1;
88         this.numberId = idNumber.incrementAndGet();
89         this.listOfC = Arrays.copyOf(c, c.length);
90         setScope(listOfC);
91         setConstraintScope(listOfC);
92         queueForward = new QueueForward<>(listOfC, arguments());
93 	// KKU, 2019-01-30; next line is wrong! it will always give queueIndex = 0 since primitive constraints have queueIndex = 0
94 	// Then... if this constraint is reified, the reified will get queueIndex = 0 as well.
95         //this.queueIndex = Arrays.stream(c).max((a, b) -> Integer.max(a.queueIndex, b.queueIndex)).map(a -> a.queueIndex).orElse(0);
96 
97     }
98 
99     private boolean propagation;
100 
consistency(Store store)101     @Override public void consistency(Store store) {
102 
103         propagation = true;
104 
105         do {
106 
107             // Variable propagation can be set to true again if queueVariable function is being called.
108             propagation = false;
109 
110             for (Constraint cc : listOfC)
111                 cc.consistency(store);
112 
113         } while (propagation);
114 
115     }
116 
getNestedPruningEvent(Var var, boolean mode)117     @Override public int getNestedPruningEvent(Var var, boolean mode) {
118         return getConsistencyPruningEvent(var);
119     }
120 
getDefaultNotConsistencyPruningEvent()121     @Override protected int getDefaultNotConsistencyPruningEvent() {
122         throw new IllegalStateException("Not implemented as more precise version exists.");
123     }
124 
getDefaultConsistencyPruningEvent()125     @Override public int getDefaultConsistencyPruningEvent() {
126         throw new IllegalStateException("Not implemented as more precise version exists.");
127     }
128 
notConsistency(Store store)129     @Override public void notConsistency(Store store) {
130 
131         int numberCertainNotSat = 0;
132         int numberCertainSat = 0;
133         int j = 0;
134         int i = 0;
135 
136         while (numberCertainNotSat == 0 && i < listOfC.length) {
137             if (listOfC[i].notSatisfied()) {
138                 numberCertainNotSat++;
139 		removeConstraint();
140 	    }
141             else {
142                 if (listOfC[i].satisfied())
143                     numberCertainSat++;
144                 else
145                     j = i;
146             }
147             i++;
148         }
149 
150         if (numberCertainNotSat == 0) {
151             if (numberCertainSat == listOfC.length - 1) {
152                 listOfC[j].notConsistency(store);
153             } else if (numberCertainSat == listOfC.length)
154                 throw Store.failException;
155         }
156     }
157 
queueVariable(int level, Var variable)158     @Override public void queueVariable(int level, Var variable) {
159 
160         propagation = true;
161         queueForward.queueForward(level, variable);
162 
163     }
164 
notSatisfied()165     @Override public boolean notSatisfied() {
166         boolean notSat = false;
167 
168         int i = 0;
169         while (!notSat && i < listOfC.length) {
170             notSat = listOfC[i].notSatisfied();
171             i++;
172         }
173         return notSat;
174     }
175 
satisfied()176     @Override public boolean satisfied() {
177 
178         for (PrimitiveConstraint c : listOfC)
179             if (!c.satisfied())
180                 return false;
181 
182         return true;
183 
184     }
185 
toString()186     @Override public String toString() {
187 
188         StringBuilder result = new StringBuilder(id());
189 
190         result.append(" : And(");
191 
192         for (int i = 0; i < listOfC.length; i++) {
193             result.append(listOfC[i]);
194             if (i != listOfC.length - 1)
195                 result.append(", ");
196         }
197 	result.append(")");
198         return result.toString();
199     }
200 
201 }
202