oxgraph_hyper/lib.rs
1//! Storage-agnostic traits for hypergraph views.
2//!
3//! `oxgraph-hyper` is the hypergraph specialization above `oxgraph-topology`. Use it
4//! to write generic hypergraph consumers over vertex, hyperedge, participant,
5//! incident-hyperedge, and directed participant-set vocabulary.
6//!
7//! Hypergraph views use topology elements as vertices, topology relations as
8//! hyperedges, and topology incidences as participant records. Concrete layouts,
9//! snapshots, builders, mutation systems, payloads, and algorithms belong in
10//! higher-level crates.
11//!
12//! # Performance contract
13//!
14//! Most of the traits and aliases in this crate are hypergraph-vocabulary
15//! shadows of topology traits. Unless a specific item documents otherwise,
16//! every method, iterator, and alias inherits its performance contract from
17//! the underlying topology trait it shadows: `O(1)` for accessors, `O(1)` to
18//! construct an iterator plus `O(k)` to yield `k` items, and `perf:
19//! unspecified` for capability-bundle marker traits and blanket impls.
20#![no_std]
21
22#[cfg(kani)]
23extern crate kani;
24
25pub use oxgraph_topology::{
26 CanonicalElementIdentity, CanonicalIncidenceIdentity, CanonicalRelationIdentity,
27 ContainsElement, ContainsIncidence, ContainsRelation, ElementIncidenceCount, ElementIncidences,
28 ElementIndex, ElementPredecessors, ElementSuccessors, ElementWeight, IncidenceBase,
29 IncidenceCounts, IncidenceElement, IncidenceIndex, IncidenceRelation, IncidenceRole,
30 IncidenceWeight, LocalElementIdentity, LocalIncidenceIdentity, LocalRelationIdentity,
31 RelationIncidenceCount, RelationIncidences, RelationIndex, RelationWeight, TopologyBase,
32 TopologyCounts, TopologyId,
33};
34
35/// Hypergraph-facing alias for a topology element ID (vertex).
36pub type VertexId<H> = <H as TopologyBase>::ElementId;
37
38/// Hypergraph-facing alias for a topology relation ID (hyperedge).
39pub type HyperedgeId<H> = <H as TopologyBase>::RelationId;
40
41/// Hypergraph-facing alias for a topology incidence ID (participant record).
42pub type ParticipantId<H> = <H as IncidenceBase>::IncidenceId;
43
44/// Hypergraph-facing alias for a topology incidence role used to distinguish
45/// source, target, input, output, or implementation-defined participant
46/// categories on directed or role-aware hypergraph views.
47pub type ParticipantRole<H> = <H as IncidenceBase>::Role;
48
49/// Base capability for hypergraph views over topology storage.
50///
51/// Hypergraph-facing name for [`TopologyBase`].
52pub trait HypergraphBase: TopologyBase {}
53
54impl<T> HypergraphBase for T where T: TopologyBase {}
55
56/// Base capability for hypergraph views that expose participant records.
57///
58/// Hypergraph-facing name for [`IncidenceBase`].
59pub trait ParticipantBase: IncidenceBase {}
60
61impl<T> ParticipantBase for T where T: IncidenceBase {}
62
63/// Count capability for a hypergraph view.
64///
65/// Hypergraph-facing name for [`TopologyCounts`].
66pub trait HypergraphCounts: TopologyCounts {
67 /// Returns the number of vertices visible in this hypergraph view.
68 fn vertex_count(&self) -> usize {
69 self.element_count()
70 }
71
72 /// Returns the number of hyperedges visible in this hypergraph view.
73 fn hyperedge_count(&self) -> usize {
74 self.relation_count()
75 }
76}
77
78/// Participant-record count capability for hypergraph views.
79///
80/// Hypergraph-facing name for [`IncidenceCounts`].
81pub trait ParticipantCounts: IncidenceCounts {
82 /// Returns the total number of participant records visible in this view.
83 fn participant_count(&self) -> usize {
84 self.incidence_count()
85 }
86}
87
88impl<T> ParticipantCounts for T where T: IncidenceCounts {}
89
90/// Dense vertex-index capability for hypergraph views.
91///
92/// Hypergraph-facing name for [`ElementIndex`].
93pub trait VertexIndex: ElementIndex {
94 /// Returns the exclusive upper bound for vertex indexes in this view.
95 fn vertex_bound(&self) -> usize {
96 self.element_bound()
97 }
98
99 /// Returns the dense index for `vertex` in this view.
100 fn vertex_index(&self, vertex: Self::ElementId) -> usize {
101 self.element_index(vertex)
102 }
103}
104
105impl<T> VertexIndex for T where T: ElementIndex {}
106
107/// Dense hyperedge-index capability for hypergraph views.
108///
109/// Hypergraph-facing name for [`RelationIndex`].
110pub trait HyperedgeIndex: RelationIndex {
111 /// Returns the exclusive upper bound for hyperedge indexes in this view.
112 fn hyperedge_bound(&self) -> usize {
113 self.relation_bound()
114 }
115
116 /// Returns the dense index for `hyperedge` in this view.
117 fn hyperedge_index(&self, hyperedge: Self::RelationId) -> usize {
118 self.relation_index(hyperedge)
119 }
120}
121
122impl<T> HyperedgeIndex for T where T: RelationIndex {}
123
124/// Dense participant-index capability for hypergraph views with incidences.
125///
126/// Hypergraph-facing name for [`IncidenceIndex`].
127pub trait ParticipantIndex: IncidenceIndex {
128 /// Returns the exclusive upper bound for participant indexes in this view.
129 fn participant_bound(&self) -> usize {
130 self.incidence_bound()
131 }
132
133 /// Returns the dense index for `participant` in this view.
134 fn participant_index(&self, participant: Self::IncidenceId) -> usize {
135 self.incidence_index(participant)
136 }
137}
138
139impl<T> ParticipantIndex for T where T: IncidenceIndex {}
140
141/// Vertex-ID containment capability for hypergraph views.
142///
143/// Hypergraph-facing name for [`ContainsElement`].
144pub trait ContainsVertex: ContainsElement {
145 /// Returns whether `vertex` is valid and visible in this hypergraph view.
146 fn contains_vertex(&self, vertex: Self::ElementId) -> bool {
147 self.contains_element(vertex)
148 }
149}
150
151impl<T> ContainsVertex for T where T: ContainsElement {}
152
153/// Hyperedge-ID containment capability for hypergraph views.
154///
155/// Hypergraph-facing name for [`ContainsRelation`].
156pub trait ContainsHyperedge: ContainsRelation {
157 /// Returns whether `hyperedge` is valid and visible in this hypergraph view.
158 fn contains_hyperedge(&self, hyperedge: Self::RelationId) -> bool {
159 self.contains_relation(hyperedge)
160 }
161}
162
163impl<T> ContainsHyperedge for T where T: ContainsRelation {}
164
165/// Participant-ID containment capability for hypergraph views with incidences.
166///
167/// Hypergraph-facing name for [`ContainsIncidence`].
168pub trait ContainsParticipant: ContainsIncidence {
169 /// Returns whether `participant` is valid and visible in this hypergraph view.
170 fn contains_participant(&self, participant: Self::IncidenceId) -> bool {
171 self.contains_incidence(participant)
172 }
173}
174
175impl<T> ContainsParticipant for T where T: ContainsIncidence {}
176
177/// Capability for traversing participant records attached to one hyperedge.
178///
179/// Hypergraph-facing name for [`RelationIncidences`]; yields raw participant
180/// IDs rather than resolved vertices. Pair with [`HyperedgeParticipants`]
181/// when callers want vertices directly.
182pub trait HyperedgeIncidences: RelationIncidences {
183 /// Iterator over participant IDs attached to one hyperedge.
184 type ParticipantIds<'view>: Iterator<Item = ParticipantId<Self>>
185 where
186 Self: 'view;
187
188 /// Returns participant IDs attached to `hyperedge`.
189 fn hyperedge_incidences(&self, hyperedge: HyperedgeId<Self>) -> Self::ParticipantIds<'_>;
190}
191
192impl<T> HyperedgeIncidences for T
193where
194 T: RelationIncidences,
195{
196 type ParticipantIds<'view>
197 = <T as RelationIncidences>::Incidences<'view>
198 where
199 T: 'view;
200
201 fn hyperedge_incidences(&self, hyperedge: HyperedgeId<Self>) -> Self::ParticipantIds<'_> {
202 <Self as RelationIncidences>::relation_incidences(self, hyperedge)
203 }
204}
205
206/// Capability for traversing participant records attached to one vertex.
207///
208/// Hypergraph-facing name for [`ElementIncidences`]; yields raw participant
209/// IDs rather than resolved hyperedges. Pair with [`IncidentHyperedges`]
210/// when callers want hyperedges directly.
211pub trait VertexIncidences: ElementIncidences {
212 /// Iterator over participant IDs attached to one vertex.
213 type ParticipantIds<'view>: Iterator<Item = ParticipantId<Self>>
214 where
215 Self: 'view;
216
217 /// Returns participant IDs attached to `vertex`.
218 fn vertex_incidences(&self, vertex: VertexId<Self>) -> Self::ParticipantIds<'_>;
219}
220
221impl<T> VertexIncidences for T
222where
223 T: ElementIncidences,
224{
225 type ParticipantIds<'view>
226 = <T as ElementIncidences>::Incidences<'view>
227 where
228 T: 'view;
229
230 fn vertex_incidences(&self, vertex: VertexId<Self>) -> Self::ParticipantIds<'_> {
231 <Self as ElementIncidences>::element_incidences(self, vertex)
232 }
233}
234
235/// Capability for resolving the vertex carried by a participant record.
236///
237/// Hypergraph-facing name for [`IncidenceElement`].
238pub trait ParticipantVertex: IncidenceElement {
239 /// Returns the vertex referenced by `participant`.
240 fn participant_vertex(&self, participant: ParticipantId<Self>) -> VertexId<Self> {
241 self.incidence_element(participant)
242 }
243}
244
245impl<T> ParticipantVertex for T where T: IncidenceElement {}
246
247/// Capability for resolving the hyperedge that carries a participant record.
248///
249/// Hypergraph-facing name for [`IncidenceRelation`].
250pub trait ParticipantHyperedge: IncidenceRelation {
251 /// Returns the hyperedge carrying `participant`.
252 fn participant_hyperedge(&self, participant: ParticipantId<Self>) -> HyperedgeId<Self> {
253 self.incidence_relation(participant)
254 }
255}
256
257impl<T> ParticipantHyperedge for T where T: IncidenceRelation {}
258
259/// Capability for resolving the role recorded for a participant.
260///
261/// Hypergraph-facing name for [`IncidenceRole`]. Trait name
262/// `ParticipantRoleOf` avoids colliding with the existing
263/// [`ParticipantRole`] type alias.
264pub trait ParticipantRoleOf: IncidenceRole {
265 /// Returns the role recorded for `participant`.
266 fn participant_role_of(&self, participant: ParticipantId<Self>) -> ParticipantRole<Self> {
267 self.incidence_role(participant)
268 }
269}
270
271impl<T> ParticipantRoleOf for T where T: IncidenceRole {}
272
273/// Capability for traversing vertices participating in one hyperedge.
274///
275/// Hypergraph-facing form of relation-to-element traversal.
276pub trait HyperedgeParticipants: HyperedgeIncidences + ParticipantVertex {
277 /// Iterator over vertices participating in one hyperedge.
278 type Participants<'view>: Iterator<Item = Self::ElementId>
279 where
280 Self: 'view;
281
282 /// Returns vertices participating in `hyperedge`.
283 fn hyperedge_participants(&self, hyperedge: Self::RelationId) -> Self::Participants<'_>;
284}
285
286/// Capability for traversing hyperedges incident to one vertex.
287///
288/// Hypergraph-facing form of element-to-relation traversal.
289pub trait IncidentHyperedges: VertexIncidences + ParticipantHyperedge {
290 /// Iterator over hyperedges incident to one vertex.
291 type IncidentHyperedges<'view>: Iterator<Item = Self::RelationId>
292 where
293 Self: 'view;
294
295 /// Returns hyperedges incident to `vertex`.
296 fn incident_hyperedges(&self, vertex: Self::ElementId) -> Self::IncidentHyperedges<'_>;
297}
298
299/// Exact hyperedge-participant count capability.
300///
301/// Pairs with [`HyperedgeParticipants`] for backends that can report a
302/// hyperedge's participant count without traversal.
303pub trait HyperedgeParticipantCount: IncidenceBase {
304 /// Returns the number of participants attached to `hyperedge`.
305 fn hyperedge_participant_count(&self, hyperedge: Self::RelationId) -> usize;
306}
307
308/// Exact incident-hyperedge count capability.
309///
310/// Pairs with [`IncidentHyperedges`] for backends that can report a vertex's
311/// incident hyperedge count without traversal.
312pub trait IncidentHyperedgeCount: IncidenceBase {
313 /// Returns the number of hyperedges incident to `vertex`.
314 fn incident_hyperedge_count(&self, vertex: Self::ElementId) -> usize;
315}
316
317/// Capability for traversing directed hyperedge participant sets.
318///
319/// Directed hypergraphs distinguish source-side and target-side participants.
320/// The core does not prescribe how a view stores those sets or whether they
321/// are derived from roles, separate indexes, or generated views.
322pub trait DirectedHyperedgeParticipants: TopologyBase {
323 /// Iterator over source-side participants in one directed hyperedge.
324 type SourceParticipants<'view>: Iterator<Item = Self::ElementId>
325 where
326 Self: 'view;
327
328 /// Iterator over target-side participants in one directed hyperedge.
329 type TargetParticipants<'view>: Iterator<Item = Self::ElementId>
330 where
331 Self: 'view;
332
333 /// Returns source-side participants for `hyperedge`.
334 fn source_participants(&self, hyperedge: Self::RelationId) -> Self::SourceParticipants<'_>;
335
336 /// Returns target-side participants for `hyperedge`.
337 fn target_participants(&self, hyperedge: Self::RelationId) -> Self::TargetParticipants<'_>;
338}
339
340/// Capability for traversing directed participant incidence IDs.
341///
342/// Incidence-ID counterpart to [`DirectedHyperedgeParticipants`]. Algorithms
343/// that need incidence weights bind on this trait so they can choose target
344/// participants by incidence ID without adding weighted expansion traits to
345/// topology.
346pub trait DirectedHyperedgeIncidences: IncidenceBase {
347 /// Iterator over source-side participant incidence IDs.
348 type SourceIncidences<'view>: Iterator<Item = Self::IncidenceId>
349 where
350 Self: 'view;
351
352 /// Iterator over target-side participant incidence IDs.
353 type TargetIncidences<'view>: Iterator<Item = Self::IncidenceId>
354 where
355 Self: 'view;
356
357 /// Returns source-side participant incidence IDs for `hyperedge`.
358 fn source_incidences(&self, hyperedge: Self::RelationId) -> Self::SourceIncidences<'_>;
359
360 /// Returns target-side participant incidence IDs for `hyperedge`.
361 fn target_incidences(&self, hyperedge: Self::RelationId) -> Self::TargetIncidences<'_>;
362}
363
364/// Capability for traversing source/target hyperedges incident to a vertex.
365///
366/// Relation-level directed expansion, distinct from successor-vertex
367/// expansion. Directed traversal consumers can use source-to-relation
368/// transitions before relation-to-target expansion.
369pub trait DirectedVertexHyperedges: TopologyBase {
370 /// Iterator over hyperedges where the vertex is source-side.
371 type OutgoingHyperedges<'view>: Iterator<Item = Self::RelationId>
372 where
373 Self: 'view;
374
375 /// Iterator over hyperedges where the vertex is target-side.
376 type IncomingHyperedges<'view>: Iterator<Item = Self::RelationId>
377 where
378 Self: 'view;
379
380 /// Returns hyperedges where `vertex` participates on the source side.
381 fn outgoing_hyperedges(&self, vertex: Self::ElementId) -> Self::OutgoingHyperedges<'_>;
382
383 /// Returns hyperedges where `vertex` participates on the target side.
384 fn incoming_hyperedges(&self, vertex: Self::ElementId) -> Self::IncomingHyperedges<'_>;
385}
386
387/// Capability for expanding a directed hypergraph vertex to successor vertices.
388///
389/// Hypergraph-facing name for [`ElementSuccessors`]. A successor vertex is a
390/// target-side participant reachable through a directed hyperedge where the
391/// input vertex participates on the source side. The associated iterator GAT
392/// is named `VertexSuccessors` to avoid colliding with the inherited
393/// `ElementSuccessors::Successors` GAT.
394pub trait DirectedVertexSuccessors: ElementSuccessors {
395 /// Iterator over successor vertices reachable from one source-side vertex.
396 type VertexSuccessors<'view>: Iterator<Item = VertexId<Self>>
397 where
398 Self: 'view;
399
400 /// Returns target-side vertices reachable from `vertex`.
401 fn successor_vertices(&self, vertex: VertexId<Self>) -> Self::VertexSuccessors<'_>;
402}
403
404impl<T> DirectedVertexSuccessors for T
405where
406 T: ElementSuccessors,
407{
408 type VertexSuccessors<'view>
409 = <T as ElementSuccessors>::Successors<'view>
410 where
411 T: 'view;
412
413 fn successor_vertices(&self, vertex: VertexId<Self>) -> Self::VertexSuccessors<'_> {
414 <Self as ElementSuccessors>::element_successors(self, vertex)
415 }
416}
417
418/// Capability for expanding a directed hypergraph vertex to predecessor vertices.
419///
420/// Hypergraph-facing name for [`ElementPredecessors`]. A predecessor vertex
421/// is a source-side participant reachable through a directed hyperedge where
422/// the input vertex participates on the target side. The associated iterator
423/// GAT is named `VertexPredecessors` to avoid colliding with the inherited
424/// `ElementPredecessors::Predecessors` GAT.
425pub trait DirectedVertexPredecessors: ElementPredecessors {
426 /// Iterator over predecessor vertices reaching one target-side vertex.
427 type VertexPredecessors<'view>: Iterator<Item = VertexId<Self>>
428 where
429 Self: 'view;
430
431 /// Returns source-side vertices that can reach `vertex`.
432 fn predecessor_vertices(&self, vertex: VertexId<Self>) -> Self::VertexPredecessors<'_>;
433}
434
435impl<T> DirectedVertexPredecessors for T
436where
437 T: ElementPredecessors,
438{
439 type VertexPredecessors<'view>
440 = <T as ElementPredecessors>::Predecessors<'view>
441 where
442 T: 'view;
443
444 fn predecessor_vertices(&self, vertex: VertexId<Self>) -> Self::VertexPredecessors<'_> {
445 <Self as ElementPredecessors>::element_predecessors(self, vertex)
446 }
447}
448
449/// Convenience marker bundling hyperedge participants and incident hyperedges.
450pub trait Hypergraph: HyperedgeParticipants + IncidentHyperedges {}
451
452impl<T> Hypergraph for T where T: HyperedgeParticipants + IncidentHyperedges {}
453
454/// Convenience marker for complete directed hypergraph traversal.
455///
456/// Bundles hyperedge-side traversal ([`Hypergraph`]), source/target
457/// participant separation ([`DirectedHyperedgeParticipants`]), and
458/// bidirectional vertex-to-vertex traversal ([`DirectedVertexSuccessors`] +
459/// [`DirectedVertexPredecessors`]).
460pub trait DirectedHypergraph:
461 Hypergraph
462 + DirectedHyperedgeParticipants
463 + DirectedHyperedgeIncidences
464 + DirectedVertexHyperedges
465 + DirectedVertexSuccessors
466 + DirectedVertexPredecessors
467{
468}
469
470impl<T> DirectedHypergraph for T where
471 T: Hypergraph
472 + DirectedHyperedgeParticipants
473 + DirectedHyperedgeIncidences
474 + DirectedVertexHyperedges
475 + DirectedVertexSuccessors
476 + DirectedVertexPredecessors
477{
478}