Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ sequential_vertex_coloring(

| IN
| `OrderPA order`
| A mapping from integers in the range _[0, num_vertices(g))_
to the vertices of the graph.
| A mapping from integers in the range _[0, n)_ to the vertices of the graph,
where _n_ is the number of vertices listed by `vertices(g)`. This is
`num_vertices(g)` for most graph types, but can be smaller for
xref:adaptors/filtered_graph.adoc[`filtered_graph`].

| OUT
| `ColorMap color`
Expand Down
10 changes: 6 additions & 4 deletions include/boost/graph/sequential_vertex_coloring.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
// Copyright 2004 The Trustees of Indiana University
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
// Copyright (c) 2026 Arnaud Becheler
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
Expand All @@ -15,10 +16,7 @@
#include <boost/tuple/tuple.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/limits.hpp>

#ifdef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
#include <iterator>
#endif

/* This algorithm is to find coloring of a graph

Expand Down Expand Up @@ -50,6 +48,10 @@ typename property_traits< ColorMap >::value_type sequential_vertex_coloring(
size_type max_color = 0;
const size_type V = num_vertices(G);

// The order only covers vertices(G), which filtered_graph leaves shorter than num_vertices(G).
const auto vertex_range = vertices(G);
const size_type n = static_cast< size_type >(std::distance(vertex_range.first, vertex_range.second));

// We need to keep track of which colors are used by
// adjacent vertices. We do this by marking the colors
// that are used. The mark array contains the mark
Expand All @@ -66,7 +68,7 @@ typename property_traits< ColorMap >::value_type sequential_vertex_coloring(
put(color, *v, V - 1);

// Determine the color for every vertex one by one
for (size_type i = 0; i < V; i++)
for (size_type i = 0; i < n; i++)
{
Vertex current = get(order, i);
typename GraphTraits::adjacency_iterator v, vend;
Expand Down
144 changes: 120 additions & 24 deletions test/sequential_vertex_coloring.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright 2004 The Trustees of Indiana University.
// Copyright (c) 2026 Arnaud Becheler

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
Expand All @@ -9,17 +10,64 @@
#include <boost/graph/sequential_vertex_coloring.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/property_map/function_property_map.hpp>
#include <cstddef>
#include <utility>
#include <vector>

using namespace boost;
using SimpleGraph = ::boost::adjacency_list< ::boost::listS, ::boost::vecS, ::boost::undirectedS >;
using BaseGraph = ::boost::adjacency_list< ::boost::vecS, ::boost::vecS, ::boost::undirectedS >;
using BaseVertex = ::boost::graph_traits< BaseGraph >::vertex_descriptor;

int main(int, char*[])
// Keeps the even numbered vertices, so vertices(g) is shorter than num_vertices(g).
struct keep_even
{
typedef adjacency_list< listS, vecS, undirectedS > Graph;
typedef graph_traits< Graph >::vertices_size_type vertices_size_type;
typedef property_map< Graph, vertex_index_t >::const_type vertex_index_map;
bool operator()(BaseVertex v) const { return v % 2 == 0; }
};

typedef std::pair< int, int > Edge;
using FilteredGraph = ::boost::filtered_graph< BaseGraph, ::boost::keep_all, keep_even >;
using size_type = ::boost::graph_traits< FilteredGraph >::vertices_size_type;

// Reports out of range queries instead of letting the algorithm read past the order.
struct counting_order
{
const std::vector< BaseVertex >* order;
std::size_t* out_of_range;

BaseVertex operator()(size_type i) const
{
if (i < order->size())
return (*order)[i];
++*out_of_range;
return order->front();
}
};

BaseGraph make_base_graph()
{
using Edge = std::pair< std::size_t, std::size_t >;
constexpr Edge edges[] = { Edge(0, 2), Edge(2, 4), Edge(1, 0), Edge(1, 2), Edge(3, 2), Edge(3, 4) };
constexpr std::size_t m = sizeof(edges) / sizeof(Edge);
return BaseGraph(edges, edges + m, 5);
}

std::vector< BaseVertex > vertex_order(const FilteredGraph& g)
{
std::vector< BaseVertex > order;
const auto vertex_range = ::boost::vertices(g);
for (auto vi = vertex_range.first; vi != vertex_range.second; ++vi)
order.push_back(*vi);
return order;
}

constexpr size_type sentinel = 99;

void test_simple_graph()
{
using vertex_descriptor = ::boost::graph_traits< SimpleGraph >::vertex_descriptor;
using vertices_size_type = ::boost::graph_traits< SimpleGraph >::vertices_size_type;
using Edge = std::pair< int, int >;
enum nodes
{
A,
Expand All @@ -29,22 +77,70 @@ int main(int, char*[])
E,
n
};
Edge edge_array[] = { Edge(A, C), Edge(B, B), Edge(B, D), Edge(B, E),
Edge(C, B), Edge(C, D), Edge(D, E), Edge(E, A), Edge(E, B) };
int m = sizeof(edge_array) / sizeof(Edge);
Graph g(edge_array, edge_array + m, n);

// Test with the normal order
std::vector< vertices_size_type > color_vec(num_vertices(g));
iterator_property_map< vertices_size_type*, vertex_index_map,
vertices_size_type, vertices_size_type& >
color(&color_vec.front(), get(vertex_index, g));
vertices_size_type num_colors = sequential_vertex_coloring(g, color);
BOOST_TEST(num_colors == 3);
BOOST_TEST(get(color, (vertices_size_type)A) == 0);
BOOST_TEST(get(color, (vertices_size_type)B) == 0);
BOOST_TEST(get(color, (vertices_size_type)C) == 1);
BOOST_TEST(get(color, (vertices_size_type)D) == 2);
BOOST_TEST(get(color, (vertices_size_type)E) == 1);
return boost::report_errors();
constexpr Edge edge_array[] = { Edge(A, C), Edge(B, B), Edge(B, D), Edge(B, E), Edge(C, B), Edge(C, D), Edge(D, E), Edge(E, A), Edge(E, B) };
constexpr std::size_t m = sizeof(edge_array) / sizeof(Edge);
const SimpleGraph g(edge_array, edge_array + m, n);

std::vector< vertices_size_type > color_vec(::boost::num_vertices(g));
auto color_map = ::boost::make_iterator_property_map(color_vec.begin(), ::boost::get(::boost::vertex_index, g));
const vertices_size_type num_colors = ::boost::sequential_vertex_coloring(g, color_map);

BOOST_TEST_EQ(num_colors, 3);
BOOST_TEST_EQ(::boost::get(color_map, static_cast< vertex_descriptor >(A)), 0);
BOOST_TEST_EQ(::boost::get(color_map, static_cast< vertex_descriptor >(B)), 0);
BOOST_TEST_EQ(::boost::get(color_map, static_cast< vertex_descriptor >(C)), 1);
BOOST_TEST_EQ(::boost::get(color_map, static_cast< vertex_descriptor >(D)), 2);
BOOST_TEST_EQ(::boost::get(color_map, static_cast< vertex_descriptor >(E)), 1);
}

// Regression for https://github.com/boostorg/graph/issues/627
void test_filtered_graph_order_bounds()
{
const BaseGraph base = make_base_graph();
const FilteredGraph g(base, ::boost::keep_all(), keep_even());
const std::vector< BaseVertex > order = vertex_order(g);

BOOST_TEST_EQ(order.size(), 3);
BOOST_TEST_EQ(::boost::num_vertices(g), 5);

std::size_t out_of_range = 0;
const counting_order query = { &order, &out_of_range };
auto order_map = ::boost::make_function_property_map< size_type >(query);

std::vector< size_type > color_vec(::boost::num_vertices(g), sentinel);
auto color_map = ::boost::make_iterator_property_map(color_vec.begin(), ::boost::get(::boost::vertex_index, g));
const size_type num_colors = ::boost::sequential_vertex_coloring(g, order_map, color_map);

BOOST_TEST_EQ(out_of_range, 0);
BOOST_TEST_EQ(num_colors, 2);
BOOST_TEST_EQ(color_vec[0], 0);
BOOST_TEST_EQ(color_vec[2], 1);
BOOST_TEST_EQ(color_vec[4], 0);
BOOST_TEST_EQ(color_vec[1], sentinel);
BOOST_TEST_EQ(color_vec[3], sentinel);
}

void test_filtered_graph_default_order()
{
const BaseGraph base = make_base_graph();
const FilteredGraph g(base, ::boost::keep_all(), keep_even());

std::vector< size_type > color_vec(::boost::num_vertices(g), sentinel);
auto color_map = ::boost::make_iterator_property_map(color_vec.begin(), ::boost::get(::boost::vertex_index, g));
const size_type num_colors = ::boost::sequential_vertex_coloring(g, color_map);

BOOST_TEST_EQ(num_colors, 2);
BOOST_TEST_EQ(color_vec[0], 0);
BOOST_TEST_EQ(color_vec[2], 1);
BOOST_TEST_EQ(color_vec[4], 0);
BOOST_TEST_EQ(color_vec[1], sentinel);
BOOST_TEST_EQ(color_vec[3], sentinel);
}

int main()
{
test_simple_graph();
test_filtered_graph_order_bounds();
test_filtered_graph_default_order();
return ::boost::report_errors();
}
Loading