1use oxgraph_hyper::{
6 ContainsElement, ContainsIncidence, ContainsRelation, DenseElementIndex, DenseIncidenceIndex,
7 DenseRelationIndex, DirectedHyperedgeIncidences, DirectedHyperedgeParticipants,
8 DirectedVertexHyperedges, ElementIncidenceCount, ElementIncidences, ElementPredecessors,
9 ElementSuccessors, HyperedgeParticipants, IncidenceBase, IncidenceCounts, IncidenceElement,
10 IncidenceRelation, IncidenceRole, IncidentHyperedges, RelationIncidenceCount,
11 RelationIncidences, TopologyBase, TopologyCounts,
12};
13
14use crate::{
15 id::{BcsrHyperedgeId, BcsrParticipantId, BcsrRole, BcsrVertexId},
16 internal::{
17 iter::{
18 BcsrChainedHyperedges, BcsrChainedParticipants, BcsrChainedRelationIncidences,
19 BcsrElementIncidences, BcsrHyperedgeSlice, BcsrParticipantSlice,
20 BcsrPredecessorVertices, BcsrSuccessorVertices, BcsrVertexSlice,
21 },
22 validation::{index_to_usize_validated, usize_to_index_validated},
23 view::BcsrHypergraph,
24 },
25 word::{BcsrWords, LayoutIndex, LayoutWord},
26};
27
28impl<'view, W: BcsrWords> BcsrHypergraph<'view, W> {
36 pub(crate) fn detached_element_incidences(
43 self,
44 element: BcsrVertexId<W::VertexIndex>,
45 ) -> BcsrElementIncidences<'view, W::OffsetWord, W::VertexWord, W::RelationWord> {
46 let sections = self.sections();
47 let counts = self.counts();
48 let v_index = index_to_usize_validated(element.get());
49 let outgoing = vertex_bucket(
50 sections.vertex_outgoing_offsets,
51 sections.vertex_outgoing_hyperedges,
52 v_index,
53 );
54 let incoming = vertex_bucket(
55 sections.vertex_incoming_offsets,
56 sections.vertex_incoming_hyperedges,
57 v_index,
58 );
59 BcsrElementIncidences::new(v_index, counts.p_outgoing, outgoing, incoming, sections)
60 }
61
62 pub(crate) fn detached_hyperedge_participants(
68 self,
69 hyperedge: BcsrHyperedgeId<W::RelationIndex>,
70 ) -> BcsrChainedParticipants<'view, W::VertexWord> {
71 let sections = self.sections();
72 let h_index = index_to_usize_validated(hyperedge.get());
73 let head = vertex_bucket(sections.head_offsets, sections.head_participants, h_index);
74 let tail = vertex_bucket(sections.tail_offsets, sections.tail_participants, h_index);
75 BcsrVertexSlice::new(head).chain(BcsrVertexSlice::new(tail))
76 }
77
78 pub(crate) fn detached_incident_hyperedges(
84 self,
85 vertex: BcsrVertexId<W::VertexIndex>,
86 ) -> BcsrChainedHyperedges<'view, W::RelationWord> {
87 let sections = self.sections();
88 let v_index = index_to_usize_validated(vertex.get());
89 let outgoing = vertex_bucket(
90 sections.vertex_outgoing_offsets,
91 sections.vertex_outgoing_hyperedges,
92 v_index,
93 );
94 let incoming = vertex_bucket(
95 sections.vertex_incoming_offsets,
96 sections.vertex_incoming_hyperedges,
97 v_index,
98 );
99 BcsrHyperedgeSlice::new(outgoing).chain(BcsrHyperedgeSlice::new(incoming))
100 }
101
102 pub(crate) fn detached_source_participants(
108 self,
109 hyperedge: BcsrHyperedgeId<W::RelationIndex>,
110 ) -> BcsrVertexSlice<'view, W::VertexWord> {
111 let sections = self.sections();
112 let h_index = index_to_usize_validated(hyperedge.get());
113 let head = vertex_bucket(sections.head_offsets, sections.head_participants, h_index);
114 BcsrVertexSlice::new(head)
115 }
116
117 pub(crate) fn detached_target_participants(
123 self,
124 hyperedge: BcsrHyperedgeId<W::RelationIndex>,
125 ) -> BcsrVertexSlice<'view, W::VertexWord> {
126 let sections = self.sections();
127 let h_index = index_to_usize_validated(hyperedge.get());
128 let tail = vertex_bucket(sections.tail_offsets, sections.tail_participants, h_index);
129 BcsrVertexSlice::new(tail)
130 }
131
132 pub(crate) fn detached_outgoing_hyperedges(
138 self,
139 vertex: BcsrVertexId<W::VertexIndex>,
140 ) -> BcsrHyperedgeSlice<'view, W::RelationWord> {
141 let sections = self.sections();
142 let v_index = index_to_usize_validated(vertex.get());
143 let outgoing = vertex_bucket(
144 sections.vertex_outgoing_offsets,
145 sections.vertex_outgoing_hyperedges,
146 v_index,
147 );
148 BcsrHyperedgeSlice::new(outgoing)
149 }
150
151 pub(crate) fn detached_incoming_hyperedges(
157 self,
158 vertex: BcsrVertexId<W::VertexIndex>,
159 ) -> BcsrHyperedgeSlice<'view, W::RelationWord> {
160 let sections = self.sections();
161 let v_index = index_to_usize_validated(vertex.get());
162 let incoming = vertex_bucket(
163 sections.vertex_incoming_offsets,
164 sections.vertex_incoming_hyperedges,
165 v_index,
166 );
167 BcsrHyperedgeSlice::new(incoming)
168 }
169
170 pub(crate) fn detached_element_successors(
176 self,
177 vertex: BcsrVertexId<W::VertexIndex>,
178 ) -> BcsrSuccessorVertices<'view, W::RelationWord, W::OffsetWord, W::VertexWord> {
179 let sections = self.sections();
180 let v_index = index_to_usize_validated(vertex.get());
181 let outgoing = vertex_bucket(
182 sections.vertex_outgoing_offsets,
183 sections.vertex_outgoing_hyperedges,
184 v_index,
185 );
186 BcsrSuccessorVertices::new(outgoing, sections.tail_offsets, sections.tail_participants)
187 }
188
189 pub(crate) fn detached_element_predecessors(
195 self,
196 vertex: BcsrVertexId<W::VertexIndex>,
197 ) -> BcsrPredecessorVertices<'view, W::RelationWord, W::OffsetWord, W::VertexWord> {
198 let sections = self.sections();
199 let v_index = index_to_usize_validated(vertex.get());
200 let incoming = vertex_bucket(
201 sections.vertex_incoming_offsets,
202 sections.vertex_incoming_hyperedges,
203 v_index,
204 );
205 BcsrPredecessorVertices::new(incoming, sections.head_offsets, sections.head_participants)
206 }
207}
208
209impl<W: BcsrWords> TopologyBase for BcsrHypergraph<'_, W> {
210 type ElementId = BcsrVertexId<W::VertexIndex>;
211 type RelationId = BcsrHyperedgeId<W::RelationIndex>;
212}
213
214impl<W: BcsrWords> IncidenceBase for BcsrHypergraph<'_, W> {
215 type IncidenceId = BcsrParticipantId<W::IncidenceIndex>;
216 type Role = BcsrRole;
217}
218
219impl<W: BcsrWords> TopologyCounts for BcsrHypergraph<'_, W> {
220 fn element_count(&self) -> usize {
221 self.vertex_count()
222 }
223
224 fn relation_count(&self) -> usize {
225 self.hyperedge_count()
226 }
227}
228
229impl<W: BcsrWords> IncidenceCounts for BcsrHypergraph<'_, W> {
230 fn incidence_count(&self) -> usize {
231 self.counts().total_incidences
232 }
233}
234
235impl<W: BcsrWords> DenseElementIndex for BcsrHypergraph<'_, W> {
236 fn element_bound(&self) -> usize {
237 self.vertex_count()
238 }
239
240 fn element_index(&self, element: BcsrVertexId<W::VertexIndex>) -> usize {
241 index_to_usize_validated(element.get())
242 }
243}
244
245impl<W: BcsrWords> DenseRelationIndex for BcsrHypergraph<'_, W> {
246 fn relation_bound(&self) -> usize {
247 self.hyperedge_count()
248 }
249
250 fn relation_index(&self, relation: BcsrHyperedgeId<W::RelationIndex>) -> usize {
251 index_to_usize_validated(relation.get())
252 }
253}
254
255impl<W: BcsrWords> DenseIncidenceIndex for BcsrHypergraph<'_, W> {
256 fn incidence_bound(&self) -> usize {
257 self.counts().total_incidences
258 }
259
260 fn incidence_index(&self, incidence: BcsrParticipantId<W::IncidenceIndex>) -> usize {
261 index_to_usize_validated(incidence.get())
262 }
263}
264
265impl<W: BcsrWords> ContainsElement for BcsrHypergraph<'_, W> {
266 fn contains_element(&self, element: BcsrVertexId<W::VertexIndex>) -> bool {
267 index_to_usize_validated(element.get()) < self.counts().vertex_count
268 }
269}
270
271impl<W: BcsrWords> ContainsRelation for BcsrHypergraph<'_, W> {
272 fn contains_relation(&self, relation: BcsrHyperedgeId<W::RelationIndex>) -> bool {
273 index_to_usize_validated(relation.get()) < self.counts().hyperedge_count
274 }
275}
276
277impl<W: BcsrWords> ContainsIncidence for BcsrHypergraph<'_, W> {
278 fn contains_incidence(&self, incidence: BcsrParticipantId<W::IncidenceIndex>) -> bool {
279 index_to_usize_validated(incidence.get()) < self.counts().total_incidences
280 }
281}
282
283impl<W: BcsrWords> IncidenceElement for BcsrHypergraph<'_, W> {
284 fn incidence_element(
285 &self,
286 incidence: BcsrParticipantId<W::IncidenceIndex>,
287 ) -> BcsrVertexId<W::VertexIndex> {
288 let incidence_index = index_to_usize_validated(incidence.get());
289 let counts = self.counts();
290 let sections = self.sections();
291 if incidence_index < counts.p_outgoing {
292 BcsrVertexId::new(sections.head_participants[incidence_index].get())
293 } else {
294 let position = incidence_index - counts.p_outgoing;
295 BcsrVertexId::new(sections.tail_participants[position].get())
296 }
297 }
298}
299
300impl<W: BcsrWords> IncidenceRelation for BcsrHypergraph<'_, W> {
301 fn incidence_relation(
302 &self,
303 incidence: BcsrParticipantId<W::IncidenceIndex>,
304 ) -> BcsrHyperedgeId<W::RelationIndex> {
305 let incidence_index = index_to_usize_validated(incidence.get());
306 let counts = self.counts();
307 let sections = self.sections();
308 if incidence_index < counts.p_outgoing {
309 BcsrHyperedgeId::new(locate_owning_bucket(sections.head_offsets, incidence_index))
310 } else {
311 let position = incidence_index - counts.p_outgoing;
312 BcsrHyperedgeId::new(locate_owning_bucket(sections.tail_offsets, position))
313 }
314 }
315}
316
317impl<W: BcsrWords> IncidenceRole for BcsrHypergraph<'_, W> {
318 fn incidence_role(&self, incidence: BcsrParticipantId<W::IncidenceIndex>) -> BcsrRole {
319 if index_to_usize_validated(incidence.get()) < self.counts().p_outgoing {
320 BcsrRole::Head
321 } else {
322 BcsrRole::Tail
323 }
324 }
325}
326
327impl<W: BcsrWords> RelationIncidences for BcsrHypergraph<'_, W> {
328 type Incidences<'view>
329 = BcsrChainedRelationIncidences<W::IncidenceIndex>
330 where
331 Self: 'view;
332
333 fn relation_incidences(
334 &self,
335 relation: BcsrHyperedgeId<W::RelationIndex>,
336 ) -> Self::Incidences<'_> {
337 let sections = self.sections();
338 let p_outgoing = self.counts().p_outgoing;
339 let h_index = index_to_usize_validated(relation.get());
340 let head_start = index_to_usize_validated(sections.head_offsets[h_index].get());
341 let head_end = index_to_usize_validated(sections.head_offsets[h_index + 1].get());
342 let tail_start = index_to_usize_validated(sections.tail_offsets[h_index].get());
343 let tail_end = index_to_usize_validated(sections.tail_offsets[h_index + 1].get());
344 BcsrParticipantSlice::new(head_start, head_end, 0)
345 .chain(BcsrParticipantSlice::new(tail_start, tail_end, p_outgoing))
346 }
347}
348
349impl<W: BcsrWords> ElementIncidences for BcsrHypergraph<'_, W> {
350 type Incidences<'view>
351 = BcsrElementIncidences<'view, W::OffsetWord, W::VertexWord, W::RelationWord>
352 where
353 Self: 'view;
354
355 fn element_incidences(&self, element: BcsrVertexId<W::VertexIndex>) -> Self::Incidences<'_> {
356 self.detached_element_incidences(element)
357 }
358}
359
360impl<W: BcsrWords> RelationIncidenceCount for BcsrHypergraph<'_, W> {
361 fn relation_incidence_count(&self, relation: BcsrHyperedgeId<W::RelationIndex>) -> usize {
362 let sections = self.sections();
363 let h_index = index_to_usize_validated(relation.get());
364 let head_size = index_to_usize_validated(sections.head_offsets[h_index + 1].get())
365 - index_to_usize_validated(sections.head_offsets[h_index].get());
366 let tail_size = index_to_usize_validated(sections.tail_offsets[h_index + 1].get())
367 - index_to_usize_validated(sections.tail_offsets[h_index].get());
368 head_size + tail_size
369 }
370}
371
372impl<W: BcsrWords> ElementIncidenceCount for BcsrHypergraph<'_, W> {
373 fn element_incidence_count(&self, element: BcsrVertexId<W::VertexIndex>) -> usize {
374 let sections = self.sections();
375 let v_index = index_to_usize_validated(element.get());
376 let out_size =
377 index_to_usize_validated(sections.vertex_outgoing_offsets[v_index + 1].get())
378 - index_to_usize_validated(sections.vertex_outgoing_offsets[v_index].get());
379 let in_size = index_to_usize_validated(sections.vertex_incoming_offsets[v_index + 1].get())
380 - index_to_usize_validated(sections.vertex_incoming_offsets[v_index].get());
381 out_size + in_size
382 }
383}
384
385impl<W: BcsrWords> HyperedgeParticipants for BcsrHypergraph<'_, W> {
390 type Participants<'view>
391 = BcsrChainedParticipants<'view, W::VertexWord>
392 where
393 Self: 'view;
394
395 fn hyperedge_participants(
396 &self,
397 hyperedge: BcsrHyperedgeId<W::RelationIndex>,
398 ) -> Self::Participants<'_> {
399 self.detached_hyperedge_participants(hyperedge)
400 }
401}
402
403impl<W: BcsrWords> IncidentHyperedges for BcsrHypergraph<'_, W> {
404 type IncidentHyperedges<'view>
405 = BcsrChainedHyperedges<'view, W::RelationWord>
406 where
407 Self: 'view;
408
409 fn incident_hyperedges(
410 &self,
411 vertex: BcsrVertexId<W::VertexIndex>,
412 ) -> Self::IncidentHyperedges<'_> {
413 self.detached_incident_hyperedges(vertex)
414 }
415}
416
417impl<W: BcsrWords> DirectedHyperedgeParticipants for BcsrHypergraph<'_, W> {
418 type SourceParticipants<'view>
419 = BcsrVertexSlice<'view, W::VertexWord>
420 where
421 Self: 'view;
422
423 type TargetParticipants<'view>
424 = BcsrVertexSlice<'view, W::VertexWord>
425 where
426 Self: 'view;
427
428 fn source_participants(
429 &self,
430 hyperedge: BcsrHyperedgeId<W::RelationIndex>,
431 ) -> Self::SourceParticipants<'_> {
432 self.detached_source_participants(hyperedge)
433 }
434
435 fn target_participants(
436 &self,
437 hyperedge: BcsrHyperedgeId<W::RelationIndex>,
438 ) -> Self::TargetParticipants<'_> {
439 self.detached_target_participants(hyperedge)
440 }
441}
442
443impl<W: BcsrWords> DirectedHyperedgeIncidences for BcsrHypergraph<'_, W> {
444 type SourceIncidences<'view>
445 = BcsrParticipantSlice<W::IncidenceIndex>
446 where
447 Self: 'view;
448
449 type TargetIncidences<'view>
450 = BcsrParticipantSlice<W::IncidenceIndex>
451 where
452 Self: 'view;
453
454 fn source_incidences(
455 &self,
456 hyperedge: BcsrHyperedgeId<W::RelationIndex>,
457 ) -> Self::SourceIncidences<'_> {
458 let sections = self.sections();
459 let h_index = index_to_usize_validated(hyperedge.get());
460 let head_start = index_to_usize_validated(sections.head_offsets[h_index].get());
461 let head_end = index_to_usize_validated(sections.head_offsets[h_index + 1].get());
462 BcsrParticipantSlice::new(head_start, head_end, 0)
463 }
464
465 fn target_incidences(
466 &self,
467 hyperedge: BcsrHyperedgeId<W::RelationIndex>,
468 ) -> Self::TargetIncidences<'_> {
469 let sections = self.sections();
470 let h_index = index_to_usize_validated(hyperedge.get());
471 let tail_start = index_to_usize_validated(sections.tail_offsets[h_index].get());
472 let tail_end = index_to_usize_validated(sections.tail_offsets[h_index + 1].get());
473 BcsrParticipantSlice::new(tail_start, tail_end, self.counts().p_outgoing)
474 }
475}
476
477impl<W: BcsrWords> DirectedVertexHyperedges for BcsrHypergraph<'_, W> {
478 type OutgoingHyperedges<'view>
479 = BcsrHyperedgeSlice<'view, W::RelationWord>
480 where
481 Self: 'view;
482
483 type IncomingHyperedges<'view>
484 = BcsrHyperedgeSlice<'view, W::RelationWord>
485 where
486 Self: 'view;
487
488 fn outgoing_hyperedges(
489 &self,
490 vertex: BcsrVertexId<W::VertexIndex>,
491 ) -> Self::OutgoingHyperedges<'_> {
492 self.detached_outgoing_hyperedges(vertex)
493 }
494
495 fn incoming_hyperedges(
496 &self,
497 vertex: BcsrVertexId<W::VertexIndex>,
498 ) -> Self::IncomingHyperedges<'_> {
499 self.detached_incoming_hyperedges(vertex)
500 }
501}
502
503impl<W: BcsrWords> ElementSuccessors for BcsrHypergraph<'_, W> {
504 type Successors<'view>
505 = BcsrSuccessorVertices<'view, W::RelationWord, W::OffsetWord, W::VertexWord>
506 where
507 Self: 'view;
508
509 fn element_successors(&self, vertex: BcsrVertexId<W::VertexIndex>) -> Self::Successors<'_> {
510 self.detached_element_successors(vertex)
511 }
512}
513
514impl<W: BcsrWords> ElementPredecessors for BcsrHypergraph<'_, W> {
515 type Predecessors<'view>
516 = BcsrPredecessorVertices<'view, W::RelationWord, W::OffsetWord, W::VertexWord>
517 where
518 Self: 'view;
519
520 fn element_predecessors(&self, vertex: BcsrVertexId<W::VertexIndex>) -> Self::Predecessors<'_> {
521 self.detached_element_predecessors(vertex)
522 }
523}
524
525fn vertex_bucket<'view, OffsetWord, ValueWord>(
527 offsets: &'view [OffsetWord],
528 values: &'view [ValueWord],
529 index: usize,
530) -> &'view [ValueWord]
531where
532 OffsetWord: LayoutWord,
533{
534 let start = index_to_usize_validated(offsets[index].get());
535 let end = index_to_usize_validated(offsets[index + 1].get());
536 &values[start..end]
537}
538
539fn locate_owning_bucket<OffsetWord, RelationIndex>(
542 offsets: &[OffsetWord],
543 target: usize,
544) -> RelationIndex
545where
546 OffsetWord: LayoutWord,
547 RelationIndex: LayoutIndex,
548{
549 let mut low = 0_usize;
550 let mut high = offsets.len() - 1;
551 while low + 1 < high {
552 let mid = low + (high - low) / 2;
553 if index_to_usize_validated(offsets[mid].get()) <= target {
554 low = mid;
555 } else {
556 high = mid;
557 }
558 }
559 usize_to_index_validated(low)
560}