// policy: callback whenever i~k but not j~k void BinaryRelation::unsafe_merge (Ob i) { Ob j = carrier().find(i); POMAGMA_ASSERT4(j < i, "BinaryRelation tried to merge item with self"); DenseSet diff(item_dim()); DenseSet rep(item_dim(), nullptr); DenseSet dep(item_dim(), nullptr); // merge rows (i, _) into (j, _) dep.init(m_lines.Lx(i)); _remove_Rx(i, dep); rep.init(m_lines.Lx(j)); if (rep.merge(dep, diff)) { for (auto k = diff.iter(); k.ok(); k.next()) { _insert_Rx(j, *k); } } // merge cols (_, i) into (_, j) dep.init(m_lines.Rx(i)); _remove_Lx(dep, i); rep.init(m_lines.Rx(j)); if (rep.merge(dep, diff)) { for (auto k = diff.iter(); k.ok(); k.next()) { _insert_Lx(*k, j); } } }
void Carrier::unsafe_remove (const Ob ob) { UniqueLock lock(m_mutex); POMAGMA_ASSERT2(m_support.contains(ob), "double removal: " << ob); Ob rep = ob; while (not m_reps[rep].compare_exchange_strong(rep, rep)) {} POMAGMA_ASSERT2(rep, "double removal: " << ob); if (rep == ob) { for (Ob other = ob + 1, end = item_dim(); other <= end; ++other) { POMAGMA_ASSERT2(m_reps[other].load() != ob, "removed rep " << ob << " before dep " << other); } --m_rep_count; } else { for (Ob other = ob + 1, end = item_dim(); other <= end; ++other) { Ob expected = ob; m_reps[other].compare_exchange_strong(expected, rep); } } m_support.remove(ob); m_reps[ob].store(0); --m_item_count; POMAGMA_DEBUG1(m_item_count.load() << " obs after remove()"); }
Ob Carrier::try_insert () const { SharedLock lock(m_mutex); while (item_count() < item_dim()) { for (Ob ob = 1, end = item_dim(); ob <= end; ++ob) { Ob zero = 0; // This could be optimized using m_support iteration. // See DenseSet::try_insert for example low-level code. bool inserted = m_reps[ob].compare_exchange_strong( zero, ob, std::memory_order_acq_rel, std::memory_order_acquire); if (unlikely(inserted)) { m_support.insert(ob, std::memory_order_release); ++m_item_count; ++m_rep_count; if (m_insert_callback) { m_insert_callback(ob); } // The following triggers a weird gcc bug or something // error: invalid memory model for ‘__atomic_load //POMAGMA_DEBUG1(m_item_count.load() << " obs after insert()"); return ob; } } } return 0; }
void SymmetricFunction::validate() const { POMAGMA_INFO("Validating SymmetricFunction"); m_lines.validate(); POMAGMA_DEBUG("validating line-value consistency"); for (size_t i = 1; i <= item_dim(); ++i) for (size_t j = i; j <= item_dim(); ++j) { auto val_iter = m_values.find(assert_sorted_pair(i, j)); if (not(support().contains(i) and support().contains(j))) { POMAGMA_ASSERT(val_iter == m_values.end(), "found unsupported lhs, rhs: " << i << ',' << j); } else if (val_iter != m_values.end()) { POMAGMA_ASSERT(defined(i, j), "found undefined value: " << i << ',' << j); Ob val = val_iter->second; POMAGMA_ASSERT(val, "found zero value: " << i << ',' << j); POMAGMA_ASSERT(support().contains(val), "found unsupported value: " << i << ',' << j); } else { POMAGMA_ASSERT(not defined(i, j), "found defined null value: " << i << ',' << j); } } }
inline oid_t dense_bin_fun::value (oid_t i, oid_t j) const { POMAGMA_ASSERT_RANGE_(5, i, item_dim()); POMAGMA_ASSERT_RANGE_(5, j, item_dim()); const oid_t * block = _block(i / ITEMS_PER_BLOCK, j / ITEMS_PER_BLOCK); return _block2value(block, i & BLOCK_POS_MASK, j & BLOCK_POS_MASK); }
void BinaryRelation::insert(Ob i, const DenseSet& js) { DenseSet diff(item_dim()); DenseSet dest(item_dim(), m_lines.Lx(i)); if (dest.ensure(js, diff)) { for (auto k = diff.iter(); k.ok(); k.next()) { _insert_Rx(i, *k); } } }
void BinaryRelation::insert(const DenseSet& is, Ob j) { DenseSet diff(item_dim()); DenseSet dest(item_dim(), m_lines.Rx(j)); if (dest.ensure(is, diff)) { for (auto k = diff.iter(); k.ok(); k.next()) { _insert_Lx(*k, j); } } }
void BinaryFunction::unsafe_merge(const Ob dep) { POMAGMA_ASSERT5(support().contains(dep), "unsupported dep: " << dep); Ob rep = carrier().find(dep); POMAGMA_ASSERT5(support().contains(rep), "unsupported rep: " << rep); POMAGMA_ASSERT4(rep != dep, "self merge: " << dep << "," << rep); // Note: in some cases, triples may move multiple times, e.g. // (dep, dep) --> (dep, rep) --> (rep, rep) // dep as rhs for (auto iter = iter_rhs(dep); iter.ok(); iter.next()) { Ob lhs = *iter; auto dep_iter = m_values.find(std::make_pair(lhs, dep)); Ob dep_val = dep_iter->second; m_values.erase(dep_iter); m_lines.Lx(lhs, dep).zero(); Ob& rep_val = m_values[std::make_pair(lhs, rep)]; if (carrier().set_or_merge(rep_val, dep_val)) { m_lines.Lx(lhs, rep).one(); } } { DenseSet dep_set(item_dim(), m_lines.Rx(dep)); DenseSet rep_set(item_dim(), m_lines.Rx(rep)); rep_set.merge(dep_set); } // dep as lhs rep = carrier().find(rep); for (auto iter = iter_lhs(dep); iter.ok(); iter.next()) { Ob rhs = *iter; auto dep_iter = m_values.find(std::make_pair(dep, rhs)); Ob dep_val = dep_iter->second; m_values.erase(dep_iter); m_lines.Rx(dep, rhs).zero(); Ob& rep_val = m_values[std::make_pair(rep, rhs)]; if (carrier().set_or_merge(rep_val, dep_val)) { m_lines.Rx(rep, rhs).one(); } } { DenseSet dep_set(item_dim(), m_lines.Lx(dep)); DenseSet rep_set(item_dim(), m_lines.Lx(rep)); rep_set.merge(dep_set); } // values must be updated in batch by update_values }
void Carrier::validate () const { UniqueLock lock(m_mutex); POMAGMA_INFO("Validating Carrier"); m_support.validate(); size_t actual_item_count = 0; size_t actual_rep_count = 0; for (Ob i = 1; i <= item_dim(); ++i) { Ob rep = m_reps[i].load(); if (contains(i)) { POMAGMA_ASSERT(rep, "supported object has no rep: " << i); POMAGMA_ASSERT(rep <= i, "rep out of order: " << rep << "," << i); ++actual_item_count; if (rep == i) { ++actual_rep_count; } } else { POMAGMA_ASSERT(rep == 0, "unsupported object has rep: " << i); } } POMAGMA_ASSERT_EQ(item_count(), actual_item_count); POMAGMA_ASSERT_EQ(rep_count(), actual_rep_count); }
void Carrier::clear () { memory_barrier(); m_support.zero(); zero_blocks(m_reps, 1 + item_dim()); m_rep_count = 0; m_item_count = 0; memory_barrier(); }
void BinaryRelation::validate_disjoint(const BinaryRelation& other) const { POMAGMA_INFO("Validating disjoint pair of BinaryRelations"); // validate supports agree POMAGMA_ASSERT_EQ(support().item_dim(), other.support().item_dim()); POMAGMA_ASSERT_EQ(support().count_items(), other.support().count_items()); POMAGMA_ASSERT(support() == other.support(), "BinaryRelation supports differ"); // validate disjointness DenseSet this_set(item_dim(), nullptr); DenseSet other_set(item_dim(), nullptr); for (auto i = support().iter(); i.ok(); i.next()) { this_set.init(m_lines.Lx(*i)); other_set.init(other.m_lines.Lx(*i)); POMAGMA_ASSERT(this_set.disjoint(other_set), "BinaryRelations intersect at row " << *i); } }
inline bool Carrier::set_and_merge(std::atomic<Ob>& destin, Ob source) const { POMAGMA_ASSERT_RANGE_(5, source, item_dim()); Ob old = 0; while (not destin.compare_exchange_strong( old, source, std::memory_order_acq_rel, std::memory_order_acquire)) { source = ensure_equal(source, old); if (old == source) return false; } return old == 0; }
inline bool Carrier::set_or_merge(std::atomic<Ob>& destin, Ob source) const { POMAGMA_ASSERT_RANGE_(5, source, item_dim()); Ob old = 0; if (destin.compare_exchange_strong(old, source, std::memory_order_acq_rel, std::memory_order_acquire)) { return true; } else { ensure_equal(source, old); return false; } }
void BinaryRelation::validate () const { POMAGMA_INFO("Validating BinaryRelation"); m_lines.validate(); size_t num_pairs = 0; DenseSet Lx(round_item_dim(), nullptr); DenseSet Rx(round_item_dim(), nullptr); for (Ob i = 1; i <= item_dim(); ++i) { bool sup_i = supports(i); Lx.init(m_lines.Lx(i)); for (Ob j = 1; j <= item_dim(); ++j) { bool sup_ij = sup_i and supports(j); Rx.init(m_lines.Rx(j)); bool Lx_ij = Lx.contains(j); bool Rx_ij = Rx.contains(i); num_pairs += Rx_ij; POMAGMA_ASSERT(Lx_ij == Rx_ij, "Lx,Rx disagree at " << i << "," << j << ", Lx is " << Lx_ij << ", Rx is " << Rx_ij ); POMAGMA_ASSERT(sup_ij or not Lx_ij, "Lx unsupported at " << i << "," << j ); POMAGMA_ASSERT(sup_ij or not Rx_ij, "Rx unsupported at " << i << "," << j ); } } size_t true_size = count_pairs(); POMAGMA_ASSERT(num_pairs == true_size, "incorrect number of pairs: " << num_pairs << " should be " << true_size); }
void SymmetricFunction::unsafe_merge(const Ob dep) { POMAGMA_ASSERT5(support().contains(dep), "unsupported dep: " << dep); Ob rep = carrier().find(dep); POMAGMA_ASSERT5(support().contains(rep), "unsupported rep: " << rep); POMAGMA_ASSERT4(rep != dep, "self merge: " << dep << "," << rep); // (dep, dep) -> (rep, rep) if (defined(dep, dep)) { auto dep_iter = m_values.find(std::make_pair(dep, dep)); Ob dep_val = dep_iter->second; m_values.erase(dep_iter); m_lines.Lx(dep, dep).zero(); Ob& rep_val = m_values[std::make_pair(rep, rep)]; if (carrier().set_or_merge(rep_val, dep_val)) { m_lines.Lx(rep, rep).one(); } } // (dep, rhs) --> (rep, rhs) for rhs != dep rep = carrier().find(rep); for (auto iter = iter_lhs(dep); iter.ok(); iter.next()) { Ob rhs = *iter; auto dep_iter = m_values.find(make_sorted_pair(dep, rhs)); Ob dep_val = dep_iter->second; m_values.erase(dep_iter); m_lines.Rx(dep, rhs).zero(); Ob& rep_val = m_values[make_sorted_pair(rep, rhs)]; if (carrier().set_or_merge(rep_val, dep_val)) { m_lines.Rx(rep, rhs).one(); } } DenseSet dep_set(item_dim(), m_lines.Lx(dep)); DenseSet rep_set(item_dim(), m_lines.Lx(rep)); rep_set.merge(dep_set); // values must be updated in batch by update_values }
// for growing void base_bin_rel::move_from (const base_bin_rel & other) { POMAGMA_DEBUG("Copying base_bin_rel"); size_t min_item_dim = min(item_dim(), other.item_dim()); size_t min_word_dim = min(word_dim(), other.word_dim()); m_support.move_from(other.m_support); if (_symmetric()) { POMAGMA_ASSERT(other._symmetric(), "symmetry mismatch"); for (size_t i = 1; i <= min_item_dim; ++i) { memcpy(Lx(i), other.Lx(i), sizeof(Word) * min_word_dim); } } else { POMAGMA_ASSERT(not other._symmetric(), "symmetry mismatch"); for (size_t i = 1; i <= min_item_dim; ++i) { memcpy(Lx(i), other.Lx(i), sizeof(Word) * min_word_dim); memcpy(Rx(i), other.Rx(i), sizeof(Word) * min_word_dim); } } }
void base_bin_rel::validate() const { m_support.validate(); // TODO validate Lx, Rx agree with support // (move code over from dense_bin_rel::validate() if (_symmetric()) { // check emptiness outside of support dense_set set(item_dim(), NULL); dense_set round_set(m_round_item_dim, NULL); for (oid_t i = 0; i < m_round_item_dim; ++i) { if (1 <= i and i <= item_dim()) { set.init(Lx(i)); set.validate(); } else { round_set.init(m_Lx_lines + m_round_word_dim * i); round_set.validate(); POMAGMA_ASSERT(round_set.empty(), "unsupported Lx(" << i << ") has " << round_set.count_items() << " items"); } } // check for Lx/Rx agreement for (oid_t i = 1; i <= item_dim(); ++i) { for (oid_t j = i; j <= item_dim(); ++j) { POMAGMA_ASSERT(Lx(i, j) == Rx(i, j), "Lx, Rx disagree at " << i << ',' << j); }} } else { // check emptiness outside of support dense_set set(item_dim(), NULL); dense_set round_set(m_round_item_dim, NULL); for (oid_t i = 0; i < m_round_item_dim; ++i) { if (1 <= i and i <= item_dim()) { set.init(Lx(i)); set.validate(); set.init(Rx(i)); set.validate(); } else { round_set.init(m_Lx_lines + m_round_word_dim * i); round_set.validate(); POMAGMA_ASSERT(round_set.empty(), "unsupported Lx(" << i << ") has " << round_set.count_items() << " items"); round_set.init(m_Rx_lines + m_round_word_dim * i); round_set.validate(); POMAGMA_ASSERT(round_set.empty(), "unsupported Rx(" << i << ") has " << round_set.count_items() << " items"); } } // check for Lx/Rx agreement for (oid_t i = 1; i <= item_dim(); ++i) { for (oid_t j = 1; j <= item_dim(); ++j) { POMAGMA_ASSERT(Lx(i, j) == Rx(i, j), "Lx, Rx disagree at " << i << ',' << j); }} } }
DenseSet Rx_set (Ob rhs) const { return DenseSet(item_dim(), const_cast<std::atomic<Word> *>(Rx(rhs))); }
// set wrappers DenseSet Lx_set (Ob lhs) const { return DenseSet(item_dim(), const_cast<std::atomic<Word> *>(Lx(lhs))); }
bool_ref Rx (Ob lhs, Ob rhs) { POMAGMA_ASSERT_RANGE_(5, lhs, item_dim()); return bool_ref::index(Rx(rhs), lhs); }
bool_ref Lx (Ob lhs, Ob rhs) { POMAGMA_ASSERT_RANGE_(5, rhs, item_dim()); return bool_ref::index(Lx(lhs), rhs); }
std::atomic<Word> * Rx (Ob rhs) { POMAGMA_ASSERT_RANGE_(5, rhs, item_dim()); return m_Rx_lines + (rhs * m_round_word_dim); }
std::atomic<Word> * Lx (Ob lhs) { POMAGMA_ASSERT_RANGE_(5, lhs, item_dim()); return m_Lx_lines + (lhs * m_round_word_dim); }
inline DenseSet::Iterator SymmetricFunction::iter_lhs(Ob lhs) const { POMAGMA_ASSERT5(support().contains(lhs), "unsupported lhs: " << lhs); return DenseSet::Iterator(item_dim(), m_lines.Lx(lhs)); }
Carrier::~Carrier () { destroy_blocks(m_reps, 1 + item_dim()); free_blocks(m_reps); }
inline DenseSet::Iterator BinaryRelation::iter_rhs(Ob rhs) const { POMAGMA_ASSERT5(support().contains(rhs), "unsupported rhs: " << rhs); return DenseSet::Iterator(item_dim(), m_lines.Rx(rhs)); }