rusticg 1.0.1

Reverses possible internal seeds of an LCG using a system of inequalities on the output of random calls
Documentation
use crate::reversal::dynamic_program::{AsFilterFn, CallType, Invertible, ReversalError};
use crate::reversal::java::java_calls::Range::{Equals, Full, Inverted, Normal};
use crate::reversal::java::{java_random, java_random_reverser};
use crate::reversal::random_reverser::RandomReverser;
use crate::util::Random;
use malachite::base::num::basic::traits::{One, Zero};
use std::fmt::Debug;
use std::ops::Rem;
use std::rc::Rc;

macro_rules! builder {
    ($name: ident, $java_name: literal, $bounds: literal, $ty: ty, $calls: literal, $lower_bound: expr, $upper_bound: expr, $precision: expr, $next_up: expr, $next_down: expr, $add_to_reverser_fn: expr) => {
        #[doc= concat!("Creates a new builder equivalent to ", $java_name, ".<br>This builder's bounds are `", $bounds, "`.")]
        pub fn $name() -> RangeCallTypeBuilder<$ty> {
            RangeCallTypeBuilder {
                calls: $calls,
                lower_bound: $lower_bound,
                upper_bound: $upper_bound,
                precision: $precision,
                next_up: Box::new($next_up),
                next_down: Box::new($next_down),
                random_call: Rc::new(java_random::$name),
                add_to_reverser_fn: Box::new($add_to_reverser_fn),
            }
        }
    };
}

/// Creates a new builder equivalent to nextBoolean().
pub fn next_boolean() -> BooleanCallTypeBuilder { BooleanCallTypeBuilder {} }
builder!(next_int, "nextInt()", "[i32::MIN, i32::MAX]", i32, 1, i32::MIN, i32::MAX, 1, |i| i + 1, |i| i - 1, java_random_reverser::add_next_int_call);
builder!(next_long, "nextLong()", "[i64::MIN, i64::MAX]", i64, 2, i64::MIN, i64::MAX, 1, |i| i + 1, |i| i - 1, java_random_reverser::add_next_long_call);
builder!(next_float, "nextFloat()", "[0, 1)", f32, 1, f32::ZERO, f32::ONE.next_down(), 1_f32 / (1 << 24) as f32, f32::next_up, f32::next_down, java_random_reverser::add_next_float_call);
builder!(next_double, "nextDouble()", "[0, 1)", f64, 2, f64::ZERO, f64::ONE.next_down(), 1_f64 / (1_i64 << 24) as f64, f64::next_up, f64::next_down, java_random_reverser::add_next_double_call);

/// Creates a new builder equivalent to nextInt(bound).<br>
/// This builder's bounds are `[0, bound)`.<br>
/// Will throw an error if the bound is < 1.
pub fn next_bound_int(bound: i32) -> Result<RangeCallTypeBuilder<i32>, ReversalError> {
    if bound < 1 {
        return Err(ReversalError::TooSmallBound);
    }

    Ok(RangeCallTypeBuilder {
        calls: 1,
        lower_bound: 0,
        upper_bound: bound - 1,
        precision: 1,
        next_up: Box::new(|i| i + 1),
        next_down: Box::new(|i| i - 1),
        random_call: Rc::new(move |random| java_random::next_bound_int(random, bound)),
        add_to_reverser_fn: Box::new(move |reverser, min, max| {
            java_random_reverser::add_bound_next_int_call(reverser, bound, min, max)
        }),
    })
}

/// The builder for call types equivalent to Java's nextBoolean.
pub struct BooleanCallTypeBuilder {}
impl BooleanCallTypeBuilder {

    /// Returns a call type equivalent to `nextBoolean() == value`.
    pub fn equal_to(self, value: bool) -> Box<BooleanCallType> {
        Box::new(BooleanCallType { value })
    }

    /// Returns a call type equivalent to `nextBoolean() != value`.
    pub fn not_equal_to(self, value: bool) -> Box<BooleanCallType> {
        Box::new(BooleanCallType { value: !value })
    }
}

/// The [CallType] generated by [BooleanCallTypeBuilder].
pub struct BooleanCallType {
    value: bool,
}

impl CallType for BooleanCallType {
    fn num_calls(&self) -> i64 {
        1
    }

    fn add_to(&self, reverser: &mut RandomReverser) -> Result<(), ReversalError> {
        java_random_reverser::add_next_boolean_call(reverser, self.value);
        Ok(())
    }
}

impl AsFilterFn for BooleanCallType {
    fn num_calls(&self) -> i64 {
        1
    }

    fn as_filter_fn(&self) -> Result<Box<dyn Fn(&mut Random) -> bool>, ReversalError> {
        let value = self.value;
        Ok(Box::new(move |r| java_random::next_boolean(r) == value))
    }
}

impl Invertible for BooleanCallType {
    fn invert(mut self) -> Box<Self> {
        self.value = !self.value;
        Box::new(self)
    }
}

#[derive(Clone)]
enum Range<T> {
    Full,
    Equals(T),
    Normal(T, T),
    Inverted(Box<Range<T>>),
}

/// A generic builder for call types equivalent to random numbers being in a known range.
/// Created using [next_bound_int], [next_int], [next_long], [next_float] or [next_double].
pub struct RangeCallTypeBuilder<T> {
    calls: i64,
    lower_bound: T,
    upper_bound: T,
    precision: T,
    next_up: Box<dyn Fn(T) -> T>,
    next_down: Box<dyn Fn(T) -> T>,
    random_call: Rc<dyn Fn(&mut Random) -> T>,
    add_to_reverser_fn: Box<dyn Fn(&mut RandomReverser, Vec<T>, Vec<T>)>,
}

impl<T: Copy + Debug + PartialOrd + From<u8> + Rem<T, Output = T>> RangeCallTypeBuilder<T> {
    fn check_precision(&self, name: &'static str, value: T) {
        if value % self.precision != 0.into() {
            eprintln!(
                "Value of {} call is too precise, the last two bits will be rounded up!",
                name
            );
        }
    }

    /// Returns a call type equivalent to `next_random_number == value`.<br>
    /// Will throw an error if the value is outside of this builder's bounds.
    pub fn equal_to(self, value: T) -> Result<Box<RangeCallType<T>>, ReversalError> {
        self.check_precision("equal_to", value);
        self.inclusive_range(value, value)
    }

    /// Returns a call type equivalent to `next_random_number < value`.<br>
    /// Will throw an error if the value is outside of this builder's bounds.
    pub fn less_than(self, value: T) -> Result<Box<RangeCallType<T>>, ReversalError> {
        self.check_precision("less_than", value);
        let lower_bound = self.lower_bound;
        let upper_bound = (&self.next_down)(value);
        self.inclusive_range(lower_bound, upper_bound)
    }

    /// Returns a call type equivalent to `next_random_number <= value`.<br>
    /// Will throw an error if the value is outside of this builder's bounds.
    pub fn less_than_eq(self, value: T) -> Result<Box<RangeCallType<T>>, ReversalError> {
        self.check_precision("less_than_eq", value);
        let lower_bound = self.lower_bound;
        self.inclusive_range(lower_bound, value)
    }

    /// Returns a call type equivalent to `next_random_number > value`.<br>
    /// Will throw an error if the value is outside of this builder's bounds.
    pub fn greater_than(self, value: T) -> Result<Box<RangeCallType<T>>, ReversalError> {
        self.check_precision("greater_than", value);
        let lower_bound = (&self.next_up)(value);
        let upper_bound = self.upper_bound;
        self.inclusive_range(lower_bound, upper_bound)
    }

    /// Returns a call type equivalent to `next_random_number >= value`.<br>
    /// Will throw an error if the value is outside of this builder's bounds.
    pub fn greater_than_eq(self, value: T) -> Result<Box<RangeCallType<T>>, ReversalError> {
        self.check_precision("greater_than_eq", value);
        let upper_bound = self.upper_bound;
        self.inclusive_range(value, upper_bound)
    }

    /// Returns a call type equivalent to the given range.<br>
    /// Will throw an error if the value is outside of this builder's bounds, if the range is empty, or `max < min`.
    pub fn range(
        self,
        mut min: T,
        mut max: T,
        min_exclusive: bool,
        max_exclusive: bool,
    ) -> Result<Box<RangeCallType<T>>, ReversalError> {
        self.check_precision("range (min)", min);
        self.check_precision("range (min)", max);

        if max == min && (min_exclusive || max_exclusive) {
            return Err(ReversalError::RangeIsEmpty);
        } else if max < min {
            return Err(ReversalError::MaxLowerThanMin);
        }

        if min_exclusive {
            min = (&self.next_up)(min);
        }

        if max_exclusive {
            max = (&self.next_down)(max);
        }

        self.inclusive_range(min, max)
    }

    fn inclusive_range(self, min: T, max: T) -> Result<Box<RangeCallType<T>>, ReversalError> {
        if min < self.lower_bound {
            return Err(ReversalError::MinLessThanLowerBound);
        } else if max > self.upper_bound {
            return Err(ReversalError::MaxGreaterThanUpperBound);
        }

        Ok(Box::new(RangeCallType {
            range: {
                if min == self.lower_bound && max == self.upper_bound {
                    Full
                } else if min == max {
                    Equals(min)
                } else {
                    Normal(min, max)
                }
            },
            processor: self,
        }))
    }
}

/// The [CallType] built by [RangeCallTypeBuilder].<br>
/// Can be used as a [CallType] and as a [FilterFn](AsFilterFn).<br>
/// Can be inverted.
pub struct RangeCallType<T> {
    processor: RangeCallTypeBuilder<T>,
    range: Range<T>,
}

impl<T: Copy + Debug + PartialOrd + From<u8> + Rem<T, Output = T> + 'static> CallType
    for RangeCallType<T>
{
    fn num_calls(&self) -> i64 {
        self.processor.calls
    }

    /// Will throw an error if the range is empty.
    fn add_to(&self, reverser: &mut RandomReverser) -> Result<(), ReversalError> {
        let p = &self.processor;

        match &self.range {
            Full => reverser.add_unmeasured_seeds(p.calls),
            Equals(value) => (p.add_to_reverser_fn)(reverser, vec![*value], vec![*value]),
            Normal(min, max) => (p.add_to_reverser_fn)(reverser, vec![*min], vec![*max]),
            Inverted(inner) => {
                macro_rules! add_arbitrary_bound {
                    ($min: expr, $max: expr) => {
                        let next_down = (p.next_down)($min);
                        let next_up = (p.next_up)($max);
                        (p.add_to_reverser_fn)(
                            reverser,
                            vec![p.lower_bound, next_up],
                            vec![next_down, p.upper_bound],
                        );
                    };
                }

                match **inner {
                    Full => return Err(ReversalError::RangeIsEmpty),
                    Equals(value) => {
                        if value == p.lower_bound {
                            (p.add_to_reverser_fn)(
                                reverser,
                                vec![(p.next_up)(p.lower_bound)],
                                vec![p.upper_bound],
                            )
                        } else if value == p.upper_bound {
                            (p.add_to_reverser_fn)(
                                reverser,
                                vec![p.lower_bound],
                                vec![(p.next_down)(p.upper_bound)],
                            )
                        }

                        add_arbitrary_bound!(value, value);
                    }
                    Normal(min, max) => {
                        add_arbitrary_bound!(min, max);
                    }
                    Inverted(_) => {
                        unreachable!()
                    }
                }
            }
        }

        Ok(())
    }
}

impl<T: Copy + Debug + PartialOrd + From<u8> + Rem<T, Output = T> + 'static> AsFilterFn
    for RangeCallType<T>
{
    fn num_calls(&self) -> i64 {
        self.processor.calls
    }

    /// Will throw an error if the range is empty.
    fn as_filter_fn(&self) -> Result<Box<(dyn Fn(&mut Random) -> bool)>, ReversalError> {
        Ok(match &self.range {
            Full => {
                let calls = self.processor.calls;
                Box::new(move |r| {
                    r.advance_steps(calls);
                    true
                })
            }
            Equals(value) => {
                let value = *value;
                let random_call = self.processor.random_call.clone();
                Box::new(move |r| random_call(r) == value)
            }
            Normal(min, max) => {
                let min = *min;
                let max = *max;
                let random_call = self.processor.random_call.clone();
                Box::new(move |r| {
                    let value = random_call(r);
                    min <= value && value <= max
                })
            }
            Inverted(inner) => match **inner {
                Full => return Err(ReversalError::RangeIsEmpty),
                Equals(value) => {
                    let random_call = self.processor.random_call.clone();
                    Box::new(move |r| random_call(r) != value)
                }
                Normal(min, max) => {
                    let random_call = self.processor.random_call.clone();
                    Box::new(move |r| {
                        let value = random_call(r);
                        min > value || value > max
                    })
                }
                Inverted(_) => {
                    unreachable!()
                }
            },
        })
    }
}

impl<T: Copy + Debug + PartialOrd + From<u8> + Rem<T, Output = T> + 'static> Invertible
    for RangeCallType<T>
{
    fn invert(mut self) -> Box<Self> {
        self.range = match self.range {
            Inverted(range) => *range,
            Normal(min, max) => {
                if min == self.processor.lower_bound {
                    Normal((&self.processor.next_up)(max), self.processor.upper_bound)
                } else if max == self.processor.upper_bound {
                    Normal(self.processor.lower_bound, (&self.processor.next_down)(min))
                } else {
                    Inverted(Box::new(self.range))
                }
            }
            other => Inverted(Box::new(other)),
        };
        Box::new(self)
    }
}