1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package org.sat4j.tools;
31
32 import java.io.PrintStream;
33 import java.io.PrintWriter;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.concurrent.atomic.AtomicInteger;
38
39 import org.sat4j.core.ASolverFactory;
40 import org.sat4j.core.ConstrGroup;
41 import org.sat4j.core.Vec;
42 import org.sat4j.core.VecInt;
43 import org.sat4j.minisat.core.Counter;
44 import org.sat4j.specs.ContradictionException;
45 import org.sat4j.specs.IConstr;
46 import org.sat4j.specs.ISolver;
47 import org.sat4j.specs.ISolverService;
48 import org.sat4j.specs.IVec;
49 import org.sat4j.specs.IVecInt;
50 import org.sat4j.specs.SearchListener;
51 import org.sat4j.specs.TimeoutException;
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public class ManyCore<S extends ISolver> implements ISolver, OutcomeListener {
66
67 private static final int NORMAL_SLEEP = 500;
68
69 private static final int FAST_SLEEP = 50;
70
71
72
73
74 private static final long serialVersionUID = 1L;
75
76 private final String[] availableSolvers;
77
78 protected final List<S> solvers;
79 protected final int numberOfSolvers;
80 private int winnerId;
81 private boolean resultFound;
82 private AtomicInteger remainingSolvers;
83 private volatile int sleepTime;
84 private volatile boolean solved;
85
86 private final IVec<Counter> solversStats = new Vec<Counter>();
87
88 public ManyCore(ASolverFactory<S> factory, String... solverNames) {
89 this.availableSolvers = solverNames;
90 this.numberOfSolvers = solverNames.length;
91 this.solvers = new ArrayList<S>(this.numberOfSolvers);
92 for (int i = 0; i < this.numberOfSolvers; i++) {
93 this.solvers.add(factory
94 .createSolverByName(this.availableSolvers[i]));
95 this.solversStats.push(new Counter(0));
96 }
97 }
98
99
100
101
102
103
104
105
106
107 public ManyCore(String[] names, S... solverObjects) {
108 this(solverObjects);
109 for (int i = 0; i < names.length; i++) {
110 this.availableSolvers[i] = names[i];
111 }
112 }
113
114 public ManyCore(S... solverObjects) {
115 this.availableSolvers = new String[solverObjects.length];
116 for (int i = 0; i < solverObjects.length; i++) {
117 this.availableSolvers[i] = "solver" + i;
118 }
119 this.numberOfSolvers = solverObjects.length;
120 this.solvers = new ArrayList<S>(this.numberOfSolvers);
121 for (int i = 0; i < this.numberOfSolvers; i++) {
122 this.solvers.add(solverObjects[i]);
123 this.solversStats.push(new Counter());
124 }
125 }
126
127 public void addAllClauses(IVec<IVecInt> clauses)
128 throws ContradictionException {
129 for (int i = 0; i < this.numberOfSolvers; i++) {
130 this.solvers.get(i).addAllClauses(clauses);
131 }
132 }
133
134 public IConstr addAtLeast(IVecInt literals, int degree)
135 throws ContradictionException {
136 ConstrGroup group = new ConstrGroup(false);
137 for (int i = 0; i < this.numberOfSolvers; i++) {
138 group.add(this.solvers.get(i).addAtLeast(literals, degree));
139 }
140 return group;
141 }
142
143 public IConstr addAtMost(IVecInt literals, int degree)
144 throws ContradictionException {
145 ConstrGroup group = new ConstrGroup(false);
146 for (int i = 0; i < this.numberOfSolvers; i++) {
147 group.add(this.solvers.get(i).addAtMost(literals, degree));
148 }
149 return group;
150 }
151
152 public IConstr addExactly(IVecInt literals, int n)
153 throws ContradictionException {
154 ConstrGroup group = new ConstrGroup(false);
155 for (int i = 0; i < this.numberOfSolvers; i++) {
156 group.add(this.solvers.get(i).addExactly(literals, n));
157 }
158 return group;
159 }
160
161 public IConstr addClause(IVecInt literals) throws ContradictionException {
162 ConstrGroup group = new ConstrGroup(false);
163 for (int i = 0; i < this.numberOfSolvers; i++) {
164 group.add(this.solvers.get(i).addClause(literals));
165 }
166 return group;
167 }
168
169 public void clearLearntClauses() {
170 for (int i = 0; i < this.numberOfSolvers; i++) {
171 this.solvers.get(i).clearLearntClauses();
172 }
173 }
174
175 public void expireTimeout() {
176 for (int i = 0; i < this.numberOfSolvers; i++) {
177 this.solvers.get(i).expireTimeout();
178 }
179 this.sleepTime = FAST_SLEEP;
180 }
181
182 public Map<String, Number> getStat() {
183 return this.solvers.get(this.winnerId).getStat();
184 }
185
186 public int getTimeout() {
187 return this.solvers.get(0).getTimeout();
188 }
189
190 public long getTimeoutMs() {
191 return this.solvers.get(0).getTimeoutMs();
192 }
193
194 public int newVar() {
195 throw new UnsupportedOperationException();
196 }
197
198 public int newVar(int howmany) {
199 int result = 0;
200 for (int i = 0; i < this.numberOfSolvers; i++) {
201 result = this.solvers.get(i).newVar(howmany);
202 }
203 return result;
204 }
205
206 @Deprecated
207 public void printStat(PrintStream out, String prefix) {
208 for (int i = 0; i < this.numberOfSolvers; i++) {
209 out.printf(
210 "%s>>>>>>>>>> Solver number %d (%d answers) <<<<<<<<<<<<<<<<<<%n",
211 prefix, i, this.solversStats.get(i).getValue());
212 this.solvers.get(i).printStat(out, prefix);
213 }
214 }
215
216 public void printStat(PrintWriter out, String prefix) {
217 for (int i = 0; i < this.numberOfSolvers; i++) {
218 out.printf(
219 "%s>>>>>>>>>> Solver number %d (%d answers) <<<<<<<<<<<<<<<<<<%n",
220 prefix, i, this.solversStats.get(i).getValue());
221 this.solvers.get(i).printStat(out, prefix);
222 }
223 }
224
225 public boolean removeConstr(IConstr c) {
226 if (c instanceof ConstrGroup) {
227 ConstrGroup group = (ConstrGroup) c;
228 boolean removed = true;
229 IConstr toRemove;
230 for (int i = 0; i < this.numberOfSolvers; i++) {
231 toRemove = group.getConstr(i);
232 if (toRemove != null) {
233 removed = removed
234 & this.solvers.get(i).removeConstr(toRemove);
235 }
236 }
237 return removed;
238 }
239 throw new IllegalArgumentException(
240 "Can only remove a group of constraints!");
241 }
242
243 public void reset() {
244 for (int i = 0; i < this.numberOfSolvers; i++) {
245 this.solvers.get(i).reset();
246 }
247 }
248
249 public void setExpectedNumberOfClauses(int nb) {
250 for (int i = 0; i < this.numberOfSolvers; i++) {
251 this.solvers.get(i).setExpectedNumberOfClauses(nb);
252 }
253 }
254
255 public void setTimeout(int t) {
256 for (int i = 0; i < this.numberOfSolvers; i++) {
257 this.solvers.get(i).setTimeout(t);
258 }
259 }
260
261 public void setTimeoutMs(long t) {
262 for (int i = 0; i < this.numberOfSolvers; i++) {
263 this.solvers.get(i).setTimeoutMs(t);
264 }
265 }
266
267 public void setTimeoutOnConflicts(int count) {
268 for (int i = 0; i < this.numberOfSolvers; i++) {
269 this.solvers.get(i).setTimeoutOnConflicts(count);
270 }
271 }
272
273 public String toString(String prefix) {
274 StringBuffer res = new StringBuffer();
275 res.append(prefix);
276 res.append("ManyCore solver with ");
277 res.append(this.numberOfSolvers);
278 res.append(" solvers running in parallel");
279 res.append("\n");
280 for (int i = 0; i < this.numberOfSolvers; i++) {
281 res.append(prefix);
282 res.append(">>>>>>>>>> Solver number ");
283 res.append(i);
284 res.append(" <<<<<<<<<<<<<<<<<<\n");
285 res.append(this.solvers.get(i).toString(prefix));
286 if (i < this.numberOfSolvers - 1) {
287 res.append("\n");
288 }
289 }
290 return res.toString();
291 }
292
293 public int[] findModel() throws TimeoutException {
294 if (isSatisfiable()) {
295 return model();
296 }
297
298 return null;
299 }
300
301 public int[] findModel(IVecInt assumps) throws TimeoutException {
302 if (isSatisfiable(assumps)) {
303 return model();
304 }
305
306 return null;
307 }
308
309 public boolean isSatisfiable() throws TimeoutException {
310 return isSatisfiable(VecInt.EMPTY, false);
311 }
312
313 public synchronized boolean isSatisfiable(IVecInt assumps,
314 boolean globalTimeout) throws TimeoutException {
315 this.remainingSolvers = new AtomicInteger(this.numberOfSolvers);
316 this.solved = false;
317 for (int i = 0; i < this.numberOfSolvers; i++) {
318 new Thread(new RunnableSolver(i, this.solvers.get(i), assumps,
319 globalTimeout, this)).start();
320 }
321 try {
322 this.sleepTime = NORMAL_SLEEP;
323 do {
324 wait(this.sleepTime);
325 } while (this.remainingSolvers.get() > 0);
326 } catch (InterruptedException e) {
327
328 }
329 if (!this.solved) {
330 assert this.remainingSolvers.get() == 0;
331 throw new TimeoutException();
332 }
333 return this.resultFound;
334 }
335
336 public boolean isSatisfiable(boolean globalTimeout) throws TimeoutException {
337 throw new UnsupportedOperationException();
338 }
339
340 public boolean isSatisfiable(IVecInt assumps) throws TimeoutException {
341 throw new UnsupportedOperationException();
342 }
343
344 public int[] model() {
345 return this.solvers.get(this.winnerId).model();
346 }
347
348 public boolean model(int var) {
349 return this.solvers.get(this.winnerId).model(var);
350 }
351
352 public int nConstraints() {
353 return this.solvers.get(0).nConstraints();
354 }
355
356 public int nVars() {
357 return this.solvers.get(0).nVars();
358 }
359
360 public void printInfos(PrintWriter out, String prefix) {
361 for (int i = 0; i < this.numberOfSolvers; i++) {
362 out.printf("%s>>>>>>>>>> Solver number %d <<<<<<<<<<<<<<<<<<%n",
363 prefix, i);
364 this.solvers.get(i).printInfos(out, prefix);
365 }
366 }
367
368 public synchronized void onFinishWithAnswer(boolean finished,
369 boolean result, int index) {
370 if (finished && !this.solved) {
371 this.winnerId = index;
372 this.solversStats.get(index).inc();
373 this.solved = true;
374 this.resultFound = result;
375 for (int i = 0; i < this.numberOfSolvers; i++) {
376 if (i != this.winnerId) {
377 this.solvers.get(i).expireTimeout();
378 }
379 }
380 this.sleepTime = FAST_SLEEP;
381 System.out.println(getLogPrefix() + "And the winner is "
382 + this.availableSolvers[this.winnerId]);
383 }
384 this.remainingSolvers.getAndDecrement();
385 }
386
387 public boolean isDBSimplificationAllowed() {
388 return this.solvers.get(0).isDBSimplificationAllowed();
389 }
390
391 public void setDBSimplificationAllowed(boolean status) {
392 for (int i = 0; i < this.numberOfSolvers; i++) {
393 this.solvers.get(0).setDBSimplificationAllowed(status);
394 }
395 }
396
397 public <I extends ISolverService> void setSearchListener(
398 SearchListener<I> sl) {
399 for (int i = 0; i < this.numberOfSolvers; i++) {
400 this.solvers.get(i).setSearchListener(sl);
401 }
402 }
403
404
405
406
407 public <I extends ISolverService> SearchListener<I> getSearchListener() {
408 return this.solvers.get(0).getSearchListener();
409 }
410
411 public int nextFreeVarId(boolean reserve) {
412 int res = -1;
413 for (int i = 0; i < this.numberOfSolvers; ++i) {
414 res = this.solvers.get(i).nextFreeVarId(reserve);
415 }
416 return res;
417 }
418
419 public IConstr addBlockingClause(IVecInt literals)
420 throws ContradictionException {
421 ConstrGroup group = new ConstrGroup(false);
422 for (int i = 0; i < this.numberOfSolvers; i++) {
423 group.add(this.solvers.get(i).addBlockingClause(literals));
424 }
425 return group;
426 }
427
428 public boolean removeSubsumedConstr(IConstr c) {
429 if (c instanceof ConstrGroup) {
430 ConstrGroup group = (ConstrGroup) c;
431 boolean removed = true;
432 IConstr toRemove;
433 for (int i = 0; i < this.numberOfSolvers; i++) {
434 toRemove = group.getConstr(i);
435 if (toRemove != null) {
436 removed = removed
437 & this.solvers.get(i)
438 .removeSubsumedConstr(toRemove);
439 }
440 }
441 return removed;
442 }
443 throw new IllegalArgumentException(
444 "Can only remove a group of constraints!");
445 }
446
447 public boolean isVerbose() {
448 return this.solvers.get(0).isVerbose();
449 }
450
451 public void setVerbose(boolean value) {
452 for (int i = 0; i < this.numberOfSolvers; i++) {
453 this.solvers.get(i).setVerbose(value);
454 }
455 }
456
457 public void setLogPrefix(String prefix) {
458 for (int i = 0; i < this.numberOfSolvers; i++) {
459 this.solvers.get(i).setLogPrefix(prefix);
460 }
461
462 }
463
464 public String getLogPrefix() {
465 return this.solvers.get(0).getLogPrefix();
466 }
467
468 public IVecInt unsatExplanation() {
469 return this.solvers.get(this.winnerId).unsatExplanation();
470 }
471
472 public int[] primeImplicant() {
473 return this.solvers.get(this.winnerId).primeImplicant();
474 }
475
476
477
478
479 public boolean primeImplicant(int p) {
480 return this.solvers.get(this.winnerId).primeImplicant(p);
481 }
482
483 public List<S> getSolvers() {
484 return new ArrayList<S>(this.solvers);
485 }
486
487 public int[] modelWithInternalVariables() {
488 return this.solvers.get(this.winnerId).modelWithInternalVariables();
489 }
490
491 public int realNumberOfVariables() {
492 return this.solvers.get(0).realNumberOfVariables();
493 }
494
495 public void registerLiteral(int p) {
496 for (int i = 0; i < this.numberOfSolvers; i++) {
497 this.solvers.get(i).registerLiteral(p);
498 }
499
500 }
501
502 public boolean isSolverKeptHot() {
503 return this.solvers.get(0).isSolverKeptHot();
504 }
505
506 public void setKeepSolverHot(boolean value) {
507 for (int i = 0; i < this.numberOfSolvers; i++) {
508 this.solvers.get(i).setKeepSolverHot(value);
509 }
510
511 }
512
513 public ISolver getSolvingEngine() {
514 throw new UnsupportedOperationException("Not supported yet in ManyCore");
515 }
516
517
518
519
520 public void printStat(PrintWriter out) {
521 printStat(out, getLogPrefix());
522 }
523
524
525
526
527 public void printInfos(PrintWriter out) {
528 for (int i = 0; i < this.numberOfSolvers; i++) {
529 out.printf("%s>>>>>>>>>> Solver number %d <<<<<<<<<<<<<<<<<<%n",
530 getLogPrefix(), i);
531 this.solvers.get(i).printInfos(out);
532 }
533
534 }
535 }
536
537 class RunnableSolver implements Runnable {
538
539 private final int index;
540 private final ISolver solver;
541 private final OutcomeListener ol;
542 private final IVecInt assumps;
543 private final boolean globalTimeout;
544
545 public RunnableSolver(int i, ISolver solver, IVecInt assumps,
546 boolean globalTimeout, OutcomeListener ol) {
547 this.index = i;
548 this.solver = solver;
549 this.ol = ol;
550 this.assumps = assumps;
551 this.globalTimeout = globalTimeout;
552 }
553
554 public void run() {
555 try {
556 boolean result = this.solver.isSatisfiable(this.assumps,
557 this.globalTimeout);
558 this.ol.onFinishWithAnswer(true, result, this.index);
559 } catch (Exception e) {
560 this.ol.onFinishWithAnswer(false, false, this.index);
561 }
562 }
563
564 }