1use core::{iter::Chain, marker::PhantomData};
6
7use crate::{
8 id::{BcsrHyperedgeId, BcsrParticipantId, BcsrVertexId},
9 internal::{
10 validation::{index_to_usize_validated, usize_to_index_validated},
11 view::BcsrSections,
12 },
13 word::{BcsrIndex, BcsrWord},
14};
15
16#[derive(Clone, Debug)]
26pub struct BcsrIdSlice<'view, Word: BcsrWord, Id> {
27 inner: core::slice::Iter<'view, Word>,
29 _id: PhantomData<fn() -> Id>,
32}
33
34impl<'view, Word: BcsrWord, Id> BcsrIdSlice<'view, Word, Id> {
35 pub(in crate::internal) fn new(slice: &'view [Word]) -> Self {
37 Self {
38 inner: slice.iter(),
39 _id: PhantomData,
40 }
41 }
42}
43
44impl<Word: BcsrWord, Id> Iterator for BcsrIdSlice<'_, Word, Id>
45where
46 Id: From<Word::Index>,
47{
48 type Item = Id;
49
50 fn next(&mut self) -> Option<Self::Item> {
51 self.inner.next().map(|word| Id::from(word.get()))
52 }
53
54 fn size_hint(&self) -> (usize, Option<usize>) {
55 self.inner.size_hint()
56 }
57}
58
59impl<Word: BcsrWord, Id> ExactSizeIterator for BcsrIdSlice<'_, Word, Id>
60where
61 Id: From<Word::Index>,
62{
63 fn len(&self) -> usize {
64 self.inner.len()
65 }
66}
67
68impl<Word: BcsrWord, Id> DoubleEndedIterator for BcsrIdSlice<'_, Word, Id>
69where
70 Id: From<Word::Index>,
71{
72 fn next_back(&mut self) -> Option<Self::Item> {
73 self.inner.next_back().map(|word| Id::from(word.get()))
74 }
75}
76
77pub type BcsrVertexSlice<'view, Word> =
83 BcsrIdSlice<'view, Word, BcsrVertexId<<Word as BcsrWord>::Index>>;
84
85pub type BcsrHyperedgeSlice<'view, Word> =
91 BcsrIdSlice<'view, Word, BcsrHyperedgeId<<Word as BcsrWord>::Index>>;
92
93pub type BcsrChainedParticipants<'view, Word> =
99 Chain<BcsrVertexSlice<'view, Word>, BcsrVertexSlice<'view, Word>>;
100
101pub type BcsrChainedHyperedges<'view, Word> =
107 Chain<BcsrHyperedgeSlice<'view, Word>, BcsrHyperedgeSlice<'view, Word>>;
108
109#[derive(Clone, Debug)]
115pub struct BcsrParticipantSlice<IncidenceIndex> {
116 cursor: usize,
118 end: usize,
120 base: usize,
122 index: PhantomData<fn() -> IncidenceIndex>,
124}
125
126impl<IncidenceIndex> BcsrParticipantSlice<IncidenceIndex> {
127 pub(in crate::internal) const fn new(start: usize, end: usize, base: usize) -> Self {
129 Self {
130 cursor: start,
131 end,
132 base,
133 index: PhantomData,
134 }
135 }
136}
137
138impl<IncidenceIndex: BcsrIndex> Iterator for BcsrParticipantSlice<IncidenceIndex> {
139 type Item = BcsrParticipantId<IncidenceIndex>;
140
141 fn next(&mut self) -> Option<Self::Item> {
142 if self.cursor == self.end {
143 return None;
144 }
145 let id = self.base.checked_add(self.cursor)?;
146 self.cursor += 1;
147 Some(BcsrParticipantId(usize_to_index_validated(id)))
148 }
149
150 fn size_hint(&self) -> (usize, Option<usize>) {
151 let len = self.end - self.cursor;
152 (len, Some(len))
153 }
154}
155
156impl<IncidenceIndex: BcsrIndex> ExactSizeIterator for BcsrParticipantSlice<IncidenceIndex> {
157 fn len(&self) -> usize {
158 self.end - self.cursor
159 }
160}
161
162impl<IncidenceIndex: BcsrIndex> DoubleEndedIterator for BcsrParticipantSlice<IncidenceIndex> {
163 fn next_back(&mut self) -> Option<Self::Item> {
164 if self.cursor == self.end {
165 return None;
166 }
167 self.end -= 1;
168 let id = self.base.checked_add(self.end)?;
169 Some(BcsrParticipantId(usize_to_index_validated(id)))
170 }
171}
172
173pub type BcsrChainedRelationIncidences<IncidenceIndex> =
180 Chain<BcsrParticipantSlice<IncidenceIndex>, BcsrParticipantSlice<IncidenceIndex>>;
181
182#[derive(Clone, Debug)]
188pub struct BcsrElementIncidences<'view, OffsetWord, VertexWord, RelationWord>
189where
190 OffsetWord: BcsrWord,
191 VertexWord: BcsrWord,
192 RelationWord: BcsrWord,
193{
194 vertex: usize,
196 p_head: usize,
198 outgoing: core::slice::Iter<'view, RelationWord>,
200 incoming: core::slice::Iter<'view, RelationWord>,
202 head_offsets: &'view [OffsetWord],
204 head_participants: &'view [VertexWord],
206 tail_offsets: &'view [OffsetWord],
208 tail_participants: &'view [VertexWord],
210}
211
212impl<'view, OffsetWord, VertexWord, RelationWord>
213 BcsrElementIncidences<'view, OffsetWord, VertexWord, RelationWord>
214where
215 OffsetWord: BcsrWord,
216 VertexWord: BcsrWord,
217 RelationWord: BcsrWord,
218{
219 pub(in crate::internal) fn new(
221 vertex: usize,
222 p_head: usize,
223 outgoing_slice: &'view [RelationWord],
224 incoming_slice: &'view [RelationWord],
225 sections: &BcsrSections<'view, OffsetWord, VertexWord, RelationWord>,
226 ) -> Self {
227 Self {
228 vertex,
229 p_head,
230 outgoing: outgoing_slice.iter(),
231 incoming: incoming_slice.iter(),
232 head_offsets: sections.head_offsets,
233 head_participants: sections.head_participants,
234 tail_offsets: sections.tail_offsets,
235 tail_participants: sections.tail_participants,
236 }
237 }
238
239 fn pull_outgoing(&mut self) -> Option<BcsrParticipantId<OffsetWord::Index>> {
241 for h_word in self.outgoing.by_ref() {
242 let hyperedge = index_to_usize_validated(h_word.get());
243 if let Some(position) = locate_in_bucket(
244 self.head_offsets,
245 self.head_participants,
246 hyperedge,
247 self.vertex,
248 ) {
249 return Some(BcsrParticipantId(usize_to_index_validated(position)));
250 }
251 }
252 None
253 }
254
255 fn pull_incoming(&mut self) -> Option<BcsrParticipantId<OffsetWord::Index>> {
257 for h_word in self.incoming.by_ref() {
258 let hyperedge = index_to_usize_validated(h_word.get());
259 if let Some(position) = locate_in_bucket(
260 self.tail_offsets,
261 self.tail_participants,
262 hyperedge,
263 self.vertex,
264 ) {
265 let id = self.p_head.checked_add(position)?;
266 return Some(BcsrParticipantId(usize_to_index_validated(id)));
267 }
268 }
269 None
270 }
271}
272
273impl<OffsetWord, VertexWord, RelationWord> Iterator
274 for BcsrElementIncidences<'_, OffsetWord, VertexWord, RelationWord>
275where
276 OffsetWord: BcsrWord,
277 VertexWord: BcsrWord,
278 RelationWord: BcsrWord,
279{
280 type Item = BcsrParticipantId<OffsetWord::Index>;
281
282 fn next(&mut self) -> Option<Self::Item> {
283 if let Some(id) = self.pull_outgoing() {
284 return Some(id);
285 }
286 self.pull_incoming()
287 }
288}
289
290fn locate_in_bucket<OffsetWord, VertexWord>(
292 offsets: &[OffsetWord],
293 participants: &[VertexWord],
294 hyperedge: usize,
295 vertex: usize,
296) -> Option<usize>
297where
298 OffsetWord: BcsrWord,
299 VertexWord: BcsrWord,
300{
301 let bucket_start = index_to_usize_validated(offsets[hyperedge].get());
302 let bucket_end = index_to_usize_validated(offsets[hyperedge + 1].get());
303 let bucket = &participants[bucket_start..bucket_end];
304 let local = bucket
305 .binary_search_by(|word| index_to_usize_validated(word.get()).cmp(&vertex))
306 .ok()?;
307 bucket_start.checked_add(local)
308}
309
310#[derive(Clone, Debug)]
322pub struct BcsrNeighborVertices<'view, RelationWord, OffsetWord, VertexWord>
323where
324 RelationWord: BcsrWord,
325 OffsetWord: BcsrWord,
326 VertexWord: BcsrWord,
327{
328 relations: core::slice::Iter<'view, RelationWord>,
330 current_bucket: core::slice::Iter<'view, VertexWord>,
332 bucket_offsets: &'view [OffsetWord],
335 bucket_participants: &'view [VertexWord],
337}
338
339impl<'view, RelationWord, OffsetWord, VertexWord>
340 BcsrNeighborVertices<'view, RelationWord, OffsetWord, VertexWord>
341where
342 RelationWord: BcsrWord,
343 OffsetWord: BcsrWord,
344 VertexWord: BcsrWord,
345{
346 pub(in crate::internal) fn new(
351 relations: &'view [RelationWord],
352 bucket_offsets: &'view [OffsetWord],
353 bucket_participants: &'view [VertexWord],
354 ) -> Self {
355 Self {
356 relations: relations.iter(),
357 current_bucket: [].iter(),
358 bucket_offsets,
359 bucket_participants,
360 }
361 }
362
363 fn advance_outer(&mut self) -> bool {
365 match self.relations.next() {
366 Some(h_word) => {
367 let h_index = index_to_usize_validated(h_word.get());
368 let start = index_to_usize_validated(self.bucket_offsets[h_index].get());
369 let end = index_to_usize_validated(self.bucket_offsets[h_index + 1].get());
370 self.current_bucket = self.bucket_participants[start..end].iter();
371 true
372 }
373 None => false,
374 }
375 }
376}
377
378impl<RelationWord, OffsetWord, VertexWord> Iterator
379 for BcsrNeighborVertices<'_, RelationWord, OffsetWord, VertexWord>
380where
381 RelationWord: BcsrWord,
382 OffsetWord: BcsrWord,
383 VertexWord: BcsrWord,
384{
385 type Item = BcsrVertexId<VertexWord::Index>;
386
387 fn next(&mut self) -> Option<Self::Item> {
388 loop {
389 if let Some(word) = self.current_bucket.next() {
390 return Some(BcsrVertexId(word.get()));
391 }
392 if !self.advance_outer() {
393 return None;
394 }
395 }
396 }
397}
398
399pub type BcsrSuccessorVertices<'view, RelationWord, OffsetWord, VertexWord> =
405 BcsrNeighborVertices<'view, RelationWord, OffsetWord, VertexWord>;
406
407pub type BcsrPredecessorVertices<'view, RelationWord, OffsetWord, VertexWord> =
413 BcsrNeighborVertices<'view, RelationWord, OffsetWord, VertexWord>;