<commit_before>use nom::{types::CompleteStr, IResult};
use std::str;

/// Describes how formats should be padded: on the left, on the right, or not at all.
#[derive(PartialEq, Eq, Debug)]
pub enum Padding {
    /// Do not pad the value.
    None,
    /// Pad the value on the left until it reaches specified width.
    Left(usize),
    /// Pad the value on the right until it reaches specified width.
    Right(usize),
}

/// Describes all the different "format specifiers" we support, plus a chunk of text that would be
/// copied to the output verbatim.
#[derive(PartialEq, Eq, Debug)]
pub enum Specifier<'a> {
    /// Will expand to pad everything that comes next to the right. Given char is used for padding.
    Spacing(char),
    /// A format to be replaced with a value (`%a`, `%t` etc.), padded to the given width on the
    /// left (if it's positive) or on the right (if it's negative).
    Format(char, Padding),
    /// A chunk of text that will be copied to the output verbatim.
    Text(&'a str),
    /// Conditional format that is replaced by one of the sub-formats depending on the value of the
    /// given key. "Else" branch might be missing.
    Conditional(char, Vec<Specifier<'a>>, Option<Vec<Specifier<'a>>>),
}

fn escaped_percent_sign(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    tag!(input, "%%").map(|result| {
        let CompleteStr(s) = result.1;
        (result.0, Specifier::Text(&s[0..1]))
    })
}

fn spacing(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    do_parse!(input, tag!("%>") >> c: take!(1) >> (c)).map(|result| {
        let CompleteStr(chr) = result.1;
        // unwrap() won't panic because we use take!(1) in parser
        let chr = chr.chars().next().unwrap();

        (result.0, Specifier::Spacing(chr))
    })
}

fn padded_format(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    do_parse!(
        input,
        tag!("%")
            >> width: take_while!(|chr: char| chr.is_ascii() && (chr.is_numeric() || chr == '-'))
            >> format: take!(1)
            >> (format, width)
    )
    .map(|result| {
        let (c, w) = result.1;

        let CompleteStr(format) = c;
        // unwrap() won't fail because parser uses take!(1) to get exactly one character
        let format = format.chars().next().unwrap();

        let CompleteStr(width) = w;
        let width = width.parse::<isize>().unwrap_or(0);
        let padding = if width == 0isize {
            Padding::None
        } else if width > 0isize {
            Padding::Left(width.abs() as usize)
        } else {
            Padding::Right(width.abs() as usize)
        };

        (result.0, Specifier::Format(format, padding))
    })
}

fn text_outside_conditional(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    take_till!(input, |chr: char| chr == '%').map(|result| {
        let CompleteStr(s) = result.1;
        (result.0, Specifier::Text(s))
    })
}

fn text_inside_conditional(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    take_till!(input, |chr: char| chr == '%' || chr == '&' || chr == '?').map(|result| {
        let CompleteStr(s) = result.1;
        (result.0, Specifier::Text(s))
    })
}

fn conditional(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    do_parse!(
        input,
        tag!("%?")
            >> cond: take!(1)
            >> tag!("?")
            >> then: conditional_branch
            >> els: alt!(
            do_parse!(
                tag!("&") >>
                els: conditional_branch >>
                tag!("?") >>

                (Some(els))) |

            tag!("?") => { |_| None})
            >> (cond, then, els)
    )
    .map(|result| {
        let (cond, then, els) = result.1;

        let CompleteStr(cond) = cond;
        assert!(cond.len() == 1);
        let cond = cond.chars().next().unwrap();

        (result.0, Specifier::Conditional(cond, then, els))
    })
}

fn conditional_branch(input: CompleteStr) -> IResult<CompleteStr, Vec<Specifier>> {
    many0!(
        input,
        alt!(escaped_percent_sign | spacing | padded_format | text_inside_conditional)
    )
}

fn parser(input: CompleteStr) -> IResult<CompleteStr, Vec<Specifier>> {
    many0!(
        input,
        alt!(
            conditional | escaped_percent_sign | spacing | padded_format | text_outside_conditional
        )
    )
}

fn sanitize(mut input: Vec<Specifier>) -> Vec<Specifier> {
    input.retain(|s| {
        if let Specifier::Format(c, _b) = s {
            c.is_ascii()
        } else {
            true
        }
    });
    input
}

pub fn parse(input: &str) -> Vec<Specifier> {
    match parser(CompleteStr(input)) {
        Ok((_leftovers, ast)) => sanitize(ast),
        Err(_) => vec![Specifier::Text("")],
    }
}

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

    #[test]
    fn t_parses_formats_without_specifiers() {
        let input = "Hello, world!";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();
        assert_eq!(leftovers, CompleteStr(""));
        assert_eq!(result, vec![Specifier::Text("Hello, world!")]);
    }

    #[test]
    fn t_replaces_double_percent_with_a_single_percent() {
        let input = "%%";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();
        assert_eq!(leftovers, CompleteStr(""));
        assert_eq!(result, vec![Specifier::Text("%")]);
    }

    #[test]
    fn t_parses_sequences_of_specifiers() {
        let input = "100%% pure Ceylon tea";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();
        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Text("100"),
            Specifier::Text("%"),
            Specifier::Text(" pure Ceylon tea"),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_formats_with_letters() {
        let input = "%t (%a)";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Format('t', Padding::None),
            Specifier::Text(" ("),
            Specifier::Format('a', Padding::None),
            Specifier::Text(")"),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_formats_with_positive_padding() {
        let input = "%8a%4b%13x";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Format('a', Padding::Left(8)),
            Specifier::Format('b', Padding::Left(4)),
            Specifier::Format('x', Padding::Left(13)),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_formats_with_negative_padding() {
        let input = "%-8a%-4b%-13x";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Format('a', Padding::Right(8)),
            Specifier::Format('b', Padding::Right(4)),
            Specifier::Format('x', Padding::Right(13)),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_spacing_format() {
        let input = "%-8a%>m%4b%> %-13x";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Format('a', Padding::Right(8)),
            Specifier::Spacing('m'),
            Specifier::Format('b', Padding::Left(4)),
            Specifier::Spacing(' '),
            Specifier::Format('x', Padding::Right(13)),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_conditionals() {
        let input = "%?x?success&failure?";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![Specifier::Conditional(
            'x',
            vec![Specifier::Text("success")],
            Some(vec![Specifier::Text("failure")]),
        )];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_conditionals_without_else_branch() {
        let input = "%?x?success?";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![Specifier::Conditional(
            'x',
            vec![Specifier::Text("success")],
            None,
        )];
        assert_eq!(result, expected);
    }
}
<commit_msg>Get rid of asserts and comment unwraps<commit_after>use nom::{types::CompleteStr, IResult};
use std::str;

/// Describes how formats should be padded: on the left, on the right, or not at all.
#[derive(PartialEq, Eq, Debug)]
pub enum Padding {
    /// Do not pad the value.
    None,
    /// Pad the value on the left until it reaches specified width.
    Left(usize),
    /// Pad the value on the right until it reaches specified width.
    Right(usize),
}

/// Describes all the different "format specifiers" we support, plus a chunk of text that would be
/// copied to the output verbatim.
#[derive(PartialEq, Eq, Debug)]
pub enum Specifier<'a> {
    /// Will expand to pad everything that comes next to the right. Given char is used for padding.
    Spacing(char),
    /// A format to be replaced with a value (`%a`, `%t` etc.), padded to the given width on the
    /// left (if it's positive) or on the right (if it's negative).
    Format(char, Padding),
    /// A chunk of text that will be copied to the output verbatim.
    Text(&'a str),
    /// Conditional format that is replaced by one of the sub-formats depending on the value of the
    /// given key. "Else" branch might be missing.
    Conditional(char, Vec<Specifier<'a>>, Option<Vec<Specifier<'a>>>),
}

fn escaped_percent_sign(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    tag!(input, "%%").map(|result| {
        let CompleteStr(s) = result.1;
        (result.0, Specifier::Text(&s[0..1]))
    })
}

fn spacing(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    do_parse!(input, tag!("%>") >> c: take!(1) >> (c)).map(|result| {
        let CompleteStr(chr) = result.1;
        // unwrap() won't panic because we use take!(1) in parser above
        let chr = chr.chars().next().unwrap();

        (result.0, Specifier::Spacing(chr))
    })
}

fn padded_format(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    do_parse!(
        input,
        tag!("%")
            >> width: take_while!(|chr: char| chr.is_ascii() && (chr.is_numeric() || chr == '-'))
            >> format: take!(1)
            >> (format, width)
    )
    .map(|result| {
        let (c, w) = result.1;

        let CompleteStr(format) = c;
        // unwrap() won't fail because parser uses take!(1) to get exactly one character
        let format = format.chars().next().unwrap();

        let CompleteStr(width) = w;
        let width = width.parse::<isize>().unwrap_or(0);
        let padding = if width == 0isize {
            Padding::None
        } else if width > 0isize {
            Padding::Left(width.abs() as usize)
        } else {
            Padding::Right(width.abs() as usize)
        };

        (result.0, Specifier::Format(format, padding))
    })
}

fn text_outside_conditional(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    take_till!(input, |chr: char| chr == '%').map(|result| {
        let CompleteStr(s) = result.1;
        (result.0, Specifier::Text(s))
    })
}

fn text_inside_conditional(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    take_till!(input, |chr: char| chr == '%' || chr == '&' || chr == '?').map(|result| {
        let CompleteStr(s) = result.1;
        (result.0, Specifier::Text(s))
    })
}

fn conditional(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    do_parse!(
        input,
        tag!("%?")
            >> cond: take!(1)
            >> tag!("?")
            >> then: conditional_branch
            >> els: alt!(
            do_parse!(
                tag!("&") >>
                els: conditional_branch >>
                tag!("?") >>

                (Some(els))) |

            tag!("?") => { |_| None})
            >> (cond, then, els)
    )
    .map(|result| {
        let (cond, then, els) = result.1;

        let CompleteStr(cond) = cond;
        // unwrap() won't panic because we're using take!(1) to get exactly one character
        let cond = cond.chars().next().unwrap();

        (result.0, Specifier::Conditional(cond, then, els))
    })
}

fn conditional_branch(input: CompleteStr) -> IResult<CompleteStr, Vec<Specifier>> {
    many0!(
        input,
        alt!(escaped_percent_sign | spacing | padded_format | text_inside_conditional)
    )
}

fn parser(input: CompleteStr) -> IResult<CompleteStr, Vec<Specifier>> {
    many0!(
        input,
        alt!(
            conditional | escaped_percent_sign | spacing | padded_format | text_outside_conditional
        )
    )
}

fn sanitize(mut input: Vec<Specifier>) -> Vec<Specifier> {
    input.retain(|s| {
        if let Specifier::Format(c, _b) = s {
            c.is_ascii()
        } else {
            true
        }
    });
    input
}

pub fn parse(input: &str) -> Vec<Specifier> {
    match parser(CompleteStr(input)) {
        Ok((_leftovers, ast)) => sanitize(ast),
        Err(_) => vec![Specifier::Text("")],
    }
}

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

    #[test]
    fn t_parses_formats_without_specifiers() {
        let input = "Hello, world!";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();
        assert_eq!(leftovers, CompleteStr(""));
        assert_eq!(result, vec![Specifier::Text("Hello, world!")]);
    }

    #[test]
    fn t_replaces_double_percent_with_a_single_percent() {
        let input = "%%";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();
        assert_eq!(leftovers, CompleteStr(""));
        assert_eq!(result, vec![Specifier::Text("%")]);
    }

    #[test]
    fn t_parses_sequences_of_specifiers() {
        let input = "100%% pure Ceylon tea";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();
        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Text("100"),
            Specifier::Text("%"),
            Specifier::Text(" pure Ceylon tea"),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_formats_with_letters() {
        let input = "%t (%a)";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Format('t', Padding::None),
            Specifier::Text(" ("),
            Specifier::Format('a', Padding::None),
            Specifier::Text(")"),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_formats_with_positive_padding() {
        let input = "%8a%4b%13x";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Format('a', Padding::Left(8)),
            Specifier::Format('b', Padding::Left(4)),
            Specifier::Format('x', Padding::Left(13)),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_formats_with_negative_padding() {
        let input = "%-8a%-4b%-13x";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Format('a', Padding::Right(8)),
            Specifier::Format('b', Padding::Right(4)),
            Specifier::Format('x', Padding::Right(13)),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_spacing_format() {
        let input = "%-8a%>m%4b%> %-13x";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Format('a', Padding::Right(8)),
            Specifier::Spacing('m'),
            Specifier::Format('b', Padding::Left(4)),
            Specifier::Spacing(' '),
            Specifier::Format('x', Padding::Right(13)),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_conditionals() {
        let input = "%?x?success&failure?";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![Specifier::Conditional(
            'x',
            vec![Specifier::Text("success")],
            Some(vec![Specifier::Text("failure")]),
        )];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_conditionals_without_else_branch() {
        let input = "%?x?success?";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![Specifier::Conditional(
            'x',
            vec![Specifier::Text("success")],
            None,
        )];
        assert_eq!(result, expected);
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::collections::hash_map::DefaultHasher;
use std::fmt;
use std::hash::{BuildHasher, Hash, Hasher};

use utils::MyBuildHasherDefault;

/// A simple implementation of a [HyperLogLog](https://en.wikipedia.org/wiki/HyperLogLog)
#[derive(Clone)]
pub struct HyperLogLog<B = MyBuildHasherDefault<DefaultHasher>>
where
    B: BuildHasher + Clone + Eq,
{
    registers: Vec<u8>,
    b: usize,
    buildhasher: B,
}

impl HyperLogLog {
    /// Creates a new, empty HyperLogLog.
    ///
    /// - `b` number of bits used for register selection, number of registers within the
    ///   HyperLogLog will be `2^b`. `b` must be in `[4, 16]`
    ///
    /// Panics when `b` is out of bounds.
    pub fn new(b: usize) -> HyperLogLog {
        assert!(b >= 4);
        assert!(b <= 16);

        let bh = MyBuildHasherDefault::<DefaultHasher>::default();
        Self::with_hash(b, bh)
    }
}

impl<B> HyperLogLog<B>
where
    B: BuildHasher + Clone + Eq,
{
    /// Same as `new` but with a specific `BuildHasher`.
    pub fn with_hash(b: usize, buildhasher: B) -> HyperLogLog<B> {
        assert!(b >= 4);
        assert!(b <= 16);

        let m = (1 as usize) << b;
        let registers = vec![0; m];
        HyperLogLog {
            registers: registers,
            b: b,
            buildhasher: buildhasher,
        }
    }

    /// Get number of bits used for register selection.
    pub fn b(&self) -> usize {
        self.b
    }

    /// Get number of registers.
    pub fn m(&self) -> usize {
        self.registers.len()
    }

    /// Get `BuildHasher`.
    pub fn buildhasher(&self) -> &B {
        &self.buildhasher
    }

    /// Adds an element to the HyperLogLog.
    pub fn add<T>(&mut self, obj: &T)
    where
        T: Hash,
    {
        let mut hasher = self.buildhasher.build_hasher();
        obj.hash(&mut hasher);
        let h: u64 = hasher.finish();

        let w = h >> self.b;
        let j = h - (w << self.b);
        let p = w.leading_zeros() + 1 - (self.b as u32);

        let m_old = self.registers[j as usize];
        self.registers[j as usize] = cmp::max(m_old, p as u8);
    }

    /// Guess the number of unique elements seen by the HyperLogLog.
    pub fn count(&self) -> usize {
        let m = self.registers.len() as f64;

        let z = 1f64
            / self.registers
                .iter()
                .map(|&x| 2f64.powi(-(x as i32)))
                .sum::<f64>();

        let am = if m >= 128. {
            0.7213 / (1. + 1.079 / m)
        } else if m >= 64. {
            0.709
        } else if m >= 32. {
            0.697
        } else {
            0.673
        };

        let e = am * m * m * z;

        let e_star = if e <= 5. / 2. * m {
            // small range correction
            let v = self.registers.iter().filter(|&&x| x == 0).count();
            if v != 0 {
                m * (m / (v as f64)).ln()
            } else {
                e
            }
        } else if e <= 1. / 30. * 2f64.powi(32) {
            // intermediate range => no correction
            e
        } else {
            // large range correction
            -2f64.powi(32) * (1. - e / 2f64.powi(32)).ln()
        };

        e_star as usize
    }

    /// Merge w/ another HyperLogLog.
    ///
    /// This HyperLogLog will then have the same state as if all elements seen by `other` where
    /// directly added to `self`.
    ///
    /// Panics when `b` or `buildhasher` parameter of `self` and `other` do not match.
    pub fn merge(&mut self, other: &HyperLogLog<B>) {
        assert_eq!(self.b, other.b);
        assert!(self.buildhasher == other.buildhasher);

        self.registers = self.registers
            .iter()
            .zip(other.registers.iter())
            .map(|x| cmp::max(x.0, x.1))
            .cloned()
            .collect();
    }

    /// Empties the HyperLogLog.
    pub fn clear(&mut self) {
        self.registers = vec![0; self.registers.len()];
    }

    /// Checks whether the HyperLogLog has never seen an element.
    pub fn is_empty(&self) -> bool {
        self.registers.iter().all(|&x| x == 0)
    }
}

impl fmt::Debug for HyperLogLog {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "HyperLogLog {{ b: {} }}", self.b)
    }
}

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

    #[test]
    fn getter() {
        let hll = HyperLogLog::new(8);
        assert_eq!(hll.b(), 8);
        assert_eq!(hll.m(), 1 << 8);
        hll.buildhasher();
    }

    #[test]
    fn empty() {
        let hll = HyperLogLog::new(8);
        assert_eq!(hll.count(), 0);
        assert!(hll.is_empty());
    }

    #[test]
    fn add_b4_n1k() {
        let mut hll = HyperLogLog::new(4);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 571);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b8_n1k() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 966);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b12_n1k() {
        let mut hll = HyperLogLog::new(12);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 984);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n1k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 998);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b8_n10k() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10196);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b12_n10k() {
        let mut hll = HyperLogLog::new(12);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10303);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n10k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10055);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n100k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..100000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 100551);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n1m() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..1000000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 1000226);
        assert!(!hll.is_empty());
    }

    #[test]
    fn clear() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..1000 {
            hll.add(&i);
        }
        hll.clear();
        assert_eq!(hll.count(), 0);
        assert!(hll.is_empty());
    }

    #[test]
    fn clone() {
        let mut hll1 = HyperLogLog::new(12);
        for i in 0..500 {
            hll1.add(&i);
        }
        let c1a = hll1.count();

        let hll2 = hll1.clone();
        assert_eq!(hll2.count(), c1a);

        for i in 501..1000 {
            hll1.add(&i);
        }
        let c1b = hll1.count();
        assert_ne!(c1b, c1a);
        assert_eq!(hll2.count(), c1a);
    }

    #[test]
    fn merge() {
        let mut hll1 = HyperLogLog::new(12);
        let mut hll2 = HyperLogLog::new(12);
        let mut hll = HyperLogLog::new(12);
        for i in 0..500 {
            hll.add(&i);
            hll1.add(&i);
        }
        for i in 501..1000 {
            hll.add(&i);
            hll2.add(&i);
        }
        assert_ne!(hll.count(), hll1.count());
        assert_ne!(hll.count(), hll2.count());

        hll1.merge(&hll2);
        assert_eq!(hll.count(), hll1.count());
    }

    #[test]
    fn debug() {
        let hll = HyperLogLog::new(12);
        assert_eq!(format!("{:?}", hll), "HyperLogLog { b: 12 }");
    }
}
<commit_msg>hyperloglog: impl Extend<commit_after>use std::cmp;
use std::collections::hash_map::DefaultHasher;
use std::fmt;
use std::hash::{BuildHasher, Hash, Hasher};

use utils::MyBuildHasherDefault;

/// A simple implementation of a [HyperLogLog](https://en.wikipedia.org/wiki/HyperLogLog)
#[derive(Clone)]
pub struct HyperLogLog<B = MyBuildHasherDefault<DefaultHasher>>
where
    B: BuildHasher + Clone + Eq,
{
    registers: Vec<u8>,
    b: usize,
    buildhasher: B,
}

impl HyperLogLog {
    /// Creates a new, empty HyperLogLog.
    ///
    /// - `b` number of bits used for register selection, number of registers within the
    ///   HyperLogLog will be `2^b`. `b` must be in `[4, 16]`
    ///
    /// Panics when `b` is out of bounds.
    pub fn new(b: usize) -> HyperLogLog {
        assert!(b >= 4);
        assert!(b <= 16);

        let bh = MyBuildHasherDefault::<DefaultHasher>::default();
        Self::with_hash(b, bh)
    }
}

impl<B> HyperLogLog<B>
where
    B: BuildHasher + Clone + Eq,
{
    /// Same as `new` but with a specific `BuildHasher`.
    pub fn with_hash(b: usize, buildhasher: B) -> HyperLogLog<B> {
        assert!(b >= 4);
        assert!(b <= 16);

        let m = (1 as usize) << b;
        let registers = vec![0; m];
        HyperLogLog {
            registers: registers,
            b: b,
            buildhasher: buildhasher,
        }
    }

    /// Get number of bits used for register selection.
    pub fn b(&self) -> usize {
        self.b
    }

    /// Get number of registers.
    pub fn m(&self) -> usize {
        self.registers.len()
    }

    /// Get `BuildHasher`.
    pub fn buildhasher(&self) -> &B {
        &self.buildhasher
    }

    /// Adds an element to the HyperLogLog.
    pub fn add<T>(&mut self, obj: &T)
    where
        T: Hash,
    {
        let mut hasher = self.buildhasher.build_hasher();
        obj.hash(&mut hasher);
        let h: u64 = hasher.finish();

        let w = h >> self.b;
        let j = h - (w << self.b);
        let p = w.leading_zeros() + 1 - (self.b as u32);

        let m_old = self.registers[j as usize];
        self.registers[j as usize] = cmp::max(m_old, p as u8);
    }

    /// Guess the number of unique elements seen by the HyperLogLog.
    pub fn count(&self) -> usize {
        let m = self.registers.len() as f64;

        let z = 1f64
            / self.registers
                .iter()
                .map(|&x| 2f64.powi(-(x as i32)))
                .sum::<f64>();

        let am = if m >= 128. {
            0.7213 / (1. + 1.079 / m)
        } else if m >= 64. {
            0.709
        } else if m >= 32. {
            0.697
        } else {
            0.673
        };

        let e = am * m * m * z;

        let e_star = if e <= 5. / 2. * m {
            // small range correction
            let v = self.registers.iter().filter(|&&x| x == 0).count();
            if v != 0 {
                m * (m / (v as f64)).ln()
            } else {
                e
            }
        } else if e <= 1. / 30. * 2f64.powi(32) {
            // intermediate range => no correction
            e
        } else {
            // large range correction
            -2f64.powi(32) * (1. - e / 2f64.powi(32)).ln()
        };

        e_star as usize
    }

    /// Merge w/ another HyperLogLog.
    ///
    /// This HyperLogLog will then have the same state as if all elements seen by `other` where
    /// directly added to `self`.
    ///
    /// Panics when `b` or `buildhasher` parameter of `self` and `other` do not match.
    pub fn merge(&mut self, other: &HyperLogLog<B>) {
        assert_eq!(self.b, other.b);
        assert!(self.buildhasher == other.buildhasher);

        self.registers = self.registers
            .iter()
            .zip(other.registers.iter())
            .map(|x| cmp::max(x.0, x.1))
            .cloned()
            .collect();
    }

    /// Empties the HyperLogLog.
    pub fn clear(&mut self) {
        self.registers = vec![0; self.registers.len()];
    }

    /// Checks whether the HyperLogLog has never seen an element.
    pub fn is_empty(&self) -> bool {
        self.registers.iter().all(|&x| x == 0)
    }
}

impl fmt::Debug for HyperLogLog {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "HyperLogLog {{ b: {} }}", self.b)
    }
}

impl<T> Extend<T> for HyperLogLog
where
    T: Hash,
{
    fn extend<S: IntoIterator<Item = T>>(&mut self, iter: S) {
        for elem in iter {
            self.add(&elem);
        }
    }
}

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

    #[test]
    fn getter() {
        let hll = HyperLogLog::new(8);
        assert_eq!(hll.b(), 8);
        assert_eq!(hll.m(), 1 << 8);
        hll.buildhasher();
    }

    #[test]
    fn empty() {
        let hll = HyperLogLog::new(8);
        assert_eq!(hll.count(), 0);
        assert!(hll.is_empty());
    }

    #[test]
    fn add_b4_n1k() {
        let mut hll = HyperLogLog::new(4);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 571);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b8_n1k() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 966);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b12_n1k() {
        let mut hll = HyperLogLog::new(12);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 984);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n1k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 998);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b8_n10k() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10196);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b12_n10k() {
        let mut hll = HyperLogLog::new(12);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10303);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n10k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10055);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n100k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..100000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 100551);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n1m() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..1000000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 1000226);
        assert!(!hll.is_empty());
    }

    #[test]
    fn clear() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..1000 {
            hll.add(&i);
        }
        hll.clear();
        assert_eq!(hll.count(), 0);
        assert!(hll.is_empty());
    }

    #[test]
    fn clone() {
        let mut hll1 = HyperLogLog::new(12);
        for i in 0..500 {
            hll1.add(&i);
        }
        let c1a = hll1.count();

        let hll2 = hll1.clone();
        assert_eq!(hll2.count(), c1a);

        for i in 501..1000 {
            hll1.add(&i);
        }
        let c1b = hll1.count();
        assert_ne!(c1b, c1a);
        assert_eq!(hll2.count(), c1a);
    }

    #[test]
    fn merge() {
        let mut hll1 = HyperLogLog::new(12);
        let mut hll2 = HyperLogLog::new(12);
        let mut hll = HyperLogLog::new(12);
        for i in 0..500 {
            hll.add(&i);
            hll1.add(&i);
        }
        for i in 501..1000 {
            hll.add(&i);
            hll2.add(&i);
        }
        assert_ne!(hll.count(), hll1.count());
        assert_ne!(hll.count(), hll2.count());

        hll1.merge(&hll2);
        assert_eq!(hll.count(), hll1.count());
    }

    #[test]
    fn debug() {
        let hll = HyperLogLog::new(12);
        assert_eq!(format!("{:?}", hll), "HyperLogLog { b: 12 }");
    }

    #[test]
    fn extend() {
        let mut hll = HyperLogLog::new(4);
        hll.extend(0..1000);
        assert_eq!(hll.count(), 571);
        assert!(!hll.is_empty());
    }
}
<|endoftext|>


<commit_before>use nalgebra::Point2;
use std::collections::HashSet;

use event::{ElementState, Event, MouseButton, Reactor};
use super::state::{Element, InputState, InputStateSnapshot, ToInputState};

impl Element for MouseButton {
    type State = ElementState;
}

#[derive(Clone, Copy)]
pub struct MouseProximity;

impl Element for MouseProximity {
    type State = bool;
}

pub struct Mouse {
    position: Point2<u32>,
    state: MouseState,
    snapshot: MouseState,
}

impl Mouse {
    pub fn new() -> Self {
        Mouse {
            position: Point2::origin(),
            state: MouseState::new(),
            snapshot: MouseState::new(),
        }
    }

    pub fn position(&self) -> &Point2<u32> {
        &self.position
    }
}

impl InputState<MouseButton> for Mouse {
    fn state(&self, button: MouseButton) -> ElementState {
        self.state.state(button)
    }
}

impl Reactor for Mouse {
    fn react(&mut self, event: &Event) {
        match *event {
            Event::MouseEntered => {
                self.state.proximity = true;
            }
            Event::MouseInput(ElementState::Pressed, button) => {
                self.state.buttons.insert(button);
            }
            Event::MouseInput(ElementState::Released, button) => {
                self.state.buttons.remove(&button);
            }
            Event::MouseLeft => {
                self.state.proximity = false;
            }
            Event::MouseMoved(x, y) => {
                self.position = Point2::new(x as u32, y as u32);
            }
            _ => {}
        }
    }
}

impl InputStateSnapshot for Mouse {
    type Snapshot = MouseState;

    fn snapshot(&mut self) {
        self.snapshot = self.to_state();
    }

    fn as_snapshot_state(&self) -> &Self::Snapshot {
        &self.snapshot
    }
}

impl ToInputState<MouseButton> for Mouse {
    type InputState = MouseState;

    fn to_state(&self) -> Self::InputState {
        self.state.clone()
    }
}

#[derive(Clone)]
pub struct MouseState {
    buttons: HashSet<MouseButton>,
    proximity: bool,
}

impl MouseState {
    pub fn new() -> Self {
        MouseState {
            buttons: HashSet::new(),
            proximity: false,
        }
    }
}

impl InputState<MouseButton> for MouseState {
    fn state(&self, button: MouseButton) -> ElementState {
        if self.buttons.contains(&button) {
            ElementState::Pressed
        }
        else {
            ElementState::Released
        }
    }
}

impl InputState<MouseProximity> for MouseState {
    fn state(&self, _: MouseProximity) -> bool {
        self.proximity
    }
}
<commit_msg>Implement `InputState` for mouse proximity.<commit_after>use nalgebra::Point2;
use std::collections::HashSet;

use event::{ElementState, Event, MouseButton, Reactor};
use super::state::{Element, InputState, InputStateSnapshot, ToInputState};

impl Element for MouseButton {
    type State = ElementState;
}

#[derive(Clone, Copy)]
pub struct MouseProximity;

impl Element for MouseProximity {
    type State = bool;
}

pub struct Mouse {
    position: Point2<u32>,
    state: MouseState,
    snapshot: MouseState,
}

impl Mouse {
    pub fn new() -> Self {
        Mouse {
            position: Point2::origin(),
            state: MouseState::new(),
            snapshot: MouseState::new(),
        }
    }

    pub fn position(&self) -> &Point2<u32> {
        &self.position
    }
}

impl InputState<MouseButton> for Mouse {
    fn state(&self, button: MouseButton) -> ElementState {
        self.state.state(button)
    }
}

impl InputState<MouseProximity> for Mouse {
    fn state(&self, proximity: MouseProximity) -> bool {
        self.state.state(proximity)
    }
}

impl Reactor for Mouse {
    fn react(&mut self, event: &Event) {
        match *event {
            Event::MouseEntered => {
                self.state.proximity = true;
            }
            Event::MouseInput(ElementState::Pressed, button) => {
                self.state.buttons.insert(button);
            }
            Event::MouseInput(ElementState::Released, button) => {
                self.state.buttons.remove(&button);
            }
            Event::MouseLeft => {
                self.state.proximity = false;
            }
            Event::MouseMoved(x, y) => {
                self.position = Point2::new(x as u32, y as u32);
            }
            _ => {}
        }
    }
}

impl InputStateSnapshot for Mouse {
    type Snapshot = MouseState;

    fn snapshot(&mut self) {
        self.snapshot = self.to_state();
    }

    fn as_snapshot_state(&self) -> &Self::Snapshot {
        &self.snapshot
    }
}

impl ToInputState<MouseButton> for Mouse {
    type InputState = MouseState;

    fn to_state(&self) -> Self::InputState {
        self.state.clone()
    }
}

#[derive(Clone)]
pub struct MouseState {
    buttons: HashSet<MouseButton>,
    proximity: bool,
}

impl MouseState {
    pub fn new() -> Self {
        MouseState {
            buttons: HashSet::new(),
            proximity: false,
        }
    }
}

impl InputState<MouseButton> for MouseState {
    fn state(&self, button: MouseButton) -> ElementState {
        if self.buttons.contains(&button) {
            ElementState::Pressed
        }
        else {
            ElementState::Released
        }
    }
}

impl InputState<MouseProximity> for MouseState {
    fn state(&self, _: MouseProximity) -> bool {
        self.proximity
    }
}
<|endoftext|>


<commit_before>use rustc::middle::{const_eval, def_id, ty};
use rustc_mir::mir_map::MirMap;
use rustc_mir::repr::{self as mir, Mir};
use syntax::ast::Attribute;
use syntax::attr::AttrMetaMethods;

use std::iter;

const TRACE_EXECUTION: bool = false;

#[derive(Clone, Debug, PartialEq)]
enum Value {
    Uninit,
    Bool(bool),
    Int(i64), // FIXME: Should be bit-width aware.
    Func(def_id::DefId),
}

#[derive(Debug)]
struct Frame {
    offset: usize,
    num_args: usize,
    num_vars: usize,
    num_temps: usize,
}

impl Frame {
    fn size(&self) -> usize {
        1 + self.num_args + self.num_vars + self.num_temps
    }
}

struct Interpreter<'a, 'tcx: 'a> {
    tcx: &'a ty::ctxt<'tcx>,
    mir_map: &'a MirMap<'tcx>,
    value_stack: Vec<Value>,
    call_stack: Vec<Frame>,
}

impl<'a, 'tcx> Interpreter<'a, 'tcx> {
    fn new(tcx: &'a ty::ctxt<'tcx>, mir_map: &'a MirMap<'tcx>) -> Self {
        Interpreter {
            tcx: tcx,
            mir_map: mir_map,
            value_stack: Vec::new(),
            call_stack: Vec::new(),
        }
    }

    fn push_stack_frame(&mut self, mir: &Mir, args: &[Value]) {
        self.call_stack.push(Frame {
            offset: self.value_stack.len(),
            num_args: mir.arg_decls.len(),
            num_vars: mir.var_decls.len(),
            num_temps: mir.temp_decls.len(),
        });

        let frame = self.call_stack.last().unwrap();
        self.value_stack.extend(iter::repeat(Value::Uninit).take(frame.size()));

        for (i, arg) in args.iter().enumerate() {
            self.value_stack[frame.offset + 1 + i] = arg.clone();
        }
    }

    fn pop_stack_frame(&mut self) {
        let frame = self.call_stack.pop().expect("tried to pop stack frame, but there were none");
        self.value_stack.truncate(frame.offset);
    }

    fn call(&mut self, mir: &Mir, args: &[Value]) -> Value {
        self.push_stack_frame(mir, args);
        let mut block = mir::START_BLOCK;

        loop {
            use rustc_mir::repr::Terminator::*;

            let block_data = mir.basic_block_data(block);

            for stmt in &block_data.statements {
                use rustc_mir::repr::StatementKind::*;

                if TRACE_EXECUTION { println!("{:?}", stmt); }

                match stmt.kind {
                    Assign(ref lvalue, ref rvalue) => {
                        let index = self.eval_lvalue(lvalue);
                        let value = self.eval_rvalue(rvalue);
                        self.value_stack[index] = value;
                    }

                    Drop(_kind, ref _lv) => {
                        // TODO
                    },
                }
            }

            if TRACE_EXECUTION { println!("{:?}", block_data.terminator); }

            match block_data.terminator {
                Return => break,
                Goto { target } => block = target,

                Call { data: mir::CallData { ref destination, ref func, ref args }, targets } => {
                    let index = self.eval_lvalue(destination);
                    let func_val = self.eval_operand(func);

                    if let Value::Func(def_id) = func_val {
                        let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
                        let mir = &self.mir_map[&node_id];
                        let arg_vals: Vec<Value> =
                            args.iter().map(|arg| self.eval_operand(arg)).collect();

                        self.value_stack[index] = self.call(mir, &arg_vals);
                        block = targets[0];
                    } else {
                        panic!("tried to call a non-function value: {:?}", func_val);
                    }
                }

                If { ref cond, targets } => {
                    match self.eval_operand(cond) {
                        Value::Bool(true) => block = targets[0],
                        Value::Bool(false) => block = targets[1],
                        cond_val => panic!("Non-boolean `if` condition value: {:?}", cond_val),
                    }
                }

                SwitchInt { ref discr, switch_ty: _, ref values, ref targets } => {
                    let discr_val = &self.value_stack[self.eval_lvalue(discr)];

                    let index = values.iter().position(|v| *discr_val == self.eval_constant(v))
                        .expect("discriminant matched no values");

                    block = targets[index];
                }

                // Diverge => unimplemented!(),
                // Panic { target } => unimplemented!(),
                // Switch { ref discr, adt_def, ref targets } => unimplemented!(),
                _ => unimplemented!(),
            }
        }

        let ret_val = self.value_stack[self.eval_lvalue(&mir::Lvalue::ReturnPointer)].clone();
        self.pop_stack_frame();
        ret_val
    }

    fn eval_lvalue(&self, lvalue: &mir::Lvalue) -> usize {
        use rustc_mir::repr::Lvalue::*;

        let frame = self.call_stack.last().expect("missing call frame");

        match *lvalue {
            ReturnPointer => frame.offset,
            Arg(i)  => frame.offset + 1 + i as usize,
            Var(i)  => frame.offset + 1 + frame.num_args + i as usize,
            Temp(i) => frame.offset + 1 + frame.num_args + frame.num_vars + i as usize,
            _ => unimplemented!(),
        }
    }

    fn eval_rvalue(&mut self, rvalue: &mir::Rvalue) -> Value {
        use rustc_mir::repr::Rvalue::*;
        use rustc_mir::repr::BinOp::*;
        use rustc_mir::repr::UnOp::*;

        match *rvalue {
            Use(ref operand) => self.eval_operand(operand),

            BinaryOp(bin_op, ref left, ref right) => {
                match (self.eval_operand(left), self.eval_operand(right)) {
                    (Value::Int(l), Value::Int(r)) => {
                        match bin_op {
                            Add => Value::Int(l + r),
                            Sub => Value::Int(l - r),
                            Mul => Value::Int(l * r),
                            Div => Value::Int(l / r),
                            Rem => Value::Int(l % r),
                            BitXor => Value::Int(l ^ r),
                            BitAnd => Value::Int(l & r),
                            BitOr => Value::Int(l | r),
                            Shl => Value::Int(l << r),
                            Shr => Value::Int(l >> r),
                            Eq => Value::Bool(l == r),
                            Lt => Value::Bool(l < r),
                            Le => Value::Bool(l <= r),
                            Ne => Value::Bool(l != r),
                            Ge => Value::Bool(l >= r),
                            Gt => Value::Bool(l > r),
                        }
                    }
                    _ => unimplemented!(),
                }
            }

            UnaryOp(un_op, ref operand) => {
                match (un_op, self.eval_operand(operand)) {
                    (Not, Value::Int(n)) => Value::Int(!n),
                    (Neg, Value::Int(n)) => Value::Int(-n),
                    _ => unimplemented!(),
                }
            }

            _ => unimplemented!(),
        }
    }

    fn eval_operand(&mut self, op: &mir::Operand) -> Value {
        use rustc_mir::repr::Operand::*;

        match *op {
            Consume(ref lvalue) => self.value_stack[self.eval_lvalue(lvalue)].clone(),

            Constant(ref constant) => {
                match constant.literal {
                    mir::Literal::Value { ref value } => self.eval_constant(value),

                    mir::Literal::Item { def_id, substs: _ } => {
                        Value::Func(def_id)
                    }
                }
            }
        }
    }

    fn eval_constant(&self, const_val: &const_eval::ConstVal) -> Value {
        use rustc::middle::const_eval::ConstVal::*;

        match *const_val {
            Float(_f) => unimplemented!(),
            Int(i) => Value::Int(i),
            Uint(_u) => unimplemented!(),
            Str(ref _s) => unimplemented!(),
            ByteStr(ref _bs) => unimplemented!(),
            Bool(b) => Value::Bool(b),
            Struct(_node_id) => unimplemented!(),
            Tuple(_node_id) => unimplemented!(),
            Function(_def_id) => unimplemented!(),
        }
    }
}

pub fn interpret_start_points<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &MirMap<'tcx>) {
    for (&id, mir) in mir_map {
        for attr in tcx.map.attrs(id) {
            if attr.check_name("miri_run") {
                let item = tcx.map.expect_item(id);

                println!("Interpreting: {}", item.name);
                let mut interpreter = Interpreter::new(tcx, mir_map);
                let val = interpreter.call(mir, &[]);
                let val_str = format!("{:?}", val);

                if !check_expected(&val_str, attr) {
                    println!("=> {}\n", val_str);
                }
            }
        }
    }
}

fn check_expected(actual: &str, attr: &Attribute) -> bool {
    if let Some(meta_items) = attr.meta_item_list() {
        for meta_item in meta_items {
            if meta_item.check_name("expected") {
                let expected = meta_item.value_str().unwrap();

                if actual == &expected[..] {
                    println!("Test passed!\n");
                } else {
                    println!("Actual value:\t{}\nExpected value:\t{}\n", actual, expected);
                }

                return true;
            }
        }
    }

    false
}
<commit_msg>Refactor stack frames and pointers in preparation for aggregates like ADTs.<commit_after>use rustc::middle::{const_eval, def_id, ty};
use rustc_mir::mir_map::MirMap;
use rustc_mir::repr::{self as mir, Mir};
use syntax::ast::Attribute;
use syntax::attr::AttrMetaMethods;

use std::iter;

const TRACE_EXECUTION: bool = false;

#[derive(Clone, Debug, PartialEq)]
enum Value {
    Uninit,
    Bool(bool),
    Int(i64), // FIXME: Should be bit-width aware.
    Func(def_id::DefId),
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Pointer {
    Stack(usize),
    // TODO(tsion): Heap
}

/// A stack frame:
///
/// ```text
/// +-----------------------+
/// | ReturnPointer         | return value
/// + - - - - - - - - - - - +
/// | Arg(0)                |
/// | Arg(1)                | arguments
/// | ...                   |
/// | Arg(num_args - 1)     |
/// + - - - - - - - - - - - +
/// | Var(0)                |
/// | Var(1)                | variables
/// | ...                   |
/// | Var(num_vars - 1)     |
/// + - - - - - - - - - - - +
/// | Temp(0)               |
/// | Temp(1)               | temporaries
/// | ...                   |
/// | Temp(num_temps - 1)   |
/// + - - - - - - - - - - - +
/// | Aggregates            | aggregates
/// +-----------------------+
/// ```
#[derive(Debug)]
struct Frame {
    offset: usize,
    num_args: usize,
    num_vars: usize,
    num_temps: usize,
    // aggregates
}

impl Frame {
    fn size(&self) -> usize {
        1 + self.num_args + self.num_vars + self.num_temps
    }

    fn return_val_offset(&self) -> usize {
        self.offset
    }

    fn arg_offset(&self, i: u32) -> usize {
        self.offset + 1 + i as usize
    }

    fn var_offset(&self, i: u32) -> usize {
        self.offset + 1 + self.num_args + i as usize
    }

    fn temp_offset(&self, i: u32) -> usize {
        self.offset + 1 + self.num_args + self.num_vars + i as usize
    }
}

struct Interpreter<'a, 'tcx: 'a> {
    tcx: &'a ty::ctxt<'tcx>,
    mir_map: &'a MirMap<'tcx>,
    value_stack: Vec<Value>,
    call_stack: Vec<Frame>,
}

impl<'a, 'tcx> Interpreter<'a, 'tcx> {
    fn new(tcx: &'a ty::ctxt<'tcx>, mir_map: &'a MirMap<'tcx>) -> Self {
        Interpreter {
            tcx: tcx,
            mir_map: mir_map,
            value_stack: Vec::new(),
            call_stack: Vec::new(),
        }
    }

    fn push_stack_frame(&mut self, mir: &Mir, args: &[Value]) {
        self.call_stack.push(Frame {
            offset: self.value_stack.len(),
            num_args: mir.arg_decls.len(),
            num_vars: mir.var_decls.len(),
            num_temps: mir.temp_decls.len(),
        });

        let frame = self.call_stack.last().unwrap();
        self.value_stack.extend(iter::repeat(Value::Uninit).take(frame.size()));

        for (i, arg) in args.iter().enumerate() {
            self.value_stack[frame.offset + 1 + i] = arg.clone();
        }
    }

    fn pop_stack_frame(&mut self) {
        let frame = self.call_stack.pop().expect("tried to pop stack frame, but there were none");
        self.value_stack.truncate(frame.offset);
    }

    fn call(&mut self, mir: &Mir, args: &[Value]) -> Value {
        self.push_stack_frame(mir, args);
        let mut block = mir::START_BLOCK;

        loop {
            use rustc_mir::repr::Terminator::*;

            let block_data = mir.basic_block_data(block);

            for stmt in &block_data.statements {
                use rustc_mir::repr::StatementKind::*;

                if TRACE_EXECUTION { println!("{:?}", stmt); }

                match stmt.kind {
                    Assign(ref lvalue, ref rvalue) => {
                        let ptr = self.eval_lvalue(lvalue);
                        let value = self.eval_rvalue(rvalue);
                        self.write_pointer(ptr, value);
                    }

                    Drop(_kind, ref _lv) => {
                        // TODO
                    },
                }
            }

            if TRACE_EXECUTION { println!("{:?}", block_data.terminator); }

            match block_data.terminator {
                Return => break,
                Goto { target } => block = target,

                Call { data: mir::CallData { ref destination, ref func, ref args }, targets } => {
                    let ptr = self.eval_lvalue(destination);
                    let func_val = self.eval_operand(func);

                    if let Value::Func(def_id) = func_val {
                        let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
                        let mir = &self.mir_map[&node_id];
                        let arg_vals: Vec<Value> =
                            args.iter().map(|arg| self.eval_operand(arg)).collect();

                        // FIXME: Pass the destination lvalue such that the ReturnPointer inside
                        // the function call will point to the destination.
                        let return_val = self.call(mir, &arg_vals);
                        self.write_pointer(ptr, return_val);
                        block = targets[0];
                    } else {
                        panic!("tried to call a non-function value: {:?}", func_val);
                    }
                }

                If { ref cond, targets } => {
                    match self.eval_operand(cond) {
                        Value::Bool(true) => block = targets[0],
                        Value::Bool(false) => block = targets[1],
                        cond_val => panic!("Non-boolean `if` condition value: {:?}", cond_val),
                    }
                }

                SwitchInt { ref discr, switch_ty: _, ref values, ref targets } => {
                    let discr_val = self.read_lvalue(discr);

                    let index = values.iter().position(|v| discr_val == self.eval_constant(v))
                        .expect("discriminant matched no values");

                    block = targets[index];
                }

                // Diverge => unimplemented!(),
                // Panic { target } => unimplemented!(),
                // Switch { ref discr, adt_def, ref targets } => unimplemented!(),
                _ => unimplemented!(),
            }
        }

        let ret_val = self.read_lvalue(&mir::Lvalue::ReturnPointer);
        self.pop_stack_frame();
        ret_val
    }

    fn eval_lvalue(&self, lvalue: &mir::Lvalue) -> Pointer {
        use rustc_mir::repr::Lvalue::*;

        let frame = self.call_stack.last().expect("missing call frame");

        match *lvalue {
            ReturnPointer => Pointer::Stack(frame.return_val_offset()),
            Arg(i)  => Pointer::Stack(frame.arg_offset(i)),
            Var(i)  => Pointer::Stack(frame.var_offset(i)),
            Temp(i) => Pointer::Stack(frame.temp_offset(i)),
            _ => unimplemented!(),
        }
    }

    fn eval_rvalue(&mut self, rvalue: &mir::Rvalue) -> Value {
        use rustc_mir::repr::Rvalue::*;
        use rustc_mir::repr::BinOp::*;
        use rustc_mir::repr::UnOp::*;

        match *rvalue {
            Use(ref operand) => self.eval_operand(operand),

            BinaryOp(bin_op, ref left, ref right) => {
                match (self.eval_operand(left), self.eval_operand(right)) {
                    (Value::Int(l), Value::Int(r)) => {
                        match bin_op {
                            Add => Value::Int(l + r),
                            Sub => Value::Int(l - r),
                            Mul => Value::Int(l * r),
                            Div => Value::Int(l / r),
                            Rem => Value::Int(l % r),
                            BitXor => Value::Int(l ^ r),
                            BitAnd => Value::Int(l & r),
                            BitOr => Value::Int(l | r),
                            Shl => Value::Int(l << r),
                            Shr => Value::Int(l >> r),
                            Eq => Value::Bool(l == r),
                            Lt => Value::Bool(l < r),
                            Le => Value::Bool(l <= r),
                            Ne => Value::Bool(l != r),
                            Ge => Value::Bool(l >= r),
                            Gt => Value::Bool(l > r),
                        }
                    }
                    _ => unimplemented!(),
                }
            }

            UnaryOp(un_op, ref operand) => {
                match (un_op, self.eval_operand(operand)) {
                    (Not, Value::Int(n)) => Value::Int(!n),
                    (Neg, Value::Int(n)) => Value::Int(-n),
                    _ => unimplemented!(),
                }
            }

            // Aggregate(mir::AggregateKind::Adt(ref adt_def, variant, substs), ref operands) => {
            //     let num_fields = adt_def.variants[variant].fields.len();
            //     debug_assert_eq!(num_fields, operands.len());

            //     let data = operands.iter().map(|op| self.eval_operand(op)).collect();
            //     Value::Adt(variant, data)
            // }

            _ => unimplemented!(),
        }
    }

    fn eval_operand(&mut self, op: &mir::Operand) -> Value {
        use rustc_mir::repr::Operand::*;

        match *op {
            Consume(ref lvalue) => self.read_lvalue(lvalue),

            Constant(ref constant) => {
                match constant.literal {
                    mir::Literal::Value { ref value } => self.eval_constant(value),

                    mir::Literal::Item { def_id, substs: _ } => {
                        Value::Func(def_id)
                    }
                }
            }
        }
    }

    fn eval_constant(&self, const_val: &const_eval::ConstVal) -> Value {
        use rustc::middle::const_eval::ConstVal::*;

        match *const_val {
            Float(_f) => unimplemented!(),
            Int(i) => Value::Int(i),
            Uint(_u) => unimplemented!(),
            Str(ref _s) => unimplemented!(),
            ByteStr(ref _bs) => unimplemented!(),
            Bool(b) => Value::Bool(b),
            Struct(_node_id) => unimplemented!(),
            Tuple(_node_id) => unimplemented!(),
            Function(_def_id) => unimplemented!(),
        }
    }

    fn read_lvalue(&self, lvalue: &mir::Lvalue) -> Value {
        self.read_pointer(self.eval_lvalue(lvalue))
    }

    fn read_pointer(&self, p: Pointer) -> Value {
        match p {
            Pointer::Stack(offset) => self.value_stack[offset].clone(),
        }
    }

    fn write_pointer(&mut self, p: Pointer, val: Value) {
        match p {
            Pointer::Stack(offset) => self.value_stack[offset] = val,
        }
    }
}

pub fn interpret_start_points<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &MirMap<'tcx>) {
    for (&id, mir) in mir_map {
        for attr in tcx.map.attrs(id) {
            if attr.check_name("miri_run") {
                let item = tcx.map.expect_item(id);

                println!("Interpreting: {}", item.name);
                let mut interpreter = Interpreter::new(tcx, mir_map);
                let val = interpreter.call(mir, &[]);
                let val_str = format!("{:?}", val);

                if !check_expected(&val_str, attr) {
                    println!("=> {}\n", val_str);
                }
            }
        }
    }
}

fn check_expected(actual: &str, attr: &Attribute) -> bool {
    if let Some(meta_items) = attr.meta_item_list() {
        for meta_item in meta_items {
            if meta_item.check_name("expected") {
                let expected = meta_item.value_str().unwrap();

                if actual == &expected[..] {
                    println!("Test passed!\n");
                } else {
                    println!("Actual value:\t{}\nExpected value:\t{}\n", actual, expected);
                }

                return true;
            }
        }
    }

    false
}
<|endoftext|>


<commit_before>use std::collections::Bitv;

use super::{
    EdgeType,
    Incoming,
};
use super::graph::{
    Graph,
    IndexType,
    NodeIndex,
};

use super::visit::HasAdjacencyMatrix;

#[derive(Debug)]
struct Vf2State<Ty, Ix> {
    /// The current mapping M(s) of nodes from G0 → G1 and G1 → G0,
    /// NodeIndex::end() for no mapping.
    mapping: Vec<NodeIndex<Ix>>,
    /// out[i] is non-zero if i is in either M_0(s) or Tout_0(s)
    /// These are all the next vertices that are not mapped yet, but
    /// have an outgoing edge from the mapping.
    out: Vec<usize>,
    /// ins[i] is non-zero if i is in either M_0(s) or Tin_0(s)
    /// These are all the incoming vertices, those not mapped yet, but
    /// have an edge from them into the mapping.
    /// Unused if graph is undirected -- it's identical with out in that case.
    ins: Vec<usize>,
    out_size: usize,
    ins_size: usize,
    adjacency_matrix: Bitv,
    generation: usize,
}

impl<Ty, Ix> Vf2State<Ty, Ix> where
    Ty: EdgeType,
    Ix: IndexType,
{
    pub fn new<N, E>(g: &Graph<N, E, Ty, Ix>) -> Self
    {
        let c0 = g.node_count();
        let mut state = Vf2State {
            mapping: Vec::with_capacity(c0),
            out: Vec::with_capacity(c0),
            ins: Vec::with_capacity(c0 * (g.is_directed() as usize)),
            out_size: 0,
            ins_size: 0,
            adjacency_matrix: g.adjacency_matrix(),
            generation: 0,
        };
        for _ in (0..c0) {
            state.mapping.push(NodeIndex::end());
            state.out.push(0);
            if <Ty as EdgeType>::is_directed() {
                state.ins.push(0);
            }
        }
        state
    }

    /// Return **true** if we have a complete mapping
    pub fn is_complete(&self) -> bool
    {
        self.generation == self.mapping.len()
    }

    /// Add mapping **from** <-> **to** to the state.
    pub fn push_mapping<N, E>(&mut self, from: NodeIndex<Ix>, to: NodeIndex<Ix>,
                              g: &Graph<N, E, Ty, Ix>)
    {
        self.generation += 1;
        let s = self.generation;
        self.mapping[from.index()] = to;
        // update T0 & T1 ins/outs
        // T0out: Node in G0 not in M0 but successor of a node in M0.
        // st.out[0]: Node either in M0 or successor of M0
        for ix in g.neighbors(from) {
            if self.out[ix.index()] == 0 {
                self.out[ix.index()] = s;
            }
            self.out_size += 1;
        }
        if g.is_directed() {
            for ix in g.neighbors_directed(from, Incoming) {
                if self.ins[ix.index()] == 0 {
                    self.ins[ix.index()] = s;
                }
            }
            self.ins_size += 1;
        }
    }

    /// Restore the state to before the last added mapping
    pub fn pop_mapping<N, E>(&mut self, from: NodeIndex<Ix>,
                             g: &Graph<N, E, Ty, Ix>)
    {
        let s = self.generation;
        self.generation -= 1;

        // undo (n, m) mapping
        self.mapping[from.index()] = NodeIndex::end();

        // unmark in ins and outs
        for ix in g.neighbors(from) {
            if self.out[ix.index()] == s {
                self.out[ix.index()] = 0;
            }
            self.out_size -= 1;
        }
        if g.is_directed() {
            for ix in g.neighbors_directed(from, Incoming) {
                if self.ins[ix.index()] == s {
                    self.ins[ix.index()] = 0;
                }
            }
            self.ins_size -= 1;
        }
    }

    /// Find the next (least) node in the Tout set.
    pub fn next_out_index(&self, from_index: usize) -> Option<usize>
    {
        self.out[from_index..].iter()
                    .enumerate()
                    .filter(|&(index, elt)| *elt > 0 && self.mapping[from_index + index] == NodeIndex::end())
                    .next()
                    .map(|(index, _)| index)
    }

    /// Find the next (least) node in the Tin set.
    pub fn next_in_index(&self, from_index: usize) -> Option<usize>
    {
        if !<Ty as EdgeType>::is_directed() {
            return None
        }
        self.ins[from_index..].iter()
                    .enumerate()
                    .filter(|&(index, elt)| *elt > 0 && self.mapping[from_index + index] == NodeIndex::end())
                    .next()
                    .map(|(index, _)| index)
    }

    /// Find the next (least) node in the N - M set.
    pub fn next_rest_index(&self, from_index: usize) -> Option<usize>
    {
        self.mapping[from_index..].iter()
               .enumerate()
               .filter(|&(_, elt)| *elt == NodeIndex::end())
               .next()
               .map(|(index, _)| index)
    }
}

/// Return **true** if the graphs **g0** and **g1** are isomorphic.
///
/// Using the VF2 algorithm.
///
/// Not implemented: Vertex or edge weight matching.
///
/// ## References
///
/// * A (Sub)Graph Isomorphism Algorithm for Matching Large Graphs
///   Luigi P. Cordella, Pasquale Foggia, Carlo Sansone,
///   and Mario Vento
pub fn is_isomorphic<N, E, Ix, Ty>(g0: &Graph<N, E, Ty, Ix>,
                                   g1: &Graph<N, E, Ty, Ix>) -> bool where
    Ix: IndexType,
    Ty: EdgeType,
{
    if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
        return false
    }

    /// Return Some(bool) if isomorphism is decided, else None.
    fn try_match<N, E, Ix, Ty>(st: &mut [Vf2State<Ty, Ix>; 2],
                               g0: &Graph<N, E, Ty, Ix>,
                               g1: &Graph<N, E, Ty, Ix>) -> Option<bool> where
        Ix: IndexType,
        Ty: EdgeType,
    {
        let g = [g0, g1];
        let graph_indices = 0..2us;
        let end = NodeIndex::end();

        // if all are mapped -- we are done and have an iso
        if st[0].is_complete() {
            return Some(true)
        }

        // A "depth first" search of a valid mapping from graph 1 to graph 2

        // F(s, n, m) -- evaluate state s and add mapping n <-> m

        // Find least T1out node (in st.out[1] but not in M[1])
        #[derive(Copy, Clone, PartialEq, Debug)]
        enum OpenList {
            Out,
            In,
            Other,
        }
        let mut open_list = OpenList::Out;

        let mut to_index;
        let mut from_index = None;
        // Try the out list
        to_index = st[1].next_out_index(0);

        if to_index.is_some() {
            from_index = st[0].next_out_index(0);
            open_list = OpenList::Out;
        }

        // Try the in list
        if to_index.is_none() || from_index.is_none() {
            to_index = st[1].next_in_index(0);

            if to_index.is_some() {
                from_index = st[0].next_in_index(0);
                open_list = OpenList::In;
            }
        }

        // Try the other list -- disconnected graph
        if to_index.is_none() || from_index.is_none() {
            to_index = st[1].next_rest_index(0);
            if to_index.is_some() {
                from_index = st[0].next_rest_index(0);
                open_list = OpenList::Other;
            }
        }

        let (cand0, cand1) = match (from_index, to_index) {
            (Some(n), Some(m)) => (n, m),
            // No more candidates
            _ => return None,
        };

        let mut nx = NodeIndex::new(cand0);
        let mx = NodeIndex::new(cand1);

        let mut first = true;

        'candidates: loop {
            if !first {
                // Find the next node index to try on the `from` side of the mapping
                let start = nx.index() + 1;
                let cand0 = match open_list {
                    OpenList::Out => st[0].next_out_index(start),
                    OpenList::In => st[0].next_in_index(start),
                    OpenList::Other => st[0].next_rest_index(start),
                }.map(|c| c + start); // compensate for start offset.
                nx = match cand0 {
                    None => break, // no more candidates
                    Some(ix) => NodeIndex::new(ix),
                };
                debug_assert!(nx.index() >= start);
            }
            first = false;

            let nodes = [nx, mx];

            /*
            print!("Mapping state: ");
            for (index, nmap) in st.mapping[0].iter().enumerate() {
                if *nmap == end {
                    continue;
                }
                print!("{} => {}, ", index, nmap.index());
            }
            println!("{} => {}", nx.index(), mx.index());
            */

            // Check syntactic feasibility of mapping by ensuring adjacencies
            // of nx map to adjacencies of mx.
            //
            // nx == map to => mx
            //
            // R_succ
            //
            // Check that every neighbor of nx is mapped to a neighbor of mx,
            // then check the reverse, from mx to nx. Check that they have the same
            // count of edges.
            let mut succ_count = [0, 0];
            for j in graph_indices.clone() {
                for n_neigh in g[j].neighbors(nodes[j]) {
                    succ_count[j] += 1;
                    let m_neigh = st[j].mapping[n_neigh.index()];
                    if m_neigh == end {
                        continue;
                    }
                    let has_edge = g[1-j].is_adjacent(&st[1-j].adjacency_matrix, nodes[1-j], m_neigh);
                    if !has_edge {
                        continue 'candidates;
                    }
                }
            }
            if succ_count[0] != succ_count[1] {
                continue 'candidates;
            }

            // R_pred
            if g[0].is_directed() {
                let mut pred_count = [0, 0];
                for j in graph_indices.clone() {
                    for n_neigh in g[j].neighbors_directed(nodes[j], Incoming) {
                        pred_count[j] += 1;
                        let m_neigh = st[j].mapping[n_neigh.index()];
                        if m_neigh == end {
                            continue;
                        }
                        let has_edge = g[1-j].is_adjacent(&st[1-j].adjacency_matrix, m_neigh, nodes[1-j]);
                        if !has_edge {
                            continue 'candidates;
                        }
                    }
                }
                if pred_count[0] != pred_count[1] {
                    continue 'candidates;
                }
            }

            // Add mapping nx <-> mx to the state
            for j in graph_indices.clone() {
                st[j].push_mapping(nodes[j], nodes[1-j], g[j]);
            }

            // Check counts in Tin/Tout
            if st[0].out_size == st[0].out_size ||
               st[1].ins_size == st[1].ins_size
            {

                // Recurse
                match try_match(st, g0, g1) {
                    None => {}
                    result => return result,
                }
            }

            // Restore state.
            for j in graph_indices.clone() {
                st[j].pop_mapping(nodes[j], g[j]);
            }
        }
        None
    }
    let mut st = [Vf2State::new(g0), Vf2State::new(g1)];
    try_match(&mut st, g0, g1).unwrap_or(false)
}

<commit_msg>Add note about the lookahead measures<commit_after>use std::collections::Bitv;

use super::{
    EdgeType,
    Incoming,
};
use super::graph::{
    Graph,
    IndexType,
    NodeIndex,
};

use super::visit::HasAdjacencyMatrix;

#[derive(Debug)]
struct Vf2State<Ty, Ix> {
    /// The current mapping M(s) of nodes from G0 → G1 and G1 → G0,
    /// NodeIndex::end() for no mapping.
    mapping: Vec<NodeIndex<Ix>>,
    /// out[i] is non-zero if i is in either M_0(s) or Tout_0(s)
    /// These are all the next vertices that are not mapped yet, but
    /// have an outgoing edge from the mapping.
    out: Vec<usize>,
    /// ins[i] is non-zero if i is in either M_0(s) or Tin_0(s)
    /// These are all the incoming vertices, those not mapped yet, but
    /// have an edge from them into the mapping.
    /// Unused if graph is undirected -- it's identical with out in that case.
    ins: Vec<usize>,
    out_size: usize,
    ins_size: usize,
    adjacency_matrix: Bitv,
    generation: usize,
}

impl<Ty, Ix> Vf2State<Ty, Ix> where
    Ty: EdgeType,
    Ix: IndexType,
{
    pub fn new<N, E>(g: &Graph<N, E, Ty, Ix>) -> Self
    {
        let c0 = g.node_count();
        let mut state = Vf2State {
            mapping: Vec::with_capacity(c0),
            out: Vec::with_capacity(c0),
            ins: Vec::with_capacity(c0 * (g.is_directed() as usize)),
            out_size: 0,
            ins_size: 0,
            adjacency_matrix: g.adjacency_matrix(),
            generation: 0,
        };
        for _ in (0..c0) {
            state.mapping.push(NodeIndex::end());
            state.out.push(0);
            if <Ty as EdgeType>::is_directed() {
                state.ins.push(0);
            }
        }
        state
    }

    /// Return **true** if we have a complete mapping
    pub fn is_complete(&self) -> bool
    {
        self.generation == self.mapping.len()
    }

    /// Add mapping **from** <-> **to** to the state.
    pub fn push_mapping<N, E>(&mut self, from: NodeIndex<Ix>, to: NodeIndex<Ix>,
                              g: &Graph<N, E, Ty, Ix>)
    {
        self.generation += 1;
        let s = self.generation;
        self.mapping[from.index()] = to;
        // update T0 & T1 ins/outs
        // T0out: Node in G0 not in M0 but successor of a node in M0.
        // st.out[0]: Node either in M0 or successor of M0
        for ix in g.neighbors(from) {
            if self.out[ix.index()] == 0 {
                self.out[ix.index()] = s;
            }
            self.out_size += 1;
        }
        if g.is_directed() {
            for ix in g.neighbors_directed(from, Incoming) {
                if self.ins[ix.index()] == 0 {
                    self.ins[ix.index()] = s;
                }
            }
            self.ins_size += 1;
        }
    }

    /// Restore the state to before the last added mapping
    pub fn pop_mapping<N, E>(&mut self, from: NodeIndex<Ix>,
                             g: &Graph<N, E, Ty, Ix>)
    {
        let s = self.generation;
        self.generation -= 1;

        // undo (n, m) mapping
        self.mapping[from.index()] = NodeIndex::end();

        // unmark in ins and outs
        for ix in g.neighbors(from) {
            if self.out[ix.index()] == s {
                self.out[ix.index()] = 0;
            }
            self.out_size -= 1;
        }
        if g.is_directed() {
            for ix in g.neighbors_directed(from, Incoming) {
                if self.ins[ix.index()] == s {
                    self.ins[ix.index()] = 0;
                }
            }
            self.ins_size -= 1;
        }
    }

    /// Find the next (least) node in the Tout set.
    pub fn next_out_index(&self, from_index: usize) -> Option<usize>
    {
        self.out[from_index..].iter()
                    .enumerate()
                    .filter(|&(index, elt)| *elt > 0 && self.mapping[from_index + index] == NodeIndex::end())
                    .next()
                    .map(|(index, _)| index)
    }

    /// Find the next (least) node in the Tin set.
    pub fn next_in_index(&self, from_index: usize) -> Option<usize>
    {
        if !<Ty as EdgeType>::is_directed() {
            return None
        }
        self.ins[from_index..].iter()
                    .enumerate()
                    .filter(|&(index, elt)| *elt > 0 && self.mapping[from_index + index] == NodeIndex::end())
                    .next()
                    .map(|(index, _)| index)
    }

    /// Find the next (least) node in the N - M set.
    pub fn next_rest_index(&self, from_index: usize) -> Option<usize>
    {
        self.mapping[from_index..].iter()
               .enumerate()
               .filter(|&(_, elt)| *elt == NodeIndex::end())
               .next()
               .map(|(index, _)| index)
    }
}

/// Return **true** if the graphs **g0** and **g1** are isomorphic.
///
/// Using the VF2 algorithm.
///
/// Not implemented: Vertex or edge weight matching.
///
/// ## References
///
/// * A (Sub)Graph Isomorphism Algorithm for Matching Large Graphs
///   Luigi P. Cordella, Pasquale Foggia, Carlo Sansone,
///   and Mario Vento
pub fn is_isomorphic<N, E, Ix, Ty>(g0: &Graph<N, E, Ty, Ix>,
                                   g1: &Graph<N, E, Ty, Ix>) -> bool where
    Ix: IndexType,
    Ty: EdgeType,
{
    if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
        return false
    }

    /// Return Some(bool) if isomorphism is decided, else None.
    fn try_match<N, E, Ix, Ty>(st: &mut [Vf2State<Ty, Ix>; 2],
                               g0: &Graph<N, E, Ty, Ix>,
                               g1: &Graph<N, E, Ty, Ix>) -> Option<bool> where
        Ix: IndexType,
        Ty: EdgeType,
    {
        let g = [g0, g1];
        let graph_indices = 0..2us;
        let end = NodeIndex::end();

        // if all are mapped -- we are done and have an iso
        if st[0].is_complete() {
            return Some(true)
        }

        // A "depth first" search of a valid mapping from graph 1 to graph 2

        // F(s, n, m) -- evaluate state s and add mapping n <-> m

        // Find least T1out node (in st.out[1] but not in M[1])
        #[derive(Copy, Clone, PartialEq, Debug)]
        enum OpenList {
            Out,
            In,
            Other,
        }
        let mut open_list = OpenList::Out;

        let mut to_index;
        let mut from_index = None;
        // Try the out list
        to_index = st[1].next_out_index(0);

        if to_index.is_some() {
            from_index = st[0].next_out_index(0);
            open_list = OpenList::Out;
        }

        // Try the in list
        if to_index.is_none() || from_index.is_none() {
            to_index = st[1].next_in_index(0);

            if to_index.is_some() {
                from_index = st[0].next_in_index(0);
                open_list = OpenList::In;
            }
        }

        // Try the other list -- disconnected graph
        if to_index.is_none() || from_index.is_none() {
            to_index = st[1].next_rest_index(0);
            if to_index.is_some() {
                from_index = st[0].next_rest_index(0);
                open_list = OpenList::Other;
            }
        }

        let (cand0, cand1) = match (from_index, to_index) {
            (Some(n), Some(m)) => (n, m),
            // No more candidates
            _ => return None,
        };

        let mut nx = NodeIndex::new(cand0);
        let mx = NodeIndex::new(cand1);

        let mut first = true;

        'candidates: loop {
            if !first {
                // Find the next node index to try on the `from` side of the mapping
                let start = nx.index() + 1;
                let cand0 = match open_list {
                    OpenList::Out => st[0].next_out_index(start),
                    OpenList::In => st[0].next_in_index(start),
                    OpenList::Other => st[0].next_rest_index(start),
                }.map(|c| c + start); // compensate for start offset.
                nx = match cand0 {
                    None => break, // no more candidates
                    Some(ix) => NodeIndex::new(ix),
                };
                debug_assert!(nx.index() >= start);
            }
            first = false;

            let nodes = [nx, mx];

            /*
            print!("Mapping state: ");
            for (index, nmap) in st.mapping[0].iter().enumerate() {
                if *nmap == end {
                    continue;
                }
                print!("{} => {}, ", index, nmap.index());
            }
            println!("{} => {}", nx.index(), mx.index());
            */

            // Check syntactic feasibility of mapping by ensuring adjacencies
            // of nx map to adjacencies of mx.
            //
            // nx == map to => mx
            //
            // R_succ
            //
            // Check that every neighbor of nx is mapped to a neighbor of mx,
            // then check the reverse, from mx to nx. Check that they have the same
            // count of edges.
            //
            // Note: We want to check the lookahead measures here if we can,
            // R_out: Equal for G0, G1: Card(Succ(G, n) ^ Tout); for both Succ and Pred
            // R_in: Same with Tin
            // R_new: Equal for G0, G1: Ñ n Pred(G, n); both Succ and Pred,
            //      Ñ is G0 - M - Tin - Tout
            // last attempt to add these did not speed up any of the testcases
            let mut succ_count = [0, 0];
            for j in graph_indices.clone() {
                for n_neigh in g[j].neighbors(nodes[j]) {
                    succ_count[j] += 1;
                    let m_neigh = st[j].mapping[n_neigh.index()];
                    if m_neigh == end {
                        continue;
                    }
                    let has_edge = g[1-j].is_adjacent(&st[1-j].adjacency_matrix, nodes[1-j], m_neigh);
                    if !has_edge {
                        continue 'candidates;
                    }
                }
            }
            if succ_count[0] != succ_count[1] {
                continue 'candidates;
            }

            // R_pred
            if g[0].is_directed() {
                let mut pred_count = [0, 0];
                for j in graph_indices.clone() {
                    for n_neigh in g[j].neighbors_directed(nodes[j], Incoming) {
                        pred_count[j] += 1;
                        let m_neigh = st[j].mapping[n_neigh.index()];
                        if m_neigh == end {
                            continue;
                        }
                        let has_edge = g[1-j].is_adjacent(&st[1-j].adjacency_matrix, m_neigh, nodes[1-j]);
                        if !has_edge {
                            continue 'candidates;
                        }
                    }
                }
                if pred_count[0] != pred_count[1] {
                    continue 'candidates;
                }
            }

            // Add mapping nx <-> mx to the state
            for j in graph_indices.clone() {
                st[j].push_mapping(nodes[j], nodes[1-j], g[j]);
            }

            // Check counts in Tin/Tout
            if st[0].out_size == st[0].out_size ||
               st[1].ins_size == st[1].ins_size
            {

                // Recurse
                match try_match(st, g0, g1) {
                    None => {}
                    result => return result,
                }
            }

            // Restore state.
            for j in graph_indices.clone() {
                st[j].pop_mapping(nodes[j], g[j]);
            }
        }
        None
    }
    let mut st = [Vf2State::new(g0), Vf2State::new(g1)];
    try_match(&mut st, g0, g1).unwrap_or(false)
}

<|endoftext|>