source: vis_dev/zchaff/zchaff_dbase.cpp @ 35

Last change on this file since 35 was 10, checked in by cecile, 13 years ago

Zchaff

File size: 15.8 KB
RevLine 
[10]1// *********************************************************************
2// Copyright 2000-2004, Princeton University.  All rights reserved.
3// By using this software the USER indicates that he or she has read,
4// understood and will comply with the following:
5//
6// --- Princeton University hereby grants USER nonexclusive permission
7// to use, copy and/or modify this software for internal, noncommercial,
8// research purposes only. Any distribution, including commercial sale
9// or license, of this software, copies of the software, its associated
10// documentation and/or modifications of either is strictly prohibited
11// without the prior consent of Princeton University.  Title to copyright
12// to this software and its associated documentation shall at all times
13// remain with Princeton University.  Appropriate copyright notice shall
14// be placed on all software copies, and a complete copy of this notice
15// shall be included in all copies of the associated documentation.
16// No right is  granted to use in advertising, publicity or otherwise
17// any trademark,  service mark, or the name of Princeton University.
18//
19//
20// --- This software and any associated documentation is provided "as is"
21//
22// PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
23// OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A
24// PARTICULAR PURPOSE, OR THAT  USE OF THE SOFTWARE, MODIFICATIONS, OR
25// ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS,
26// TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.
27//
28// Princeton University shall not be liable under any circumstances for
29// any direct, indirect, special, incidental, or consequential damages
30// with respect to any claim by USER or any third party on account of
31// or arising from the use, or inability to use, this software or its
32// associated documentation, even if Princeton University has been advised
33// of the possibility of those damages.
34// ********************************************************************/
35
36#include <cstdlib>
37
38#include <iostream>
39#include <vector>
40#include <set>
41
42using namespace std;
43
44#include "zchaff_dbase.h"
45
46CDatabase::CDatabase(void) {
47  _stats.mem_used_up                 = false;
48  _stats.init_num_clauses            = 0;
49  _stats.init_num_literals           = 0;
50  _stats.num_added_clauses           = 0;
51  _stats.num_added_literals          = 0;
52  _stats.num_deleted_clauses         = 0;
53  _stats.num_del_orig_cls            = 0;
54  _stats.num_deleted_literals        = 0;
55  _stats.num_enlarge                 = 0;
56  _stats.num_compact                 = 0;
57  _lit_pool_start = (CLitPoolElement *) malloc(sizeof(CLitPoolElement) *
58                                               STARTUP_LIT_POOL_SIZE);
59  _lit_pool_finish = _lit_pool_start;
60  _lit_pool_end_storage = _lit_pool_start + STARTUP_LIT_POOL_SIZE;
61  lit_pool_push_back(0);  // set the first element as a dummy element
62  _params.mem_limit = 1024 * 1024 * 1024;  // that's 1 G
63  variables()->resize(1);                  // var_id == 0 is never used.
64  _allocated_gid                    = 0;
65}
66
67CDatabase::~CDatabase(void) {
68  free(_lit_pool_start);
69}
70
71unsigned CDatabase::estimate_mem_usage(void) {
72  unsigned mem_lit_pool = sizeof(CLitPoolElement) * (lit_pool_size() +
73                                                     lit_pool_free_space());
74  unsigned mem_vars = sizeof(CVariable) * variables()->capacity();
75  unsigned mem_cls = sizeof(CClause) * clauses()->capacity();
76  unsigned mem_cls_queue = sizeof(int) * _unused_clause_idx.size();
77  unsigned mem_watched = 2 * num_clauses() * sizeof(CLitPoolElement *);
78  unsigned mem_lit_clauses = 0;
79#ifdef KEEP_LIT_CLAUSES
80  mem_lit_clauses = num_literals() * sizeof(ClauseIdx);
81#endif
82  return (mem_lit_pool + mem_vars + mem_cls +
83          mem_cls_queue + mem_watched + mem_lit_clauses);
84}
85
86unsigned CDatabase::mem_usage(void) {
87  int mem_lit_pool = (lit_pool_size() + lit_pool_free_space()) *
88                     sizeof(CLitPoolElement);
89  int mem_vars = sizeof(CVariable) * variables()->capacity();
90  int mem_cls = sizeof(CClause) * clauses()->capacity();
91  int mem_cls_queue = sizeof(int) * _unused_clause_idx.size();
92  int mem_watched = 0, mem_lit_clauses = 0;
93  for (unsigned i = 0, sz = variables()->size(); i < sz ;  ++i) {
94    CVariable & v = variable(i);
95    mem_watched        += v.watched(0).capacity() + v.watched(1).capacity();
96#ifdef KEEP_LIT_CLAUSES
97    mem_lit_clauses += v.lit_clause(0).capacity() + v.lit_clause(1).capacity();
98#endif
99  }
100  mem_watched *= sizeof(CLitPoolElement*);
101  mem_lit_clauses *= sizeof(ClauseIdx);
102  return (mem_lit_pool + mem_vars + mem_cls +
103          mem_cls_queue + mem_watched + mem_lit_clauses);
104}
105
106int CDatabase::alloc_gid(void) {
107  for (unsigned i = 1; i <= WORD_WIDTH; ++i) {
108    if (is_gid_allocated(i) == false) {
109      _allocated_gid |= (1 << (i-1));
110      return i;
111    }
112  }
113  warning(_POSITION_, "Not enough GID");
114  return VOLATILE_GID;
115}
116
117void CDatabase::free_gid(int gid) {
118  assert(gid > 0 && "Can't free volatile or permanent group");
119  assert(gid <= WORD_WIDTH && "gid > WORD_WIDTH?");
120  if (!is_gid_allocated(gid)) {
121    fatal(_POSITION_, "Can't free unallocated GID");
122  }
123  _allocated_gid &= (~(1<< (gid-1)));
124}
125
126bool CDatabase::is_gid_allocated(int gid) {
127  if (gid == VOLATILE_GID || gid == PERMANENT_GID)
128    return true;
129  assert(gid <= WORD_WIDTH && gid > 0);
130  if (_allocated_gid & (1 << (gid -1)))
131    return true;
132  return false;
133}
134
135int CDatabase::merge_clause_group(int g2, int g1) {
136  assert(g1 >0 && g2> 0 && "Can't merge with permanent or volatile group");
137  assert(g1 != g2);
138  assert(is_gid_allocated(g1) && is_gid_allocated(g2));
139  for (unsigned i = 0, sz = clauses()->size(); i < sz; ++i) {
140    if (clause(i).status() != DELETED_CL) {
141      if (clause(i).gid(g1) == true) {
142        clause(i).clear_gid(g1);
143        clause(i).set_gid(g2);
144      }
145    }
146  }
147  free_gid(g1);
148  return g2;
149}
150
151void CDatabase::mark_clause_deleted(CClause & cl) {
152  ++_stats.num_deleted_clauses;
153  _stats.num_deleted_literals += cl.num_lits();
154  CLAUSE_STATUS status = cl.status();
155  if (status == ORIGINAL_CL)
156     _stats.num_del_orig_cls++;
157  cl.set_status(DELETED_CL);
158  for (unsigned i = 0; i < cl.num_lits(); ++i) {
159    CLitPoolElement & l = cl.literal(i);
160    --variable(l.var_index()).lits_count(l.var_sign());
161    l.val() = 0;
162  }
163  _unused_clause_idx.insert(&cl - &(*clauses()->begin()));
164}
165
166bool CDatabase::is_conflicting(ClauseIdx cl) {
167  CLitPoolElement * lits = clause(cl).literals();
168  for (int i = 0, sz= clause(cl).num_lits(); i < sz;  ++i) {
169    if (literal_value(lits[i]) != 0)
170      return false;
171  }
172  return true;
173}
174
175bool CDatabase::is_satisfied(ClauseIdx cl) {
176  CLitPoolElement * lits = clause(cl).literals();
177  for (int i = 0, sz = clause(cl).num_lits(); i < sz; ++i) {
178    if (literal_value(lits[i]) == 1)
179      return true;
180  }
181  return false;
182}
183
184bool CDatabase::is_unit(ClauseIdx cl) {
185  int num_unassigned = 0;
186  CLitPoolElement * lits = clause(cl).literals();
187  for (unsigned i = 0, sz= clause(cl).num_lits(); i < sz;  ++i) {
188    int value = literal_value(lits[i]);
189    if (value == 1)
190      return false;
191    else if (value != 0)
192      ++num_unassigned;
193  }
194  return num_unassigned == 1;
195}
196
197int CDatabase::find_unit_literal(ClauseIdx cl) {
198  // will return 0 if not unit
199  int unit_lit = 0;
200  for (int i = 0, sz = clause(cl).num_lits(); i < sz;  ++i) {
201    int value = literal_value(clause(cl).literal(i));
202    if (value == 1)
203      return 0;
204    else if (value != 0) {
205      if (unit_lit == 0)
206        unit_lit = clause(cl).literals()[i].s_var();
207      else
208        return 0;
209    }
210  }
211  return unit_lit;
212}
213
214inline CLitPoolElement * CDatabase::lit_pool_begin(void) {
215  return _lit_pool_start;
216}
217
218inline CLitPoolElement * CDatabase::lit_pool_end(void) {
219  return _lit_pool_finish;
220}
221
222inline void CDatabase::lit_pool_incr_size(int size) {
223  _lit_pool_finish += size;
224  assert(_lit_pool_finish <= _lit_pool_end_storage);
225}
226
227inline void CDatabase::lit_pool_push_back(int value) {
228  assert(_lit_pool_finish <= _lit_pool_end_storage);
229  _lit_pool_finish->val() = value;
230  ++_lit_pool_finish;
231}
232
233inline int CDatabase::lit_pool_size(void) {
234  return _lit_pool_finish - _lit_pool_start;
235}
236
237inline int CDatabase::lit_pool_free_space(void) {
238  return _lit_pool_end_storage - _lit_pool_finish;
239}
240
241inline double CDatabase::lit_pool_utilization(void) {
242    // minus num_clauses() is because of spacing (i.e. clause indices)
243  return (double)num_literals() / ((double) (lit_pool_size() - num_clauses())) ;
244}
245
246inline CLitPoolElement & CDatabase::lit_pool(int i) {
247  return _lit_pool_start[i];
248}
249
250void CDatabase::compact_lit_pool(void) {
251  unsigned i, sz;
252  int new_index = 1;
253  // first do the compaction for the lit pool
254  for (i = 1, sz = lit_pool_size(); i < sz;  ++i) {
255    // begin with 1 because 0 position is always 0
256    if (!lit_pool(i).is_literal() && !lit_pool(i-1).is_literal()) {
257      continue;
258    } else {
259      lit_pool(new_index) = lit_pool(i);
260      ++new_index;
261    }
262  }
263  _lit_pool_finish = lit_pool_begin() + new_index;
264  // update all the pointers to the literals;
265  // 1. clean up the watched pointers from variables
266  for (i = 1, sz = variables()->size(); i < sz;  ++i) {
267    variable(i).watched(0).clear();
268    variable(i).watched(1).clear();
269  }
270  for (i = 1, sz = lit_pool_size(); i < sz;  ++i) {
271    CLitPoolElement & lit = lit_pool(i);
272    // 2. reinsert the watched pointers
273    if (lit.is_literal()) {
274      if (lit.is_watched()) {
275         int var_idx = lit.var_index();
276         int sign = lit.var_sign();
277         variable(var_idx).watched(sign).push_back(& lit_pool(i));
278       }
279    } else {  // lit is not literal
280    // 3. update the clauses' first literal pointer
281      int cls_idx = lit.get_clause_index();
282      clause(cls_idx).first_lit() = &lit_pool(i) - clause(cls_idx).num_lits();
283    }
284  }
285  ++_stats.num_compact;
286}
287
288bool CDatabase::enlarge_lit_pool(void) {
289  // will return true if successful, otherwise false.
290  unsigned i, sz;
291  // if memory efficiency < 2/3, we do a compaction
292  if (lit_pool_utilization() < 0.67) {
293    compact_lit_pool();
294    return true;
295  }
296  // otherwise we have to enlarge it.
297  // first, check if memory is running out
298  int current_mem = estimate_mem_usage();
299  float grow_ratio = 1;
300  if (current_mem < _params.mem_limit / 4)
301    grow_ratio = 2;
302  else if (current_mem < _params.mem_limit /2 )
303    grow_ratio = 1.5;
304  else if (current_mem < _params.mem_limit * 0.8)
305    grow_ratio = 1.2;
306  if (grow_ratio < 1.2) {
307    if (lit_pool_utilization() < 0.9) {  // still has some garbage
308      compact_lit_pool();
309      return true;
310    }
311    else
312      return false;
313  }
314  // second, make room for new lit pool.
315  CLitPoolElement * old_start = _lit_pool_start;
316  CLitPoolElement * old_finish = _lit_pool_finish;
317  int old_size = _lit_pool_end_storage - _lit_pool_start;
318  int new_size = (int)(old_size * grow_ratio);
319  _lit_pool_start = (CLitPoolElement *) realloc(_lit_pool_start,
320                                                sizeof(CLitPoolElement) *
321                                                new_size);
322  _lit_pool_finish = _lit_pool_start + (old_finish - old_start);
323  _lit_pool_end_storage = _lit_pool_start + new_size;
324
325  // update all the pointers
326  int displacement = _lit_pool_start - old_start;
327  for (i = 0; i < clauses()->size(); ++i) {
328    if (clause(i).status() != DELETED_CL)
329      clause(i).first_lit() += displacement;
330  }
331  for (i = 0, sz = variables()->size(); i < sz ;  ++i) {
332    CVariable & v = variable(i);
333    for (int j = 0; j < 2 ; ++j) {
334      int k, sz1;
335      vector<CLitPoolElement *> & watched = v.watched(j);
336      for (k = 0, sz1 = watched.size(); k < sz1 ; ++k) {
337        watched[k] += displacement;
338      }
339    }
340  }
341  ++_stats.num_enlarge;
342  return true;
343}
344
345ClauseIdx CDatabase::get_free_clause_idx(void) {
346  ClauseIdx new_cl;
347  new_cl = _clauses.size();
348  _clauses.resize(new_cl + 1);
349  clause(new_cl).set_id(_stats.num_added_clauses);
350  return new_cl;
351}
352
353ClauseIdx CDatabase::add_clause(int * lits, int n_lits, int gflag) {
354  int new_cl;
355  // a. do we need to enlarge lits pool?
356  while (lit_pool_free_space() <= n_lits + 1) {
357    if (enlarge_lit_pool() == false)
358      return -1;  // mem out, can't enlarge lit pool, because
359      // ClauseIdx can't be -1, so it shows error.
360  }
361  // b. get a free cl index;
362  new_cl = get_free_clause_idx();
363  // c. add the clause lits to lits pool
364  CClause & cl = clause(new_cl);
365  cl.init(lit_pool_end(), n_lits, gflag);
366  lit_pool_incr_size(n_lits + 1);
367  if (n_lits == 2) {
368    ++variable(lits[0]>>1).two_lits_count(lits[0] & 0x1);
369    ++variable(lits[1]>>1).two_lits_count(lits[1] & 0x1);
370  }
371  for (int i = 0; i < n_lits; ++i) {
372    int var_idx = lits[i] >> 1;
373    assert((unsigned)var_idx < variables()->size());
374    int var_sign = lits[i] & 0x1;
375    cl.literal(i).set(var_idx, var_sign);
376    ++variable(var_idx).lits_count(var_sign);
377#ifdef KEEP_LIT_CLAUSES
378    variable(var_idx).lit_clause(var_sign).push_back(new_cl);
379#endif
380  }
381  // the element after the last one is the spacing element
382  cl.literal(n_lits).set_clause_index(new_cl);
383  // d. set the watched pointers
384  if (cl.num_lits() > 1) {
385    // add the watched literal. note: watched literal must be the last free var
386    int max_idx = -1, max_dl = -1;
387    int i, sz = cl.num_lits();
388    // set the first watched literal
389    for (i = 0; i < sz; ++i) {
390      int v_idx = cl.literal(i).var_index();
391      int v_sign = cl.literal(i).var_sign();
392      CVariable & v = variable(v_idx);
393      if (literal_value(cl.literal(i)) != 0) {
394        v.watched(v_sign).push_back(&cl.literal(i));
395        cl.literal(i).set_watch(1);
396        break;
397      } else {
398        if (v.dlevel() > max_dl) {
399          max_dl = v.dlevel();
400          max_idx = i;
401        }
402      }
403    }
404    if (i >= sz) {  // no unassigned literal. so watch literal with max dlevel
405      int v_idx = cl.literal(max_idx).var_index();
406      int v_sign = cl.literal(max_idx).var_sign();
407      variable(v_idx).watched(v_sign).push_back(&cl.literal(max_idx));
408      cl.literal(max_idx).set_watch(1);
409    }
410
411    // set the second watched literal
412    max_idx = -1;
413    max_dl = -1;
414    for (i = sz-1; i >= 0; --i) {
415      if (cl.literal(i).is_watched())
416        continue;  // need to watch two different literals
417      int v_idx = cl.literal(i).var_index();
418      int v_sign = cl.literal(i).var_sign();
419      CVariable & v = variable(v_idx);
420      if (literal_value(cl.literal(i)) != 0) {
421        v.watched(v_sign).push_back(&cl.literal(i));
422        cl.literal(i).set_watch(-1);
423        break;
424      } else {
425        if (v.dlevel() > max_dl) {
426          max_dl = v.dlevel();
427          max_idx = i;
428        }
429      }
430    }
431    if (i < 0) {
432      int v_idx = cl.literal(max_idx).var_index();
433      int v_sign = cl.literal(max_idx).var_sign();
434      variable(v_idx).watched(v_sign).push_back(&cl.literal(max_idx));
435      cl.literal(max_idx).set_watch(-1);
436    }
437  }
438  // update some statistics
439  ++_stats.num_added_clauses;
440  _stats.num_added_literals += n_lits;
441  return new_cl;
442}
443
444void CDatabase::output_lit_pool_stats(void) {
445  cout << "Lit_Pool Used " << lit_pool_size() << " Free "
446       << lit_pool_free_space()
447       << " Total " << lit_pool_size() + lit_pool_free_space()
448       << " Num. Cl " << num_clauses() << " Num. Lit " << num_literals()
449       << " Efficiency " <<  lit_pool_utilization() << endl;
450}
451
452void CDatabase::detail_dump_cl(ClauseIdx cl_idx, ostream & os) {
453  os << "CL : " << cl_idx;
454  CClause & cl = clause(cl_idx);
455  if (cl.status() == DELETED_CL)
456    os << "\t\t\t======removed=====";
457  char value;
458  for (unsigned i = 0; i < cl.num_lits(); ++i) {
459    if (literal_value(cl.literal(i)) == 0)
460      value = '0';
461    else if (literal_value(cl.literal(i)) == 1)
462      value = '1';
463    else
464      value = 'X';
465    os << cl.literal(i) << "(" << value << "@"
466       << variable(cl.literal(i).var_index()).dlevel()<< ")  ";
467  }
468  os << endl;
469}
470
471void CDatabase::dump(ostream & os) {
472  unsigned i;
473  os << "Dump Database: " << endl;
474  for (i = 0; i < _clauses.size(); ++i)
475    detail_dump_cl(i);
476  for (i = 1; i < _variables.size(); ++i)
477    os << "VID " << i << ":\t" << variable(i);
478}
Note: See TracBrowser for help on using the repository browser.