Program Listing for File instance.cpp

Return to documentation for file (src/instance.cpp)

#include <sys/stat.h>
#include <algorithm>
#include <fstream>
#include <string>
#include <vector>

#include "instance.h"
#include "model_sampler.h"

void Instance::cleanClause(ClauseOfs cl_ofs) {
  bool satisfied = false;
  for (auto it = beginOf(cl_ofs); *it != SENTINEL_LIT; it++)
    if (isSatisfied(*it)) {
      satisfied = true;
      break;
    }
  // mark the clause as empty if satisfied
  if (satisfied) {
    *beginOf(cl_ofs) = SENTINEL_LIT;
    return;
  }
  auto jt = beginOf(cl_ofs);
  auto it = beginOf(cl_ofs);
  // from now, all inactive literals are resolved
  for (; *it != SENTINEL_LIT; it++, jt++) {
    while (*jt != SENTINEL_LIT && !isActive(*jt))
      jt++;
    *it = *jt;
    if (*jt == SENTINEL_LIT)
      break;
  }
  unsigned length = it - beginOf(cl_ofs);
  // if it has become a unit clause, it should have already been asserted
  if (length == 1) {
    *beginOf(cl_ofs) = SENTINEL_LIT;
    // if it has become binary, transform it to binary and delete it
  } else if (length == 2) {
    addBinaryClause(*beginOf(cl_ofs), *(beginOf(cl_ofs) + 1));
    *beginOf(cl_ofs) = SENTINEL_LIT;
  }
}

void Instance::compactClauses() {
  std::vector<ClauseOfs> clause_ofs;
  clause_ofs.reserve(statistics_.num_long_clauses_);

  // clear watch links and occurrence lists
  for (auto it_lit = literal_pool_.begin(); it_lit != literal_pool_.end();
      it_lit++) {
    if (*it_lit == SENTINEL_LIT) {
      if (it_lit + 1 == literal_pool_.end())
        break;
      it_lit += ClauseHeader::overheadInLits();
      clause_ofs.push_back(1 + it_lit - literal_pool_.begin());
    }
  }

  for (auto ofs : clause_ofs)
    cleanClause(ofs);

  for (auto &l : literals_)
    l.resetWatchList();

  occurrence_lists_.clear();
  occurrence_lists_.resize(variables_.size());

  std::vector<LiteralID> tmp_pool = literal_pool_;
  literal_pool_.clear();
  literal_pool_.push_back(SENTINEL_LIT);
  ClauseOfs new_ofs;
  unsigned num_clauses = 0;
  for (auto ofs : clause_ofs) {
    auto it = (tmp_pool.begin() + ofs);
    if (*it != SENTINEL_LIT) {
      for (unsigned i = 0; i < ClauseHeader::overheadInLits(); i++)
        literal_pool_.emplace_back(0);
      new_ofs = literal_pool_.size();
      literal(*it).addWatchLinkTo(new_ofs);
      literal(*(it + 1)).addWatchLinkTo(new_ofs);
      num_clauses++;
      for (; *it != SENTINEL_LIT; it++) {
        literal_pool_.push_back(*it);
        occurrence_lists_[*it].push_back(new_ofs);
      }
      literal_pool_.push_back(SENTINEL_LIT);
    }
  }

  std::vector<LiteralID> tmp_bin;
  unsigned bin_links = 0;
  for (auto &l : literals_) {
    tmp_bin.clear();
    for (auto it = l.binary_links_.begin(); *it != SENTINEL_LIT; it++)
      if (isActive(*it))
        tmp_bin.push_back(*it);
    bin_links += tmp_bin.size();
    tmp_bin.push_back(SENTINEL_LIT);
    l.binary_links_ = tmp_bin;
  }
  statistics_.num_long_clauses_ = num_clauses;
  statistics_.num_binary_clauses_ = bin_links >> 1;
}

void Instance::compactVariables() {
  std::vector<unsigned> var_map(variables_.size(), 0);
  unsigned last_ofs = 0;
  unsigned num_isolated = 0;  // Emancipated/freed variables no longer in any clause
  LiteralIndexedVector<std::vector<LiteralID> > _tmp_bin_links(1);
  LiteralIndexedVector<TriValue> _tmp_values = literal_values_;

  for (auto l : literals_)
    _tmp_bin_links.push_back(l.binary_links_);

  assert(_tmp_bin_links.size() == literals_.size());
  for (unsigned v = 1; v < variables_.size(); v++)
    if (isActive(v)) {
      if (isolated(v)) {
        std::cout << "Variable " << v << " is isolated." << std::endl;
        num_isolated++;
        continue;
      }
      last_ofs++;
      var_map[v] = last_ofs;
    }

  variables_.clear();
  variables_.resize(last_ofs + 1);
  occurrence_lists_.clear();
  occurrence_lists_.resize(variables_.size());
  literals_.clear();
  literals_.resize(variables_.size());
  literal_values_.clear();
  literal_values_.resize(variables_.size(), X_TRI);

  unsigned bin_links = 0;
  LiteralID newlit;
  for (auto l = LiteralID(0, false); l != _tmp_bin_links.end_lit(); l.inc()) {
    if (var_map[l.var()] != 0) {
      newlit = LiteralID(var_map[l.var()], l.sign());
      for (auto it = _tmp_bin_links[l].begin(); *it != SENTINEL_LIT; it++) {
        assert(var_map[it->var()] != 0);
        literals_[newlit].addBinLinkTo(
            LiteralID(var_map[it->var()], it->sign()));
      }
      bin_links += literals_[newlit].binary_links_.size() - 1;
    }
  }

  std::vector<ClauseOfs> clause_ofs;
  clause_ofs.reserve(statistics_.num_long_clauses_);
  // clear watch links and occurrence lists
  for (auto it_lit = literal_pool_.begin(); it_lit != literal_pool_.end();
      it_lit++) {
    if (*it_lit == SENTINEL_LIT) {
      if (it_lit + 1 == literal_pool_.end())
        break;
      it_lit += ClauseHeader::overheadInLits();
      clause_ofs.push_back(1 + it_lit - literal_pool_.begin());
    }
  }

  for (auto ofs : clause_ofs) {
    literal(LiteralID(var_map[beginOf(ofs)->var()], beginOf(ofs)->sign())).addWatchLinkTo(
        ofs);
    literal(LiteralID(var_map[(beginOf(ofs) + 1)->var()],
            (beginOf(ofs) + 1)->sign())).addWatchLinkTo(ofs);
    for (auto it_lit = beginOf(ofs); *it_lit != SENTINEL_LIT; it_lit++) {
      *it_lit = LiteralID(var_map[it_lit->var()], it_lit->sign());
      occurrence_lists_[*it_lit].push_back(ofs);
    }
  }

  literal_values_.clear();
  literal_values_.resize(variables_.size(), X_TRI);
  unit_clauses_.clear();

  statistics_.num_variables_ = variables_.size() - 1 + num_isolated;

  statistics_.num_used_variables_ = num_variables();
  statistics_.num_free_variables_ = num_isolated;
}

void Instance::compactConflictLiteralPool() {
  auto write_pos = conflict_clauses_begin();
  std::vector<ClauseOfs> tmp_conflict_clauses = conflict_clauses_;
  conflict_clauses_.clear();
  for (auto clause_ofs : tmp_conflict_clauses) {
    auto read_pos = beginOf(clause_ofs) - ClauseHeader::overheadInLits();
    for (unsigned i = 0; i < ClauseHeader::overheadInLits(); i++)
      *(write_pos++) = *(read_pos++);
    ClauseOfs new_ofs =  write_pos - literal_pool_.begin();
    conflict_clauses_.push_back(new_ofs);
    // first substitute antecedent if clause_ofs implied something
    if (isAntecedentOf(clause_ofs, *beginOf(clause_ofs)))
      var(*beginOf(clause_ofs)).ante = Antecedent(new_ofs);

    // now redo the watches
    literal(*beginOf(clause_ofs)).replaceWatchLinkTo(clause_ofs, new_ofs);
    literal(*(beginOf(clause_ofs)+1)).replaceWatchLinkTo(clause_ofs, new_ofs);
    // next, copy clause data
    assert(read_pos == beginOf(clause_ofs));
    while (*read_pos != SENTINEL_LIT)
      *(write_pos++) = *(read_pos++);
    *(write_pos++) = SENTINEL_LIT;
  }
  literal_pool_.erase(write_pos, literal_pool_.end());
}


//bool Instance::deleteConflictClauses() {
//  statistics_.times_conflict_clauses_cleaned_++;
//  std::vector<ClauseOfs> tmp_conflict_clauses = conflict_clauses_;
//  conflict_clauses_.clear();
//  std::vector<double> tmp_ratios;
//  double score, lifetime;
//  for (auto clause_ofs: tmp_conflict_clauses) {
//    score = getHeaderOf(clause_ofs).score();
//    lifetime = statistics_.num_conflicts_ - getHeaderOf(clause_ofs).creation_time();
//    tmp_ratios.push_back(score/lifetime/(getHeaderOf(clause_ofs).length()));
//  }
//  std::vector<double> tmp_ratiosB = tmp_ratios;
//
//  sort(tmp_ratiosB.begin(), tmp_ratiosB.end());
//
//  double cutoff = tmp_ratiosB[tmp_ratiosB.size()/2];
//
//  for (unsigned i = 0; i < tmp_conflict_clauses.size(); i++) {
//    if (tmp_ratios[i] < cutoff) {
//      if (!markClauseDeleted(tmp_conflict_clauses[i]))
//        conflict_clauses_.push_back(tmp_conflict_clauses[i]);
//    } else
//      conflict_clauses_.push_back(tmp_conflict_clauses[i]);
//  }
//  return true;
//}

bool Instance::deleteConflictClauses(bool delete_all) {
  statistics_.times_conflict_clauses_cleaned_++;
  std::vector<ClauseOfs> tmp_conflict_clauses = conflict_clauses_;
  conflict_clauses_.clear();
  std::vector<double> tmp_ratios;
  for (auto clause_ofs : tmp_conflict_clauses) {
    double score = getHeaderOf(clause_ofs).score();
//    lifetime = statistics_.num_conflicts_ - getHeaderOf(clause_ofs).creation_time();
//    tmp_ratios.push_back(score/lifetime);
    tmp_ratios.push_back(score);
  }
  std::vector<double> tmp_ratiosB = tmp_ratios;

  sort(tmp_ratiosB.begin(), tmp_ratiosB.end());

  double cutoff = -1;
  if (!tmp_ratiosB.empty())
    cutoff = tmp_ratiosB[tmp_ratiosB.size()/2];

  for (unsigned i = 0; i < tmp_conflict_clauses.size(); i++) {
    if (delete_all) {
      markClauseDeleted(tmp_conflict_clauses[i]);
      continue;
    }
    if (tmp_ratios[i] < cutoff) {
      if (!markClauseDeleted(tmp_conflict_clauses[i]))
        conflict_clauses_.push_back(tmp_conflict_clauses[i]);
    } else {
      conflict_clauses_.push_back(tmp_conflict_clauses[i]);
    }
  }
  return true;
}


bool Instance::markClauseDeleted(ClauseOfs cl_ofs) {
  // only first literal may possibly have cl_ofs as antecedent
  if (isAntecedentOf(cl_ofs, *beginOf(cl_ofs)))
    return false;

  literal(*beginOf(cl_ofs)).removeWatchLinkTo(cl_ofs);
  literal(*(beginOf(cl_ofs)+1)).removeWatchLinkTo(cl_ofs);
  return true;
}


bool Instance::createfromFile(const std::string &file_name) {
  if (!file_name.empty())
    statistics_.input_file_ = file_name;
  unsigned max_ignore = 1000000;  // Max number of characters on line to ignore.

  // Initialize the literal pool
  literal_pool_.clear();
  literal_pool_.push_back(SENTINEL_LIT);

  // Builds the list
  variables_.clear();
  variables_.emplace_back();  //initializing the Sentinel
  literal_values_.clear();
  unit_clauses_.clear();
  unused_vars_.clear();

  // BEGIN File input
  std::ifstream input_file(statistics_.input_file_);
  if (!input_file)
    ExitWithError("Cannot open file: " + statistics_.input_file_, EX_IOERR);

  char c;
  while ((input_file >> c) && c != 'p')
    ParseCnfCommentForSupport(input_file);
  std::string idstring;
  long nVars = -1, nCls = -1;
  if (!((input_file >> idstring) && idstring == "cnf" && (input_file >> nVars)
      && (input_file >> nCls)))
    ExitWithError("Invalid CNF file", EX_PROTOCOL);
  else if (nVars <= 0)
    ExitWithError("Invalid variable count.  At least one variable is required.", EX_PROTOCOL);
  else if (nCls < 0)
    ExitWithError("Invalid clause count.  A negative clause count is invalid.", EX_PROTOCOL);

  variables_.resize(nVars + FIRST_VAR);
  literal_values_.resize(nVars + FIRST_VAR, X_TRI);
  struct stat file_status;
  stat(statistics_.input_file_ .c_str(), &file_status);
  literal_pool_.reserve(file_status.st_size);
  conflict_clauses_.reserve(2 * nCls);
  occurrence_lists_.clear();
  occurrence_lists_.resize(nVars + FIRST_VAR);

  std::vector<LiteralID> literals;
  literals_.clear();
  literals_.resize(nVars + FIRST_VAR);
  std::vector<bool> var_used(nVars + FIRST_VAR, false);

  // Analyze each clause and add literals/variables as appropriate.
  unsigned clauses_added = 0;
  while ((input_file >> c) && clauses_added < nCls) {
    input_file.unget();  // extracted a nonspace character to determine if
                         // we have a clause, so put it back

    if ((c == '-') || isdigit(c)) {
      literals.clear();  // Empty the literal set in the clause
      bool skip_clause = false;
      long lit;
      while ((input_file >> lit) && lit != 0) {
        var_used[abs(lit)] = true;  // Mark the variable as used.
        bool duplicate_literal = false;
        for (auto i : literals) {
          // Checks if same literal already in the clause
          if (i.toInt() == lit) {
            duplicate_literal = true;
            break;
          }
          // Checks if a clause has a literal and its complement in the same clause.
          if (i.toInt() == -lit) {
            skip_clause = true;
            break;
          }
        }
        if (!duplicate_literal)
          literals.emplace_back(lit);
      }
      if (!skip_clause) {
        assert(!literals.empty());  // May report a fail in an UNSAT file.
        clauses_added++;
        statistics_.incorporateClauseData(literals);
        long cl_ofs = addClause(literals);
        if (cl_ofs == CLAUSE_ADDING_ERROR)
          return false;
        // If the clause is non-binary and non-unit, then
        // Add to the occurrence list for the literal.
        if (literals.size() >= 3)
          for (auto l : literals)
            occurrence_lists_[l].push_back(cl_ofs);
      }
    } else if (c == 'c') {
      input_file >> c;
      ParseCnfCommentForSupport(input_file);
      continue;
    }
    input_file.ignore(max_ignore, '\n');
  }
  // END NEW
  input_file.close();
  //  /// END FILE input
  statistics_.num_variables_ = statistics_.num_original_variables_ = (VariableIndex)nVars;
  statistics_.num_used_variables_ = num_variables();
  statistics_.num_indep_support_variables_ = independent_support.size();
//  statistics_.num_free_variables_ = nVars - num_variables();  // This line seems not to work right
  if (!independent_support.empty()) {
    has_independent_support_ = true;
    std::sort(independent_support.begin(), independent_support.end());
  }

  // Get a list of unused variables.
  statistics_.num_free_variables_ = 0;
  for (VariableIndex i = 1; i < var_used.size(); i++) {
    if (!var_used[i]) {
      statistics_.num_free_variables_++;
//      unused_vars_.push_back(i);  // Done instead at the top of var stack
    }
  }
  statistics_.num_original_clauses_ = static_cast<ClauseIndex>(nCls);

  statistics_.num_original_binary_clauses_ = statistics_.num_binary_clauses_;
  statistics_.num_original_unit_clauses_ = statistics_.num_unit_clauses_ = unit_clauses_.size();

  original_lit_pool_size_ = literal_pool_.size();
  return true;
}


void Instance::ParseCnfCommentForSupport(std::ifstream &input_file) {
  std::string ind_str, line;
  std::istringstream iss;
  // Check if the comment line contains an independent support
  std::getline(input_file, line);
  iss.str(line);
  iss.clear();
  iss >> ind_str;
  if (ind_str != "ind")
    return;
  VariableIndex support_var;
  while ((iss >> support_var) && support_var != 0)
    independent_support.emplace_back(support_var);
}