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, 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}