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/// Hypergraph-facing name for [`RelationIncidenceCount`]: a hyperedge's
302/// participant count is its relation's incidence count. The default body and
303/// blanket impl mean any [`RelationIncidenceCount`] backend gets this vocabulary
304/// name for free, matching the [`ParticipantCounts`]/[`HypergraphCounts`]
305/// pattern; backends implement only the topology count trait once.
306pub trait HyperedgeParticipantCount: RelationIncidenceCount {
307 /// Returns the number of participants attached to `hyperedge`.
308 fn hyperedge_participant_count(&self, hyperedge: Self::RelationId) -> usize {
309 self.relation_incidence_count(hyperedge)
310 }
311}
312
313impl<T> HyperedgeParticipantCount for T where T: RelationIncidenceCount {}
314
315/// Exact incident-hyperedge count capability.
316///
317/// Hypergraph-facing name for [`ElementIncidenceCount`]: a vertex's incident
318/// hyperedge count is its element's incidence count. Provided by default body
319/// and blanket impl, mirroring [`HyperedgeParticipantCount`].
320pub trait IncidentHyperedgeCount: ElementIncidenceCount {
321 /// Returns the number of hyperedges incident to `vertex`.
322 fn incident_hyperedge_count(&self, vertex: Self::ElementId) -> usize {
323 self.element_incidence_count(vertex)
324 }
325}
326
327impl<T> IncidentHyperedgeCount for T where T: ElementIncidenceCount {}
328
329/// Capability for traversing directed hyperedge participant sets.
330///
331/// Directed hypergraphs distinguish source-side and target-side participants.
332/// The core does not prescribe how a view stores those sets or whether they
333/// are derived from roles, separate indexes, or generated views.
334pub trait DirectedHyperedgeParticipants: TopologyBase {
335 /// Iterator over source-side participants in one directed hyperedge.
336 type SourceParticipants<'view>: Iterator<Item = Self::ElementId>
337 where
338 Self: 'view;
339
340 /// Iterator over target-side participants in one directed hyperedge.
341 type TargetParticipants<'view>: Iterator<Item = Self::ElementId>
342 where
343 Self: 'view;
344
345 /// Returns source-side participants for `hyperedge`.
346 fn source_participants(&self, hyperedge: Self::RelationId) -> Self::SourceParticipants<'_>;
347
348 /// Returns target-side participants for `hyperedge`.
349 fn target_participants(&self, hyperedge: Self::RelationId) -> Self::TargetParticipants<'_>;
350}
351
352/// Capability for traversing directed participant incidence IDs.
353///
354/// Incidence-ID counterpart to [`DirectedHyperedgeParticipants`]. Algorithms
355/// that need incidence weights bind on this trait so they can choose target
356/// participants by incidence ID without adding weighted expansion traits to
357/// topology.
358pub trait DirectedHyperedgeIncidences: IncidenceBase {
359 /// Iterator over source-side participant incidence IDs.
360 type SourceIncidences<'view>: Iterator<Item = Self::IncidenceId>
361 where
362 Self: 'view;
363
364 /// Iterator over target-side participant incidence IDs.
365 type TargetIncidences<'view>: Iterator<Item = Self::IncidenceId>
366 where
367 Self: 'view;
368
369 /// Returns source-side participant incidence IDs for `hyperedge`.
370 fn source_incidences(&self, hyperedge: Self::RelationId) -> Self::SourceIncidences<'_>;
371
372 /// Returns target-side participant incidence IDs for `hyperedge`.
373 fn target_incidences(&self, hyperedge: Self::RelationId) -> Self::TargetIncidences<'_>;
374}
375
376/// Capability for traversing source/target hyperedges incident to a vertex.
377///
378/// Relation-level directed expansion, distinct from successor-vertex
379/// expansion. Directed traversal consumers can use source-to-relation
380/// transitions before relation-to-target expansion.
381pub trait DirectedVertexHyperedges: TopologyBase {
382 /// Iterator over hyperedges where the vertex is source-side.
383 type OutgoingHyperedges<'view>: Iterator<Item = Self::RelationId>
384 where
385 Self: 'view;
386
387 /// Iterator over hyperedges where the vertex is target-side.
388 type IncomingHyperedges<'view>: Iterator<Item = Self::RelationId>
389 where
390 Self: 'view;
391
392 /// Returns hyperedges where `vertex` participates on the source side.
393 fn outgoing_hyperedges(&self, vertex: Self::ElementId) -> Self::OutgoingHyperedges<'_>;
394
395 /// Returns hyperedges where `vertex` participates on the target side.
396 fn incoming_hyperedges(&self, vertex: Self::ElementId) -> Self::IncomingHyperedges<'_>;
397}
398
399/// Capability for expanding a directed hypergraph vertex to successor vertices.
400///
401/// Hypergraph-facing name for [`ElementSuccessors`]. A successor vertex is a
402/// target-side participant reachable through a directed hyperedge where the
403/// input vertex participates on the source side. The associated iterator GAT
404/// is named `VertexSuccessors` to avoid colliding with the inherited
405/// `ElementSuccessors::Successors` GAT.
406pub trait DirectedVertexSuccessors: ElementSuccessors {
407 /// Iterator over successor vertices reachable from one source-side vertex.
408 type VertexSuccessors<'view>: Iterator<Item = VertexId<Self>>
409 where
410 Self: 'view;
411
412 /// Returns target-side vertices reachable from `vertex`.
413 fn successor_vertices(&self, vertex: VertexId<Self>) -> Self::VertexSuccessors<'_>;
414}
415
416impl<T> DirectedVertexSuccessors for T
417where
418 T: ElementSuccessors,
419{
420 type VertexSuccessors<'view>
421 = <T as ElementSuccessors>::Successors<'view>
422 where
423 T: 'view;
424
425 fn successor_vertices(&self, vertex: VertexId<Self>) -> Self::VertexSuccessors<'_> {
426 <Self as ElementSuccessors>::element_successors(self, vertex)
427 }
428}
429
430/// Capability for expanding a directed hypergraph vertex to predecessor vertices.
431///
432/// Hypergraph-facing name for [`ElementPredecessors`]. A predecessor vertex
433/// is a source-side participant reachable through a directed hyperedge where
434/// the input vertex participates on the target side. The associated iterator
435/// GAT is named `VertexPredecessors` to avoid colliding with the inherited
436/// `ElementPredecessors::Predecessors` GAT.
437pub trait DirectedVertexPredecessors: ElementPredecessors {
438 /// Iterator over predecessor vertices reaching one target-side vertex.
439 type VertexPredecessors<'view>: Iterator<Item = VertexId<Self>>
440 where
441 Self: 'view;
442
443 /// Returns source-side vertices that can reach `vertex`.
444 fn predecessor_vertices(&self, vertex: VertexId<Self>) -> Self::VertexPredecessors<'_>;
445}
446
447impl<T> DirectedVertexPredecessors for T
448where
449 T: ElementPredecessors,
450{
451 type VertexPredecessors<'view>
452 = <T as ElementPredecessors>::Predecessors<'view>
453 where
454 T: 'view;
455
456 fn predecessor_vertices(&self, vertex: VertexId<Self>) -> Self::VertexPredecessors<'_> {
457 <Self as ElementPredecessors>::element_predecessors(self, vertex)
458 }
459}
460
461/// Convenience marker bundling hyperedge participants and incident hyperedges.
462pub trait Hypergraph: HyperedgeParticipants + IncidentHyperedges {}
463
464impl<T> Hypergraph for T where T: HyperedgeParticipants + IncidentHyperedges {}
465
466/// Convenience marker for complete directed hypergraph traversal.
467///
468/// Bundles hyperedge-side traversal ([`Hypergraph`]), source/target
469/// participant separation ([`DirectedHyperedgeParticipants`]), and
470/// bidirectional vertex-to-vertex traversal ([`DirectedVertexSuccessors`] +
471/// [`DirectedVertexPredecessors`]).
472pub trait DirectedHypergraph:
473 Hypergraph
474 + DirectedHyperedgeParticipants
475 + DirectedHyperedgeIncidences
476 + DirectedVertexHyperedges
477 + DirectedVertexSuccessors
478 + DirectedVertexPredecessors
479{
480}
481
482impl<T> DirectedHypergraph for T where
483 T: Hypergraph
484 + DirectedHyperedgeParticipants
485 + DirectedHyperedgeIncidences
486 + DirectedVertexHyperedges
487 + DirectedVertexSuccessors
488 + DirectedVertexPredecessors
489{
490}