use core::fmt;
use crate::{
error::BcsrError,
internal::validation::{BcsrValidation, DerivedCounts, validate_sections},
word::{BcsrWords, LayoutWord},
};
#[derive(Clone, Copy, Debug)]
pub struct BcsrSections<'view, OffsetWord, VertexWord, RelationWord>
where
OffsetWord: LayoutWord,
VertexWord: LayoutWord,
RelationWord: LayoutWord,
{
pub head_offsets: &'view [OffsetWord],
pub head_participants: &'view [VertexWord],
pub tail_offsets: &'view [OffsetWord],
pub tail_participants: &'view [VertexWord],
pub vertex_outgoing_offsets: &'view [OffsetWord],
pub vertex_outgoing_hyperedges: &'view [RelationWord],
pub vertex_incoming_offsets: &'view [OffsetWord],
pub vertex_incoming_hyperedges: &'view [RelationWord],
}
#[cfg(kani)]
impl<'view, OffsetWord, VertexWord, RelationWord>
BcsrSections<'view, OffsetWord, VertexWord, RelationWord>
where
OffsetWord: LayoutWord,
VertexWord: LayoutWord,
RelationWord: LayoutWord,
{
#[expect(
clippy::too_many_arguments,
reason = "eight slice arguments mirror the eight BcsrSections fields in the documented declaration order"
)]
pub(crate) fn for_kani(
head_offsets: &'view [OffsetWord],
head_participants: &'view [VertexWord],
tail_offsets: &'view [OffsetWord],
tail_participants: &'view [VertexWord],
vertex_outgoing_offsets: &'view [OffsetWord],
vertex_outgoing_hyperedges: &'view [RelationWord],
vertex_incoming_offsets: &'view [OffsetWord],
vertex_incoming_hyperedges: &'view [RelationWord],
) -> Self {
Self {
head_offsets,
head_participants,
tail_offsets,
tail_participants,
vertex_outgoing_offsets,
vertex_outgoing_hyperedges,
vertex_incoming_offsets,
vertex_incoming_hyperedges,
}
}
}
pub struct BcsrHypergraph<'view, W: BcsrWords> {
counts: DerivedCounts,
sections: BcsrSections<'view, W::OffsetWord, W::VertexWord, W::RelationWord>,
}
impl<W: BcsrWords> Clone for BcsrHypergraph<'_, W> {
fn clone(&self) -> Self {
*self
}
}
impl<W: BcsrWords> Copy for BcsrHypergraph<'_, W> {}
impl<W: BcsrWords> fmt::Debug for BcsrHypergraph<'_, W>
where
W::OffsetWord: fmt::Debug,
W::VertexWord: fmt::Debug,
W::RelationWord: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BcsrHypergraph")
.field("counts", &self.counts)
.field("sections", &self.sections)
.finish()
}
}
impl<'view, W: BcsrWords> BcsrHypergraph<'view, W> {
pub fn open(
sections: BcsrSections<'view, W::OffsetWord, W::VertexWord, W::RelationWord>,
) -> Result<Self, BcsrError> {
Self::open_with(sections, BcsrValidation::Layout)
}
pub fn open_with(
sections: BcsrSections<'view, W::OffsetWord, W::VertexWord, W::RelationWord>,
level: BcsrValidation,
) -> Result<Self, BcsrError> {
let counts = validate_sections(§ions, level)?;
Ok(Self { counts, sections })
}
pub(crate) const fn from_validated_sections(
sections: BcsrSections<'view, W::OffsetWord, W::VertexWord, W::RelationWord>,
) -> Self {
let p_outgoing = sections.vertex_outgoing_hyperedges.len();
let p_incoming = sections.vertex_incoming_hyperedges.len();
let counts = DerivedCounts {
vertex_count: sections.vertex_outgoing_offsets.len().saturating_sub(1),
hyperedge_count: sections.head_offsets.len().saturating_sub(1),
p_outgoing,
p_incoming,
total_incidences: p_outgoing.saturating_add(p_incoming),
};
Self { counts, sections }
}
#[must_use]
pub const fn vertex_count(&self) -> usize {
self.counts.vertex_count
}
#[must_use]
pub const fn hyperedge_count(&self) -> usize {
self.counts.hyperedge_count
}
#[must_use]
pub const fn outgoing_incidence_count(&self) -> usize {
self.counts.p_outgoing
}
#[must_use]
pub const fn incoming_incidence_count(&self) -> usize {
self.counts.p_incoming
}
pub(in crate::internal) const fn counts(&self) -> DerivedCounts {
self.counts
}
pub(in crate::internal) const fn sections(
&self,
) -> &BcsrSections<'view, W::OffsetWord, W::VertexWord, W::RelationWord> {
&self.sections
}
}