smc_scan_core 0.1.0

Core module for the Scan model checker.
Documentation
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
use rand::SeedableRng;
use rand::rngs::SmallRng;
use scan_core::program_graph::*;
use scan_core::*;

#[inline(always)]
fn run_to_completion(pg: &mut ProgramGraphRun) {
    let mut rng = SmallRng::from_seed([0; 32]);

    while let Some((action, post)) = pg
        .possible_transitions()
        .filter_map(|(a, iter)| {
            iter.into_iter()
                .map(|v| v.last())
                .collect::<Option<Vec<_>>>()
                .map(|l| (a, l))
        })
        .last()
    {
        assert!(pg.transition(action, post.as_slice(), &mut rng).is_ok());
    }
}

#[inline(always)]
fn simple_pg() -> ProgramGraphBuilder {
    let mut pg = ProgramGraphBuilder::new();
    let pre = pg.new_initial_location();
    let action = pg.new_action();
    let post = pg.new_location();
    pg.add_transition(pre, action, post, None).unwrap();
    pg
}

#[inline(always)]
fn condition_pg() -> ProgramGraphBuilder {
    let mut pg = ProgramGraphBuilder::new();
    let pre = pg.new_initial_location();
    let action = pg.new_action();
    let post = pg.new_location();
    pg.add_transition(
        pre,
        action,
        post,
        Some(BooleanExpr::Implies(Box::new((
            Expression::less_than_or_equal_to(
                ((((Expression::from(Val::Integer(1)) + Expression::from(Val::Integer(2)))
                    .unwrap()
                    + Expression::from(Val::Integer(3)))
                .unwrap()
                    + Expression::from(Val::Integer(4)))
                .unwrap()
                    + Expression::from(Val::Integer(5)))
                .unwrap(),
                Expression::from(Val::Integer(100)),
            )
            .unwrap(),
            Expression::greater_than(
                Expression::from(Val::Integer(5)),
                Expression::from(Val::Integer(6)),
            )
            .unwrap(),
        )))),
    )
    .unwrap();
    pg
}

#[inline(always)]
fn long_pg() -> ProgramGraphBuilder {
    let mut pg = ProgramGraphBuilder::new();
    let mut pre = pg.new_initial_location();
    let action = pg.new_action();
    for _ in 0..10 {
        let post = pg.new_location();
        pg.add_transition(pre, action, post, None).unwrap();
        pre = post;
    }
    pg
}

#[inline(always)]
fn counter_pg() -> ProgramGraphBuilder {
    let mut pg = ProgramGraphBuilder::new();
    let initial = pg.new_initial_location();
    let action = pg.new_action();
    let var = pg.new_var(Val::Integer(0)).unwrap();
    pg.add_effect(
        action,
        var,
        (Expression::from_var(var, Type::Integer) + Expression::from(Val::Integer(1))).unwrap(),
    )
    .unwrap();
    for counter in 0..10 {
        let guard = Expression::equal_to(
            Expression::from_var(var, Type::Integer),
            Expression::from(Val::Integer(counter)),
        )
        .unwrap();
        pg.add_transition(initial, action, initial, Some(guard))
            .unwrap();
    }
    pg
}

fn possible_transitions(c: &mut Criterion) {
    let pgs = [
        (simple_pg(), "simple pg"),
        (condition_pg(), "condition pg"),
        (long_pg(), "long pg"),
        (counter_pg(), "counter pg"),
    ];
    for (pg, name) in pgs.into_iter() {
        let pg = pg.build();
        let pg = pg.new_instance();
        c.bench_with_input(
            BenchmarkId::new("possible transitions", name),
            &pg,
            |b, pg| {
                b.iter(|| pg.possible_transitions().count());
            },
        );
    }
}

fn run(c: &mut Criterion) {
    let pgs = [
        (simple_pg(), "simple pg"),
        (condition_pg(), "condition pg"),
        (long_pg(), "long pg"),
        (counter_pg(), "counter pg"),
    ];
    for (pg, name) in pgs.into_iter() {
        let pg = pg.build();
        c.bench_with_input(
            BenchmarkId::new("execute to termination", name),
            &pg,
            |b, pg| {
                let mut pg = pg.new_instance();
                b.iter(|| run_to_completion(&mut pg));
            },
        );
    }
}

criterion_group!(benches, possible_transitions, run);
criterion_main!(benches);