1 /********************************************************************
2  * AUTHORS: Vijay Ganesh, Trevor Hansen, Dan Liew, Mate Soos
3  *
4  * BEGIN DATE: November, 2005
5  *
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE.
23 ********************************************************************/
24 
25 #include "stp/ToSat/AIG/ToSATAIG.h"
26 #include "stp/Simplifier/Simplifier.h"
27 #include "stp/Simplifier/constantBitP/ConstantBitPropagation.h"
28 
29 namespace stp
30 {
31 
32 THREAD_LOCAL int ToSATAIG::cnf_calls = 0;
33 
CallSAT(SATSolver & satSolver,const ASTNode & input,bool needAbsRef)34 bool ToSATAIG::CallSAT(SATSolver& satSolver, const ASTNode& input,
35                        bool needAbsRef)
36 {
37   if (cb != NULL && cb->isUnsatisfiable())
38     return false;
39 
40   if (!first)
41   {
42     assert(input == ASTTrue);
43     return runSolver(satSolver);
44   }
45 
46   // Shortcut if known. This avoids calling the setup of the CNF generator.
47   // setup of the CNF generator is expensive. NB, these checks have to occur
48   // after calling the sat solver (if it's not the first time.)
49   if (input == ASTFalse)
50     return false;
51 
52   if (input == ASTTrue)
53     return true;
54 
55   first = false;
56   Cnf_Dat_t* cnfData = bitblast(input, needAbsRef);
57   handle_cnf_options(cnfData, needAbsRef);
58 
59   assert(satSolver.nVars() == 0);
60   add_cnf_to_solver(satSolver, cnfData);
61 
62   if (bm->UserFlags.output_bench_flag)
63   {
64     cerr << "Converting to CNF via ABC's AIG package can't yet print out bench "
65             "format"
66          << endl;
67   }
68   release_cnf_memory(cnfData);
69 
70   mark_variables_as_frozen(satSolver);
71 
72   return runSolver(satSolver);
73 }
74 
release_cnf_memory(Cnf_Dat_t * cnfData)75 void ToSATAIG::release_cnf_memory(Cnf_Dat_t* cnfData)
76 {
77   // This releases the memory used by the CNF generator, particularly some data
78   // tables.
79   // If CNF generation is going to be called lots, we'd rather keep it around.
80   // because the datatables are expensive to generate.
81   if (cnf_calls == 0)
82     Cnf_ClearMemory();
83 
84   Cnf_DataFree(cnfData);
85   cnf_calls++;
86 }
87 
handle_cnf_options(Cnf_Dat_t * cnfData,bool needAbsRef)88 void ToSATAIG::handle_cnf_options(Cnf_Dat_t* cnfData, bool needAbsRef)
89 {
90   if (bm->UserFlags.output_CNF_flag)
91   {
92     std::stringstream fileName;
93     fileName << "output_" << bm->CNFFileNameCounter++ << ".cnf";
94     Cnf_DataWriteIntoFile(cnfData, (char*)fileName.str().c_str(), 0);
95   }
96 
97   if (bm->UserFlags.exit_after_CNF)
98   {
99     if (bm->UserFlags.quick_statistics_flag)
100       bm->GetRunTimes()->print();
101 
102     if (needAbsRef)
103     {
104       cerr << "Warning: STP is exiting after generating the first CNF."
105            << " But the CNF is probably partial which you probably don't want."
106            << " You probably want to disable"
107            << " refinement with the \"-r\" command line option." << endl;
108     }
109 
110     exit(0);
111   }
112 }
113 
bitblast(const ASTNode & input,bool needAbsRef)114 Cnf_Dat_t* ToSATAIG::bitblast(const ASTNode& input, bool needAbsRef)
115 {
116   Simplifier simp(bm);
117 
118   BBNodeManagerAIG mgr;
119   BitBlaster<BBNodeAIG, BBNodeManagerAIG> bb(
120       &mgr, &simp, bm->defaultNodeFactory, &bm->UserFlags, cb);
121 
122   bm->GetRunTimes()->start(RunTimes::BitBlasting);
123   BBNodeAIG BBFormula = bb.BBForm(input);
124   bm->GetRunTimes()->stop(RunTimes::BitBlasting);
125 
126   delete cb;
127   cb = NULL;
128   bb.cb = NULL;
129 
130   bm->GetRunTimes()->start(RunTimes::CNFConversion);
131   Cnf_Dat_t* cnfData = NULL;
132   toCNF.toCNF(BBFormula, cnfData, nodeToSATVar, needAbsRef, mgr);
133   bm->GetRunTimes()->stop(RunTimes::CNFConversion);
134 
135   // Free the memory in the AIGs.
136   BBFormula = BBNodeAIG(); // null node
137   mgr.stop();
138 
139   return cnfData;
140 }
141 
add_cnf_to_solver(SATSolver & satSolver,Cnf_Dat_t * cnfData)142 void ToSATAIG::add_cnf_to_solver(SATSolver& satSolver, Cnf_Dat_t* cnfData)
143 {
144   bm->GetRunTimes()->start(RunTimes::SendingToSAT);
145 
146   // Create a new sat variable for each of the variables in the CNF.
147   int satV = satSolver.nVars();
148   for (int i = 0; i < cnfData->nVars - satV; i++)
149     satSolver.newVar();
150 
151   SATSolver::vec_literals satSolverClause;
152   for (int i = 0; i < cnfData->nClauses; i++)
153   {
154     satSolverClause.clear();
155     for (int *pLit = cnfData->pClauses[i], *pStop = cnfData->pClauses[i + 1];
156          pLit < pStop; pLit++)
157     {
158       uint32_t var = (*pLit) >> 1;
159       assert((var < satSolver.nVars()));
160       Minisat::Lit l = SATSolver::mkLit(var, (*pLit) & 1);
161       satSolverClause.push(l);
162     }
163 
164     satSolver.addClause(satSolverClause);
165     if (!satSolver.okay())
166       break;
167   }
168   bm->GetRunTimes()->stop(RunTimes::SendingToSAT);
169 }
170 
mark_variables_as_frozen(SATSolver & satSolver)171 void ToSATAIG::mark_variables_as_frozen(SATSolver& satSolver)
172 {
173   for (ArrayTransformer::ArrType::iterator it =
174            arrayTransformer->arrayToIndexToRead.begin();
175        it != arrayTransformer->arrayToIndexToRead.end(); it++)
176   {
177     const ArrayTransformer::arrTypeMap& atm = it->second;
178 
179     for (ArrayTransformer::arrTypeMap::const_iterator arr_it = atm.begin();
180          arr_it != atm.end(); arr_it++)
181     {
182       const ArrayTransformer::ArrayRead& ar = arr_it->second;
183       ASTNodeToSATVar::iterator it = nodeToSATVar.find(ar.index_symbol);
184       if (it != nodeToSATVar.end())
185       {
186         const vector<unsigned>& v = it->second;
187         for (size_t i = 0, size = v.size(); i < size; ++i)
188           satSolver.setFrozen(v[i]);
189       }
190 
191       ASTNodeToSATVar::iterator it2 = nodeToSATVar.find(ar.symbol);
192       if (it2 != nodeToSATVar.end())
193       {
194         const vector<unsigned>& v = it2->second;
195         for (size_t i = 0, size = v.size(); i < size; ++i)
196           satSolver.setFrozen(v[i]);
197       }
198     }
199   }
200 }
201 
runSolver(SATSolver & satSolver)202 bool ToSATAIG::runSolver(SATSolver& satSolver)
203 {
204   bm->GetRunTimes()->start(RunTimes::Solving);
205   satSolver.solve(bm->soft_timeout_expired);
206   bm->GetRunTimes()->stop(RunTimes::Solving);
207 
208   if (bm->UserFlags.stats_flag)
209     satSolver.printStats();
210 
211   return satSolver.okay();
212 }
213 
~ToSATAIG()214 ToSATAIG::~ToSATAIG()
215 {
216   ClearAllTables();
217 }
218 }
219