Skip to content

Commit a8c1b67

Browse files
committed
Correction: Function returns EdgeIndex
- Cycle_basis_edges now returns a list of edgeIDs.
1 parent 35eea7e commit a8c1b67

File tree

2 files changed

+52
-60
lines changed

2 files changed

+52
-60
lines changed

rustworkx-core/src/connectivity/cycle_basis.rs

Lines changed: 48 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ where
116116
cycles
117117
}
118118

119-
/// Return a list of edges representing cycles which form a basis for cycles of a given graph.
119+
/// Return a list of edge indices representing cycles which form a basis for
120+
/// cycles of a given graph.
120121
///
121122
/// A basis for cycles of a graph is a minimal collection of
122123
/// cycles such that any cycle in the graph can be written
@@ -145,20 +146,45 @@ where
145146
///
146147
/// let edge_list = [(0, 1), (0, 3), (0, 5), (1, 2), (2, 3), (3, 4), (4, 5)];
147148
/// let graph = UnGraph::<i32, i32>::from_edges(&edge_list);
148-
/// let mut res: Vec<Vec<(NodeIndex, NodeIndex)>> = cycle_basis_edges(&graph, Some(NodeIndex::new(0)));
149+
/// let mut res: Vec<Vec<EdgeIndex>> = cycle_basis_edges(&graph, Some(NodeIndex::new(0)));
149150
/// ```
150-
pub fn cycle_basis_edges<G>(graph: G, root: Option<G::NodeId>) -> Vec<Vec<(G::NodeId, G::NodeId)>>
151+
pub fn cycle_basis_edges<G>(graph: G, root: Option<G::NodeId>) -> Vec<Vec<G::EdgeId>>
151152
where
152153
G: NodeCount,
153154
G: IntoNeighbors,
154155
G: IntoEdges,
155156
G: IntoNodeIdentifiers,
156157
G::NodeId: Eq + Hash,
158+
G::EdgeId: Eq + Hash,
157159
{
158160
let mut root_node = root;
159161
let mut graph_nodes: HashSet<G::NodeId> = graph.node_identifiers().collect();
162+
let mut cycles: Vec<Vec<G::EdgeId>> = Vec::new();
163+
164+
// Method used to retrieve all the edges between an origin node and a target node.
165+
// Can be used to check if a node loops back to itself by enabling equiv
166+
fn get_edge_between<G>(
167+
orig_graph: G,
168+
origin: G::NodeId,
169+
target: G::NodeId,
170+
equiv: bool,
171+
) -> Vec<G::EdgeId>
172+
where
173+
G: IntoEdges,
174+
{
175+
orig_graph
176+
.edges(origin)
177+
.filter(|edge: &G::EdgeRef| {
178+
if equiv {
179+
edge.source() == target && edge.target() == target
180+
} else {
181+
edge.source() == target || edge.target() == target
182+
}
183+
})
184+
.map(|edge: G::EdgeRef| edge.id())
185+
.collect()
186+
}
160187

161-
let mut cycles: Vec<Vec<(G::NodeId, G::NodeId)>> = Vec::new();
162188
while !graph_nodes.is_empty() {
163189
let temp_value: G::NodeId;
164190
// If root_node is not set get an arbitrary node from the set of graph
@@ -194,37 +220,25 @@ where
194220
used.insert(neighbor, temp_set);
195221
// A self loop:
196222
} else if z == neighbor {
197-
let cycle_edge: Vec<(G::NodeId, G::NodeId)> = graph
198-
.edges(z)
199-
.filter(|edge: &G::EdgeRef| edge.source() == z && edge.target() == z)
200-
.map(|edge: G::EdgeRef| (edge.source(), edge.target()))
201-
.collect();
223+
let cycle_edge: Vec<G::EdgeId> = get_edge_between(graph, z, z, true);
202224
cycles.push(cycle_edge);
203225
// A cycle was found:
204226
} else if !used.get(&z).unwrap().contains(&neighbor) {
205227
let pn = used.get(&neighbor).unwrap();
206-
let mut cycle: Vec<(G::NodeId, G::NodeId)> = vec![];
228+
let mut cycle: Vec<G::EdgeId> = vec![];
207229
let mut p = pred.get(&z).unwrap();
208230
// Retreive all edges from z to neighbor and vice versa
209-
let mut neigh_edge: Vec<(G::NodeId, G::NodeId)> = graph
210-
.edges(z)
211-
.filter(|edge: &G::EdgeRef| {
212-
edge.source() == neighbor || edge.target() == neighbor
213-
})
214-
.map(|edge: G::EdgeRef| (edge.source(), edge.target()))
215-
.collect();
231+
let mut neigh_edge: Vec<G::EdgeId> =
232+
get_edge_between(graph, z, neighbor, false);
216233
// Append to cycle
217234
cycle.append(&mut neigh_edge);
218235
// Make last p_node == z
219236
let mut prev_p: &G::NodeId = &z;
220237
// While p is in the neighborhood of neighbor
221238
while !pn.contains(p) {
222239
// Retrieve all edges from prev_p to p and vice versa
223-
let mut neigh_edge: Vec<(G::NodeId, G::NodeId)> = graph
224-
.edges(*prev_p)
225-
.filter(|edge: &G::EdgeRef| edge.target() == *p || edge.source() == *p)
226-
.map(|edge: G::EdgeRef| (edge.source(), edge.target()))
227-
.collect();
240+
let mut neigh_edge: Vec<G::EdgeId> =
241+
get_edge_between(graph, *prev_p, *p, false);
228242
// Append to cycle
229243
cycle.append(&mut neigh_edge);
230244
// Update prev_p to p
@@ -233,20 +247,12 @@ where
233247
p = pred.get(p).unwrap();
234248
}
235249
// When loop ends add remaining edges from prev_p to p.
236-
let mut neigh_edge: Vec<(G::NodeId, G::NodeId)> = graph
237-
.edges(*prev_p)
238-
.filter(|edge: &G::EdgeRef| edge.target() == *p || edge.source() == *p)
239-
.map(|edge: G::EdgeRef| (edge.source(), edge.target()))
240-
.collect();
250+
let mut neigh_edge: Vec<G::EdgeId> =
251+
get_edge_between(graph, *prev_p, *p, false);
241252
cycle.append(&mut neigh_edge);
242253
// Also retreive all edges between the last p and neighbor
243-
let mut neigh_edge: Vec<(G::NodeId, G::NodeId)> = graph
244-
.edges(*p)
245-
.filter(|edge: &G::EdgeRef| {
246-
edge.target() == neighbor || edge.source() == neighbor
247-
})
248-
.map(|edge: G::EdgeRef| (edge.source(), edge.target()))
249-
.collect();
254+
let mut neigh_edge: Vec<G::EdgeId> =
255+
get_edge_between(graph, *p, neighbor, false);
250256
cycle.append(&mut neigh_edge);
251257

252258
// Once all edges within cycle have been found, push to cycle list.
@@ -283,19 +289,10 @@ mod tests {
283289
sorted_cycles
284290
}
285291

286-
fn sorted_cycle_edges(cycles: Vec<Vec<(NodeIndex, NodeIndex)>>) -> Vec<Vec<(usize, usize)>> {
287-
let mut sorted_cycles: Vec<Vec<(usize, usize)>> = vec![];
292+
fn sorted_cycle_edges(cycles: Vec<Vec<EdgeIndex>>) -> Vec<Vec<usize>> {
293+
let mut sorted_cycles: Vec<Vec<usize>> = vec![];
288294
for cycle in cycles {
289-
let mut cycle: Vec<(usize, usize)> = cycle
290-
.iter()
291-
.map(|x| {
292-
if x.0 < x.1 {
293-
(x.0.index(), x.1.index())
294-
} else {
295-
(x.1.index(), x.0.index())
296-
}
297-
})
298-
.collect();
295+
let mut cycle: Vec<usize> = cycle.iter().map(|x| x.index()).collect();
299296
cycle.sort();
300297
sorted_cycles.push(cycle);
301298
}
@@ -342,7 +339,7 @@ mod tests {
342339
(3, 4),
343340
];
344341
let graph = UnGraph::<i32, i32>::from_edges(&edge_list);
345-
let expected = vec![vec![(0, 0)], vec![(2, 3), (2, 5), (3, 6), (5, 6)]];
342+
let expected = vec![vec![0], vec![3, 4, 5, 6]];
346343
let res_0 = cycle_basis_edges(&graph, Some(NodeIndex::new(0)));
347344
assert_eq!(sorted_cycle_edges(res_0), expected);
348345
let res_1 = cycle_basis_edges(&graph, Some(NodeIndex::new(2)));
@@ -403,10 +400,10 @@ mod tests {
403400
assert_eq!(
404401
sorted_cycle_edges(res_0),
405402
vec![
406-
vec![(0, 1), (0, 3), (1, 2), (2, 3)],
407-
vec![(0, 1), (0, 8), (1, 6), (6, 7), (7, 8)],
408-
vec![(0, 3), (0, 5), (3, 4), (4, 5)],
409-
vec![(1, 1)],
403+
vec![0, 1, 4, 6],
404+
vec![0, 3, 5, 9, 10],
405+
vec![1, 2, 7, 8],
406+
vec![12],
410407
]
411408
);
412409
}

src/connectivity/mod.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,23 +92,18 @@ pub fn cycle_basis(graph: &graph::PyGraph, root: Option<usize>) -> Vec<Vec<usize
9292
/// :param PyGraph graph: The graph to find the cycle basis in
9393
/// :param int root: Optional index for starting node for basis
9494
///
95-
/// :returns: A list of edge lists. Each list is a list of tuples of node ids which
96-
/// forms a cycle (loop) in the input graph
95+
/// :returns: A list of edge indices list. Each list is a list of edge indices which
96+
/// form a cycle (loop) in the input graph
9797
/// :rtype: list
9898
///
9999
/// .. [1] Paton, K. An algorithm for finding a fundamental set of
100100
/// cycles of a graph. Comm. ACM 12, 9 (Sept 1969), 514-518.
101101
#[pyfunction]
102102
#[pyo3(text_signature = "(graph, /, root=None)")]
103-
pub fn cycle_basis_edges(graph: &graph::PyGraph, root: Option<usize>) -> Vec<Vec<(usize, usize)>> {
103+
pub fn cycle_basis_edges(graph: &graph::PyGraph, root: Option<usize>) -> Vec<Vec<usize>> {
104104
connectivity::cycle_basis_edges(&graph.graph, root.map(NodeIndex::new))
105105
.into_iter()
106-
.map(|res_map| {
107-
res_map
108-
.into_iter()
109-
.map(|x| (x.0.index(), x.1.index()))
110-
.collect()
111-
})
106+
.map(|res_map| res_map.into_iter().map(|x| x.index()).collect())
112107
.collect()
113108
}
114109

0 commit comments

Comments
 (0)