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