Timetabler
tsolver.cpp
1 /*
2  * Large portions of code in this file have been taken from
3  * algorithms/Alg_OLL.cc of Open WBO The LICENSE of that is given below
4  */
5 
33 #include "tsolver.h"
34 
35 #include "algorithms/Alg_OLL.h"
36 #include "mtl/Vec.h"
37 #include "utils.h"
38 
39 using namespace NSPACE;
40 using namespace openwbo;
41 
48 TSolver::TSolver(int verb, int enc) : OLL(verb, enc) {}
49 
61 std::vector<lbool> TSolver::tSearch() {
62  if (encoding != _CARD_TOTALIZER_) {
63  printf(
64  "Error: Currently algorithm MSU3 with iterative encoding only "
65  "supports the totalizer encoding.\n");
66  printf("s UNKNOWN\n");
67  exit(_ERROR_);
68  }
69 
70  if (maxsat_formula->getProblemType() == _WEIGHTED_) {
71  tWeighted();
72  return Utils::convertVecDataToVector<lbool>(model, model.size());
73  } else {
74  printf("Error: Use the solver in 'weighted' mode only!\n");
75  exit(_ERROR_);
76  }
77 }
78 
88  // nbInitialVariables = nVars();
89  lbool res = l_True;
90  initRelaxation();
91  solver = rebuildSolver();
92 
93  vec<Lit> assumptions;
94  vec<Lit> joinObjFunction;
95  vec<Lit> currentObjFunction;
96  vec<Lit> encodingAssumptions;
97  encoder.setIncremental(_INCREMENTAL_ITERATIVE_);
98 
99  activeSoft.growTo(maxsat_formula->nSoft(), false);
100  for (int i = 0; i < maxsat_formula->nSoft(); i++)
101  coreMapping[maxsat_formula->getSoftClause(i).assumption_var] = i;
102 
103  std::set<Lit> cardinality_assumptions;
104  vec<Encoder *> soft_cardinality;
105 
106  min_weight = maxsat_formula->getMaximumWeight();
107  // printf("current weight %d\n",maxsat_formula->getMaximumWeight());
108 
109  for (;;) {
110  res = searchSATSolver(solver, assumptions);
111  if (res == l_True) {
112  nbSatisfiable++;
113  uint64_t newCost = computeCostModel(solver->model);
114  if (newCost < ubCost || nbSatisfiable == 1) {
115  saveModel(solver->model);
116  if (maxsat_formula->getFormat() == _FORMAT_PB_) {
117  // optimization problem
118  if (maxsat_formula->getObjFunction() != NULL) {
119  // printf("o %" PRId64 "\n", newCost + off_set);
120  }
121  } else
122  // printf("o %" PRId64 "\n", newCost + off_set);
123  ubCost = newCost;
124  }
125 
126  if (nbSatisfiable == 1) {
127  min_weight =
128  findNextWeightDiversity(min_weight, cardinality_assumptions);
129  // printf("current weight %d\n",min_weight);
130 
131  for (int i = 0; i < maxsat_formula->nSoft(); i++)
132  if (maxsat_formula->getSoftClause(i).weight >= min_weight)
133  assumptions.push(~maxsat_formula->getSoftClause(i).assumption_var);
134  } else {
135  // compute min weight in soft
136  int not_considered = 0;
137  for (int i = 0; i < maxsat_formula->nSoft(); i++) {
138  if (maxsat_formula->getSoftClause(i).weight < min_weight)
139  not_considered++;
140  }
141 
142  // printf("not considered %d\n",not_considered);
143 
144  for (std::set<Lit>::iterator it = cardinality_assumptions.begin();
145  it != cardinality_assumptions.end(); ++it) {
146  assert(boundMapping.find(*it) != boundMapping.end());
147  std::pair<std::pair<int, uint64_t>, uint64_t> soft_id =
148  boundMapping[*it];
149  if (soft_id.second < min_weight) not_considered++;
150  }
151 
152  if (not_considered != 0) {
153  min_weight =
154  findNextWeightDiversity(min_weight, cardinality_assumptions);
155 
156  // printf("currentWeight %d\n",currentWeight);
157 
158  // reset the assumptions
159  assumptions.clear();
160  int active_soft = 0;
161  for (int i = 0; i < maxsat_formula->nSoft(); i++) {
162  if (!activeSoft[i] &&
163  maxsat_formula->getSoftClause(i).weight >= min_weight) {
164  assumptions.push(
165  ~maxsat_formula->getSoftClause(i).assumption_var);
166  // printf("s assumption
167  // %d\n",var(softClauses[i].assumptionVar)+1);
168  } else
169  active_soft++;
170  }
171 
172  // printf("assumptions %d\n",assumptions.size());
173  for (std::set<Lit>::iterator it = cardinality_assumptions.begin();
174  it != cardinality_assumptions.end(); ++it) {
175  assert(boundMapping.find(*it) != boundMapping.end());
176  std::pair<std::pair<int, uint64_t>, uint64_t> soft_id =
177  boundMapping[*it];
178  if (soft_id.second >= min_weight) assumptions.push(~(*it));
179  // printf("c assumption %d\n",var(*it)+1);
180  }
181 
182  } else {
183  assert(lbCost == newCost);
184  return;
185  }
186  }
187  }
188 
189  if (res == l_False) {
190  // reduce the weighted to the unweighted case
191  uint64_t min_core = UINT64_MAX;
192  for (int i = 0; i < solver->conflict.size(); i++) {
193  Lit p = solver->conflict[i];
194  if (coreMapping.find(p) != coreMapping.end()) {
195  assert(!activeSoft[coreMapping[p]]);
196  if (maxsat_formula->getSoftClause(coreMapping[solver->conflict[i]])
197  .weight < min_core)
198  min_core =
199  maxsat_formula->getSoftClause(coreMapping[solver->conflict[i]])
200  .weight;
201  }
202 
203  if (boundMapping.find(p) != boundMapping.end()) {
204  std::pair<std::pair<int, uint64_t>, uint64_t> soft_id =
205  boundMapping[solver->conflict[i]];
206  if (soft_id.second < min_core) min_core = soft_id.second;
207  }
208  }
209 
210  // printf("MIN CORE %d\n",min_core);
211 
212  lbCost += min_core;
213  nbCores++;
214  if (verbosity > 0)
215  // printf("c LB : %-12" PRIu64 "\n", lbCost);
216 
217  if (nbSatisfiable == 0) {
218  return;
219  }
220 
221  if (lbCost == ubCost) {
222  assert(nbSatisfiable > 0);
223  if (verbosity > 0)
224  // printf("c LB = UB\n");
225  return;
226  }
227 
228  sumSizeCores += solver->conflict.size();
229 
230  vec<Lit> soft_relax;
231  vec<Lit> cardinality_relax;
232 
233  for (int i = 0; i < solver->conflict.size(); i++) {
234  Lit p = solver->conflict[i];
235  if (coreMapping.find(p) != coreMapping.end()) {
236  if (maxsat_formula->getSoftClause(coreMapping[p]).weight > min_core) {
237  // printf("SPLIT THE CLAUSE\n");
238  assert(!activeSoft[coreMapping[p]]);
239  // SPLIT THE CLAUSE
240  int indexSoft = coreMapping[p];
241  assert(maxsat_formula->getSoftClause(indexSoft).weight - min_core >
242  0);
243 
244  // Update the weight of the soft clause.
245  maxsat_formula->getSoftClause(indexSoft).weight -= min_core;
246 
247  vec<Lit> clause;
248  vec<Lit> vars;
249 
250  maxsat_formula->getSoftClause(indexSoft).clause.copyTo(clause);
251  // Since cardinality constraints are added the variables
252  // are not in sync...
253  while (maxsat_formula->nVars() < solver->nVars())
254  maxsat_formula->newLiteral();
255 
256  Lit l = maxsat_formula->newLiteral();
257  vars.push(l);
258 
259  // Add a new soft clause with the weight of the core.
260  // addSoftClause(softClauses[indexSoft].weight-min_core,
261  // clause, vars);
262  maxsat_formula->addSoftClause(min_core, clause, vars);
263  activeSoft.push(true);
264 
265  // Add information to the SAT solver
266  newSATVariable(solver);
267  clause.push(l);
268  solver->addClause(clause);
269 
270  assert(clause.size() - 1 ==
271  maxsat_formula->getSoftClause(indexSoft).clause.size());
272  assert(maxsat_formula->getSoftClause(maxsat_formula->nSoft() - 1)
273  .relaxation_vars.size() == 1);
274 
275  // Create a new assumption literal.
276 
277  maxsat_formula->getSoftClause(maxsat_formula->nSoft() - 1)
278  .assumption_var = l;
279  assert(maxsat_formula->getSoftClause(maxsat_formula->nSoft() - 1)
280  .assumption_var ==
281  maxsat_formula->getSoftClause(maxsat_formula->nSoft() - 1)
282  .relaxation_vars[0]);
283  coreMapping[l] =
284  maxsat_formula->nSoft() - 1; // Map the new soft clause to its
285  // assumption literal.
286 
287  soft_relax.push(l);
288  assert(maxsat_formula->getSoftClause(coreMapping[l]).weight ==
289  min_core);
290  assert(activeSoft.size() == maxsat_formula->nSoft());
291 
292  } else {
293  // printf("NOT SPLITTING\n");
294  assert(
295  maxsat_formula->getSoftClause(coreMapping[solver->conflict[i]])
296  .weight == min_core);
297  soft_relax.push(p);
298  // printf("ASSERT %d\n",var(p)+1);
299  assert(!activeSoft[coreMapping[p]]);
300  activeSoft[coreMapping[p]] = true;
301  }
302  }
303 
304  if (boundMapping.find(p) != boundMapping.end()) {
305  // printf("CARD IN CORE\n");
306 
307  std::set<Lit>::iterator it;
308  it = cardinality_assumptions.find(p);
309  assert(it != cardinality_assumptions.end());
310 
311  // this is a soft cardinality -- bound must be increased
312  std::pair<std::pair<int, uint64_t>, uint64_t> soft_id =
313  boundMapping[solver->conflict[i]];
314  // increase the bound
315  assert(soft_id.first.first < soft_cardinality.size());
316  assert(soft_cardinality[soft_id.first.first]->hasCardEncoding());
317 
318  if (soft_id.second == min_core) {
319  cardinality_assumptions.erase(it);
320  cardinality_relax.push(p);
321 
322  joinObjFunction.clear();
323  encodingAssumptions.clear();
324  soft_cardinality[soft_id.first.first]->incUpdateCardinality(
325  solver, joinObjFunction,
326  soft_cardinality[soft_id.first.first]->lits(),
327  soft_id.first.second + 1, encodingAssumptions);
328 
329  // if the bound is the same as the number of lits then
330  // no restriction is applied
331  if (soft_id.first.second + 1 <
332  (unsigned)soft_cardinality[soft_id.first.first]
333  ->outputs()
334  .size()) {
335  assert((unsigned)soft_cardinality[soft_id.first.first]
336  ->outputs()
337  .size() > soft_id.first.second + 1);
338  Lit out = soft_cardinality[soft_id.first.first]
339  ->outputs()[soft_id.first.second + 1];
340  boundMapping[out] = std::make_pair(
341  std::make_pair(soft_id.first.first, soft_id.first.second + 1),
342  min_core);
343  cardinality_assumptions.insert(out);
344  }
345 
346  } else {
347 #if 1
348  // duplicate cardinality constraint???
349  Encoder *e = new Encoder();
350  e->setIncremental(_INCREMENTAL_ITERATIVE_);
351  e->buildCardinality(solver,
352  soft_cardinality[soft_id.first.first]->lits(),
353  soft_id.first.second);
354 
355  assert((unsigned)e->outputs().size() > soft_id.first.second);
356  Lit out = e->outputs()[soft_id.first.second];
357  soft_cardinality.push(e);
358 
359  boundMapping[out] =
360  std::make_pair(std::make_pair(soft_cardinality.size() - 1,
361  soft_id.first.second),
362  min_core);
363  cardinality_relax.push(out);
364 
365  // Update value of the previous cardinality constraint
366  assert(soft_id.second - min_core > 0);
367  boundMapping[p] = std::make_pair(
368  std::make_pair(soft_id.first.first, soft_id.first.second),
369  soft_id.second - min_core);
370 
371  // Update bound as usual...
372 
373  std::pair<std::pair<int, int>, int> soft_core_id =
374  boundMapping[out];
375 
376  joinObjFunction.clear();
377  encodingAssumptions.clear();
378  soft_cardinality[soft_core_id.first.first]->incUpdateCardinality(
379  solver, joinObjFunction,
380  soft_cardinality[soft_core_id.first.first]->lits(),
381  soft_core_id.first.second + 1, encodingAssumptions);
382 
383  // if the bound is the same as the number of lits then
384  // no restriction is applied
385  if (soft_core_id.first.second + 1 <
386  soft_cardinality[soft_core_id.first.first]->outputs().size()) {
387  assert(
388  soft_cardinality[soft_core_id.first.first]->outputs().size() >
389  soft_core_id.first.second + 1);
390  Lit out = soft_cardinality[soft_core_id.first.first]
391  ->outputs()[soft_core_id.first.second + 1];
392  boundMapping[out] =
393  std::make_pair(std::make_pair(soft_core_id.first.first,
394  soft_core_id.first.second + 1),
395  min_core);
396  cardinality_assumptions.insert(out);
397  }
398 #else
399 
400  // FIXME: improve the OLL algorithm by reusing the
401  // cardinality constraint This current alternative does
402  // not work!
403  while (nVars() < solver->nVars()) newLiteral();
404 
405  Lit l = newLiteral();
406 
407  // Add information to the SAT solver
408  newSATVariable(solver);
409  vec<Lit> clause;
410  clause.push(l);
411  clause.push(~p);
412  solver->addClause(clause);
413 
414  clause.clear();
415  clause.push(~l);
416  clause.push(p);
417  solver->addClause(clause);
418 
419  boundMapping[l] = std::make_pair(
420  std::make_pair(soft_id.first.first, soft_id.first.second),
421  min_core);
422  cardinality_relax.push(l);
423 
424  // Update bound as usual...
425 
426  std::pair<std::pair<int, int>, int> soft_core_id = boundMapping[p];
427 
428  joinObjFunction.clear();
429  encodingAssumptions.clear();
430  soft_cardinality[soft_core_id.first.first]->incUpdateCardinality(
431  solver, joinObjFunction,
432  soft_cardinality[soft_core_id.first.first]->lits(),
433  soft_core_id.first.second + 1, encodingAssumptions);
434 
435  // if the bound is the same as the number of lits then
436  // no restriction is applied
437  if (soft_core_id.first.second + 1 <
438  soft_cardinality[soft_core_id.first.first]->outputs().size()) {
439  assert(
440  soft_cardinality[soft_core_id.first.first]->outputs().size() >
441  soft_core_id.first.second + 1);
442  Lit out = soft_cardinality[soft_core_id.first.first]
443  ->outputs()[soft_core_id.first.second + 1];
444  boundMapping[out] =
445  std::make_pair(std::make_pair(soft_core_id.first.first,
446  soft_core_id.first.second + 1),
447  min_core);
448  cardinality_assumptions.insert(out);
449  }
450 
451  // Update value of the previous cardinality constraint
452  assert(soft_id.second - min_core > 0);
453  boundMapping[p] = std::make_pair(
454  std::make_pair(soft_id.first.first, soft_id.first.second),
455  soft_id.second - min_core);
456 
457 #endif
458  }
459  }
460  }
461 
462  assert(soft_relax.size() + cardinality_relax.size() > 0);
463 
464  if (soft_relax.size() == 1 && cardinality_relax.size() == 0) {
465  // Unit core
466  // printf("UNIT CORE\n");
467  solver->addClause(soft_relax[0]);
468  }
469 
470  // assert (soft_relax.size() > 0 || cardinality_relax.size() != 1);
471 
472  if (soft_relax.size() + cardinality_relax.size() > 1) {
473  vec<Lit> relax_harden;
474  soft_relax.copyTo(relax_harden);
475  for (int i = 0; i < cardinality_relax.size(); i++)
476  relax_harden.push(cardinality_relax[i]);
477 
478  /*
479  for (int i = 0; i < nSoft(); i++){
480  printf("soft %d, w: %d, r:
481  %d\n",i,softClauses[i].weight,var(softClauses[i].relaxationVars[0])+1);
482  for (int j = 0; j < softClauses[i].clause.size(); j++){
483  printf("%d ",var(softClauses[i].clause[j])+1);
484  }
485  printf("\n");
486  }
487 
488  for (int i = 0; i < relax_harden.size(); i++)
489  printf("+1 x%d ",var(relax_harden[i])+1);
490  printf(" <= 1\n");
491  */
492  Encoder *e = new Encoder();
493  e->setIncremental(_INCREMENTAL_ITERATIVE_);
494  e->buildCardinality(solver, relax_harden, 1);
495  soft_cardinality.push(e);
496  assert(e->outputs().size() > 1);
497 
498  // printf("outputs %d\n",e->outputs().size());
499  Lit out = e->outputs()[1];
500  boundMapping[out] = std::make_pair(
501  std::make_pair(soft_cardinality.size() - 1, 1), min_core);
502  cardinality_assumptions.insert(out);
503  }
504 
505  // reset the assumptions
506  assumptions.clear();
507  int active_soft = 0;
508  for (int i = 0; i < maxsat_formula->nSoft(); i++) {
509  if (!activeSoft[i] &&
510  maxsat_formula->getSoftClause(i).weight >= min_weight) {
511  assumptions.push(~maxsat_formula->getSoftClause(i).assumption_var);
512  // printf("s assumption
513  // %d\n",var(softClauses[i].assumptionVar)+1);
514  } else
515  active_soft++;
516  }
517 
518  // printf("assumptions %d\n",assumptions.size());
519  for (std::set<Lit>::iterator it = cardinality_assumptions.begin();
520  it != cardinality_assumptions.end(); ++it) {
521  assert(boundMapping.find(*it) != boundMapping.end());
522  std::pair<std::pair<int, uint64_t>, uint64_t> soft_id =
523  boundMapping[*it];
524  if (soft_id.second >= min_weight) assumptions.push(~(*it));
525  // printf("c assumption %d\n",var(*it)+1);
526  }
527 
528  // printf("card assumptions %d\n",assumptions.size());
529 
530  if (verbosity > 0) {
531  // printf("c Relaxed soft clauses %d / %d\n", active_soft,
532  // maxsat_formula->nSoft());
533  }
534  }
535  }
536 }
std::vector< lbool > tSearch()
Solves the MaxSAT problem by calling the solver.
Definition: tsolver.cpp:61
void tWeighted()
Solves a weighted MaxSAT problem.
Definition: tsolver.cpp:87
TSolver(int verb=_VERBOSITY_MINIMAL_, int enc=_CARD_TOTALIZER_)
Constructs the TSolver object.
Definition: tsolver.cpp:48