1 /******************************************
2 Copyright (c) 2016, Mate Soos
3 
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 ***********************************************/
22 
23 #include "subsumeimplicit.h"
24 #include "clausecleaner.h"
25 #include "time_mem.h"
26 #include "solver.h"
27 #include "watchalgos.h"
28 #include "clauseallocator.h"
29 #include "sqlstats.h"
30 
31 #include <cmath>
32 #include <iomanip>
33 using std::cout;
34 using std::endl;
35 using namespace CMSat;
36 
SubsumeImplicit(Solver * _solver)37 SubsumeImplicit::SubsumeImplicit(Solver* _solver) :
38     solver(_solver)
39 {
40 }
41 
try_subsume_bin(const Lit lit,Watched * i,Watched * & j,int64_t * timeAvail,TouchList * touched)42 void SubsumeImplicit::try_subsume_bin(
43     const Lit lit
44     , Watched* i
45     , Watched*& j
46     , int64_t *timeAvail
47     , TouchList* touched
48 ) {
49     //Subsume bin with bin
50     if (i->lit2() == lastLit2) {
51         //The sorting algorithm prefers irred to red, so it is
52         //impossible to have irred before red
53         assert(!(i->red() == false && lastRed == true));
54 
55         runStats.remBins++;
56         assert(i->lit2().var() != lit.var());
57         *timeAvail -= 30;
58         *timeAvail -= solver->watches[i->lit2()].size();
59         removeWBin(solver->watches, i->lit2(), lit, i->red());
60         if (touched) {
61             touched->touch(i->lit2());
62         }
63         if (i->red()) {
64             solver->binTri.redBins--;
65         } else {
66             solver->binTri.irredBins--;
67         }
68         (*solver->drat) << del << lit << i->lit2() << fin;
69 
70         return;
71     } else {
72         lastBin = j;
73         lastLit2 = i->lit2();
74         lastRed = i->red();
75         *j++ = *i;
76     }
77 }
78 
subsume_at_watch(const uint32_t at,int64_t * timeAvail,TouchList * touched)79 uint32_t SubsumeImplicit::subsume_at_watch(const uint32_t at,
80                                            int64_t* timeAvail,
81                                            TouchList* touched)
82 {
83     runStats.numWatchesLooked++;
84     const Lit lit = Lit::toLit(at);
85     watch_subarray ws = solver->watches[lit];
86 
87     if (ws.size() > 1) {
88         *timeAvail -= (int64_t)(ws.size()*std::ceil(std::log((double)ws.size())) + 20);
89         std::sort(ws.begin(), ws.end(), WatchSorterBinTriLong());
90     }
91     /*cout << "---> Before" << endl;
92     print_watch_list(ws, lit);*/
93 
94     Watched* i = ws.begin();
95     Watched* j = i;
96     clear();
97 
98     for (Watched* end = ws.end(); i != end; i++) {
99         if (*timeAvail < 0) {
100             *j++ = *i;
101             continue;
102         }
103 
104         switch(i->getType()) {
105             case CMSat::watch_clause_t:
106                 *j++ = *i;
107                 break;
108 
109             case CMSat::watch_binary_t:
110                 try_subsume_bin(lit, i, j, timeAvail, touched);
111                 break;
112 
113             default:
114                 assert(false);
115                 break;
116         }
117     }
118     ws.shrink(i-j);
119     return i-j;
120 }
121 
subsume_implicit(const bool check_stats,std::string caller)122 void SubsumeImplicit::subsume_implicit(const bool check_stats, std::string caller)
123 {
124     assert(solver->okay());
125     const double myTime = cpuTime();
126     const uint64_t orig_timeAvailable =
127         1000LL*1000LL*solver->conf.subsume_implicit_time_limitM
128         *solver->conf.global_timeout_multiplier;
129     timeAvailable = orig_timeAvailable;
130     runStats.clear();
131 
132     //For randomization, we must have at least 1
133     if (solver->watches.size() == 0) {
134         return;
135     }
136 
137     //Randomize starting point
138     const size_t rnd_start = solver->mtrand.randInt(solver->watches.size()-1);
139     size_t numDone = 0;
140     for (;numDone < solver->watches.size() && timeAvailable > 0 && !solver->must_interrupt_asap()
141          ;numDone++
142     ) {
143         const size_t at = (rnd_start + numDone)  % solver->watches.size();
144         subsume_at_watch(at, &timeAvailable);
145     }
146 
147     const double time_used = cpuTime() - myTime;
148     const bool time_out = (timeAvailable <= 0);
149     const double time_remain = float_div(timeAvailable, orig_timeAvailable);
150     runStats.numCalled++;
151     runStats.time_used += time_used;
152     runStats.time_out += time_out;
153     if (solver->conf.verbosity) {
154         runStats.print_short(solver, caller.c_str());
155     }
156     if (solver->sqlStats) {
157         solver->sqlStats->time_passed(
158             solver
159             , std::string("subsume implicit")+caller
160             , time_used
161             , time_out
162             , time_remain
163         );
164     }
165 
166     if (check_stats) {
167         #ifdef DEBUG_IMPLICIT_STATS
168         solver->check_stats();
169         #endif
170     }
171 
172     globalStats += runStats;
173 }
174 
operator +=(const SubsumeImplicit::Stats & other)175 SubsumeImplicit::Stats SubsumeImplicit::Stats::operator+=(const SubsumeImplicit::Stats& other)
176 {
177     numCalled+= other.numCalled;
178     time_out += other.time_out;
179     time_used += other.time_used;
180     remBins += other.remBins;
181     numWatchesLooked += other.numWatchesLooked;
182 
183     return *this;
184 }
185 
print_short(const Solver * _solver,const char * caller) const186 void SubsumeImplicit::Stats::print_short(const Solver* _solver, const char* caller) const
187 {
188     cout
189     << "c [impl sub" << caller << "]"
190     << " bin: " << remBins
191     << _solver->conf.print_times(time_used, time_out)
192     << " w-visit: " << numWatchesLooked
193     << endl;
194 }
195 
print(const char * caller) const196 void SubsumeImplicit::Stats::print(const char* caller) const
197 {
198     cout << "c -------- IMPLICIT SUB " << caller << " STATS --------" << endl;
199     print_stats_line("c time"
200         , time_used
201         , float_div(time_used, numCalled)
202         , "per call"
203     );
204 
205     print_stats_line("c timed out"
206         , time_out
207         , stats_line_percent(time_out, numCalled)
208         , "% of calls"
209     );
210 
211     print_stats_line("c rem bins"
212         , remBins
213     );
214     cout << "c -------- IMPLICIT SUB STATS END --------" << endl;
215 }
216 
get_stats() const217 SubsumeImplicit::Stats SubsumeImplicit::get_stats() const
218 {
219     return globalStats;
220 }
221 
mem_used() const222 double SubsumeImplicit::mem_used() const
223 {
224     double mem = sizeof(SubsumeImplicit);
225     mem += tmplits.size()*sizeof(Lit);
226 
227     return mem;
228 }
229