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, DenseElementIndex, DenseIncidenceIndex,
28 DenseRelationIndex, ElementIncidenceCount, ElementIncidences, ElementPredecessors,
29 ElementSuccessors, ElementWeight, IncidenceBase, IncidenceCounts, IncidenceElement,
30 IncidenceRelation, IncidenceRole, IncidenceWeight, LocalElementIdentity,
31 LocalIncidenceIdentity, LocalRelationIdentity, RelationIncidenceCount, RelationIncidences,
32 RelationWeight, TopologyBase, 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
78impl<T> HypergraphCounts for T where T: TopologyCounts {}
79
80/// Participant-record count capability for hypergraph views.
81///
82/// Hypergraph-facing name for [`IncidenceCounts`].
83pub trait ParticipantCounts: IncidenceCounts {
84 /// Returns the total number of participant records visible in this view.
85 fn participant_count(&self) -> usize {
86 self.incidence_count()
87 }
88}
89
90impl<T> ParticipantCounts for T where T: IncidenceCounts {}
91
92/// Dense vertex-index capability for hypergraph views.
93///
94/// Hypergraph-facing name for [`DenseElementIndex`].
95pub trait DenseVertexIndex: DenseElementIndex {
96 /// Returns the exclusive upper bound for vertex indexes in this view.
97 fn vertex_bound(&self) -> usize {
98 self.element_bound()
99 }
100
101 /// Returns the dense index for `vertex` in this view.
102 fn vertex_index(&self, vertex: Self::ElementId) -> usize {
103 self.element_index(vertex)
104 }
105}
106
107impl<T> DenseVertexIndex for T where T: DenseElementIndex {}
108
109/// Dense hyperedge-index capability for hypergraph views.
110///
111/// Hypergraph-facing name for [`DenseRelationIndex`].
112pub trait DenseHyperedgeIndex: DenseRelationIndex {
113 /// Returns the exclusive upper bound for hyperedge indexes in this view.
114 fn hyperedge_bound(&self) -> usize {
115 self.relation_bound()
116 }
117
118 /// Returns the dense index for `hyperedge` in this view.
119 fn hyperedge_index(&self, hyperedge: Self::RelationId) -> usize {
120 self.relation_index(hyperedge)
121 }
122}
123
124impl<T> DenseHyperedgeIndex for T where T: DenseRelationIndex {}
125
126/// Dense participant-index capability for hypergraph views with incidences.
127///
128/// Hypergraph-facing name for [`DenseIncidenceIndex`].
129pub trait DenseParticipantIndex: DenseIncidenceIndex {
130 /// Returns the exclusive upper bound for participant indexes in this view.
131 fn participant_bound(&self) -> usize {
132 self.incidence_bound()
133 }
134
135 /// Returns the dense index for `participant` in this view.
136 fn participant_index(&self, participant: Self::IncidenceId) -> usize {
137 self.incidence_index(participant)
138 }
139}
140
141impl<T> DenseParticipantIndex for T where T: DenseIncidenceIndex {}
142
143/// Vertex-ID containment capability for hypergraph views.
144///
145/// Hypergraph-facing name for [`ContainsElement`].
146pub trait ContainsVertex: ContainsElement {
147 /// Returns whether `vertex` is valid and visible in this hypergraph view.
148 fn contains_vertex(&self, vertex: Self::ElementId) -> bool {
149 self.contains_element(vertex)
150 }
151}
152
153impl<T> ContainsVertex for T where T: ContainsElement {}
154
155/// Hyperedge-ID containment capability for hypergraph views.
156///
157/// Hypergraph-facing name for [`ContainsRelation`].
158pub trait ContainsHyperedge: ContainsRelation {
159 /// Returns whether `hyperedge` is valid and visible in this hypergraph view.
160 fn contains_hyperedge(&self, hyperedge: Self::RelationId) -> bool {
161 self.contains_relation(hyperedge)
162 }
163}
164
165impl<T> ContainsHyperedge for T where T: ContainsRelation {}
166
167/// Participant-ID containment capability for hypergraph views with incidences.
168///
169/// Hypergraph-facing name for [`ContainsIncidence`].
170pub trait ContainsParticipant: ContainsIncidence {
171 /// Returns whether `participant` is valid and visible in this hypergraph view.
172 fn contains_participant(&self, participant: Self::IncidenceId) -> bool {
173 self.contains_incidence(participant)
174 }
175}
176
177impl<T> ContainsParticipant for T where T: ContainsIncidence {}
178
179/// Capability for traversing participant records attached to one hyperedge.
180///
181/// Hypergraph-facing name for [`RelationIncidences`]; yields raw participant
182/// IDs rather than resolved vertices. Pair with [`HyperedgeParticipants`]
183/// when callers want vertices directly.
184pub trait HyperedgeIncidences: RelationIncidences {
185 /// Iterator over participant IDs attached to one hyperedge.
186 type ParticipantIds<'view>: Iterator<Item = ParticipantId<Self>>
187 where
188 Self: 'view;
189
190 /// Returns participant IDs attached to `hyperedge`.
191 fn hyperedge_incidences(&self, hyperedge: HyperedgeId<Self>) -> Self::ParticipantIds<'_>;
192}
193
194impl<T> HyperedgeIncidences for T
195where
196 T: RelationIncidences,
197{
198 type ParticipantIds<'view>
199 = <T as RelationIncidences>::Incidences<'view>
200 where
201 T: 'view;
202
203 fn hyperedge_incidences(&self, hyperedge: HyperedgeId<Self>) -> Self::ParticipantIds<'_> {
204 <Self as RelationIncidences>::relation_incidences(self, hyperedge)
205 }
206}
207
208/// Capability for traversing participant records attached to one vertex.
209///
210/// Hypergraph-facing name for [`ElementIncidences`]; yields raw participant
211/// IDs rather than resolved hyperedges. Pair with [`IncidentHyperedges`]
212/// when callers want hyperedges directly.
213pub trait VertexIncidences: ElementIncidences {
214 /// Iterator over participant IDs attached to one vertex.
215 type ParticipantIds<'view>: Iterator<Item = ParticipantId<Self>>
216 where
217 Self: 'view;
218
219 /// Returns participant IDs attached to `vertex`.
220 fn vertex_incidences(&self, vertex: VertexId<Self>) -> Self::ParticipantIds<'_>;
221}
222
223impl<T> VertexIncidences for T
224where
225 T: ElementIncidences,
226{
227 type ParticipantIds<'view>
228 = <T as ElementIncidences>::Incidences<'view>
229 where
230 T: 'view;
231
232 fn vertex_incidences(&self, vertex: VertexId<Self>) -> Self::ParticipantIds<'_> {
233 <Self as ElementIncidences>::element_incidences(self, vertex)
234 }
235}
236
237/// Capability for resolving the vertex carried by a participant record.
238///
239/// Hypergraph-facing name for [`IncidenceElement`].
240pub trait ParticipantVertex: IncidenceElement {
241 /// Returns the vertex referenced by `participant`.
242 fn participant_vertex(&self, participant: ParticipantId<Self>) -> VertexId<Self> {
243 self.incidence_element(participant)
244 }
245}
246
247impl<T> ParticipantVertex for T where T: IncidenceElement {}
248
249/// Capability for resolving the hyperedge that carries a participant record.
250///
251/// Hypergraph-facing name for [`IncidenceRelation`].
252pub trait ParticipantHyperedge: IncidenceRelation {
253 /// Returns the hyperedge carrying `participant`.
254 fn participant_hyperedge(&self, participant: ParticipantId<Self>) -> HyperedgeId<Self> {
255 self.incidence_relation(participant)
256 }
257}
258
259impl<T> ParticipantHyperedge for T where T: IncidenceRelation {}
260
261/// Capability for resolving the role recorded for a participant.
262///
263/// Hypergraph-facing name for [`IncidenceRole`]. Trait name
264/// `ParticipantRoleOf` avoids colliding with the existing
265/// [`ParticipantRole`] type alias.
266pub trait ParticipantRoleOf: IncidenceRole {
267 /// Returns the role recorded for `participant`.
268 fn participant_role_of(&self, participant: ParticipantId<Self>) -> ParticipantRole<Self> {
269 self.incidence_role(participant)
270 }
271}
272
273impl<T> ParticipantRoleOf for T where T: IncidenceRole {}
274
275/// Capability for traversing vertices participating in one hyperedge.
276///
277/// Hypergraph-facing form of relation-to-element traversal.
278pub trait HyperedgeParticipants: HyperedgeIncidences + ParticipantVertex {
279 /// Iterator over vertices participating in one hyperedge.
280 type Participants<'view>: Iterator<Item = Self::ElementId>
281 where
282 Self: 'view;
283
284 /// Returns vertices participating in `hyperedge`.
285 fn hyperedge_participants(&self, hyperedge: Self::RelationId) -> Self::Participants<'_>;
286}
287
288/// Capability for traversing hyperedges incident to one vertex.
289///
290/// Hypergraph-facing form of element-to-relation traversal.
291pub trait IncidentHyperedges: VertexIncidences + ParticipantHyperedge {
292 /// Iterator over hyperedges incident to one vertex.
293 type IncidentHyperedges<'view>: Iterator<Item = Self::RelationId>
294 where
295 Self: 'view;
296
297 /// Returns hyperedges incident to `vertex`.
298 fn incident_hyperedges(&self, vertex: Self::ElementId) -> Self::IncidentHyperedges<'_>;
299}
300
301/// Exact hyperedge-participant count capability.
302///
303/// Hypergraph-facing name for [`RelationIncidenceCount`]: a hyperedge's
304/// participant count is its relation's incidence count. The default body and
305/// blanket impl mean any [`RelationIncidenceCount`] backend gets this vocabulary
306/// name for free, matching the [`ParticipantCounts`]/[`HypergraphCounts`]
307/// pattern; backends implement only the topology count trait once.
308pub trait HyperedgeParticipantCount: RelationIncidenceCount {
309 /// Returns the number of participants attached to `hyperedge`.
310 fn hyperedge_participant_count(&self, hyperedge: Self::RelationId) -> usize {
311 self.relation_incidence_count(hyperedge)
312 }
313}
314
315impl<T> HyperedgeParticipantCount for T where T: RelationIncidenceCount {}
316
317/// Exact incident-hyperedge count capability.
318///
319/// Hypergraph-facing name for [`ElementIncidenceCount`]: a vertex's incident
320/// hyperedge count is its element's incidence count. Provided by default body
321/// and blanket impl, mirroring [`HyperedgeParticipantCount`].
322pub trait IncidentHyperedgeCount: ElementIncidenceCount {
323 /// Returns the number of hyperedges incident to `vertex`.
324 fn incident_hyperedge_count(&self, vertex: Self::ElementId) -> usize {
325 self.element_incidence_count(vertex)
326 }
327}
328
329impl<T> IncidentHyperedgeCount for T where T: ElementIncidenceCount {}
330
331/// Capability for traversing directed hyperedge participant sets.
332///
333/// Directed hypergraphs distinguish source-side and target-side participants.
334/// The core does not prescribe how a view stores those sets or whether they
335/// are derived from roles, separate indexes, or generated views.
336pub trait DirectedHyperedgeParticipants: TopologyBase {
337 /// Iterator over source-side participants in one directed hyperedge.
338 type SourceParticipants<'view>: Iterator<Item = Self::ElementId>
339 where
340 Self: 'view;
341
342 /// Iterator over target-side participants in one directed hyperedge.
343 type TargetParticipants<'view>: Iterator<Item = Self::ElementId>
344 where
345 Self: 'view;
346
347 /// Returns source-side participants for `hyperedge`.
348 fn source_participants(&self, hyperedge: Self::RelationId) -> Self::SourceParticipants<'_>;
349
350 /// Returns target-side participants for `hyperedge`.
351 fn target_participants(&self, hyperedge: Self::RelationId) -> Self::TargetParticipants<'_>;
352}
353
354/// Capability for traversing directed participant incidence IDs.
355///
356/// Incidence-ID counterpart to [`DirectedHyperedgeParticipants`]. Algorithms
357/// that need incidence weights bind on this trait so they can choose target
358/// participants by incidence ID without adding weighted expansion traits to
359/// topology.
360pub trait DirectedHyperedgeIncidences: IncidenceBase {
361 /// Iterator over source-side participant incidence IDs.
362 type SourceIncidences<'view>: Iterator<Item = Self::IncidenceId>
363 where
364 Self: 'view;
365
366 /// Iterator over target-side participant incidence IDs.
367 type TargetIncidences<'view>: Iterator<Item = Self::IncidenceId>
368 where
369 Self: 'view;
370
371 /// Returns source-side participant incidence IDs for `hyperedge`.
372 fn source_incidences(&self, hyperedge: Self::RelationId) -> Self::SourceIncidences<'_>;
373
374 /// Returns target-side participant incidence IDs for `hyperedge`.
375 fn target_incidences(&self, hyperedge: Self::RelationId) -> Self::TargetIncidences<'_>;
376}
377
378/// Capability for traversing source/target hyperedges incident to a vertex.
379///
380/// Relation-level directed expansion, distinct from successor-vertex
381/// expansion. Directed traversal consumers can use source-to-relation
382/// transitions before relation-to-target expansion.
383pub trait DirectedVertexHyperedges: TopologyBase {
384 /// Iterator over hyperedges where the vertex is source-side.
385 type OutgoingHyperedges<'view>: Iterator<Item = Self::RelationId>
386 where
387 Self: 'view;
388
389 /// Iterator over hyperedges where the vertex is target-side.
390 type IncomingHyperedges<'view>: Iterator<Item = Self::RelationId>
391 where
392 Self: 'view;
393
394 /// Returns hyperedges where `vertex` participates on the source side.
395 fn outgoing_hyperedges(&self, vertex: Self::ElementId) -> Self::OutgoingHyperedges<'_>;
396
397 /// Returns hyperedges where `vertex` participates on the target side.
398 fn incoming_hyperedges(&self, vertex: Self::ElementId) -> Self::IncomingHyperedges<'_>;
399}
400
401/// Capability for expanding a directed hypergraph vertex to successor vertices.
402///
403/// Hypergraph-facing name for [`ElementSuccessors`]. A successor vertex is a
404/// target-side participant reachable through a directed hyperedge where the
405/// input vertex participates on the source side. The associated iterator GAT
406/// is named `VertexSuccessors` to avoid colliding with the inherited
407/// `ElementSuccessors::Successors` GAT.
408pub trait DirectedVertexSuccessors: ElementSuccessors {
409 /// Iterator over successor vertices reachable from one source-side vertex.
410 type VertexSuccessors<'view>: Iterator<Item = VertexId<Self>>
411 where
412 Self: 'view;
413
414 /// Returns target-side vertices reachable from `vertex`.
415 fn successor_vertices(&self, vertex: VertexId<Self>) -> Self::VertexSuccessors<'_>;
416}
417
418impl<T> DirectedVertexSuccessors for T
419where
420 T: ElementSuccessors,
421{
422 type VertexSuccessors<'view>
423 = <T as ElementSuccessors>::Successors<'view>
424 where
425 T: 'view;
426
427 fn successor_vertices(&self, vertex: VertexId<Self>) -> Self::VertexSuccessors<'_> {
428 <Self as ElementSuccessors>::element_successors(self, vertex)
429 }
430}
431
432/// Capability for expanding a directed hypergraph vertex to predecessor vertices.
433///
434/// Hypergraph-facing name for [`ElementPredecessors`]. A predecessor vertex
435/// is a source-side participant reachable through a directed hyperedge where
436/// the input vertex participates on the target side. The associated iterator
437/// GAT is named `VertexPredecessors` to avoid colliding with the inherited
438/// `ElementPredecessors::Predecessors` GAT.
439pub trait DirectedVertexPredecessors: ElementPredecessors {
440 /// Iterator over predecessor vertices reaching one target-side vertex.
441 type VertexPredecessors<'view>: Iterator<Item = VertexId<Self>>
442 where
443 Self: 'view;
444
445 /// Returns source-side vertices that can reach `vertex`.
446 fn predecessor_vertices(&self, vertex: VertexId<Self>) -> Self::VertexPredecessors<'_>;
447}
448
449impl<T> DirectedVertexPredecessors for T
450where
451 T: ElementPredecessors,
452{
453 type VertexPredecessors<'view>
454 = <T as ElementPredecessors>::Predecessors<'view>
455 where
456 T: 'view;
457
458 fn predecessor_vertices(&self, vertex: VertexId<Self>) -> Self::VertexPredecessors<'_> {
459 <Self as ElementPredecessors>::element_predecessors(self, vertex)
460 }
461}
462
463/// Convenience marker bundling hyperedge participants and incident hyperedges.
464pub trait Hypergraph: HyperedgeParticipants + IncidentHyperedges {}
465
466impl<T> Hypergraph for T where T: HyperedgeParticipants + IncidentHyperedges {}
467
468/// Convenience marker for complete directed hypergraph traversal.
469///
470/// Bundles hyperedge-side traversal ([`Hypergraph`]), source/target
471/// participant separation ([`DirectedHyperedgeParticipants`]), and
472/// bidirectional vertex-to-vertex traversal ([`DirectedVertexSuccessors`] +
473/// [`DirectedVertexPredecessors`]).
474pub trait DirectedHypergraph:
475 Hypergraph
476 + DirectedHyperedgeParticipants
477 + DirectedHyperedgeIncidences
478 + DirectedVertexHyperedges
479 + DirectedVertexSuccessors
480 + DirectedVertexPredecessors
481{
482}
483
484impl<T> DirectedHypergraph for T where
485 T: Hypergraph
486 + DirectedHyperedgeParticipants
487 + DirectedHyperedgeIncidences
488 + DirectedVertexHyperedges
489 + DirectedVertexSuccessors
490 + DirectedVertexPredecessors
491{
492}