1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//! Submodule defining a trait characterizing monoplex bipartite graphs.
//!
//! These graphs are characterized by the fact that:
//!
//! * They are bipartite, i.e., they have two types of nodes.
//! * They are monoplex, i.e., they have only one type of edges.
use super::{BipartiteGraph, Edges, MonoplexGraph};
/// Trait defining the properties of a monoplex bipartite graph.
///
/// This trait combines `MonoplexGraph` and `BipartiteGraph`, ensuring the
/// edges have source/destination node types matching the left/right node types.
pub trait MonoplexBipartiteGraph:
MonoplexGraph<Edges = Self::MonoplexBipartiteEdges> + BipartiteGraph
{
/// The edges of the graph, with source matching left nodes and destination
/// matching right nodes.
type MonoplexBipartiteEdges: Edges<
SourceNodeId = <Self as BipartiteGraph>::LeftNodeId,
DestinationNodeId = <Self as BipartiteGraph>::RightNodeId,
>;
/// Returns a DOT representation for the Monoplex Bipartite Graph.
///
/// # Examples
///
/// ```
/// use geometric_traits::{
/// impls::{CSR2D, SortedVec},
/// naive_structs::{GenericEdgesBuilder, named_types::BiGraph},
/// prelude::*,
/// traits::{EdgesBuilder, VocabularyBuilder},
/// };
///
/// let left_nodes: Vec<usize> = vec![0, 1];
/// let right_nodes: Vec<usize> = vec![0, 1];
/// let edges: Vec<(usize, usize)> = vec![(0, 1), (1, 0)];
/// let left_nodes: SortedVec<usize> = GenericVocabularyBuilder::default()
/// .expected_number_of_symbols(left_nodes.len())
/// .symbols(left_nodes.into_iter().enumerate())
/// .build()
/// .unwrap();
/// let right_nodes: SortedVec<usize> = GenericVocabularyBuilder::default()
/// .expected_number_of_symbols(right_nodes.len())
/// .symbols(right_nodes.into_iter().enumerate())
/// .build()
/// .unwrap();
/// let edges: CSR2D<usize, usize, usize> =
/// GenericEdgesBuilder::<_, CSR2D<usize, usize, usize>>::default()
/// .expected_number_of_edges(edges.len())
/// .expected_shape((left_nodes.len(), right_nodes.len()))
/// .edges(edges.into_iter())
/// .build()
/// .unwrap();
/// let graph: BiGraph<usize, usize> = BiGraph::try_from((left_nodes, right_nodes, edges)).unwrap();
///
/// let dot = graph.to_mb_dot();
/// assert!(dot.contains("L0 -> R1;"));
/// assert!(dot.contains("L1 -> R0;"));
/// ```
#[cfg(feature = "alloc")]
#[inline]
fn to_mb_dot(&self) -> alloc::string::String {
use core::fmt::Write;
let mut dot = alloc::string::String::new();
writeln!(dot, " graph {{").unwrap();
for left_node_id in self.left_node_ids() {
writeln!(dot, " L{left_node_id} [color=red];").unwrap();
}
for right_node_id in self.right_node_ids() {
writeln!(dot, " R{right_node_id} [color=blue];").unwrap();
}
for (src, dst) in self.edges().sparse_coordinates() {
writeln!(dot, " L{src} -> R{dst};").unwrap();
}
writeln!(dot, " }}").unwrap();
dot
}
}
impl<G> MonoplexBipartiteGraph for G
where
G: MonoplexGraph,
G: BipartiteGraph,
G::Edges: Edges<
SourceNodeId = <G as BipartiteGraph>::LeftNodeId,
DestinationNodeId = <G as BipartiteGraph>::RightNodeId,
>,
{
type MonoplexBipartiteEdges = G::Edges;
}