-
Notifications
You must be signed in to change notification settings - Fork 153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
moving greedy-color to rustworkx-core #875
Changes from 6 commits
dff323a
31432fb
92126c9
0ab19ba
80651ce
f154353
40fbbb3
3509aa9
a9e7cea
4cd5665
56ad8e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
features: | ||
- | | ||
The function ``greedy_color``has been migrated to the ``rustworkx-core`` | ||
crate in the ``coloring`` module. It colors a graph using a greedy | ||
graph coloring algorithm. | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// Licensed under the Apache License, Version 2.0 (the "License"); you may | ||
// not use this file except in compliance with the License. You may obtain | ||
// a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
// License for the specific language governing permissions and limitations | ||
// under the License. | ||
|
||
use std::cmp::Reverse; | ||
use std::hash::Hash; | ||
|
||
use crate::dictmap::*; | ||
use hashbrown::{HashMap, HashSet}; | ||
use petgraph::visit::{EdgeRef, IntoEdges, IntoNodeIdentifiers, NodeCount}; | ||
use rayon::prelude::*; | ||
|
||
/// Color a graph using a greedy graph coloring algorithm. | ||
/// | ||
/// This function uses a `largest-first` strategy as described in [1]_ and colors | ||
mtreinish marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// the nodes with higher degree first. | ||
mtreinish marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// | ||
/// Arguments: | ||
/// | ||
/// * `graph` - The graph object to run the algorithm on | ||
/// | ||
/// # Example | ||
/// ```rust | ||
/// | ||
/// use petgraph::graph::Graph; | ||
/// use petgraph::graph::NodeIndex; | ||
/// use petgraph::Undirected; | ||
/// use rustworkx_core::dictmap::*; | ||
/// use rustworkx_core::coloring::greedy_color; | ||
/// | ||
/// let g = Graph::<(), (), Undirected>::from_edges(&[(0, 1), (0, 2)]); | ||
/// let colors = greedy_color(&g); | ||
/// let mut expected_colors = DictMap::new(); | ||
/// expected_colors.insert(NodeIndex::new(0), 0); | ||
/// expected_colors.insert(NodeIndex::new(1), 1); | ||
/// expected_colors.insert(NodeIndex::new(2), 1); | ||
/// assert_eq!(colors, expected_colors); | ||
/// ``` | ||
/// | ||
/// | ||
/// .. [1] Adrian Kosowski, and Krzysztof Manuszewski, Classical Coloring of Graphs, | ||
/// Graph Colorings, 2-19, 2004. ISBN 0-8218-3458-4. | ||
pub fn greedy_color<G>(graph: G) -> DictMap<G::NodeId, usize> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if we want to call this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have changed the name of the internal rust function to |
||
where | ||
G: NodeCount + IntoNodeIdentifiers + IntoEdges, | ||
G::NodeId: Hash + Eq + Send + Sync, | ||
{ | ||
let mut colors: DictMap<G::NodeId, usize> = DictMap::new(); | ||
let mut node_vec: Vec<G::NodeId> = graph.node_identifiers().collect(); | ||
|
||
let mut sort_map: HashMap<G::NodeId, usize> = HashMap::with_capacity(graph.node_count()); | ||
for k in node_vec.iter() { | ||
sort_map.insert(*k, graph.edges(*k).count()); | ||
} | ||
node_vec.par_sort_by_key(|k| Reverse(sort_map.get(k))); | ||
|
||
for node in node_vec { | ||
let mut neighbor_colors: HashSet<usize> = HashSet::new(); | ||
for edge in graph.edges(node) { | ||
let target = edge.target(); | ||
let existing_color = match colors.get(&target) { | ||
Some(color) => color, | ||
None => continue, | ||
}; | ||
neighbor_colors.insert(*existing_color); | ||
} | ||
let mut current_color: usize = 0; | ||
loop { | ||
if !neighbor_colors.contains(¤t_color) { | ||
break; | ||
} | ||
current_color += 1; | ||
} | ||
colors.insert(node, current_color); | ||
} | ||
|
||
colors | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,51 @@ | ||||||||||||||||||||||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may | ||||||||||||||||||||||||
// not use this file except in compliance with the License. You may obtain | ||||||||||||||||||||||||
// a copy of the License at | ||||||||||||||||||||||||
// | ||||||||||||||||||||||||
// http://www.apache.org/licenses/LICENSE-2.0 | ||||||||||||||||||||||||
// | ||||||||||||||||||||||||
// Unless required by applicable law or agreed to in writing, software | ||||||||||||||||||||||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||||||||||||||||||||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||||||||||||||||||||||
// License for the specific language governing permissions and limitations | ||||||||||||||||||||||||
// under the License. | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
//! Test module for coloring algorithms. | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
use petgraph::graph::Graph; | ||||||||||||||||||||||||
use petgraph::graph::NodeIndex; | ||||||||||||||||||||||||
use petgraph::Undirected; | ||||||||||||||||||||||||
use rustworkx_core::dictmap::*; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
use rustworkx_core::coloring::greedy_color; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||
fn test_greedy_color_empty_graph() { | ||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd be tempted to put these 3 test files under #[cfg(test)]
mod tests {
} in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think in our previous discussions, we want to put tests that are for only one module inside the module as you suggest. Putting new modules in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! I have moved the tests to the coloring module (and I can see these running, now that I have learned to run |
||||||||||||||||||||||||
let graph = Graph::<(), (), Undirected>::new_undirected(); | ||||||||||||||||||||||||
let colors = greedy_color(&graph); | ||||||||||||||||||||||||
let expected_colors = DictMap::new(); | ||||||||||||||||||||||||
assert_eq!(colors, expected_colors); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||
fn test_greedy_color_simple_graph() { | ||||||||||||||||||||||||
let graph = Graph::<(), (), Undirected>::from_edges(&[(0, 1), (0, 2)]); | ||||||||||||||||||||||||
let colors = greedy_color(&graph); | ||||||||||||||||||||||||
let mut expected_colors = DictMap::new(); | ||||||||||||||||||||||||
expected_colors.insert(NodeIndex::new(0), 0); | ||||||||||||||||||||||||
expected_colors.insert(NodeIndex::new(1), 1); | ||||||||||||||||||||||||
expected_colors.insert(NodeIndex::new(2), 1); | ||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since you asked somewhere you can do this construction with something like:
Suggested change
but manually calling insert works fine too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! I like the suggested approach (and in this case we also don't need the |
||||||||||||||||||||||||
assert_eq!(colors, expected_colors); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||
fn test_greedy_color_simple_graph_large_degree() { | ||||||||||||||||||||||||
let graph = | ||||||||||||||||||||||||
Graph::<(), (), Undirected>::from_edges(&[(0, 1), (0, 2), (0, 2), (0, 2), (0, 2), (0, 2)]); | ||||||||||||||||||||||||
let colors = greedy_color(&graph); | ||||||||||||||||||||||||
let mut expected_colors = DictMap::new(); | ||||||||||||||||||||||||
expected_colors.insert(NodeIndex::new(0), 0); | ||||||||||||||||||||||||
expected_colors.insert(NodeIndex::new(1), 1); | ||||||||||||||||||||||||
expected_colors.insert(NodeIndex::new(2), 1); | ||||||||||||||||||||||||
assert_eq!(colors, expected_colors); | ||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.