Skip to content

Commit

Permalink
Merge branch 'main' into shorter-dispatch
Browse files Browse the repository at this point in the history
  • Loading branch information
IvanIsCoding committed Jul 9, 2023
2 parents f72b556 + a45c016 commit 7e89202
Show file tree
Hide file tree
Showing 14 changed files with 569 additions and 32 deletions.
42 changes: 21 additions & 21 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ serde_json = "1.0"
rustworkx-core = { path = "rustworkx-core", version = "=0.14.0" }

[dependencies.pyo3]
version = "0.19.0"
version = "0.19.1"
features = ["extension-module", "hashbrown", "num-bigint", "num-complex", "indexmap"]

[dependencies.hashbrown]
Expand Down
1 change: 1 addition & 0 deletions constraints.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
decorator==4.4.2
importlib-metadata==4.13.0;python_version<'3.8'
pillow<10.0.0
2 changes: 2 additions & 0 deletions docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ Other Algorithm Functions
rustworkx.transitivity
rustworkx.core_number
rustworkx.graph_greedy_color
rustworkx.graph_greedy_edge_color
rustworkx.graph_line_graph
rustworkx.metric_closure
rustworkx.is_planar

Expand Down
1 change: 1 addition & 0 deletions docs/source/sources.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ rustworkx.graph_distance_matrix.html
rustworkx.graph_floyd_warshall.html
rustworkx.graph_floyd_warshall_numpy.html
rustworkx.graph_greedy_color.html
rustworkx.graph_greedy_edge_color.html
rustworkx.graph_is_isomorphic.html
rustworkx.graph_is_subgraph_isomorphic.html
rustworkx.graph_k_shortest_path_lengths.html
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
features:
- |
Added a new function, :func:`~.graph_line_graph` to construct a line
graph of a :class:`~.PyGraph` object.
The line graph `L(G)` of a graph `G` represents the adjacencies between edges of G.
`L(G)` contains a vertex for every edge in `G`, and `L(G)` contains an edge between two
vertices if the corresponding edges in `G` have a vertex in common.
.. jupyter-execute::
import rustworkx as rx
graph = rx.PyGraph()
node_a = graph.add_node("a")
node_b = graph.add_node("b")
node_c = graph.add_node("c")
node_d = graph.add_node("d")
edge_ab = graph.add_edge(node_a, node_b, 1)
edge_ac = graph.add_edge(node_a, node_c, 1)
edge_bc = graph.add_edge(node_b, node_c, 1)
edge_ad = graph.add_edge(node_a, node_d, 1)
out_graph, out_edge_map = rx.graph_line_graph(graph)
assert out_graph.node_indices() == [0, 1, 2, 3]
assert out_graph.edge_list() == [(3, 1), (3, 0), (1, 0), (2, 0), (2, 1)]
assert out_edge_map == {edge_ab: 0, edge_ac: 1, edge_bc: 2, edge_ad: 3}
- |
Added a new function, :func:`~.graph_greedy_edge_color` to color edges
of a :class:`~.PyGraph` object using a greedy approach.
This function works by greedily coloring the line graph of the given graph.
.. jupyter-execute::
import rustworkx as rx
graph = rx.generators.cycle_graph(7)
edge_colors = rx.graph_greedy_edge_color(graph)
assert edge_colors == {0: 0, 1: 1, 2: 0, 3: 1, 4: 0, 5: 1, 6: 2}
111 changes: 108 additions & 3 deletions rustworkx-core/src/coloring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ use std::cmp::Reverse;
use std::hash::Hash;

use crate::dictmap::*;
use crate::line_graph::line_graph;
use hashbrown::{HashMap, HashSet};
use petgraph::visit::{EdgeRef, IntoEdges, IntoNodeIdentifiers, NodeCount};
use petgraph::graph::NodeIndex;
use petgraph::visit::{EdgeCount, EdgeRef, IntoEdges, IntoNodeIdentifiers, NodeCount};
use rayon::prelude::*;

/// Color a graph using a greedy graph coloring algorithm.
Expand Down Expand Up @@ -52,13 +54,12 @@ use rayon::prelude::*;
/// assert_eq!(colors, expected_colors);
/// ```
///
///
pub fn greedy_node_color<G>(graph: G) -> DictMap<G::NodeId, usize>
where
G: NodeCount + IntoNodeIdentifiers + IntoEdges,
G::NodeId: Hash + Eq + Send + Sync,
{
let mut colors: DictMap<G::NodeId, usize> = DictMap::new();
let mut colors: DictMap<G::NodeId, usize> = DictMap::with_capacity(graph.node_count());
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());
Expand Down Expand Up @@ -90,6 +91,60 @@ where
colors
}

/// Color edges of a graph using a greedy approach.
///
/// This function works by greedily coloring the line graph of the given graph.
///
/// The coloring problem is NP-hard and this is a heuristic algorithm
/// which may not return an optimal solution.
///
/// Arguments:
///
/// * `graph` - The graph object to run the algorithm on
///
/// # Example
/// ```rust
///
/// use petgraph::graph::Graph;
/// use petgraph::graph::EdgeIndex;
/// use petgraph::Undirected;
/// use rustworkx_core::dictmap::*;
/// use rustworkx_core::coloring::greedy_edge_color;
///
/// let g = Graph::<(), (), Undirected>::from_edges(&[(0, 1), (1, 2), (0, 2), (2, 3)]);
/// let colors = greedy_edge_color(&g);
/// let mut expected_colors = DictMap::new();
/// expected_colors.insert(EdgeIndex::new(0), 2);
/// expected_colors.insert(EdgeIndex::new(1), 0);
/// expected_colors.insert(EdgeIndex::new(2), 1);
/// expected_colors.insert(EdgeIndex::new(3), 2);
/// assert_eq!(colors, expected_colors);
/// ```
///
pub fn greedy_edge_color<G>(graph: G) -> DictMap<G::EdgeId, usize>
where
G: EdgeCount + IntoNodeIdentifiers + IntoEdges,
G::EdgeId: Hash + Eq,
{
let (new_graph, edge_to_node_map): (
petgraph::graph::UnGraph<(), ()>,
HashMap<G::EdgeId, NodeIndex>,
) = line_graph(&graph, || (), || ());

let colors = greedy_node_color(&new_graph);

let mut edge_colors: DictMap<G::EdgeId, usize> = DictMap::with_capacity(graph.edge_count());

for edge in graph.edge_references() {
let edge_index = edge.id();
let node_index = edge_to_node_map.get(&edge_index).unwrap();
let edge_color = colors.get(node_index).unwrap();
edge_colors.insert(edge_index, *edge_color);
}

edge_colors
}

#[cfg(test)]

mod test_node_coloring {
Expand Down Expand Up @@ -147,3 +202,53 @@ mod test_node_coloring {
assert_eq!(colors, expected_colors);
}
}

#[cfg(test)]
mod test_edge_coloring {
use crate::coloring::greedy_edge_color;
use crate::dictmap::DictMap;
use crate::petgraph::Graph;

use petgraph::graph::{edge_index, EdgeIndex};
use petgraph::Undirected;

#[test]
fn test_greedy_edge_color_empty_graph() {
// Empty graph
let graph = Graph::<(), (), Undirected>::new_undirected();
let colors = greedy_edge_color(&graph);
let expected_colors: DictMap<EdgeIndex, usize> = [].into_iter().collect();
assert_eq!(colors, expected_colors);
}

#[test]
fn test_greedy_edge_color_simple_graph() {
// Graph with an edge removed
let graph = Graph::<(), (), Undirected>::from_edges(&[(0, 1), (1, 2), (2, 3)]);
let colors = greedy_edge_color(&graph);
let expected_colors: DictMap<EdgeIndex, usize> = [
(EdgeIndex::new(0), 1),
(EdgeIndex::new(1), 0),
(EdgeIndex::new(2), 1),
]
.into_iter()
.collect();
assert_eq!(colors, expected_colors);
}

#[test]
fn test_greedy_edge_color_graph_with_removed_edges() {
// Simple graph
let mut graph = Graph::<(), (), Undirected>::from_edges(&[(0, 1), (1, 2), (2, 3), (3, 0)]);
graph.remove_edge(edge_index(1));
let colors = greedy_edge_color(&graph);
let expected_colors: DictMap<EdgeIndex, usize> = [
(EdgeIndex::new(0), 1),
(EdgeIndex::new(1), 0),
(EdgeIndex::new(2), 1),
]
.into_iter()
.collect();
assert_eq!(colors, expected_colors);
}
}
1 change: 1 addition & 0 deletions rustworkx-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub mod centrality;
pub mod coloring;
pub mod connectivity;
pub mod generators;
pub mod line_graph;
/// Module for maximum weight matching algorithms.
pub mod max_weight_matching;
pub mod planar;
Expand Down
Loading

0 comments on commit 7e89202

Please sign in to comment.