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