Program Listing for File rmat_edge_generator.hpp¶
↰ Return to documentation for file (bfs/rmat_edge_generator/rmat_edge_generator.hpp
)
/*
* Copyright (c) 2013, Lawrence Livermore National Security, LLC.
* Produced at the Lawrence Livermore National Laboratory.
* Written by Roger Pearce <rpearce@llnl.gov>.
* LLNL-CODE-644630.
* All rights reserved.
*
* This file is part of HavoqGT, Version 0.1.
* For details, see https://computation.llnl.gov/casc/dcca-pub/dcca/Downloads.html
*
* Please also read this link – Our Notice and GNU Lesser General Public License.
* http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License (as published by the Free
* Software Foundation) version 2.1 dated February 1999.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the IMPLIED WARRANTY OF MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the terms and conditions of the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* OUR NOTICE AND TERMS AND CONDITIONS OF THE GNU GENERAL PUBLIC LICENSE
*
* Our Preamble Notice
*
* A. This notice is required to be provided under our contract with the
* U.S. Department of Energy (DOE). This work was produced at the Lawrence
* Livermore National Laboratory under Contract No. DE-AC52-07NA27344 with the DOE.
*
* B. Neither the United States Government nor Lawrence Livermore National
* Security, LLC nor any of their employees, makes any warranty, express or
* implied, or assumes any liability or responsibility for the accuracy,
* completeness, or usefulness of any information, apparatus, product, or process
* disclosed, or represents that its use would not infringe privately-owned rights.
*
* C. Also, reference herein to any specific commercial products, process, or
* services by trade name, trademark, manufacturer or otherwise does not
* necessarily constitute or imply its endorsement, recommendation, or favoring by
* the United States Government or Lawrence Livermore National Security, LLC. The
* views and opinions of authors expressed herein do not necessarily state or
* reflect those of the United States Government or Lawrence Livermore National
* Security, LLC, and shall not be used for advertising or product endorsement
* purposes.
*
*/
#ifndef BFS_RMAT_EDGE_GENERATOR_HPP
#define BFS_RMAT_EDGE_GENERATOR_HPP
#include <iostream>
#include <random>
#include <cassert>
#include "hash.hpp"
#include <utility>
/// RMAT edge generator, based on Boost Graph's RMAT generator
///
/// Options include scrambling vertices based on a hash funciton, and
/// symmetrizing the list. Generated edges are not sorted. May contain
/// duplicate and self edges.
class rmat_edge_generator {
public:
typedef uint64_t vertex_descriptor;
typedef std::pair<uint64_t, uint64_t> value_type;
typedef value_type edge_type;
///
/// InputIterator class for rmat_edge_generator
class input_iterator_type : public std::iterator<std::input_iterator_tag,
edge_type,
ptrdiff_t,
const edge_type *,
const edge_type &> {
public:
input_iterator_type(rmat_edge_generator *ptr_rmat, uint64_t count)
: m_ptr_rmat(ptr_rmat), m_rng(ptr_rmat->m_seed), m_dis(0.0, 1.0), m_count(count), m_make_undirected(false) {
if (m_count == 0) {
get_next();
m_count = 0; //reset to zero
}
}
const edge_type &operator*() const { return m_current; }
//const uint64_t* operator->() const { return &(operator*()); }
input_iterator_type &operator++() {
get_next();
return *this;
}
input_iterator_type operator++(int) {
input_iterator_type __tmp = *this;
get_next();
return __tmp;
}
edge_type *operator->() {
return &m_current;
}
bool is_equal(const input_iterator_type &_x) const {
return m_count == (_x.m_count);
}
/// Return true if x and y are both end or not end, or x and y are the same.
friend bool
operator==(const input_iterator_type &x, const input_iterator_type &y) { return x.is_equal(y); }
/// Return false if x and y are both end or not end, or x and y are the same.
friend bool
operator!=(const input_iterator_type &x, const input_iterator_type &y) { return !x.is_equal(y); }
private:
input_iterator_type();
void get_next() {
if (m_ptr_rmat->m_undirected && m_make_undirected) {
std::swap(m_current.first, m_current.second);
m_make_undirected = false;
} else {
m_current = m_ptr_rmat->generate_edge(m_rng, m_dis);
++m_count;
m_make_undirected = true;
}
assert(m_current.first <= m_ptr_rmat->max_vertex_id());
assert(m_current.second <= m_ptr_rmat->max_vertex_id());
}
rmat_edge_generator *m_ptr_rmat;
std::mt19937 m_rng;
std::uniform_real_distribution<> m_dis;
uint64_t m_count;
edge_type m_current;
bool m_make_undirected;
};
/// seed used to be 5489
rmat_edge_generator(uint64_t seed, uint64_t vertex_scale,
uint64_t edge_count, double a, double b, double c,
double d, bool scramble, bool undirected)
: m_seed(seed),
m_rng(seed),
m_dis(0.0, 1.0),
m_vertex_scale(vertex_scale),
m_edge_count(edge_count),
m_scramble(scramble),
m_undirected(undirected),
m_rmat_a(a),
m_rmat_b(b),
m_rmat_c(c),
m_rmat_d(d) {
// sanity_max_vertex_id();
// #ifdef DEBUG
// auto itr1 = begin();
// auto itr2 = begin();
// while (itr1 != end()) {
// assert(itr2 != end());
// assert(*itr1 == *itr2);
// assert(itr1 == itr2);
// itr1++;
// itr2++;
// }
// #endif
}
/// Returns the begin of the input iterator
input_iterator_type begin() {
return input_iterator_type(this, 0);
}
/// Returns the end of the input iterator
input_iterator_type end() {
return input_iterator_type(this, m_edge_count);
}
void sanity_max_vertex_id() {
auto itr = begin();
auto itr_end = end();
uint64_t value = 0;
while (itr != itr_end) {
value = std::max(value, (*itr).first);
value = std::max(value, (*itr).second);
}
std::cout << " value: " << value << std::endl;
assert(max_vertex_id() == value);
}
uint64_t max_vertex_id() {
return (uint64_t(1) << uint64_t(m_vertex_scale)) - 1;
}
size_t size() {
return m_edge_count;
}
protected:
/// Generates a new RMAT edge. This function was adapted from the Boost Graph Library.
edge_type generate_edge() {
return generate_edge(m_rng, m_dis);
}
edge_type generate_edge(std::mt19937& rng, std::uniform_real_distribution<> &dis) {
double rmat_a = m_rmat_a;
double rmat_b = m_rmat_b;
double rmat_c = m_rmat_c;
double rmat_d = m_rmat_d;
uint64_t u = 0, v = 0;
uint64_t step = (uint64_t(1) << m_vertex_scale) / 2;
for (unsigned int j = 0; j < m_vertex_scale; ++j) {
double p = dis(rng);
if (p < rmat_a);
else if (p >= rmat_a && p < rmat_a + rmat_b)
v += step;
else if (p >= rmat_a + rmat_b && p < rmat_a + rmat_b + rmat_c)
u += step;
else { // p > a + b + c && p < a + b + c + d
u += step;
v += step;
}
step /= 2;
// 0.2 and 0.9 are hardcoded in the reference SSCA implementation.
// The maximum change in any given value should be less than 10%
rmat_a *= 0.9 + 0.2 * dis(rng);
rmat_b *= 0.9 + 0.2 * dis(rng);
rmat_c *= 0.9 + 0.2 * dis(rng);
rmat_d *= 0.9 + 0.2 * dis(rng);
double S = rmat_a + rmat_b + rmat_c + rmat_d;
rmat_a /= S;
rmat_b /= S;
rmat_c /= S;
// d /= S;
// Ensure all values add up to 1, regardless of floating point errors
rmat_d = 1. - rmat_a - rmat_b - rmat_c;
}
if (m_scramble) {
u = rmat_edge_generator_detail::hash_nbits(u, m_vertex_scale);
v = rmat_edge_generator_detail::hash_nbits(v, m_vertex_scale);
}
return std::make_pair(u, v);
}
const uint64_t m_seed;
std::mt19937 m_rng;
std::uniform_real_distribution<> m_dis;
const uint64_t m_vertex_scale;
const uint64_t m_edge_count;
const bool m_scramble;
const bool m_undirected;
const double m_rmat_a;
const double m_rmat_b;
const double m_rmat_c;
const double m_rmat_d;
};
#endif //BFS_RMAT_EDGE_GENERATOR_HPP