easy-smt 0.3.2

Easily interact with an smt solver as a subprocess
Documentation
// In this example, we assert quantified formulas over uninterpreted
// sorts and functions.

fn main() -> std::io::Result<()> {
    env_logger::init();
    let mut ctx = easy_smt::ContextBuilder::new().with_z3_defaults().build()?;

    // Declare an uninterpreted representation for sets.
    ctx.declare_sort("MySet", 0)?;
    // Declare representation for elements of those sets.
    ctx.declare_sort("MyElement", 0)?;

    // Our sets have a simple interface of predicates: empty(s),
    // member(x,s), and subset(s1,s2).
    ctx.declare_fun("empty", vec![ctx.atom("MySet")], ctx.bool_sort())?;
    ctx.declare_fun(
        "member",
        vec![ctx.atom("MyElement"), ctx.atom("MySet")],
        ctx.bool_sort(),
    )?;
    ctx.declare_fun(
        "subset",
        vec![ctx.atom("MySet"), ctx.atom("MySet")],
        ctx.bool_sort(),
    )?;

    // We assert some simple axioms on this interface.

    // First, a set s1 is either a subset of s2, or a member of s1
    // exists which is not a member of s2.
    ctx.assert(
        // For any pair of sets,
        ctx.forall(
            [("s1", ctx.atom("MySet")), ("s2", ctx.atom("MySet"))],
            // One of the following is true:
            ctx.or(
                // (1) s1 is a subset of s2, or
                ctx.list(vec![ctx.atom("subset"), ctx.atom("s1"), ctx.atom("s2")]),
                // (2) an element exists which is a member of s1, and
                // not a member of s2.
                ctx.exists(
                    [("x", ctx.atom("MyElement"))],
                    ctx.and(
                        ctx.list(vec![ctx.atom("member"), ctx.atom("x"), ctx.atom("s1")]),
                        ctx.not(ctx.list(vec![ctx.atom("member"), ctx.atom("x"), ctx.atom("s2")])),
                    ),
                ),
            ),
        ),
    )?;

    // Second, a set is empty iff no member exists.
    ctx.assert(
        // For any set,
        ctx.forall(
            [("s1", ctx.atom("MySet"))],
            // The following formulas are equivalent:
            ctx.eq(
                // (1) the set is not empty, and
                ctx.not(ctx.list(vec![ctx.atom("empty"), ctx.atom("s1")])),
                // (2) an element exists that is a member of the set.
                ctx.exists(
                    [("x", ctx.atom("MyElement"))],
                    ctx.list(vec![ctx.atom("member"), ctx.atom("x"), ctx.atom("s1")]),
                ),
            ),
        ),
    )?;

    // Now, let's check whether a relationship between two sets is
    // possible.
    ctx.declare_const("s1", ctx.atom("MySet"))?;
    ctx.declare_const("s2", ctx.atom("MySet"))?;

    // Is it possible for s1 to be empty,
    ctx.assert(ctx.list(vec![ctx.atom("empty"), ctx.atom("s1")]))?;
    // while also s1 is not a subset of s2?
    ctx.assert(ctx.not(ctx.list(vec![ctx.atom("subset"), ctx.atom("s1"), ctx.atom("s2")])))?;

    // We expect the answer to be no (UNSAT).
    match ctx.check()? {
        easy_smt::Response::Sat => {
            println!("Solver returned SAT. This is unexpected!");
        }
        easy_smt::Response::Unsat => {
            println!("Solver returned UNSAT. This is expected.");
        }
        easy_smt::Response::Unknown => {
            println!("Solver returned UNKNOWN. This is unexpected!");
        }
    }
    Ok(())
}