Program Listing for File component_cache.h

Return to documentation for file (src/component_cache.h)

#ifndef COMPONENT_CACHE_H_
#define COMPONENT_CACHE_H_

#include <gmpxx.h>

#include <vector>
#include <sstream>

#include "component_types/cacheable_component.h"
#include "statistics.h"
#include "component_types/component.h"
#include "stack.h"
#include "solver_config.h"
#include "cached_assignment.h"

class ComponentCache {
 public:
  ComponentCache(DataAndStatistics &statistics, SolverConfiguration &config);

  ~ComponentCache() {
    // debug_dump_data();
    for (auto &pentry : entry_base_) {
//      if (pentry != nullptr)
//        delete pentry;
      delete pentry;  // Do NOT need the check as deleting nullptr has no effect
    }
  }

  void init(Component &super_comp, bool quiet = false);

  // compute the size in bytes of the component cache from scratch
  // the value is stored in bytes_memory_usage_
  uint64_t compute_byte_size_infrastructure();
  const CacheableComponent &entry_const(const CacheEntryID id) const {
    assert(entry_base_.size() > id);  // Verify the ID is value for the size.
    assert(entry_base_[id] != nullptr);
    return *entry_base_[id];
  }
  CacheableComponent &entry(const CacheEntryID id) {
    return const_cast<CacheableComponent&>(entry_const(id));
  }
//  /**
//   * Uses a cached component's CacheEntryID to extract the components
//   * cached information.
//   *
//   * @param comp Component to be extracted from the cache.
//   * @return Cache entry for the specified component.
//   */
//  CacheableComponent &entry(const Component& comp) {
//    return entry(comp.id());
//  }
  bool hasEntry(CacheEntryID id) const {
    assert(entry_base_.size() > id);
    return static_cast<bool>(entry_base_[id]);
  }
  inline void removeFromHashTable(CacheEntryID id);

  // we delete the Component with ID id
  // and all its descendants from the cache
  inline void cleanPollutionsInvolving(CacheEntryID id);

  // creates a CCacheEntry in the entry base
  // which contains a packed copy of comp
  // returns the id of the entry created
  // stores in the entry the position of
  // comp which is a part of the component stack
  inline CacheEntryID storeAsEntry(CacheableComponent &ccomp,
                                   CacheEntryID super_comp_id);
  bool manageNewComponent(StackLevel &top, CacheableComponent &packed_comp,
                          Component * unpacked_comp, CachedAssignment &cached_assn,
                          CacheEntryID &cache_entry_id) {
    statistics_.num_cache_look_ups_++;
    unsigned table_ofs =  packed_comp.hashkey() & table_size_mask_;

    CacheEntryID act_id = table_[table_ofs];
    while (act_id) {
      if (entry(act_id).equals(packed_comp)) {
        if (config_.verbose) {
          std::stringstream ss;
          ss << "\tCache hit for component #" << top.super_component() << " with model count "
             << entry(act_id).model_count() << " for cache ID #" << act_id;
          PrintInColor(ss, COLOR_YELLOW);
        }
//        if (config_.perform_random_sampling_ && config_.perform_sample_caching()) {
        if (config_.perform_sample_caching()) {
          // ToDo Add support for multiple samples in cache.
          assert(config_.num_samples_to_cache_ == 1);
          VariableIndex num_vars = unpacked_comp->num_variables();
          VariableIndex bit_shift = CACHED_VARIABLE_LEN * num_vars;
          mpz_class actual_model_count = entry(act_id).model_count() >> bit_shift;
          top.includeSolution(actual_model_count);
          cached_assn.ProcessComponent(unpacked_comp, entry(act_id).model_count());
        } else {
          top.includeSolution(entry(act_id).model_count());
        }
        cache_entry_id = act_id;  // Store the cache ID
        statistics_.incorporate_cache_hit(packed_comp);
        return true;
      }
      act_id = entry(act_id).next_bucket_element();
    }
    return false;
  }


  // unchecked erase of an entry from entry_base_
  void eraseEntry(CacheEntryID id) {
    statistics_.incorporate_cache_erase(*entry_base_[id]);
    delete entry_base_[id];
    entry_base_[id] = nullptr;
    free_entry_base_slots_.push_back(id);
  }

  // store the number in model_count as the model count of CacheEntryID id
  inline void storeValueOf(CacheEntryID id, const mpz_class &model_count);
  bool deleteEntries();

  // delete entries, keeping the descendants tree consistent
  inline void removeFromDescendantsTree(CacheEntryID id);

  // test function to ensure consistency of the descendant tree
  inline void test_descendantstree_consistency();

  void debug_dump_data();

 private:
  void considerCacheResize() {
    if (entry_base_.size() > table_.size()) {
      reHashTable(2*table_.size());
    }
  }

  void reHashTable(unsigned long size) {
    table_.clear();
    table_.resize(size, 0);
    // we assert that table size is a power of 2
    // otherwise the table_size_mask_ doesn't work
    assert((table_.size() & (table_.size() - 1)) == 0);
    table_size_mask_ = table_.size() - 1;
    std::cout << "ZH - Rehash the table.\n";
    std::cout << "ts " << table_.size() << " " << table_size_mask_ << std::endl;
    unsigned collisions = 0;
    for (unsigned id = 2; id < entry_base_.size(); id++) {
      if (entry_base_[id] != nullptr) {
        entry_base_[id]->set_next_bucket_element(0);
        if (entry_base_[id]->modelCountFound()) {
          unsigned table_ofs = tableEntry(id);
          collisions += (table_[table_ofs] > 0 ? 1 : 0);
          entry_base_[id]->set_next_bucket_element(table_[table_ofs]);
          table_[table_ofs] = id;
        }
      }
    }
    std::cout << "ZH - Number of collisions.\n" << "coll " << collisions << std::endl;
  }

  unsigned tableEntry(CacheEntryID id) {
    return entry(id).hashkey() & table_size_mask_;
  }

  void add_descendant(CacheEntryID compid, CacheEntryID descendantid) {
    assert(descendantid != entry_const(compid).first_descendant());
    entry(descendantid).set_next_sibling(entry_const(compid).first_descendant());
    entry(compid).set_first_descendant(descendantid);
  }

  void remove_firstdescendantOf(CacheEntryID compid) {
    CacheEntryID desc = entry(compid).first_descendant();
    if (desc != 0)
      entry(compid).set_first_descendant(entry(desc).next_sibling());
  }

  std::vector<CacheableComponent *> entry_base_;
  std::vector<CacheEntryID> free_entry_base_slots_;

  // the actual hash table
  // by means of which the cache is accessed
  std::vector<CacheEntryID> table_;

  unsigned table_size_mask_ = INT_MAX;

  DataAndStatistics &statistics_;

  unsigned long my_time_ = 0;

  SolverConfiguration &config_;
};


#include "component_cache.inc"


#endif /* COMPONENT_CACHE_H_ */