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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
//! Vertex match inference from edge matches in the MCES pipeline.
//!
//! Given a maximum clique in the modular product of two line graphs (i.e.,
//! a set of matched edge pairs), this module infers which original graph
//! vertices correspond to each other.
//!
//! The algorithm follows the RASCAL approach (Raymond, Gardiner, Willett 2002)
//! with three phases:
//!
//! 1. **Shared endpoints** — adjacent matched edges share a vertex in each
//! graph; those shared vertices are unambiguously matched.
//! 2. **Propagation** — for each matched edge where one endpoint is already
//! resolved, the other is forced.
//! 3. **Disambiguation** — for isolated edges (neither endpoint resolved), a
//! caller-provided closure decides the mapping.
use ;
/// Returns the shared endpoint of two edges, if they share exactly one.
///
/// Given edges `(a, b)` and `(c, d)`, returns `Some(v)` where `v` is the
/// single vertex common to both edges.
///
/// Returns `None` if the edges are disjoint (no shared endpoint) or share
/// both endpoints (same edge, possibly reversed).
///
/// # Examples
///
/// ```
/// use geometric_traits::prelude::shared_endpoint;
///
/// assert_eq!(shared_endpoint((1_u32, 2), (2, 3)), Some(2));
/// assert_eq!(shared_endpoint((1_u32, 2), (3, 1)), Some(1));
/// assert_eq!(shared_endpoint::<u32>((1, 2), (3, 4)), None);
/// assert_eq!(shared_endpoint::<u32>((1, 2), (1, 2)), None);
/// ```
/// Inserts a vertex match into the map if the key is not already present.
///
/// Returns `true` if the insertion succeeded (key was vacant), `false` if the
/// key was already mapped (possibly to a different value). Conflicts are
/// expected for symmetric graphs where the same vertex participates in
/// multiple matched edges with ambiguous mappings.
/// Infers vertex matches from edge matches in the MCES pipeline.
///
/// Given a maximum clique in the modular product of two line graphs, infers
/// which vertices of the original graphs are matched. Each clique member
/// represents a matched edge pair; this function resolves the implied vertex
/// correspondence through three phases:
///
/// 1. **Shared endpoints**: for all pairs of matched edges that share an
/// endpoint in both graphs, the shared vertices are matched.
/// 2. **Propagation**: for each matched edge where one endpoint is already
/// resolved, the other is forced.
/// 3. **Disambiguation**: for isolated edges (neither endpoint resolved), the
/// caller-provided closure decides the mapping.
///
/// # Parameters
///
/// - `clique` — indices into `vertex_pairs` (the maximum clique result).
/// - `vertex_pairs` — from [`ModularProductResult::vertex_pairs()`], maps
/// product vertex → `(lg1_vertex, lg2_vertex)`.
/// - `edge_map_first` — from [`LineGraphResult::edge_map()`] of the first
/// graph, maps line graph vertex → original edge `(src, dst)`.
/// - `edge_map_second` — same for the second graph.
/// - `disambiguate` — called for isolated edges as `disambiguate(a, b, c, d)`
/// where `(a, b)` is the G1 edge and `(c, d)` is the G2 edge. Returns `true`
/// for mapping `a↔c, b↔d`; `false` for `a↔d, b↔c`.
///
/// # Returns
///
/// A sorted `Vec<(N, N)>` of matched vertex pairs, deduplicated.
///
/// # Complexity
///
/// O(|clique|²) time, O(V) space.
///
/// [`ModularProductResult::vertex_pairs()`]: crate::traits::algorithms::modular_product::ModularProductResult::vertex_pairs
/// [`LineGraphResult::edge_map()`]: crate::traits::algorithms::line_graph::LineGraphResult::edge_map
///
/// # Examples
///
/// ```
/// use geometric_traits::prelude::infer_vertex_matches;
///
/// // Path graph 0-1-2 matched to path graph 10-11-12.
/// // Line graph vertices: 0=(0,1), 1=(1,2) and 0=(10,11), 1=(11,12)
/// // Clique matches both edges: product vertices [(0,0), (1,1)]
/// let clique = [0, 1];
/// let vertex_pairs = [(0_usize, 0_usize), (1, 1)];
/// let edge_map1 = [(0_u32, 1_u32), (1, 2)];
/// let edge_map2 = [(10_u32, 11_u32), (11, 12)];
///
/// let matches =
/// infer_vertex_matches(&clique, &vertex_pairs, &edge_map1, &edge_map2, |_, _, _, _| true);
/// // Shared endpoint: 1↔11 (Phase 1)
/// // Propagation: 0↔10 and 2↔12 (Phase 2)
/// assert_eq!(matches, vec![(0, 10), (1, 11), (2, 12)]);
/// ```