use super::bvgraph::EF;
use crate::traits::*;
use common_traits::UnsignedInt;
use epserde::Epserde;
use lender::{IntoLender, Lend, Lender, Lending, check_covariance, for_};
use sux::{
bits::BitFieldVec,
dict::EliasFanoBuilder,
rank_sel::{SelectAdaptConst, SelectZeroAdaptConst},
};
use value_traits::{
iter::{IterFrom, IterateByValueFrom},
slices::SliceByValue,
};
pub type CompressedCsrGraph = CsrGraph<EF, BitFieldVec>;
pub type CompressedCsrSortedGraph = CsrSortedGraph<EF, BitFieldVec>;
#[derive(Debug, Clone, Epserde)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CsrGraph<DCF = Box<[usize]>, S = Box<[usize]>> {
dcf: DCF,
successors: S,
}
#[derive(Debug, Clone, Epserde)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CsrSortedGraph<DCF = Box<[usize]>, S = Box<[usize]>>(CsrGraph<DCF, S>);
impl<DCF, S> CsrGraph<DCF, S> {
pub unsafe fn from_parts(dcf: DCF, successors: S) -> Self {
Self { dcf, successors }
}
#[inline(always)]
pub fn dcf(&self) -> &DCF {
&self.dcf
}
#[inline(always)]
pub fn successors(&self) -> &S {
&self.successors
}
#[inline(always)]
pub fn into_inner(self) -> (DCF, S) {
(self.dcf, self.successors)
}
}
impl core::default::Default for CsrGraph {
fn default() -> Self {
Self {
dcf: vec![0].into(),
successors: vec![].into(),
}
}
}
impl CsrGraph {
pub fn new() -> Self {
Self::default()
}
fn _from_lender<I: IntoLender>(
iter_nodes: I,
num_nodes_hint: Option<usize>,
num_arcs_hint: Option<usize>,
) -> Self
where
I::Lender: for<'next> NodeLabelsLender<'next, Label = usize> + SortedLender,
{
let mut max_node = 0;
let mut dcf = Vec::with_capacity(num_nodes_hint.unwrap_or(0) + 1);
dcf.push(0);
let mut successors = Vec::with_capacity(num_arcs_hint.unwrap_or(0));
let mut last_src = 0;
for_!( (src, succs) in iter_nodes {
while last_src < src {
dcf.push(successors.len());
last_src += 1;
}
max_node = max_node.max(src);
for succ in succs {
successors.push(succ);
max_node = max_node.max(succ);
}
});
for _ in last_src..=max_node {
dcf.push(successors.len());
}
dcf.shrink_to_fit();
successors.shrink_to_fit();
unsafe { Self::from_parts(dcf.into(), successors.into()) }
}
pub fn from_lender<I: IntoLender>(iter_nodes: I) -> Self
where
I::Lender: for<'next> NodeLabelsLender<'next, Label = usize> + SortedLender,
{
Self::_from_lender(iter_nodes, None, None)
}
pub fn from_sorted_lender<I: IntoLender>(iter_nodes: I) -> Self
where
I::Lender: for<'next> NodeLabelsLender<'next, Label = usize> + SortedLender,
for<'succ> LenderIntoIter<'succ, I::Lender>: SortedIterator,
{
Self::from_lender(iter_nodes)
}
pub fn from_seq_graph<G: SequentialGraph>(g: &G) -> Self
where
for<'a> G::Lender<'a>: SortedLender,
{
Self::_from_lender(
g.iter(),
Some(g.num_nodes()),
g.num_arcs_hint().map(|n| n as usize),
)
}
}
impl CsrSortedGraph {
pub fn from_lender<I: IntoLender>(iter_nodes: I) -> Self
where
I::Lender: for<'next> NodeLabelsLender<'next, Label = usize> + SortedLender,
for<'succ> LenderIntoIter<'succ, I::Lender>: SortedIterator,
{
CsrSortedGraph(CsrGraph::from_lender(iter_nodes))
}
pub fn from_seq_graph<G: SequentialGraph>(g: &G) -> Self
where
for<'a> G::Lender<'a>: SortedLender,
for<'a, 'b> LenderIntoIter<'b, G::Lender<'a>>: SortedIterator,
{
CsrSortedGraph(CsrGraph::from_seq_graph(g))
}
}
impl CompressedCsrGraph {
pub fn try_from_graph<G: SequentialGraph>(g: &G) -> anyhow::Result<Self>
where
for<'a> G::Lender<'a>: SortedLender,
{
let n = g.num_nodes();
let u = g.num_arcs_hint().ok_or(anyhow::Error::msg(
"This sequential graph does not provide the number of arcs",
))?;
let mut efb = EliasFanoBuilder::new(n + 1, u as usize + 1);
efb.push(0);
let mut successors = BitFieldVec::with_capacity(
if n == 0 { 0 } else { n.ilog2_ceil() as usize },
u as usize,
);
let mut last_src = 0;
for_!((src, succ) in g.iter() {
while last_src < src {
efb.push(successors.len());
last_src += 1;
}
successors.extend(succ);
});
for _ in last_src..g.num_nodes() {
efb.push(successors.len());
}
let ef = efb.build();
let ef: EF = unsafe { ef.map_high_bits(SelectAdaptConst::<_, _, 12, 4>::new) };
unsafe { Ok(Self::from_parts(ef, successors)) }
}
}
impl CompressedCsrSortedGraph {
pub fn try_from_graph<G: SequentialGraph>(g: &G) -> anyhow::Result<Self>
where
for<'a> G::Lender<'a>: SortedLender,
for<'a, 'b> LenderIntoIter<'b, G::Lender<'a>>: SortedIterator,
{
Ok(CsrSortedGraph(CsrGraph::try_from_graph(g)?))
}
}
impl<'a, DCF, S> IntoLender for &'a CsrGraph<DCF, S>
where
DCF: SliceByValue + IterateByValueFrom<Item = usize>,
S: SliceByValue + IterateByValueFrom<Item = usize>,
{
type Lender = NodeLabels<IterFrom<'a, DCF>, IterFrom<'a, S>>;
#[inline(always)]
fn into_lender(self) -> Self::Lender {
self.iter()
}
}
impl<'a, DCF, S> IntoLender for &'a CsrSortedGraph<DCF, S>
where
DCF: SliceByValue + IterateByValueFrom<Item = usize>,
S: SliceByValue + IterateByValueFrom<Item = usize>,
{
type Lender = <Self as SequentialLabeling>::Lender<'a>;
#[inline(always)]
fn into_lender(self) -> Self::Lender {
self.iter()
}
}
impl<DCF, S> SequentialLabeling for CsrGraph<DCF, S>
where
DCF: SliceByValue + IterateByValueFrom<Item = usize>,
S: SliceByValue + IterateByValueFrom<Item = usize>,
{
type Label = usize;
type Lender<'a>
= NodeLabels<IterFrom<'a, DCF>, IterFrom<'a, S>>
where
Self: 'a;
#[inline(always)]
fn num_nodes(&self) -> usize {
self.dcf.len() - 1
}
#[inline(always)]
fn num_arcs_hint(&self) -> Option<u64> {
Some(self.successors.len() as u64)
}
#[inline(always)]
fn iter_from(&self, from: usize) -> Self::Lender<'_> {
let mut offsets_iter = self.dcf.iter_value_from(from);
let offset = offsets_iter.next().unwrap_or(0);
NodeLabels {
node: from,
last_offset: offset,
current_offset: offset,
offsets_iter,
successors_iter: self.successors.iter_value_from(offset),
}
}
fn build_dcf(&self) -> crate::graphs::bvgraph::DCF {
let n = self.num_nodes();
let num_arcs = self.num_arcs_hint().unwrap() as usize;
let mut efb = EliasFanoBuilder::new(n + 1, num_arcs);
for val in self.dcf.iter_value_from(0).take(n + 1) {
efb.push(val);
}
unsafe {
efb.build().map_high_bits(|high_bits| {
SelectZeroAdaptConst::<_, _, 12, 4>::new(SelectAdaptConst::<_, _, 12, 4>::new(
high_bits,
))
})
}
}
}
impl<DCF, S> SequentialLabeling for CsrSortedGraph<DCF, S>
where
DCF: SliceByValue + IterateByValueFrom<Item = usize>,
S: SliceByValue + IterateByValueFrom<Item = usize>,
{
type Label = usize;
type Lender<'a>
= LenderSortedImpl<IterFrom<'a, DCF>, IterFrom<'a, S>>
where
Self: 'a;
#[inline(always)]
fn num_nodes(&self) -> usize {
self.0.num_nodes()
}
#[inline(always)]
fn num_arcs_hint(&self) -> Option<u64> {
self.0.num_arcs_hint()
}
#[inline(always)]
fn iter_from(&self, from: usize) -> Self::Lender<'_> {
LenderSortedImpl(self.0.iter_from(from))
}
fn build_dcf(&self) -> crate::graphs::bvgraph::DCF {
self.0.build_dcf()
}
}
impl<D, S> SequentialGraph for CsrGraph<D, S>
where
D: SliceByValue + IterateByValueFrom<Item = usize>,
S: SliceByValue + IterateByValueFrom<Item = usize>,
{
}
impl<D, S> SequentialGraph for CsrSortedGraph<D, S>
where
D: SliceByValue + IterateByValueFrom<Item = usize>,
S: SliceByValue + IterateByValueFrom<Item = usize>,
{
}
impl<DCF, S> RandomAccessLabeling for CsrGraph<DCF, S>
where
DCF: SliceByValue<Value = usize> + IterateByValueFrom<Item = usize>,
S: SliceByValue<Value = usize> + IterateByValueFrom<Item = usize>,
{
type Labels<'succ>
= core::iter::Take<IterFrom<'succ, S>>
where
Self: 'succ;
#[inline(always)]
fn num_arcs(&self) -> u64 {
self.successors.len() as u64
}
#[inline(always)]
fn outdegree(&self, node: usize) -> usize {
self.dcf.index_value(node + 1) - self.dcf.index_value(node)
}
#[inline(always)]
fn labels(&self, node: usize) -> <Self as RandomAccessLabeling>::Labels<'_> {
let start = self.dcf.index_value(node);
let end = self.dcf.index_value(node + 1);
self.successors.iter_value_from(start).take(end - start)
}
}
impl<DCF, S> RandomAccessLabeling for CsrSortedGraph<DCF, S>
where
DCF: SliceByValue<Value = usize> + IterateByValueFrom<Item = usize>,
S: SliceByValue<Value = usize> + IterateByValueFrom<Item = usize>,
{
type Labels<'succ>
= AssumeSortedIterator<core::iter::Take<IterFrom<'succ, S>>>
where
Self: 'succ;
#[inline(always)]
fn num_arcs(&self) -> u64 {
self.0.num_arcs()
}
#[inline(always)]
fn outdegree(&self, node: usize) -> usize {
self.0.outdegree(node)
}
#[inline(always)]
fn labels(&self, node: usize) -> <Self as RandomAccessLabeling>::Labels<'_> {
let labels = <CsrGraph<DCF, S> as RandomAccessLabeling>::labels(&self.0, node);
unsafe { AssumeSortedIterator::new(labels) }
}
}
impl<DCF, S> RandomAccessGraph for CsrGraph<DCF, S>
where
DCF: SliceByValue<Value = usize> + IterateByValueFrom<Item = usize>,
S: SliceByValue<Value = usize> + IterateByValueFrom<Item = usize>,
{
}
impl<DCF, S> RandomAccessGraph for CsrSortedGraph<DCF, S>
where
DCF: SliceByValue<Value = usize> + IterateByValueFrom<Item = usize>,
S: SliceByValue<Value = usize> + IterateByValueFrom<Item = usize>,
{
}
#[derive(Debug, Clone)]
pub struct NodeLabels<O: Iterator<Item = usize>, S: Iterator<Item = usize>> {
node: usize,
last_offset: usize,
current_offset: usize,
offsets_iter: O,
successors_iter: S,
}
unsafe impl<O: Iterator<Item = usize>, S: Iterator<Item = usize>> SortedLender
for NodeLabels<O, S>
{
}
impl<'succ, I, D> NodeLabelsLender<'succ> for NodeLabels<I, D>
where
I: Iterator<Item = usize>,
D: Iterator<Item = usize>,
{
type Label = usize;
type IntoIterator = SeqSucc<'succ, D>;
}
impl<'succ, I, D> Lending<'succ> for NodeLabels<I, D>
where
I: Iterator<Item = usize>,
D: Iterator<Item = usize>,
{
type Lend = (usize, SeqSucc<'succ, D>);
}
impl<I, D> Lender for NodeLabels<I, D>
where
I: Iterator<Item = usize>,
D: Iterator<Item = usize>,
{
check_covariance!();
#[inline(always)]
fn next(&mut self) -> Option<Lend<'_, Self>> {
while self.current_offset < self.last_offset {
self.current_offset += 1;
self.successors_iter.next()?;
}
let offset = self.offsets_iter.next()?;
self.last_offset = offset;
let node = self.node;
self.node += 1;
Some((
node,
SeqSucc {
succ_iter: &mut self.successors_iter,
current_offset: &mut self.current_offset,
last_offset: &self.last_offset,
},
))
}
}
#[derive(Debug, Clone)]
#[repr(transparent)]
pub struct LenderSortedImpl<O: Iterator<Item = usize>, S: Iterator<Item = usize>>(NodeLabels<O, S>);
unsafe impl<O: Iterator<Item = usize>, S: Iterator<Item = usize>> SortedLender
for LenderSortedImpl<O, S>
{
}
impl<'succ, I, D> NodeLabelsLender<'succ> for LenderSortedImpl<I, D>
where
I: Iterator<Item = usize>,
D: Iterator<Item = usize>,
{
type Label = usize;
type IntoIterator = AssumeSortedIterator<SeqSucc<'succ, D>>;
}
impl<'succ, I, D> Lending<'succ> for LenderSortedImpl<I, D>
where
I: Iterator<Item = usize>,
D: Iterator<Item = usize>,
{
type Lend = (usize, AssumeSortedIterator<SeqSucc<'succ, D>>);
}
impl<I, D> Lender for LenderSortedImpl<I, D>
where
I: Iterator<Item = usize>,
D: Iterator<Item = usize>,
{
check_covariance!();
#[inline(always)]
fn next(&mut self) -> Option<Lend<'_, Self>> {
let (src, succ) = self.0.next()?;
Some((src, unsafe { AssumeSortedIterator::new(succ) }))
}
}
pub struct SeqSucc<'a, D> {
succ_iter: &'a mut D,
current_offset: &'a mut usize,
last_offset: &'a usize,
}
impl<D: Iterator<Item = usize>> Iterator for SeqSucc<'_, D> {
type Item = usize;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if *self.current_offset >= *self.last_offset {
return None;
}
*self.current_offset += 1;
self.succ_iter.next()
}
#[inline(always)]
fn count(self) -> usize {
self.len()
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.last_offset - *self.current_offset;
(len, Some(len))
}
}
impl<D: Iterator<Item = usize>> ExactSizeIterator for SeqSucc<'_, D> {
#[inline(always)]
fn len(&self) -> usize {
self.last_offset - *self.current_offset
}
}