Skip to main content

Solver

Struct Solver 

Source
pub struct Solver { /* private fields */ }
Expand description

Main interface to SMT solvers.

The Solver type is at the core of formally::smt, providing high-level access to backend solvers.

One can create a Solver in three ways, all accepting a Config reference to configure the solver:

Solver is responsible to implement name lookup on terms used in definitions and assertions. A term such as term!(> p q) contains three unresolved symbols, ">", "p", and "q". Without name resolution the term would be unusable by the backends.

Solver implements Stack to provide the usual incremental interface of most SAT/SMT solvers.

Implementations§

Source§

impl Solver

Source

pub fn with_manager( config: &Config, manager: impl Into<Rc<TermManager>>, ) -> Result<Solver>

Create a Solver over a given TermManager.

Use this constructor to share the same TermManager among different solvers.

Source

pub fn with_backend(config: &Config, backend: impl Backend) -> Result<Solver>

Create a Solver over a given Backend.

Backends provided by this crate are defined in formally::smt::backend.

Source

pub fn with_backend_name<'a>( config: &Config, backend: impl Into<Identifier<'a>>, ) -> Result<Solver>

Create a Solver over the given Backend specified by name, if it exists.

Backends provided by this crate are defined in formally::smt::backend.

Source

pub fn new(config: &Config) -> Result<Solver>

Create a Solver with a default backend and a dedicated TermManager.

Source

pub fn logic(&self) -> &dyn Logic

Get the currently selected Logic.

Source

pub fn config(&self, config: &Config) -> Result<()>

Set a new configuration for the solver.

Note that the logic field is ignored when changing configuration after construction.

Source

pub fn env(&self) -> &Env

Get the Env object holding the current scopes for functions and sorts declared and defined in the solver.

Source

pub fn pool(&self) -> &dyn TermPool

Return a reference to the TermPool of the underlying TermManager.

Source

pub fn lookup<T: ToTerm>(&self, term: T, role: Role) -> Result<Term>

Convert a ToTerm object into a Term including name resolution and type checking.

This method uniques a ToTerm object into a Term using the TermPool of the underlying TermManager and then performs name resolution and type checking on the term.

The resulting term is guaranteed to be well typed and fully resolved.

Since terms can describe sorts as well, and SMT-LIBv2 defines two different namespaces for sorts and functions, the Role argument is needed to tell whether the term has to be interpreted as a sort or as a value term.

Source

pub fn lookup_sort<S: ToSort>(&self, sort: &S) -> Result<Sort>

Convert a ToSort object into a Sort including name resolution and type checking.

This method uniques a ToSort object into a Sort and then performs name resolution and type checking on the sort.

The resulting sort is guaranteed to be well-formed and fully resolved.

Source

pub fn lookup_var<S: ToSort>(&self, variable: &Variable<S>) -> Result<Variable>

Create a fully resolved Variable by looking up its sort.

This convenience method is equivalent to constructing a new Variable instance by calling Solver::lookup_sort() on the variable’s sort.

This method is needed to obtain a fully resolved Variable that can be used without further name resolution, but it is not needed when normally using variables to define functions that then refer to them by name.

Example:

 use formally::smt::*;

 let config = Config::default();
 let mut solver = Solver::new(&config)?;

 // we construct the variable directly.
 let x = Variable::new("x", sort!(Int));

 // here the variable `x` is moved and `lookup_var()` is called internally.
 let f = solver.define(Definition::function("f", [x], sort!(Int), term!(* x 2)));

 // here the variable is #expanded in the term so we need to do name resolution earlier
 let y = solver.lookup_var(&Variable::new("y", sort!(Int)))?;
 let g = solver.define(Definition::function("g", [y.clone()], sort!(Int), term!(* #y 2)));

 solver.require(term!(distinct (f 21) (g 21) 42))?;

 assert_eq!(solver.check()?, Answer::No);
Source

pub fn lookup_binding<T: ToTerm>( &self, binding: Binding<Infer, T>, ) -> Result<Binding>

Create a fully resolved Binding by looking up its sort and term.

This convenience method is useful to infer automatically the sort of the binding from its defining term. It is designed to be used in pair with Binding::new().

Source

pub fn declare<R: ToSort, B: ToSort>( &mut self, decl: Declaration<R, B>, ) -> Result<Declared>

Declare a function (or a constant, or a sort).

As explained in the overview, declare() registers a Declaration value in the suitable scope and returns a Declared object that immutably points to the registered Declaration object. The registered Declaration object is not equal to the one passed as argument, in general, because name resolution occurs.

Remember that constants are seen as functions with no arguments, and sorts as constants of the special sort Sort::sort(). See also Declaration::function(), Declaration::constant(), and Declaration::sort() for details.

Source

pub fn define<V: ToSort, R: ToSort, B: ToTerm>( &mut self, def: Definition<V, R, B>, ) -> Result<Defined>

Define a function (or a constant, or a sort).

As explained in the overview, define() registers a Definition value in the suitable scope and returns a Defined object that immutably points to the registered Definition object. The registered Definition object is not equal to the one passed as argument, in general, because name resolution occurs.

Remember that constants are seen as functions with no arguments, and sorts as constants of the special sort Sort::sort(). See also Definition::function(), Definition::constant(), and Definition::sort() for details.

See also the documentation of Solver::lookup_var() to know when name lookup is needed to be done manually on the variables used in a definition.

Source

pub fn require<T: ToTerm>(&mut self, term: T) -> Result<()>

Assert the given term to the current assertion stack

The term undergoes name resolution and must be well-typed and be of sort Core::Bool().

Source

pub fn check(&mut self) -> Result<Answer>

Check the satisfiability of the current assertions.

The return value distinguishes between errors occurred during the solving process (Err(_)) and the case where no error occurred but the solver gave up on finding an answer (Ok(Answer::Unknown)).

Source

pub fn model(&self) -> Result<Option<Model<'_>>>

Get a model of the current assertions, if they were found to be satisfiable.

The return value distinguishes between errors occurred while extracting the model from the backend (Err(_)), and the case where no error occurred but there is no model available (Ok(None)), for example because the last call to check() did not return Ok(Answer::Yes) or because model production was turned off in the solver’s Config.

Note that the representation of model values is still incomplete and only Boolean and numerical values can be currently extracted.

Trait Implementations§

Source§

impl Stack for Solver

Source§

fn push(&mut self) -> Result<()>

Push a new frame in the assertions stack.

The assertion stack includes asserted terms and declared/defined entities. Currently, the :global-declarations option of SMT-LIBv2 is not supported.

Source§

fn pop_n(&mut self, n: usize) -> Result<()>

Pops a frame from the assertions stack, doing nothing if there is no frame to remove.

The assertion stack includes asserted terms and declared/defined entities. Currently, the :global-declarations option of SMT-LIBv2 is not supported.

Source§

fn pop(&mut self) -> Result<(), DiagnosticEmitted>

Shortcut for pop_n(1)

Auto Trait Implementations§

§

impl !RefUnwindSafe for Solver

§

impl !Send for Solver

§

impl !Sync for Solver

§

impl !UnwindSafe for Solver

§

impl Freeze for Solver

§

impl Unpin for Solver

§

impl UnsafeUnpin for Solver

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Az for T

Source§

fn az<Dst>(self) -> Dst
where T: Cast<Dst>,

Casts the value.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<Src, Dst> CastFrom<Src> for Dst
where Src: Cast<Dst>,

Source§

fn cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T> CheckedAs for T

Source§

fn checked_as<Dst>(self) -> Option<Dst>
where T: CheckedCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> CheckedCastFrom<Src> for Dst
where Src: CheckedCast<Dst>,

Source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> OverflowingAs for T

Source§

fn overflowing_as<Dst>(self) -> (Dst, bool)
where T: OverflowingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dst
where Src: OverflowingCast<Dst>,

Source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
Source§

impl<T> SaturatingAs for T

Source§

fn saturating_as<Dst>(self) -> Dst
where T: SaturatingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dst
where Src: SaturatingCast<Dst>,

Source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T> StrictAs for T

Source§

fn strict_as<Dst>(self) -> Dst
where T: StrictCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> StrictCastFrom<Src> for Dst
where Src: StrictCast<Dst>,

Source§

fn strict_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> UnwrappedAs for T

Source§

fn unwrapped_as<Dst>(self) -> Dst
where T: UnwrappedCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dst
where Src: UnwrappedCast<Dst>,

Source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T> WrappingAs for T

Source§

fn wrapping_as<Dst>(self) -> Dst
where T: WrappingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> WrappingCastFrom<Src> for Dst
where Src: WrappingCast<Dst>,

Source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.