webgraph 0.6.1

A Rust port of the WebGraph framework (http://webgraph.di.unimi.it/).
Documentation
/*
 * SPDX-FileCopyrightText: 2023 Sebastiano Vigna
 *
 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
 */

use crate::prelude::*;
use lender::*;

/// A wrapper exhibiting the union of two graphs.
#[derive(Debug, Clone)]
pub struct UnionGraph<G: SequentialGraph, H: SequentialGraph>(pub G, pub H);

impl<G: SequentialGraph, H: SequentialGraph> SequentialLabeling for UnionGraph<G, H>
where
    for<'a> G::Lender<'a>: SortedLender,
    for<'a, 'b> LenderIntoIter<'b, G::Lender<'a>>: SortedIterator,
    for<'a> H::Lender<'a>: SortedLender,
    for<'a, 'b> LenderIntoIter<'b, H::Lender<'a>>: SortedIterator,
{
    type Label = usize;
    type Lender<'b>
        = NodeLabels<G::Lender<'b>, H::Lender<'b>>
    where
        Self: 'b;

    #[inline(always)]
    fn num_nodes(&self) -> usize {
        self.0.num_nodes().max(self.1.num_nodes())
    }

    #[inline(always)]
    fn num_arcs_hint(&self) -> Option<u64> {
        None
    }

    #[inline(always)]
    fn iter_from(&self, from: usize) -> Self::Lender<'_> {
        NodeLabels(
            self.0.iter_from(from.min(self.0.num_nodes())),
            self.1.iter_from(from.min(self.1.num_nodes())),
        )
    }
}

impl<G: SequentialGraph, H: SequentialGraph> SplitLabeling for UnionGraph<G, H>
where
    for<'a> G::Lender<'a>: SortedLender + Clone + Send + Sync,
    for<'a, 'b> LenderIntoIter<'b, G::Lender<'a>>: SortedIterator,
    for<'a> H::Lender<'a>: SortedLender + Clone + Send + Sync,
    for<'a, 'b> LenderIntoIter<'b, H::Lender<'a>>: SortedIterator,
{
    type SplitLender<'a>
        = split::seq::Lender<'a, UnionGraph<G, H>>
    where
        Self: 'a;
    type IntoIterator<'a>
        = split::seq::IntoIterator<'a, UnionGraph<G, H>>
    where
        Self: 'a;

    fn split_iter(&self, how_many: usize) -> Self::IntoIterator<'_> {
        split::seq::Iter::new(self.iter(), self.num_nodes(), how_many)
    }
}

impl<G: SequentialGraph, H: SequentialGraph> SequentialGraph for UnionGraph<G, H>
where
    for<'a> G::Lender<'a>: SortedLender + Clone,
    for<'a, 'b> LenderIntoIter<'b, G::Lender<'a>>: SortedIterator,
    for<'a> H::Lender<'a>: SortedLender + Clone,
    for<'a, 'b> LenderIntoIter<'b, H::Lender<'a>>: SortedIterator,
{
}

/// Convenience implementation that makes it possible to iterate
/// over the graph using the [`for_`] macro
/// (see the [crate documentation](crate)).
impl<'c, G: SequentialGraph, H: SequentialGraph> IntoLender for &'c UnionGraph<G, H>
where
    for<'a> G::Lender<'a>: SortedLender + Clone,
    for<'a, 'b> LenderIntoIter<'b, G::Lender<'a>>: SortedIterator,
    for<'a> H::Lender<'a>: SortedLender + Clone,
    for<'a, 'b> LenderIntoIter<'b, H::Lender<'a>>: SortedIterator,
{
    type Lender = <UnionGraph<G, H> as SequentialLabeling>::Lender<'c>;

    #[inline(always)]
    fn into_lender(self) -> Self::Lender {
        self.iter()
    }
}

#[doc(hidden)]
#[derive(Debug, Clone)]
pub struct NodeLabels<L, M>(L, M);

impl<
    'succ,
    L: Lender + for<'next> NodeLabelsLender<'next, Label = usize>,
    M: Lender + for<'next> NodeLabelsLender<'next, Label = usize>,
> NodeLabelsLender<'succ> for NodeLabels<L, M>
{
    type Label = usize;
    type IntoIterator = Succ<LenderIntoIter<'succ, L>, LenderIntoIter<'succ, M>>;
}

impl<
    'succ,
    L: Lender + for<'next> NodeLabelsLender<'next, Label = usize>,
    M: Lender + for<'next> NodeLabelsLender<'next, Label = usize>,
> Lending<'succ> for NodeLabels<L, M>
{
    type Lend = (usize, <Self as NodeLabelsLender<'succ>>::IntoIterator);
}

impl<
    L: Lender + for<'next> NodeLabelsLender<'next, Label = usize>,
    M: Lender + for<'next> NodeLabelsLender<'next, Label = usize>,
> Lender for NodeLabels<L, M>
{
    // SAFETY: the lend is covariant as it contains only a usize and an iterator
    // over usize values derived from the underlying lenders L and M.
    unsafe_assume_covariance!();

    #[inline(always)]
    fn next(&mut self) -> Option<Lend<'_, Self>> {
        let (node0, iter0) = self.0.next().unzip();
        let (node1, iter1) = self.1.next().unzip();
        Some((
            node0.or(node1)?,
            Succ::new(
                iter0.map(IntoIterator::into_iter),
                iter1.map(IntoIterator::into_iter),
            ),
        ))
    }

    #[inline(always)]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (min0, max0) = self.0.size_hint();
        let (min1, max1) = self.1.size_hint();
        (
            min0.max(min1),
            match (max0, max1) {
                (None, None) => None,
                (Some(max), None) => Some(max),
                (None, Some(max)) => Some(max),
                (Some(max0), Some(max1)) => Some(max0.max(max1)),
            },
        )
    }
}

impl<
    L: Lender + for<'next> NodeLabelsLender<'next, Label = usize> + ExactSizeLender,
    M: Lender + for<'next> NodeLabelsLender<'next, Label = usize> + ExactSizeLender,
> ExactSizeLender for NodeLabels<L, M>
{
    #[inline(always)]
    fn len(&self) -> usize {
        self.0.len().max(self.1.len())
    }
}

unsafe impl<
    L: Lender + for<'next> NodeLabelsLender<'next, Label = usize> + SortedLender,
    M: Lender + for<'next> NodeLabelsLender<'next, Label = usize> + SortedLender,
> SortedLender for NodeLabels<L, M>
{
}

#[derive(Debug, Clone)]
pub struct Succ<I: Iterator<Item = usize>, J: Iterator<Item = usize>> {
    iter0: Option<core::iter::Peekable<I>>,
    iter1: Option<core::iter::Peekable<J>>,
}

impl<I: Iterator<Item = usize>, J: Iterator<Item = usize>> Succ<I, J> {
    pub fn new(iter0: Option<I>, iter1: Option<J>) -> Self {
        Self {
            iter0: iter0.map(Iterator::peekable),
            iter1: iter1.map(Iterator::peekable),
        }
    }
}
impl<I: Iterator<Item = usize>, J: Iterator<Item = usize>> Iterator for Succ<I, J> {
    type Item = usize;
    #[inline(always)]
    fn next(&mut self) -> Option<Self::Item> {
        let next0 = self.iter0.as_mut().and_then(|iter| iter.peek().copied());
        let next1 = self.iter1.as_mut().and_then(|iter| iter.peek().copied());
        match next0
            .unwrap_or(usize::MAX)
            .cmp(&next1.unwrap_or(usize::MAX))
        {
            std::cmp::Ordering::Greater => self.iter1.as_mut().and_then(Iterator::next),
            std::cmp::Ordering::Less => self.iter0.as_mut().and_then(Iterator::next),
            std::cmp::Ordering::Equal => {
                self.iter0.as_mut().and_then(Iterator::next);
                self.iter1.as_mut().and_then(Iterator::next)
            }
        }
    }
}

unsafe impl<I: Iterator<Item = usize> + SortedIterator, J: Iterator<Item = usize> + SortedIterator>
    SortedIterator for Succ<I, J>
{
}

impl<I: Iterator<Item = usize>, J: Iterator<Item = usize>> std::iter::FusedIterator for Succ<I, J> {}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_union_graph() -> anyhow::Result<()> {
        use crate::graphs::vec_graph::VecGraph;
        let g = [
            VecGraph::from_arcs([
                (0, 1),
                (0, 3),
                (1, 2),
                (2, 0),
                (2, 2),
                (2, 4),
                (3, 4),
                (3, 5),
                (4, 1),
            ]),
            VecGraph::from_arcs([
                (1, 2),
                (1, 3),
                (2, 1),
                (2, 3),
                (2, 4),
                (4, 0),
                (5, 1),
                (5, 2),
                (6, 6),
            ]),
        ];
        for i in 0..2 {
            let union = UnionGraph(g[i].clone(), g[1 - i].clone());
            assert_eq!(union.num_nodes(), 7);

            let mut iter = union.iter();
            let Some((x, s)) = iter.next() else { panic!() };
            assert_eq!(x, 0);
            assert_eq!(s.collect::<Vec<_>>(), vec![1, 3]);
            let Some((x, s)) = iter.next() else { panic!() };
            assert_eq!(x, 1);
            assert_eq!(s.collect::<Vec<_>>(), vec![2, 3]);
            let Some((x, s)) = iter.next() else { panic!() };
            assert_eq!(x, 2);
            assert_eq!(s.collect::<Vec<_>>(), vec![0, 1, 2, 3, 4]);
            let Some((x, s)) = iter.next() else { panic!() };
            assert_eq!(x, 3);
            assert_eq!(s.collect::<Vec<_>>(), vec![4, 5]);
            let Some((x, s)) = iter.next() else { panic!() };
            assert_eq!(x, 4);
            assert_eq!(s.collect::<Vec<_>>(), vec![0, 1]);
            let Some((x, s)) = iter.next() else { panic!() };
            assert_eq!(x, 5);
            assert_eq!(s.collect::<Vec<_>>(), vec![1, 2]);
            let Some((x, s)) = iter.next() else { panic!() };
            assert_eq!(x, 6);
            assert_eq!(s.collect::<Vec<_>>(), vec![6]);
            assert!(iter.next().is_none());
        }
        Ok(())
    }
}