1use oxgraph_hyper::{
6 ContainsElement, ContainsIncidence, ContainsRelation, DirectedHyperedgeIncidences,
7 DirectedHyperedgeParticipants, DirectedVertexHyperedges, ElementIncidenceCount,
8 ElementIncidences, ElementIndex, ElementPredecessors, ElementSuccessors,
9 HyperedgeParticipantCount, HyperedgeParticipants, HypergraphCounts, IncidenceBase,
10 IncidenceCounts, IncidenceElement, IncidenceIndex, IncidenceRelation, IncidenceRole,
11 IncidentHyperedgeCount, IncidentHyperedges, RelationIncidenceCount, RelationIncidences,
12 RelationIndex, TopologyBase, TopologyCounts,
13};
14
15use crate::{
16 id::{BcsrHyperedgeId, BcsrParticipantId, BcsrRole, BcsrVertexId},
17 internal::{
18 iter::{
19 BcsrChainedHyperedges, BcsrChainedParticipants, BcsrChainedRelationIncidences,
20 BcsrElementIncidences, BcsrHyperedgeSlice, BcsrParticipantSlice,
21 BcsrPredecessorVertices, BcsrSuccessorVertices, BcsrVertexSlice,
22 },
23 validation::{index_to_usize_validated, usize_to_index_validated},
24 view::BcsrHypergraph,
25 },
26 word::{BcsrIndex, BcsrWord},
27};
28
29type View<'a, V, R, I, O, VW, RW> = BcsrHypergraph<'a, V, R, I, O, VW, RW>;
31
32impl<V, R, I, O, VW, RW> TopologyBase for View<'_, V, R, I, O, VW, RW>
33where
34 V: BcsrIndex,
35 R: BcsrIndex,
36 I: BcsrIndex,
37 O: BcsrWord<Index = I>,
38 VW: BcsrWord<Index = V>,
39 RW: BcsrWord<Index = R>,
40{
41 type ElementId = BcsrVertexId<V>;
42 type RelationId = BcsrHyperedgeId<R>;
43}
44
45impl<V, R, I, O, VW, RW> IncidenceBase for View<'_, V, R, I, O, VW, RW>
46where
47 V: BcsrIndex,
48 R: BcsrIndex,
49 I: BcsrIndex,
50 O: BcsrWord<Index = I>,
51 VW: BcsrWord<Index = V>,
52 RW: BcsrWord<Index = R>,
53{
54 type IncidenceId = BcsrParticipantId<I>;
55 type Role = BcsrRole;
56}
57
58impl<V, R, I, O, VW, RW> TopologyCounts for View<'_, V, R, I, O, VW, RW>
59where
60 V: BcsrIndex,
61 R: BcsrIndex,
62 I: BcsrIndex,
63 O: BcsrWord<Index = I>,
64 VW: BcsrWord<Index = V>,
65 RW: BcsrWord<Index = R>,
66{
67 fn element_count(&self) -> usize {
68 self.vertex_count()
69 }
70
71 fn relation_count(&self) -> usize {
72 self.hyperedge_count()
73 }
74}
75
76impl<V, R, I, O, VW, RW> IncidenceCounts for View<'_, V, R, I, O, VW, RW>
77where
78 V: BcsrIndex,
79 R: BcsrIndex,
80 I: BcsrIndex,
81 O: BcsrWord<Index = I>,
82 VW: BcsrWord<Index = V>,
83 RW: BcsrWord<Index = R>,
84{
85 fn incidence_count(&self) -> usize {
86 self.counts().total_incidences
87 }
88}
89
90impl<V, R, I, O, VW, RW> HypergraphCounts for View<'_, V, R, I, O, VW, RW>
91where
92 V: BcsrIndex,
93 R: BcsrIndex,
94 I: BcsrIndex,
95 O: BcsrWord<Index = I>,
96 VW: BcsrWord<Index = V>,
97 RW: BcsrWord<Index = R>,
98{
99}
100
101impl<V, R, I, O, VW, RW> ElementIndex for View<'_, V, R, I, O, VW, RW>
102where
103 V: BcsrIndex,
104 R: BcsrIndex,
105 I: BcsrIndex,
106 O: BcsrWord<Index = I>,
107 VW: BcsrWord<Index = V>,
108 RW: BcsrWord<Index = R>,
109{
110 fn element_bound(&self) -> usize {
111 self.vertex_count()
112 }
113
114 fn element_index(&self, element: BcsrVertexId<V>) -> usize {
115 index_to_usize_validated(element.0)
116 }
117}
118
119impl<V, R, I, O, VW, RW> RelationIndex for View<'_, V, R, I, O, VW, RW>
120where
121 V: BcsrIndex,
122 R: BcsrIndex,
123 I: BcsrIndex,
124 O: BcsrWord<Index = I>,
125 VW: BcsrWord<Index = V>,
126 RW: BcsrWord<Index = R>,
127{
128 fn relation_bound(&self) -> usize {
129 self.hyperedge_count()
130 }
131
132 fn relation_index(&self, relation: BcsrHyperedgeId<R>) -> usize {
133 index_to_usize_validated(relation.0)
134 }
135}
136
137impl<V, R, I, O, VW, RW> IncidenceIndex for View<'_, V, R, I, O, VW, RW>
138where
139 V: BcsrIndex,
140 R: BcsrIndex,
141 I: BcsrIndex,
142 O: BcsrWord<Index = I>,
143 VW: BcsrWord<Index = V>,
144 RW: BcsrWord<Index = R>,
145{
146 fn incidence_bound(&self) -> usize {
147 self.counts().total_incidences
148 }
149
150 fn incidence_index(&self, incidence: BcsrParticipantId<I>) -> usize {
151 index_to_usize_validated(incidence.0)
152 }
153}
154
155impl<V, R, I, O, VW, RW> ContainsElement for View<'_, V, R, I, O, VW, RW>
156where
157 V: BcsrIndex,
158 R: BcsrIndex,
159 I: BcsrIndex,
160 O: BcsrWord<Index = I>,
161 VW: BcsrWord<Index = V>,
162 RW: BcsrWord<Index = R>,
163{
164 fn contains_element(&self, element: BcsrVertexId<V>) -> bool {
165 index_to_usize_validated(element.0) < self.counts().vertex_count
166 }
167}
168
169impl<V, R, I, O, VW, RW> ContainsRelation for View<'_, V, R, I, O, VW, RW>
170where
171 V: BcsrIndex,
172 R: BcsrIndex,
173 I: BcsrIndex,
174 O: BcsrWord<Index = I>,
175 VW: BcsrWord<Index = V>,
176 RW: BcsrWord<Index = R>,
177{
178 fn contains_relation(&self, relation: BcsrHyperedgeId<R>) -> bool {
179 index_to_usize_validated(relation.0) < self.counts().hyperedge_count
180 }
181}
182
183impl<V, R, I, O, VW, RW> ContainsIncidence for View<'_, V, R, I, O, VW, RW>
184where
185 V: BcsrIndex,
186 R: BcsrIndex,
187 I: BcsrIndex,
188 O: BcsrWord<Index = I>,
189 VW: BcsrWord<Index = V>,
190 RW: BcsrWord<Index = R>,
191{
192 fn contains_incidence(&self, incidence: BcsrParticipantId<I>) -> bool {
193 index_to_usize_validated(incidence.0) < self.counts().total_incidences
194 }
195}
196
197impl<V, R, I, O, VW, RW> IncidenceElement for View<'_, V, R, I, O, VW, RW>
198where
199 V: BcsrIndex,
200 R: BcsrIndex,
201 I: BcsrIndex,
202 O: BcsrWord<Index = I>,
203 VW: BcsrWord<Index = V>,
204 RW: BcsrWord<Index = R>,
205{
206 fn incidence_element(&self, incidence: BcsrParticipantId<I>) -> BcsrVertexId<V> {
207 let incidence_index = index_to_usize_validated(incidence.0);
208 let counts = self.counts();
209 let sections = self.sections();
210 if incidence_index < counts.p_outgoing {
211 BcsrVertexId(sections.head_participants[incidence_index].get())
212 } else {
213 let position = incidence_index - counts.p_outgoing;
214 BcsrVertexId(sections.tail_participants[position].get())
215 }
216 }
217}
218
219impl<V, R, I, O, VW, RW> IncidenceRelation for View<'_, V, R, I, O, VW, RW>
220where
221 V: BcsrIndex,
222 R: BcsrIndex,
223 I: BcsrIndex,
224 O: BcsrWord<Index = I>,
225 VW: BcsrWord<Index = V>,
226 RW: BcsrWord<Index = R>,
227{
228 fn incidence_relation(&self, incidence: BcsrParticipantId<I>) -> BcsrHyperedgeId<R> {
229 let incidence_index = index_to_usize_validated(incidence.0);
230 let counts = self.counts();
231 let sections = self.sections();
232 if incidence_index < counts.p_outgoing {
233 BcsrHyperedgeId(locate_owning_bucket(sections.head_offsets, incidence_index))
234 } else {
235 let position = incidence_index - counts.p_outgoing;
236 BcsrHyperedgeId(locate_owning_bucket(sections.tail_offsets, position))
237 }
238 }
239}
240
241impl<V, R, I, O, VW, RW> IncidenceRole for View<'_, V, R, I, O, VW, RW>
242where
243 V: BcsrIndex,
244 R: BcsrIndex,
245 I: BcsrIndex,
246 O: BcsrWord<Index = I>,
247 VW: BcsrWord<Index = V>,
248 RW: BcsrWord<Index = R>,
249{
250 fn incidence_role(&self, incidence: BcsrParticipantId<I>) -> BcsrRole {
251 if index_to_usize_validated(incidence.0) < self.counts().p_outgoing {
252 BcsrRole::Head
253 } else {
254 BcsrRole::Tail
255 }
256 }
257}
258
259impl<V, R, I, O, VW, RW> RelationIncidences for View<'_, V, R, I, O, VW, RW>
260where
261 V: BcsrIndex,
262 R: BcsrIndex,
263 I: BcsrIndex,
264 O: BcsrWord<Index = I>,
265 VW: BcsrWord<Index = V>,
266 RW: BcsrWord<Index = R>,
267{
268 type Incidences<'view>
269 = BcsrChainedRelationIncidences<I>
270 where
271 Self: 'view;
272
273 fn relation_incidences(&self, relation: BcsrHyperedgeId<R>) -> Self::Incidences<'_> {
274 let sections = self.sections();
275 let p_outgoing = self.counts().p_outgoing;
276 let h_index = index_to_usize_validated(relation.0);
277 let head_start = index_to_usize_validated(sections.head_offsets[h_index].get());
278 let head_end = index_to_usize_validated(sections.head_offsets[h_index + 1].get());
279 let tail_start = index_to_usize_validated(sections.tail_offsets[h_index].get());
280 let tail_end = index_to_usize_validated(sections.tail_offsets[h_index + 1].get());
281 BcsrParticipantSlice::new(head_start, head_end, 0)
282 .chain(BcsrParticipantSlice::new(tail_start, tail_end, p_outgoing))
283 }
284}
285
286impl<V, R, I, O, VW, RW> ElementIncidences for View<'_, V, R, I, O, VW, RW>
287where
288 V: BcsrIndex,
289 R: BcsrIndex,
290 I: BcsrIndex,
291 O: BcsrWord<Index = I>,
292 VW: BcsrWord<Index = V>,
293 RW: BcsrWord<Index = R>,
294{
295 type Incidences<'view>
296 = BcsrElementIncidences<'view, O, VW, RW>
297 where
298 Self: 'view;
299
300 fn element_incidences(&self, element: BcsrVertexId<V>) -> Self::Incidences<'_> {
301 let sections = self.sections();
302 let counts = self.counts();
303 let v_index = index_to_usize_validated(element.0);
304 let outgoing = vertex_bucket(
305 sections.vertex_outgoing_offsets,
306 sections.vertex_outgoing_hyperedges,
307 v_index,
308 );
309 let incoming = vertex_bucket(
310 sections.vertex_incoming_offsets,
311 sections.vertex_incoming_hyperedges,
312 v_index,
313 );
314 BcsrElementIncidences::new(v_index, counts.p_outgoing, outgoing, incoming, sections)
315 }
316}
317
318impl<V, R, I, O, VW, RW> RelationIncidenceCount for View<'_, V, R, I, O, VW, RW>
319where
320 V: BcsrIndex,
321 R: BcsrIndex,
322 I: BcsrIndex,
323 O: BcsrWord<Index = I>,
324 VW: BcsrWord<Index = V>,
325 RW: BcsrWord<Index = R>,
326{
327 fn relation_incidence_count(&self, relation: BcsrHyperedgeId<R>) -> usize {
328 let sections = self.sections();
329 let h_index = index_to_usize_validated(relation.0);
330 let head_size = index_to_usize_validated(sections.head_offsets[h_index + 1].get())
331 - index_to_usize_validated(sections.head_offsets[h_index].get());
332 let tail_size = index_to_usize_validated(sections.tail_offsets[h_index + 1].get())
333 - index_to_usize_validated(sections.tail_offsets[h_index].get());
334 head_size + tail_size
335 }
336}
337
338impl<V, R, I, O, VW, RW> ElementIncidenceCount for View<'_, V, R, I, O, VW, RW>
339where
340 V: BcsrIndex,
341 R: BcsrIndex,
342 I: BcsrIndex,
343 O: BcsrWord<Index = I>,
344 VW: BcsrWord<Index = V>,
345 RW: BcsrWord<Index = R>,
346{
347 fn element_incidence_count(&self, element: BcsrVertexId<V>) -> usize {
348 let sections = self.sections();
349 let v_index = index_to_usize_validated(element.0);
350 let out_size =
351 index_to_usize_validated(sections.vertex_outgoing_offsets[v_index + 1].get())
352 - index_to_usize_validated(sections.vertex_outgoing_offsets[v_index].get());
353 let in_size = index_to_usize_validated(sections.vertex_incoming_offsets[v_index + 1].get())
354 - index_to_usize_validated(sections.vertex_incoming_offsets[v_index].get());
355 out_size + in_size
356 }
357}
358
359impl<V, R, I, O, VW, RW> HyperedgeParticipantCount for View<'_, V, R, I, O, VW, RW>
360where
361 V: BcsrIndex,
362 R: BcsrIndex,
363 I: BcsrIndex,
364 O: BcsrWord<Index = I>,
365 VW: BcsrWord<Index = V>,
366 RW: BcsrWord<Index = R>,
367{
368 fn hyperedge_participant_count(&self, hyperedge: BcsrHyperedgeId<R>) -> usize {
369 self.relation_incidence_count(hyperedge)
370 }
371}
372
373impl<V, R, I, O, VW, RW> IncidentHyperedgeCount for View<'_, V, R, I, O, VW, RW>
374where
375 V: BcsrIndex,
376 R: BcsrIndex,
377 I: BcsrIndex,
378 O: BcsrWord<Index = I>,
379 VW: BcsrWord<Index = V>,
380 RW: BcsrWord<Index = R>,
381{
382 fn incident_hyperedge_count(&self, vertex: BcsrVertexId<V>) -> usize {
383 self.element_incidence_count(vertex)
384 }
385}
386
387impl<V, R, I, O, VW, RW> HyperedgeParticipants for View<'_, V, R, I, O, VW, RW>
388where
389 V: BcsrIndex,
390 R: BcsrIndex,
391 I: BcsrIndex,
392 O: BcsrWord<Index = I>,
393 VW: BcsrWord<Index = V>,
394 RW: BcsrWord<Index = R>,
395{
396 type Participants<'view>
397 = BcsrChainedParticipants<'view, VW>
398 where
399 Self: 'view;
400
401 fn hyperedge_participants(&self, hyperedge: BcsrHyperedgeId<R>) -> Self::Participants<'_> {
402 let sections = self.sections();
403 let h_index = index_to_usize_validated(hyperedge.0);
404 let head = vertex_bucket(sections.head_offsets, sections.head_participants, h_index);
405 let tail = vertex_bucket(sections.tail_offsets, sections.tail_participants, h_index);
406 BcsrVertexSlice::new(head).chain(BcsrVertexSlice::new(tail))
407 }
408}
409
410impl<V, R, I, O, VW, RW> IncidentHyperedges for View<'_, V, R, I, O, VW, RW>
411where
412 V: BcsrIndex,
413 R: BcsrIndex,
414 I: BcsrIndex,
415 O: BcsrWord<Index = I>,
416 VW: BcsrWord<Index = V>,
417 RW: BcsrWord<Index = R>,
418{
419 type IncidentHyperedges<'view>
420 = BcsrChainedHyperedges<'view, RW>
421 where
422 Self: 'view;
423
424 fn incident_hyperedges(&self, vertex: BcsrVertexId<V>) -> Self::IncidentHyperedges<'_> {
425 let sections = self.sections();
426 let v_index = index_to_usize_validated(vertex.0);
427 let outgoing = vertex_bucket(
428 sections.vertex_outgoing_offsets,
429 sections.vertex_outgoing_hyperedges,
430 v_index,
431 );
432 let incoming = vertex_bucket(
433 sections.vertex_incoming_offsets,
434 sections.vertex_incoming_hyperedges,
435 v_index,
436 );
437 BcsrHyperedgeSlice::new(outgoing).chain(BcsrHyperedgeSlice::new(incoming))
438 }
439}
440
441impl<V, R, I, O, VW, RW> DirectedHyperedgeParticipants for View<'_, V, R, I, O, VW, RW>
442where
443 V: BcsrIndex,
444 R: BcsrIndex,
445 I: BcsrIndex,
446 O: BcsrWord<Index = I>,
447 VW: BcsrWord<Index = V>,
448 RW: BcsrWord<Index = R>,
449{
450 type SourceParticipants<'view>
451 = BcsrVertexSlice<'view, VW>
452 where
453 Self: 'view;
454
455 type TargetParticipants<'view>
456 = BcsrVertexSlice<'view, VW>
457 where
458 Self: 'view;
459
460 fn source_participants(&self, hyperedge: BcsrHyperedgeId<R>) -> Self::SourceParticipants<'_> {
461 let sections = self.sections();
462 let h_index = index_to_usize_validated(hyperedge.0);
463 let head = vertex_bucket(sections.head_offsets, sections.head_participants, h_index);
464 BcsrVertexSlice::new(head)
465 }
466
467 fn target_participants(&self, hyperedge: BcsrHyperedgeId<R>) -> Self::TargetParticipants<'_> {
468 let sections = self.sections();
469 let h_index = index_to_usize_validated(hyperedge.0);
470 let tail = vertex_bucket(sections.tail_offsets, sections.tail_participants, h_index);
471 BcsrVertexSlice::new(tail)
472 }
473}
474
475impl<V, R, I, O, VW, RW> DirectedHyperedgeIncidences for View<'_, V, R, I, O, VW, RW>
476where
477 V: BcsrIndex,
478 R: BcsrIndex,
479 I: BcsrIndex,
480 O: BcsrWord<Index = I>,
481 VW: BcsrWord<Index = V>,
482 RW: BcsrWord<Index = R>,
483{
484 type SourceIncidences<'view>
485 = BcsrParticipantSlice<I>
486 where
487 Self: 'view;
488
489 type TargetIncidences<'view>
490 = BcsrParticipantSlice<I>
491 where
492 Self: 'view;
493
494 fn source_incidences(&self, hyperedge: BcsrHyperedgeId<R>) -> Self::SourceIncidences<'_> {
495 let sections = self.sections();
496 let h_index = index_to_usize_validated(hyperedge.0);
497 let head_start = index_to_usize_validated(sections.head_offsets[h_index].get());
498 let head_end = index_to_usize_validated(sections.head_offsets[h_index + 1].get());
499 BcsrParticipantSlice::new(head_start, head_end, 0)
500 }
501
502 fn target_incidences(&self, hyperedge: BcsrHyperedgeId<R>) -> Self::TargetIncidences<'_> {
503 let sections = self.sections();
504 let h_index = index_to_usize_validated(hyperedge.0);
505 let tail_start = index_to_usize_validated(sections.tail_offsets[h_index].get());
506 let tail_end = index_to_usize_validated(sections.tail_offsets[h_index + 1].get());
507 BcsrParticipantSlice::new(tail_start, tail_end, self.counts().p_outgoing)
508 }
509}
510
511impl<V, R, I, O, VW, RW> DirectedVertexHyperedges for View<'_, V, R, I, O, VW, RW>
512where
513 V: BcsrIndex,
514 R: BcsrIndex,
515 I: BcsrIndex,
516 O: BcsrWord<Index = I>,
517 VW: BcsrWord<Index = V>,
518 RW: BcsrWord<Index = R>,
519{
520 type OutgoingHyperedges<'view>
521 = BcsrHyperedgeSlice<'view, RW>
522 where
523 Self: 'view;
524
525 type IncomingHyperedges<'view>
526 = BcsrHyperedgeSlice<'view, RW>
527 where
528 Self: 'view;
529
530 fn outgoing_hyperedges(&self, vertex: BcsrVertexId<V>) -> Self::OutgoingHyperedges<'_> {
531 let sections = self.sections();
532 let v_index = index_to_usize_validated(vertex.0);
533 let outgoing = vertex_bucket(
534 sections.vertex_outgoing_offsets,
535 sections.vertex_outgoing_hyperedges,
536 v_index,
537 );
538 BcsrHyperedgeSlice::new(outgoing)
539 }
540
541 fn incoming_hyperedges(&self, vertex: BcsrVertexId<V>) -> Self::IncomingHyperedges<'_> {
542 let sections = self.sections();
543 let v_index = index_to_usize_validated(vertex.0);
544 let incoming = vertex_bucket(
545 sections.vertex_incoming_offsets,
546 sections.vertex_incoming_hyperedges,
547 v_index,
548 );
549 BcsrHyperedgeSlice::new(incoming)
550 }
551}
552
553impl<V, R, I, O, VW, RW> ElementSuccessors for View<'_, V, R, I, O, VW, RW>
554where
555 V: BcsrIndex,
556 R: BcsrIndex,
557 I: BcsrIndex,
558 O: BcsrWord<Index = I>,
559 VW: BcsrWord<Index = V>,
560 RW: BcsrWord<Index = R>,
561{
562 type Successors<'view>
563 = BcsrSuccessorVertices<'view, RW, O, VW>
564 where
565 Self: 'view;
566
567 fn element_successors(&self, vertex: BcsrVertexId<V>) -> Self::Successors<'_> {
568 let sections = self.sections();
569 let v_index = index_to_usize_validated(vertex.0);
570 let outgoing = vertex_bucket(
571 sections.vertex_outgoing_offsets,
572 sections.vertex_outgoing_hyperedges,
573 v_index,
574 );
575 BcsrSuccessorVertices::new(outgoing, sections.tail_offsets, sections.tail_participants)
576 }
577}
578
579impl<V, R, I, O, VW, RW> ElementPredecessors for View<'_, V, R, I, O, VW, RW>
580where
581 V: BcsrIndex,
582 R: BcsrIndex,
583 I: BcsrIndex,
584 O: BcsrWord<Index = I>,
585 VW: BcsrWord<Index = V>,
586 RW: BcsrWord<Index = R>,
587{
588 type Predecessors<'view>
589 = BcsrPredecessorVertices<'view, RW, O, VW>
590 where
591 Self: 'view;
592
593 fn element_predecessors(&self, vertex: BcsrVertexId<V>) -> Self::Predecessors<'_> {
594 let sections = self.sections();
595 let v_index = index_to_usize_validated(vertex.0);
596 let incoming = vertex_bucket(
597 sections.vertex_incoming_offsets,
598 sections.vertex_incoming_hyperedges,
599 v_index,
600 );
601 BcsrPredecessorVertices::new(incoming, sections.head_offsets, sections.head_participants)
602 }
603}
604
605fn vertex_bucket<'view, OffsetWord, ValueWord>(
607 offsets: &'view [OffsetWord],
608 values: &'view [ValueWord],
609 index: usize,
610) -> &'view [ValueWord]
611where
612 OffsetWord: BcsrWord,
613{
614 let start = index_to_usize_validated(offsets[index].get());
615 let end = index_to_usize_validated(offsets[index + 1].get());
616 &values[start..end]
617}
618
619fn locate_owning_bucket<OffsetWord, RelationIndex>(
622 offsets: &[OffsetWord],
623 target: usize,
624) -> RelationIndex
625where
626 OffsetWord: BcsrWord,
627 RelationIndex: BcsrIndex,
628{
629 let mut low = 0_usize;
630 let mut high = offsets.len() - 1;
631 while low + 1 < high {
632 let mid = low + (high - low) / 2;
633 if index_to_usize_validated(offsets[mid].get()) <= target {
634 low = mid;
635 } else {
636 high = mid;
637 }
638 }
639 usize_to_index_validated(low)
640}