1/****************************************** 2Copyright (c) 2016, Mate Soos 3 4Permission is hereby granted, free of charge, to any person obtaining a copy 5of this software and associated documentation files (the "Software"), to deal 6in the Software without restriction, including without limitation the rights 7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8copies of the Software, and to permit persons to whom the Software is 9furnished to do so, subject to the following conditions: 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20THE SOFTWARE. 21***********************************************/ 22 23#include "solutionextender.h" 24#include "varreplacer.h" 25#include "occsimplifier.h" 26#include "solver.h" 27#include "completedetachreattacher.h" 28using namespace CMSat; 29using std::cout; 30using std::endl; 31 32SolutionExtender::SolutionExtender( 33 Solver* _solver 34 , const vector<lbool>& _solution 35) : 36 solver(_solver) 37 , qhead (0) 38 , assigns(_solution) 39{ 40 solver->model.resize(nVarsOuter(), l_Undef); 41 for (uint32_t var = 0; var < nVarsOuter(); var++) { 42 solver->model[var] = value(var); 43 } 44 release_assert(solver->verify_model()); 45} 46 47/** 48@brief Extends a SAT solution to the full solution 49 50variable elimination, variable replacement, sub-part solving, etc. all need to 51be handled correctly to arrive at a solution that is a solution to ALL of the 52original problem, not just of what remained of it at the end inside this class 53(i.e. we need to combine things from the helper classes) 54*/ 55void SolutionExtender::extend() 56{ 57 if (solver->conf.verbosity >= 3) { 58 cout << "c Extending solution" << endl; 59 } 60 61 assert(clausesToFree.empty()); 62 63 //First detach all long clauses 64 CompleteDetachReatacher detachReattach(solver); 65 detachReattach.detach_nonbins_nontris(); 66 67 //Make watches large enough to fit occur of all 68 solver->watches.resize(nVarsOuter()*2); 69 70 //Sanity check 71 if (solver->occsimplifier) { 72 solver->occsimplifier->check_elimed_vars_are_unassignedAndStats(); 73 } 74 75 //Adding binary clauses representing equivalent literals 76 if (solver->conf.verbosity >= 3) { 77 cout << "c Adding equivalent literals" << endl; 78 } 79 solver->varReplacer->extend_model(this); 80 81 if (solver->conf.verbosity >= 3) { 82 cout << "c Picking braches and propagating" << endl; 83 } 84 85 //Pick branches as long as we can 86 for (uint32_t var = 0; var < nVarsOuter(); var++) { 87 if (value(var) == l_Undef 88 //Don't pick replaced variables 89 && solver->varData[var].removed != Removed::replaced 90 ) { 91 Lit toEnqueue = Lit(var, false); 92 #ifdef VERBOSE_DEBUG_RECONSTRUCT 93 cout << "c Picking lit for reconstruction: " << toEnqueue << endl; 94 #endif 95 enqueue(toEnqueue); 96 97 const bool OK = propagate(); 98 if (!OK) { 99 cout 100 << "Error while picking lit " << toEnqueue 101 << " and propagating after solution reconstruction" 102 << endl; 103 assert(false); 104 105 std::exit(-1); 106 } 107 } 108 } 109 110 if (solver->conf.verbosity >= 3) { 111 cout << "c Adding blocked clauses" << endl; 112 } 113 if (solver->occsimplifier) { 114 solver->occsimplifier->extend_model(this); 115 } 116 117 //Copy&check model 118 solver->model.resize(nVarsOuter(), l_Undef); 119 for (uint32_t var = 0; var < nVarsOuter(); var++) { 120 solver->model[var] = value(var); 121 } 122 123 release_assert(solver->verify_model()); 124 125 //free clauses 126 for (vector<ClOffset>::iterator 127 it = clausesToFree.begin(), end = clausesToFree.end() 128 ; it != end 129 ; ++it 130 ) { 131 solver->cl_alloc.clauseFree(*it); 132 } 133 clausesToFree.clear(); 134 135 //Reset watch size to smaller one 136 solver->watches.resize(solver->nVars()*2); 137 138 //Remove occur, go back to 0, and 139 detachReattach.detach_nonbins_nontris(); 140 solver->cancelUntil(0); 141 detachReattach.reattachLongs(); 142} 143 144bool SolutionExtender::satisfiedNorm(const vector<Lit>& lits) const 145{ 146 for (vector<Lit>::const_iterator 147 it = lits.begin(), end = lits.end() 148 ; it != end 149 ; ++it 150 ) { 151 if (value(*it) == l_True) 152 return true; 153 } 154 155 return false; 156} 157 158bool SolutionExtender::satisfiedXor(const vector<Lit>& lits, const bool rhs) const 159{ 160 bool val = false; 161 uint32_t undef = 0; 162 for (vector<Lit>::const_iterator it = lits.begin(), end = lits.end(); it != end; ++it) { 163 assert(it->unsign() == *it); 164 if (value(it->var()) == l_True) val ^= true; 165 if (value(it->var()) == l_Undef) undef++; 166 } 167 return (undef > 0 || val == rhs); 168} 169 170bool SolutionExtender::addClause( 171 const vector< Lit >& givenLits 172 , const Lit blockedOn 173) { 174 tmpLits = givenLits; 175 176 //Remove lits set at 0-level or return TRUE if any is set to TRUE at 0-level 177 vector<Lit>::iterator i = tmpLits.begin(); 178 vector<Lit>::iterator j = i; 179 for (vector<Lit>::iterator end = tmpLits.end(); i != end; i++) { 180 if (value(*i) == l_True && solver->varData[i->var()].level == 0) { 181 return true; 182 } 183 184 if (value(*i) == l_False && solver->varData[i->var()].level == 0) { 185 continue; 186 } 187 188 *j++ = *i; 189 } 190 tmpLits.resize(tmpLits.size()-(i-j)); 191 192 #ifdef VERBOSE_DEBUG_RECONSTRUCT 193 cout << "c Adding extend clause: " << tmpLits << " blocked on: " << blockedOn << endl; 194 #endif 195 196 //Empty clause, oops! 197 if (tmpLits.empty()) 198 return false; 199 200 //Create new clause, and add it 201 Clause* cl = solver->cl_alloc.Clause_new( 202 tmpLits //the literals 203 , 0 //the time it was created -- useless, ignoring 204 ); 205 ClOffset offset = solver->cl_alloc.get_offset(cl); 206 clausesToFree.push_back(offset); 207 for (vector<Lit>::const_iterator 208 it = tmpLits.begin(), end = tmpLits.end() 209 ; it != end 210 ; ++it 211 ) { 212 //Special used of blocked Lit -- for blocking, but not in the same 213 //sense as the original 214 solver->watches[it->toInt()].push(Watched(offset, blockedOn)); 215 } 216 217 propagateCl(cl, blockedOn); 218 if (!propagate()) { 219 assert(false); 220 return false; 221 } 222 223 return true; 224} 225 226inline bool SolutionExtender::prop_bin_cl( 227 Watched*& i 228 , const Lit p 229) { 230 const lbool val = value(i->lit2()); 231 if (val == l_Undef) { 232 #ifdef VERBOSE_DEBUG_RECONSTRUCT 233 cout 234 << "c Due to cl " 235 << ~p << ", " << i->lit2() 236 << " propagate enqueueing " 237 << i->lit2() << endl; 238 #endif 239 enqueue(i->lit2()); 240 } else if (val == l_False){ 241 return false; 242 } 243 244 return true; 245} 246 247bool SolutionExtender::propagate() 248{ 249 bool ret = true; 250 while(qhead < trail.size()) { 251 const Lit p = trail[qhead++]; 252 watch_subarray_const ws = solver->watches[~p]; 253 for(const Watched* 254 it = ws.begin(), end = ws.end() 255 ; it != end 256 ; ++it 257 ) { 258 if (it->isBin() && !it->red()) { 259 bool thisret = prop_bin_cl(it, p); 260 ret &= thisret; 261 if (!thisret) { 262 cout 263 << "Problem with implicit binary clause: " 264 << ~p 265 << ", " << it->lit2() 266 << endl; 267 } 268 269 continue; 270 } 271 272 if (it->isClause()) { 273 ClOffset offset = it->get_offset(); 274 const Clause* cl = solver->cl_alloc.ptr(offset); 275 const Lit blockedOn = it->getBlockedLit(); 276 const bool thisRet = propagateCl(cl, blockedOn); 277 if (!thisRet) { 278 cout << "Problem with clause: " << (*it) << endl; 279 } 280 ret &= thisRet; 281 } 282 } 283 } 284 285 return ret; 286} 287 288bool SolutionExtender::propagateCl( 289 const Clause* cl 290 , const Lit blockedOn 291) { 292 size_t numUndef = 0; 293 Lit lastUndef = lit_Undef; 294 for (const Lit 295 *it = cl->begin(), *end = cl->end() 296 ; it != end 297 ; ++it 298 ) { 299 if (value(*it) == l_True) return true; 300 if (value(*it) == l_False) continue; 301 302 assert(value(*it) == l_Undef); 303 numUndef++; 304 305 //Doesn't propagate anything 306 if (numUndef > 1) 307 break; 308 309 lastUndef = *it; 310 } 311 312 //Must set this one value 313 if (numUndef == 1) { 314 #ifdef VERBOSE_DEBUG_RECONSTRUCT 315 cout << "c Due to cl " << *cl << " propagate enqueueing " << lastUndef << endl; 316 #endif 317 enqueue(lastUndef); 318 } 319 320 if (numUndef >= 1) 321 return true; 322 323 //Must flip 324 #ifdef VERBOSE_DEBUG_RECONSTRUCT 325 cout 326 << "Flipping lit " << blockedOn 327 << " due to clause " << *cl << endl; 328 #endif 329 assert(blockedOn != lit_Undef); 330 331 if (solver->varData[blockedOn.var()].level == 0) { 332 cout 333 << "!! Flip 0-level var:" 334 << solver->map_inter_to_outer(blockedOn.var()) + 1 335 << endl; 336 } 337 338 assert( 339 (solver->varData[blockedOn.var()].level != 0 340 //|| solver->varData[blockedOn.var()].removed == Removed::decomposed 341 ) 342 && "We cannot flip 0-level vars" 343 ); 344 enqueue(blockedOn); 345 replaceSet(blockedOn); 346 return true; 347} 348 349void SolutionExtender::enqueue(const Lit lit) 350{ 351 assigns[lit.var()] = boolToLBool(!lit.sign()); 352 trail.push_back(lit); 353 #ifdef VERBOSE_DEBUG_RECONSTRUCT 354 cout << "c Enqueueing lit " << lit << " during solution reconstruction" << endl; 355 #endif 356 solver->varData[lit.var()].level = std::numeric_limits< uint32_t >::max(); 357} 358 359void SolutionExtender::replaceSet(Lit toSet) 360{ 361 //set forward equivalent 362 if (solver->varReplacer->isReplaced(toSet)) { 363 assert(false && "Cannot use isReplaced from outside of solver!!!!"); 364 toSet = solver->varReplacer->get_lit_replaced_with(toSet); 365 enqueue(toSet); 366 } 367 replaceBackwardSet(toSet); 368 369 #ifdef VERBOSE_DEBUG_RECONSTRUCT 370 cout << "c recursive set(s) done." << endl; 371 #endif 372} 373 374void SolutionExtender::replaceBackwardSet(const Lit toSet) 375{ 376 //set backward equiv 377 map<uint32_t, vector<uint32_t> >::const_iterator revTable = solver->varReplacer->getReverseTable().find(toSet.var()); 378 if (revTable != solver->varReplacer->getReverseTable().end()) { 379 const vector<uint32_t>& toGoThrough = revTable->second; 380 for (size_t i = 0; i < toGoThrough.size(); i++) { 381 //Get sign of replacement 382 const Lit lit = Lit(toGoThrough[i], false); 383 Lit tmp = solver->varReplacer->get_lit_replaced_with(lit); 384 385 //Set var 386 enqueue(lit ^ tmp.sign() ^ toSet.sign()); 387 } 388 } 389} 390