Theory Reference: Datatypes
cvc5 implements some extensions to the support for datatypes in SMT-LIB 2.
Logic
To enable cvc5’s decision procedure for datatypes, include
DT
in the logic:
(set-logic QF_DT)
Alternatively, use the
ALL
logic:
(set-logic ALL)
Syntax
cvc5 supports the following syntax for declaring mutually recursive blocks of
datatypes in
*.smt2
input files in the smt lib 2.6 format:
(declare-datatypes ((D1 n1) ... (Dk nk))
(((C1 (S11 T1) ... (S1i Ti)) ... (Cj ... ))
...
((...) ... (...)))
where
D1
...
Dk
are datatype types,
C1
...
Cj
are the constructors for
datatype
D1
,
S11
...
S1i
are the selectors (or “destructors”) of constructor
C1
, and
each
T1
...
Ti
is a previously declared type or one of
D1
...
Dk
.
The numbers
n1
...
nk
denote the number of type
parameters for the datatype, where
0
is used for non-parametric datatypes.
In addition to declaring symbols for constructors and selectors, the above
command also allows for tester (or “discriminator”) indexed symbols of the form
(_
is
C)
for each constructor
C
, which are unary predicates which
evaluate to true iff their argument has top-symbol
C
. It also allows for
updater indexed symbols of the form
(_
update
Sij)
for each selector
Sij
,
whose semantics are described below.
Semantics
The decision procedure for inductive datatypes is described in [ BST07 ] .
Example Declarations
An enumeration:
(declare-datatypes ((Color 0))
(((Red) (Black))))
A List of
Int
with
cons
and
nil
as constructors:
(declare-datatypes ((list 0))
(((cons (head Int) (tail list)) (nil))))
A parametric List of T’s:
(declare-datatypes ((list 1))
((par (T) ((cons (head T) (tail (list T))) (nil)))))
Mutual recursion:
(declare-datatypes ((list 0) (tree 0))
(((cons (head tree) (tail list)) (nil))
((node (data Int) (children list)))))
A (non-recursive) record type:
(declare-datatypes ((record 0))
(((rec (fname String) (lname String) (id Int)))))
Examples
(declare-datatypes ((list 0))
(((cons (head Int) (tail list)) (nil))))
(declare-const a list)
(declare-const b list)
(assert (and (= (tail a) b) (not ((_ is nil) b)) (> (head b) 0)))
(check-sat)
(declare-datatypes ((record 0))
(((rec (fname String) (lname String) (id Int)))))
(declare-const x record)
(assert (and (= (fname x) "John") (= (lname x) "Smith")))
(check-sat)
Datatype Updaters
Datatype updaters are a (non-standard) extension available in datatype logics. The term:
((_ update Sij) t u)
is equivalent to replacing the field of
t
denoted by the selector
Sij
with the value
u
, or
t
itself if that selector does not apply to the
constructor symbol of
t
. For example, for the list datatype, we have that:
((_ update head) (cons 4 nil) 7) = (cons 7 nil)
((_ update tail) (cons 4 nil) (cons 5 nil)) = (cons 4 (cons 5 nil))
((_ update head) nil 5) = nil
Note that datatype updaters can be seen as syntax sugar for an if-then-else
term that checks whether the constructor of
t
is the same as the one
associated with the given selector.
Parametric Datatypes
Instances of parametric datatypes must have their arguments instantiated with concrete types. For instance, in the example:
(declare-datatypes ((list 1)) ((par (T) (cons (head T) (tail (list T))) (nil))))
To declare a list of
Int
, use the command:
(declare-const f (list Int))
Use of constructors that are ambiguously typed must be cast to a concrete type,
for instance all occurrences of
nil
for the above datatype must be cast with
the syntax:
(as nil (list Int))
Tuples
Tuples are a particular instance of an inductive datatype. cvc5 supports special syntax for tuples as an extension of the SMT-LIB version 2 format. For example:
(declare-const t (Tuple Int Int))
(assert (= ((_ tuple.select 0) t) 3))
(assert (not (= t (tuple 3 4))))
Codatatypes
cvc5 also supports co-inductive datatypes, as described in [ RB15 ] .
The syntax for declaring mutually recursive coinductive datatype blocks is
identical to inductive datatypes, except that
declare-datatypes
is replaced
by
declare-codatatypes
. For example, the following declares the type denote
streams of
Int
:
(declare-codatatypes ((stream 0))
(((cons (head Int) (tail stream)))))
Syntax/API
For the C++ API examples in the table below, we assume that we have created a cvc5::Solver solver object.
SMTLIB language |
C++ API |
|
Logic String |
|
|
Datatype Sort |
|
|
Datatype Sorts |
|
|
Constructor |
|
|
Selector |
|
|
Updater |
|
|
Tester |
|
|
Tuple Sort |
|
|
|
|
|
Tuple Constructor |
|
|
Unit Tuple Sort |
|
|
Tuple Unit |
|
|
Tuple Selector |
|
|
Tuple Updater |
|
|
Tuple Projection |
|
|
Record Sort |
n/a |
|
n/a |
|
|
Record Constructor |
n/a |
|
Record Selector |
n/a |
|
Record Updater |
n/a |
|