// Initialize for edge generation
    rmat_iterator(RandomGenerator& gen, vertices_size_type n,
                  edges_size_type m, double a, double b, double c,
                  double d, bool permute_vertices = true)
      : gen(), n(n), a(a), b(b), c(c), d(d), edge(m),
        permute_vertices(permute_vertices),
        SCALE(int_log2(n))

    {
      this->gen.reset(new uniform_01<RandomGenerator>(gen));

      assert(boost::test_tools::check_is_close(a + b + c + d, 1., boost::test_tools::fraction_tolerance(1.e-5)));

      if (permute_vertices)
        generate_permutation_vector(gen, vertexPermutation, n);

      // TODO: Generate the entire adjacency matrix then "Clip and flip" if undirected graph

      // Generate the first edge
      vertices_size_type u, v;
      boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d);

      if (permute_vertices)
        current = std::make_pair(vertexPermutation[u],
                                 vertexPermutation[v]);
      else
        current = std::make_pair(u, v);

      --edge;
    }
    // Initialize for edge generation
    unique_rmat_iterator(RandomGenerator& gen, vertices_size_type n,
                         edges_size_type m, double a, double b, double c,
                         double d, bool permute_vertices = true,
                         EdgePredicate ep = keep_all_edges())
      : gen(), done(false)

    {
      assert(boost::test_tools::check_is_close(a + b + c + d, 1., boost::test_tools::fraction_tolerance(1.e-5)));

      this->gen.reset(new uniform_01<RandomGenerator>(gen));

      std::vector<vertices_size_type> vertexPermutation;
      if (permute_vertices)
        generate_permutation_vector(gen, vertexPermutation, n);

      int SCALE = int_log2(n);

      std::map<value_type, bool> edge_map;

      edges_size_type edges = 0;
      do {
        vertices_size_type u, v;
        boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d);

        // Lowest vertex number always comes first
        // (this means we don't have to worry about i->j and j->i being in the edge list)
        if (u > v && is_same<directed_category, undirected_tag>::value)
          std::swap(u, v);

        if (edge_map.find(std::make_pair(u, v)) == edge_map.end()) {
          edge_map[std::make_pair(u, v)] = true;

          if (permute_vertices) {
            if (ep(vertexPermutation[u], vertexPermutation[v]))
              values.push_back(std::make_pair(vertexPermutation[u], vertexPermutation[v]));
          } else {
            if (ep(u, v))
              values.push_back(std::make_pair(u, v));
          }

          edges++;
        }
      } while (edges < m);
      // NGE - Asking for more than n^2 edges will result in an infinite loop here
      //       Asking for a value too close to n^2 edges may as well

      current = values.back();
      values.pop_back();
    }
    // Initialize for edge generation
    sorted_rmat_iterator(RandomGenerator& gen, vertices_size_type n,
                         edges_size_type m, double a, double b, double c,
                         double d, bool permute_vertices = true,
                         EdgePredicate ep = keep_all_edges())
      : gen(), permute_vertices(permute_vertices),
        values(sort_pair<vertices_size_type>()), done(false)

    {
      assert(boost::test_tools::check_is_close(a + b + c + d, 1., boost::test_tools::fraction_tolerance(1.e-5)));

      this->gen.reset(new uniform_01<RandomGenerator>(gen));

      std::vector<vertices_size_type> vertexPermutation;
      if (permute_vertices)
        generate_permutation_vector(gen, vertexPermutation, n);

      // TODO: "Clip and flip" if undirected graph
      int SCALE = int_log2(n);

      for (edges_size_type i = 0; i < m; ++i) {

        vertices_size_type u, v;
        boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d);

        if (permute_vertices) {
          if (ep(vertexPermutation[u], vertexPermutation[v]))
            values.push(std::make_pair(vertexPermutation[u], vertexPermutation[v]));
        } else {
          if (ep(u, v))
            values.push(std::make_pair(u, v));
        }

      }

      current = values.top();
      values.pop();
    }
    // Initialize for edge generation
    scalable_rmat_iterator(ProcessGroup pg, Distribution distrib,
                           RandomGenerator& gen, vertices_size_type n,
                           edges_size_type m, double a, double b, double c,
                           double d, bool permute_vertices = true)
        : gen(), done(false)
    {
        BOOST_ASSERT(a + b + c + d == 1);
        int id = process_id(pg);

        this->gen.reset(new uniform_01<RandomGenerator>(gen));

        std::vector<vertices_size_type> vertexPermutation;
        if (permute_vertices)
            generate_permutation_vector(gen, vertexPermutation, n);

        int SCALE = int(floor(log(double(n))/log(2.)));
        boost::uniform_01<RandomGenerator> prob(gen);

        std::map<value_type, bool> edge_map;

        edges_size_type generated = 0, local_edges = 0;
        do {
            edges_size_type tossed = 0;
            do {
                vertices_size_type u, v;
                boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d);

                if (permute_vertices) {
                    u = vertexPermutation[u];
                    v = vertexPermutation[v];
                }

                // Lowest vertex number always comes first (this
                // means we don't have to worry about i->j and j->i
                // being in the edge list)
                if (u > v && is_same<directed_category, undirected_tag>::value)
                    std::swap(u, v);

                if (distrib(u) == id || distrib(v) == id) {
                    if (edge_map.find(std::make_pair(u, v)) == edge_map.end()) {
                        edge_map[std::make_pair(u, v)] = true;
                        local_edges++;
                    } else {
                        tossed++;

                        // special case - if both u and v are on same
                        // proc, ++ twice, since we divide by two (to
                        // cover the two process case)
                        if (distrib(u) == id && distrib(v) == id)
                            tossed++;
                    }
                }
                generated++;

            } while (generated < m);
            tossed = all_reduce(pg, tossed, boost::parallel::sum<vertices_size_type>());
            generated -= (tossed / 2);
        } while (generated < m);
        // NGE - Asking for more than n^2 edges will result in an infinite loop here
        //       Asking for a value too close to n^2 edges may as well

        values.reserve(local_edges);
        typename std::map<value_type, bool>::reverse_iterator em_end = edge_map.rend();
        for (typename std::map<value_type, bool>::reverse_iterator em_i = edge_map.rbegin();
                em_i != em_end ;
                ++em_i) {
            values.push_back(em_i->first);
        }

        current = values.back();
        values.pop_back();
    }