Skip to main content

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}