-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathversion3-proposal.shtml
More file actions
2914 lines (2572 loc) · 95.9 KB
/
version3-proposal.shtml
File metadata and controls
2914 lines (2572 loc) · 95.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!--
Design by http://www.bluewebtemplates.com
Released for free under a Creative Commons Attribution 3.0 License
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>SMT-LIB The Satisfiability Modulo Theories Library</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="style.css" rel="stylesheet" type="text/css" />
<style>
.collapsible {
background-color: #777;
color: white;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
}
.active, .collapsible:hover {
background-color: #555;
}
.coll_content {
padding: 0 18px;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
background-color: #f1f1f1;
}
</style>
<!-- CuFon: Enables smooth pretty custom font rendering. 100% SEO friendly. To disable, remove this section -->
<script type="text/javascript" src="js/cufon-yui.js"></script>
<script type="text/javascript" src="js/arial.js"></script>
<script type="text/javascript" src="js/cuf_run.js"></script>
<!-- CuFon ends -->
<link href="code-prettify/prettify.css" type="text/css" rel="stylesheet" />
<script src="code-prettify/run_prettify.js?lang=smt3&skin=default"></script>
</head>
<body onload="PR.prettyPrint()">
<div class="main">
<div class="header">
<div class="header_resize">
<div class="menu_nav">
<ul>
<li><a href="index.shtml">Home</a></li>
<li><a href="about.shtml">About</a></li>
<li><a href="news.shtml">News</a></li>
<li><a href="standard.shtml">Standard</a></li>
<li><a href="benchmarks.shtml">Benchmarks</a></li>
<li><a href="software.shtml">Software</a></li>
<li><a href="credits.shtml">Credits</a></li>
</ul>
</div>
<div class="clr"></div>
<div class="logo">
<h1><a href="index.shtml">SMT-LIB <br/>
<small>The Satisfiability Modulo Theories Library</small></a>
</h1>
</div>
</div>
</div>
<div class="content">
<div class="content_resize">
<div class="mainbar">
<h2>SMT-LIB Version 3.0 - Preliminary Proposal</h2>
<h4>by C. Barrett, P. Fontaine, and C. Tinelli</h4>
<b>Last updated:</b> 2026-03-26
<h3>Overview</h3>
<p>This page contains a high-level proposal for SMT-LIB Version 3.
While some aspects of the language are still being worked out,
this document is a fairly accurate description of the new format.
A reference document is under construction and will contain
a description of the proposal in full detail.
This page focuses on the most salient aspects of the proposal,
for a quicker overview.
More content will be added with time as needed.
</p>
<h4>Preamble</h4>
<em>The great majority of the changes described below will affect
the way theories and logics are defined.
It will minimally affect scripts that rely on (the equivalent of)
SMT-LIB 2.7 logics.
</em>
This means that most of the features of the Version 3 will not have
to be supported by current SMT solvers.
Support for some of new features of SMT-LIB 3 can be introduced gradually
over time in a solver as a consequence of deciding to support new theories
and logics that rely on those features.
<h4>New underlying logic</h4>
<p>The main new aspect of the proposed new version is the move from
(an extension of) many-sorted first-order logic as the underlying logic
of SMT-LIB to a higher-order logic with polymorphism and dependent types
but classical semantics.
An important aspect of this change is that the new language for SMT-LIB
scripts strives to be as backward-compatible as possible to that
of Version 2.7.
This is achieved in two ways:
<ol>
<li>Giving new meaning to old syntax as needed.</li>
<li>Defining the formal semantics so that it is essentially the same as
the old one over the old syntax.</li>
</ol>
For example, monomorphic sorts from SMT-LIB 2.7 are interpreted
as simple types, and polymorphic sorts are interpreted as polymorphic types;
maps from Version 2.7 are identified with functions, which are now
first class and can be passed to and returned by other functions;
sorted constant and function symbols are interpreted as typed constants,
with function symbols of arity > 1 becoming higher-order constants,
Curry-style;
index symbols, as in
<code class="prettyprint lang-smt3">(_ extract i j)</code>
or
<code class="prettyprint lang-smt3">(_ BitVec 4)</code>,
are now seen as syntactic sugar for symbols with a dependent type/kind.
As in SMT-LIB 2, a number of additional syntactic restrictions on scripts
are imposed to obtain various fragments of interests or <em>logics</em>,
in SMT-LIB 2 terminology.
</p>
<p>The underlying logic of SMT-LIB 3 has many elements of the Calculus
of Inductive Constructions (CIC), which are at the basis of the formal
foundation of proof assistants like Rocq and Lean.
The main restriction is allowing only rank-1 (prenex) polymorphism and
not having a <code class="prettyprint lang-smt3">Prop</code>-like kind
for (constructive) propositions.
So, contrary to CIC, formulas are not types and instead continue to be
expressed as terms of a two-element <code class="prettyprint
lang-smt3">Bool</code> type;
this is more similar to the logic of the PVS proof assistant or
proof assistants of the HOL family.
However, as in SMT-LIB 2.7, type polymorphism is approximated
by having global (i.e., top-level) type variables,
as opposed to actual quantification over types, and so making
polymorphic constants actually families of overloaded symbols.
In addition to being polymorphic, and contrary to Version 2.7,
types can now depend on values as in dependently-typed logics.
</p>
<h3>Motivation</h3>
<p>
The main motivation for the move to a CIC-like logic is manyfold.
<ol>
<li>Having a more expressive underlying logic considerably simplifies
the design and the formal foundations of the SMT-LIB standard.
It obviates the need for most of the ad-hoc extensions to many-sorted
first-order logic we had to introduce in Version 2 while also providing
enough expressive power to define most theories formally,
as opposed to textually as is done in SMT-LIB 2.
That includes theories that are not easily definable in Version 2
such as the theory of parametric bit vectors.
</li>
<li>It facilitates the definition of a <em>single</em> language
to define theories, logics, and benchmarks.
</li>
<li>It extends the possibility for SMT solvers to provide support
for higher-order reasoning, facilitating their integration
as automated reasoning back ends into higher-order theorem provers
<!--, such as
<a href="http://page.mi.fu-berlin.de/lex/leo3/">Leo III</a>,
-->
and into proof assistants,
<!--
such as
<a href="https://coq.inria.fr">Coq</a>,
<a href="https://hol-theorem-prover.org">HOL4</a>,
<a href="https://isabelle.in.tum.de">Isabelle/HOL</a>,
and
<a href="https://leanprover.github.io">Lean</a>
-->
which are also based on a higher-order logic.
Current integrations rely on complex encodings from the higher-order logics
supported by these tools to the many-sorted logic of SMT-LIB 2.
Moving to a higher-order logic should dramatically simplify these encodings,
improving the trustworthiness of the integration.
Natively reasoning with higher-order constructs
(e.g., via higher-order equational reasoning) by the SMT solver could also
considerably improve solving times on goals coming from these tools.
</li>
<li>It enables the introduction of a number of new SMT-LIB theories
(for sets, relations, database tables, sequences) which benefit
from the availability of second-order functions such as as fold, map,
filter and so on, both to define common operations and to reason about them.
</li>
</ol>
</p>
<p>The move to the new logic maintains backward compatibility
with SMT-LIB 2.7 to a very large extent.
In particular, it should minimally affect SMT-LIB 2.7-compliant solvers
whose developers choose not to support the new features.
</p>
<h3>The core language</h3>
<p>
Technically, the core language of SMT-LIB 3 is a higher-order logic
with dependent types and rank-1 polymorphism</a>.
Terms in this logic are built out of variables, constants, applications,
Π-abstractions, and λ-abstractions, as in the CIC calculus.
There are three classes of (well-formed) terms in the language:
<ul>
<li>terms denoting <em>values</em>, such as
<code class="prettyprint lang-smt3">3</code>,
<code class="prettyprint lang-smt3">(+ x 3)</code>,
<code class="prettyprint lang-smt3">(lambda ((x Int)) (+ x 3))</code>;
</li>
<li>terms denoting <em>types</em>, such as
<code class="prettyprint lang-smt3">Bool</code>,
<code class="prettyprint lang-smt3">Int</code>,
<code class="prettyprint lang-smt3">(-> Int Real)</code>,
<code class="prettyprint lang-smt3">(Array Int Bool)</code>,
<code class="prettyprint lang-smt3">(List Int)</code>,
<code class="prettyprint lang-smt3">(BitVec 3)</code>;
</li>
<li>terms denoting <em>kinds</em>, such as
<code class="prettyprint lang-smt3">Type</code>,
<code class="prettyprint lang-smt3">(-> Int Type)</code>.
</li>
</ul>
Types classify values and kinds classify types.
Except for <code class="prettyprint lang-smt3">Type</code>,
the kind of all types, kinds are actually not directly expressible
in the concrete syntax of SMT-LIB 3, as that is not necessary.
They appear only in abtract syntax where they are used to specify
the logic's type system.
The symbol <code class="prettyprint lang-smt3">-></code>,
which in Version 2.7 denotes the constructor of the map sort,
now denotes the function type/kind constructor
(as maps and functions are idenfitied in Version 3).
We will write it as <code class="prettyprint lang-smt3">→</code>
in this document from now on, for readability.
</p>
<p>
Well-formed value terms have an associated type term (or, simply, type).
Well-formed type terms have an associated kind term (or, simply, kind).
For instance,
<ul>
<li>
<code class="prettyprint lang-smt3">3</code>
is a constant of type
<code class="prettyprint lang-smt3">Int</code>,
which has kind
<code class="prettyprint lang-smt3">Type</code>;
</li>
<li>
<code class="prettyprint lang-smt3">not</code>
is a constant of type
<code class="prettyprint lang-smt3">(→ Bool Bool)</code>,
which has kind
<code class="prettyprint lang-smt3">Type</code>;
</li>
<li>
<code class="prettyprint lang-smt3">List</code>
is a type constant of kind
<code class="prettyprint lang-smt3">(→ Type Type)</code>;
</li>
<li>
<code class="prettyprint lang-smt3">BitVec</code>
is a type constant of kind
<code class="prettyprint lang-smt3">(→ Int Type)</code>.
</li>
</ul>
Note that <code class="prettyprint lang-smt3">→</code> is both a type and
a kind constant.
The syntax <code class="prettyprint lang-smt3">(→ α β)</code> can be understood
as an abbreviation of the CIC type or kind Π x:α β.
The constant
<code class="prettyprint lang-smt3">→</code>
can be used as a multiarity right-associative symbol.
This allows one, for example, to write the type
<code class="prettyprint lang-smt3">(→ A (→ B C))</code>
as
<code class="prettyprint lang-smt3">(→ A B C)</code>,
and the kind
<code class="prettyprint lang-smt3">(→ Type (→ Int Type))</code>
as
<code class="prettyprint lang-smt3">(→ Type Int Type)</code>.
Function symbols of rank
<code class="prettyprint lang-smt3">(τ₁ ⋅⋅⋅ τᵢ)</code>
in Version 2.7 become constants of type
<code class="prettyprint lang-smt3">(→ τ₁ ⋅⋅⋅ τᵢ)</code>
in Version 3.
This means that function symbols with more than one argument become
higher-order in Version 3.
For instance, the integer addition operator
<code class="prettyprint lang-smt3">+</code>
now has type
<code class="prettyprint lang-smt3">(→ Int Int Int)</code>,
that is,
<code class="prettyprint lang-smt3">(→ Int (→ Int Int))</code>.
</p>
<p>
With the shift to seeing funtion symbols as constants of
<code class="prettyprint lang-smt3">→</code>
type, the command
<code class="prettyprint lang-smt3">declare-const</code>
becomes primitive, and
<code class="prettyprint lang-smt3">declare-fun</code>
and
<code class="prettyprint lang-smt3">define-fun</code>
are now derived from it.
For example, following commands
<pre class="prettyprint lang-smt3">
(declare-fun h (Int Real) Real)
(define-fun avg ((x Real) (y Real)) Real (/ (+ x y) 2.0))
</pre>
are defined as having the same effect as
<pre class="prettyprint lang-smt3">
(declare-const h (→ Int Real Real))
(define-const avg (→ Real Real Real)
(lambda ((x Real) (y Real)) (/ (+ x y) 2.0)))
</pre>
For similar reasons,
<code class="prettyprint lang-smt3">define-fun-rec</code>
is now defined in terms of the new primitive command
<code class="prettyprint lang-smt3">define-const-rec</code>.
(See the Commands section below for more details on commands.)
</p>
<h4>Name Space and Shadowing</h4>
<p>
There is a single name space for identifiers, regardless of whether
they are used as value constants, type constants, or variables.
Within this name space, bound variables, that is, variables local
to a specific binder, can shadow any identifier with the same name,
including other variables, in accordance with the standard
lexical scoping discipline.
Note that this policy is more flexible than in Version 2,
where bound variables cannot have the same name as, and so cannot shadow,
theory symbols.
</p>
<h4>Dependent Types</h4>
<p>
In Version 3, constants that have a type τ dependent on a value take
as extra argument also the value that τ depends on.
For instance, bit vector function symbols take as argument also the size
of the bit vector.
For conciseness and backward compatibility, however,
such arguments are declared as <em>implicit</em>
any time they can be inferred from later arguments.
</p>
<p>
Concretely, dependent function types are expressed with the syntax
illustrated in this example:
<pre class="prettyprint lang-smt3">
(→ (! Int :var n) (BitVec n) (BitVec (+ n 1)))
</pre>
This expression denotes the type of a function that takes as input
an integer
<code class="prettyprint lang-smt3">n</code>
and returns a function that takes a bit vector of size
<code class="prettyprint lang-smt3">n</code>,
and returns a bit vector of size
<code class="prettyprint lang-smt3">n + 1</code>.
Note that
<code class="prettyprint lang-smt3">(! Int :var n)</code>
uses the same term annotation syntax as in Version 2
but extended to type terms as well.
The new predefined
<code class="prettyprint lang-smt3">:var</code>
attribute annotating
<code class="prettyprint lang-smt3">Int</code>
in this case provides a name
(<code class="prettyprint lang-smt3">n</code>)
for the first input.
The general syntax for dependent types is
<pre class="prettyprint lang-smt3">
(→ (! <i>τ₁</i> :var <i>x</i>) <i>τ₂</i>)
</pre>
where
<code class="prettyprint lang-smt3"><i>x</i></code>
is a bound variable whose scope is
<code class="prettyprint lang-smt3">τ₂</code>.
An alternative syntax, more reminiscent of that of dependently type logics,
might have been:
</p>
<p style="text-align: center;">
<code class="prettyprint lang-smt3">(Pi (<i>x</i> <i>τ₁</i>) <i>τ₂</i>)
</code>
or
<code class="prettyprint lang-smt3">(Forall (<i>x</i> <i>τ₁</i>) <i>τ₂</i>)
</code>
</p>
which perhaps makes it clearer that
<code class="prettyprint lang-smt3"><i>x</i></code>
is a variable bound by the binder
<code class="prettyprint lang-smt3">Pi</code>
or
<code class="prettyprint lang-smt3">Forall</code>
in the scope
<code class="prettyprint lang-smt3"><i>τ₂</i></code>.
However, the annotation-based syntax is possibly more legible and,
more importantly, more flexible because it allows the annotation
of function inputs with further attributes.
In particular, it allows one to declare an input argument as implicit.
This is done with the new valueless attribute
<code class="prettyprint lang-smt3">:implicit</code>
that can be associated to a function argument.
For example,
<pre class="prettyprint lang-smt3">
(→ (! Int :var n :implicit) (BitVec n) (BitVec n))
</pre>
makes the first argument implicit — in the sense that
it is not needed in applications of functions of that type.
This is sensible since the value of the first argument can be inferred
from the type of the second argument.
</p>
<p>A further attribute,
<code class="prettyprint lang-smt3">:restrict</code>,
permits the imposition of semantic restrictions on input and output values
of a function, something that, in its full generality, effectively allows
the definition of PVS-style predicate subtypes (aka, refinement types).
For instance, in type
<pre class="prettyprint lang-smt3">
(→ (! Int :var n :implicit :restrict (> n 0)) (BitVec n) (BitVec n))
</pre>
the implicit argument
<code class="prettyprint lang-smt3">n</code>
is required to be a positive integer.
In PVS syntax, this would be the dependent type
<pre class="prettyprint lang-smt3">
[n: {m : Int | m > 0} → BitVec(n) → BitVec(n)]
</pre>
This notation can also express relational constraints on the input and
output types, as for instance, in
<pre class="prettyprint lang-smt3">
(→ (! Int :var m :implicit :restrict (> m 0))
(! Int :var n :implicit :restrict (> n m))
(BitVec m) (BitVec n) (BitVec (- n m)))
</pre>
Yet another attribute,
<code class="prettyprint lang-smt3">:syntax</code>,
allows the introduction of <em>syntactic restrictions</em> on input terms:
<pre class="prettyprint lang-smt3">
(→ (! Int :var n :implicit :restrict (> n 0) :syntax <.numeral.>)
(BitVec n) (BitVec n))
</pre>
The additional restriction
<code class="prettyprint lang-smt3">:syntax <.numeral.></code>
specifies that the only permitted applications of functions
of the type above are those where the argument
<code class="prettyprint lang-smt3">n</code>
is (αβ-reducible to) a concrete constant
(<code class="prettyprint lang-smt3">0</code>,
<code class="prettyprint lang-smt3">1</code>,
<code class="prettyprint lang-smt3">2</code>, ...)
and not a symbolic term
(<code class="prettyprint lang-smt3">x</code>,
<code class="prettyprint lang-smt3">(+ x 1)</code>, ...).
This is convenient, for instance, when defining the current SMT-LIB 2 logics
with bit vectors, where bit vector sizes cannot be symbolic.
The language includes constructs to define syntactic categories like
<code class="prettyprint lang-smt3"><.numeral.></code> (see later).
</p>
<h4>Polymorphic Types</h4>
<p>
Polymorphic types reproduce the polymorphic sorts of Version 2.7
through the introduction of globally-declared <em>type variables</em>.
A polymorphic type is either a type variable, a nullary type constant,
or the application of a non-nullary type constant to value terms and/or
polymorphic types.
For instance, if
<code class="prettyprint lang-smt3">X</code>
and
<code class="prettyprint lang-smt3">Y</code>
are type variables, and
<code class="prettyprint lang-smt3">Int</code>
and
<code class="prettyprint lang-smt3">Array</code>
are type constants, then
<code class="prettyprint lang-smt3">(Array Int Int)</code>,
<code class="prettyprint lang-smt3">(Array Int Y)</code>,
<code class="prettyprint lang-smt3">(Array X Int)</code>,
and
<code class="prettyprint lang-smt3">(Array X Y)</code>
are all polymorphic types.
A <em>monomorphic type</em> is a polymorphic type with no occurrences
of type variables.
For example,
<code class="prettyprint lang-smt3">(Array Int Int)</code>
is a polymorphic type that is also monomorphic.
</p>
<p>Note that this version of polymorphism is (intentionally) not equivalent
to polymorphism in logics like CIC, where polymorphic functions take types
as input.
For example, the array <code class="prettyprint lang-smt3">select</code> function in <b>does not</b> have type:
<pre class="prettyprint lang-smt3">
(→ (! Type :var I :implicit) (! Type :var E :implicit) (Array I E) I E)
</pre>
where the first two, implicit arguments
<code class="prettyprint lang-smt3">I</code>
and
<code class="prettyprint lang-smt3">E</code>
are types.
In contrast, and in full analogy with SMT-LIB 2.7, it has type
<pre class="prettyprint lang-smt3">
(→ (Array I E) I E)
</pre>
where
<code class="prettyprint lang-smt3">I</code>
and
<code class="prettyprint lang-smt3">E</code>
are two previously declared type variables.
The difference between the two types is subtle but significant.
A constant of type
<code class="prettyprint lang-smt3">(→ (Array I E) I E)</code>
does not denote a single function but a <em>family</em> of functions
of monomorphic type, one for each monomorphic instance of
<code class="prettyprint lang-smt3">(→ (Array I E) I E)</code>.
This effectively allows <em></em>only prenex</em> polymorphism,
in contrast to the unrestricted polymorphism of logics like CIC.
In fact, it does not even allow (ML-style) let-polymorphism
since the
<code class="prettyprint lang-smt3">let</code>
binder does not locally bind type variables.
<h4>Terms</h4>
<p>
A consequence of identifying functions and maps from Version 2.7
is that the
<code class="prettyprint lang-smt3">lambda</code>
binder of Version 2.7 can now be used to construct
the lamba abstractions for all types, not just map types.
Its general form is now
<pre class="prettyprint lang-smt3">
(lambda ((<i>x</i> <i>τ₁</i>)) <i>t</i>)
</pre>
where <i>t</i> is a value term and <i>x</i> is a bound variable of type
<i>τ₁</i> with scope <i>t</i>.
As usual, the abstraction has type
<code class="prettyprint lang-smt3">(→ τ₁ τ₂)</code>
if <i>t</i> has type τ₂ in the typing context that assigns type τ₁ to <i>x</i>.
For instance, this allows the construction of lambda abstractions such as
<pre class="prettyprint lang-smt3">
(lambda ((x A)) (lambda ((y A)) (not (= x y))))
</pre>
or, more concisely,
<code class="prettyprint lang-smt3">(lambda ((x A) (y A)) (not (= x y))</code>,
of type
<code class="prettyprint lang-smt3">(→ A Bool)</code>.
</p>
<p>Since a constant <code class="prettyprint lang-smt3">f</code> of type
<code class="prettyprint lang-smt3">(→ σ₁ ⋅⋅⋅ σᵢ)</code>
is a higher-order function when i > 2, partial applications of such constants,
e.g.,
<code class="prettyprint lang-smt3">(f t)</code>,
are meaningful and legal.
The syntax
<code class="prettyprint lang-smt3">(f t₁ ⋅⋅⋅ tᵢ)</code>
for the full application of
<code class="prettyprint lang-smt3">f</code>
remains the same as in Version 2.7 although it is now seen as an abbreviation of
<code class="prettyprint lang-smt3">( ⋅⋅⋅ ((f t₁) t₂) ⋅⋅⋅ tᵢ)</code>.
</p>
<p>
Version 2.7 allows the application of maps via the <em>apply</em> operator
<code class="prettyprint lang-smt3">@</code>,
as in
<code class="prettyprint lang-smt3">(@ f a)</code>.
This syntax is maintained but is now extended to all functions,
because of the identification of maps with functions.
</p>
<h4>Formulas</h4>
<p>
As in Version 2, formulas are terms of type
<code class="prettyprint lang-smt3">Bool</code>.
Predefined constants include
<ul>
<li>the constants
<code class="prettyprint lang-smt3">true</code> and
<code class="prettyprint lang-smt3">false</code> of type
<code class="prettyprint lang-smt3">Bool</code>,
</li>
<li>the equality operator
<code class="prettyprint lang-smt3">=</code>,
now a polymorphic constant of type
<code class="prettyprint lang-smt3">(→ <i>α</i> <i>α</i> Bool)</code>,
</li>
<li> the
<code class="prettyprint lang-smt3">ite</code>
operator, now a polymorphic constant of type
<code class="prettyprint lang-smt3">(→ Bool <i>α</i> <i>α</i> <i>α</i>)</code>,
</li>
</ul>
where <i>α</i> is a type variable.
</p>
<p>A core language of commands allows one to declare new type variables,
type constants, and value constants, and to assert formulas.
<pre class="prettyprint lang-smt3">
(declare-type-var X) ; declares a new type variable
(declare-type A ()) ; declares a new simple type (a nullary type constant)
(declare-type B ())
(declare-const a A) ; declares a constant of type A
(declare-const f (→ A B)) ; declares a constant of type (→ A B)
(declare-const g (→ A B))
(declare-const p (→ A B Bool))
(declare-const id (→ X X)) ; a polymorphic function
(assert (= b (f a)))
(assert (= f g)) ; higher-order assertion
(assert (= p (lambda ((x A) (y B)) (= (g x) y)))) ; higher-order assertion
(assert (forall ((x X)) (= x (id x)))) ; polymorphic assertion
</pre>
Constants for polymorphic/dependent types can be declared
as in the examples below:
<pre class="prettyprint lang-smt3">
(declare-type Collection (Type))
(declare-type Pair (Type Type))
(declare-type BitVec (Int))
(declare-type Vector (Type Int))
</pre>
All these constants take types and/or values as input and construct a type.
This means that type constant <code class="prettyprint lang-smt3">Collection</code>
has kind
<code class="prettyprint lang-smt3">(→ Type Type)</code>.
Type constant <code class="prettyprint lang-smt3">Pair</code> has kind
<code class="prettyprint lang-smt3">(→ Type Type Type)</code>.
Type constant <code class="prettyprint lang-smt3">BitVec</code>
has kind <code class="prettyprint lang-smt3">(→ Int Type)</code>.
<br>
Type constant <code class="prettyprint lang-smt3">Vector</code>
has kind <code class="prettyprint lang-smt3">(→ Type Int Type)</code>.
If <code class="prettyprint lang-smt3">X</code> is a type variable,
the type
<code class="prettyprint lang-smt3">
(→ (! Int :var n) (Vector X n))
</code>
is both polymorphic (in
<code class="prettyprint lang-smt3">X</code>),
and dependent (on
<code class="prettyprint lang-smt3">n</code>).
</p>
<p>
Note that since
<code class="prettyprint lang-smt3">declare-type</code>
is essentially a constant declaration but the at level of kinds,
the command
<code class="prettyprint lang-smt3">(declare-type Vector (Type Int))</code>,
say, could be understood as an abbreviation of
<code class="prettyprint lang-smt3">
(declare-const Vector (→ Type Int Type))</code>,
although the latter syntax is not actually allowed.
</p>
<h4>Semantic restrictions on types</h4>
<p>
While semantic restrictions on types yield the full power
of predicate subtyping, their intended use in SMT-LIB 3 is
to document precisely the input domain over which a partial function or
type constant is defined.
<em>So they are meant to be used as formal documentation,
not as the definition of a subtype.</em>
The type system SMT-LIB 3 remains without subtypes which means that
semantic restrictions on types can be completely ignored
for type checking purposes.
That said, solvers can use type restriction information to provide
more informative messages in case of scripts that use
partial functions outside of their domain of definition.
As an example, the integer division operator in Version 3 is defined
as follows
<pre class="prettyprint lang-smt3">
(declare-const div (→ Int (! Int :var n :restrict (distinct n 0)) Int)
</pre>
A solver could use the knowledge of the <em>official</em> restriction above
for instance to issue a warning when it returns a model that gives value 0
to a term occurring as the second argument of a
<code class="prettyprint lang-smt3">div</code>
application in an assertion.
Alternatively, it could try to determine statically,
before solving an input problem, if all applications of partial functions
in the problem are provably to values within the function's domain, and
issue a warning otherwise.
</p>
<p>
Semantic restrictions can be introduced in declarations and
definitions, and can apply also to the returned value,
as shown in the following example.
<pre class="prettyprint lang-smt3">
(declare-const f
(-> (! Int :var m1 :restrict (> m1 0))
(! Int :var m2 :restrict (> m2 m1))
(! Int :var n :restrict (exists ((x Int)) (= n (* 2 x)))))
)
</pre>
or, equivalently
<pre class="prettyprint lang-smt3">
(declare-fun f ((m1 Int :restrict (> m1 0)) (m2 Int :restrict (> m2 m1)))
(! Int :var n :restrict (exists ((x Int)) (= n (* 2 x))))
)
</pre>
Both commands introduce a function
<code class="prettyprint lang-smt3">f</code>
that takes two integers as input and returns an integer.
The semantic restrictions indicate that the function is not arbitrary:
whenever the first argument is greater than 0 and the second argument is
greater than the first, the returned value is an even integer.
Note how in the case of
<code class="prettyprint lang-smt3">declare-fun</code>
the
<code class="prettyprint lang-smt3">:restrict</code>
attribute is added directly to the declaration of each named input,
making the
<code class="prettyprint lang-smt3">:var</code>
attribute is unnecessary.
</p>
<p>
As another example, the bit vector type
in the theory of bit vectors could be defined as follows:
<pre class="prettyprint lang-smt3">
(declare-type BitVec ((! Int :var m :restrict (>= m 0)))
</pre>
Since the parameter
<code class="prettyprint lang-smt3">m</code>
expresses the size of the vector, the added restriction limits the value of
<code class="prettyprint lang-smt3">m</code>
to the positive integers.
</p>
<h4>Syntactic restrictions on types</h4>
<p>
Syntactic restrictions on types are orthogonal to semantic ones and
have a different purpose: to restrict the set of expressible terms and
formulas in a benchmark so as to achieve decidability
of the satisfiability problem or some other computational objective —
as done, for instance, in the various BV logics of SMT-LIB 2.
Concretely, in modules corresponding to SMT-LIB logics (see later),
the parameter
<code class="prettyprint lang-smt3">m</code> of the bit vector type above
is further constrained to be a numeral, as opposed to an arbitrary
<code class="prettyprint lang-smt3">Int</code>
integer term, as follows:
<pre class="prettyprint lang-smt3">
(declare-type BitVec ((! Int :var m :restrict (>= m 0) :syntax <.numeral.>)))
</pre>
This means that, in those logics, the
<code class="prettyprint lang-smt3">BitVec</code>
constant can be applied only to terms that evaluate (that is, αβ-reduce)
to numerals.
The same mechanism is applied in logics of linear integer arithmetic
to restrict applications of the multiplication operator
to linear multiplications.
For instance, in linear integer arithmetic, multiplication could be defined
as follows (the actual definition is more elaborate):
<pre class="prettyprint lang-smt3">
(define-fun-rec * ((x Int :syntax <.signed_numeral.>) (y Int))
(ite (= x 0) 0
(ite (< x 0) (* (- x) y)
(+ x (* ((- x 1) y)))))
:left-assoc)
</pre>
where
<code class="prettyprint lang-smt3"><.signed numeral.></code>
denotes the set of numerals and negated positive numerals
(<code class="prettyprint lang-smt3">(- 1)</code>,
<code class="prettyprint lang-smt3">(- 2)</code>,
...).
Note that the first argument in the recursive calls in the definition of
<code class="prettyprint lang-smt3">*</code>
are terms that reduce to a term in
<code class="prettyprint lang-smt3"><.signed numeral.></code>
whenever the value of argument
<code class="prettyprint lang-smt3">x</code>
is a term in that set.
</p>
<p>
Contrary to semantic restrictions, syntactic restrictions must be enforced
by compliant SMT solvers.
</p>
<h3>Commands</h3>
<p>The SMT-LIB 3 language contains almost all commands in Version 2.7
as well as an additional number of new constructs and commands.
A large number of them, however, are defined in terms of the core language
above.
This includes all the commands from Version 2.7, none of which change
semantics in practice in Version 3.
Most of them become syntactic sugar of <em>core</em> Version 3 commands.
Some of them will be deprecated and eventually phased out.
For instance,
<code class="prettyprint lang-smt3">declare-const</code>
is now a core command while
<code class="prettyprint lang-smt3">declare-fun</code>
is not.
The SMT-LIB 2.7 expression
<pre class="prettyprint lang-smt3">
(declare-fun <i>f</i> (τ₁ ⋅⋅⋅ τᵢ) τ)
</pre>
with i > 0 is now an abbreviation of
<pre class="prettyprint lang-smt3">
(declare-const <i>f</i> (→ τ₁ ⋅⋅⋅ τᵢ τ))
</pre>
Similarly,
<pre class="prettyprint lang-smt3">
(define-fun <i>f</i> ((<i>x₁</i> τ₁) ⋅⋅⋅ ((<i>xᵢ</i> τᵢ)) τ <i>t</i>)
</pre>
and
<pre class="prettyprint lang-smt3">
(define-fun-rec <i>f</i> ((<i>x₁</i> τ₁) ⋅⋅⋅ ((<i>xᵢ</i> τᵢ)) τ <i>t</i>)
</pre>
are now respective abbreviations of
<pre class="prettyprint lang-smt3">
(define-const <i>f</i> (→ τ₁ ⋅⋅⋅ τᵢ τ) (lambda ((<i>x₁</i> τ₁) ⋅⋅⋅ ((<i>xᵢ</i> τᵢ)) <i>t</i>))
</pre>
and
<pre class="prettyprint lang-smt3">
(define-const-rec <i>f</i> (→ τ₁ ⋅⋅⋅ τᵢ τ) (lambda ((<i>x₁</i> τ₁) ⋅⋅⋅ ((<i>xᵢ</i> τᵢ)) <i>t</i>))
</pre>
where
<code class="prettyprint lang-smt3">define-const-rec</code>
is a new core command.
</p>
<p>In a similar vein, sorts are not primitive anymore and become types.
Correspondingly,
<code class="prettyprint lang-smt3">declare-sort</code>
is now a special case of the new core command
<code class="prettyprint lang-smt3">declare-type</code>.
For instance,
<pre class="prettyprint lang-smt3">
(declare-sort <i>S</i> <i>n</i>)
</pre>
with <i>n</i> ≥ 0 now becomes an alternative syntax for
<pre class="prettyprint lang-smt3">
(declare-type <i>S</i> (Type ⋅⋅⋅ Type))
</pre>
with <i>n</i> occurrences of <code class="prettyprint lang-smt3">Type</code>.
Similarly,
<pre class="prettyprint lang-smt3">
(define-sort <i>S</i> (<i>u</i>₁ ⋅⋅⋅ <i>u</i>ᵢ) σ)
</pre>
now becomes an alternative syntax for
<pre class="prettyprint lang-smt3">
(define-type <i>S</i> ((<i>u</i>₁ Type) ⋅⋅⋅ (<i>u</i>ᵢ Type)) σ)
</pre>
Note that
<code class="prettyprint lang-smt3">declare-type</code>
and
<code class="prettyprint lang-smt3">define-type</code>
are more general than their Version 2 counterparts
because they can introduce (value) dependent types as well.
<pre class="prettyprint lang-smt3">
(declare-type Vector (Type (! Int :var m :restrict (>= m 0)))
(define-type NonEmptyRealVector ((n Int :restrict (> n 0))) (Vector Real n))
(define-type RealVector8 () (NonEmptyRealVector 8))
</pre>
</p>
<h4>Command attributes</h4>
The syntax of commands is extended with the addition
of optional attributes which can inserted in arbitrary order
after the command's arguments.
This is most useful for
<code class="prettyprint lang-smt3">declare-const</code>
and similar commands as it allows the incorporation
of Version 2 attributes from the theory definition sublanguage,
as well as new ones.
<pre class="prettyprint lang-smt3">
(declare-type-var A)
...
(declare-const = (-> A A Bool)
:pairwise
:builtin
"= denotes the identity function, which returns true iff
its two arguments are identical.")
(define-fun or ((b1 Bool) (b2 Bool)) Bool
(ite b1 true b2)
:left-assoc)
</pre>
The full list of attributes per command will be provided
in the reference document.
More examples can be found in the sample theory modules below.
<h3>Binders</h3>
<p>The primitive binders in Version 3 are
<ul>
<li>
<code class="prettyprint lang-smt3">let</code>,
the parallel version of local definitions
(<code class="prettyprint lang-smt3">(let ((<i>x₁ t₁</i>) ⋅⋅⋅ (<i>x<sub>n</sub> t<sub>n</sub></i>)) <i>t</i>)</code>);
</li>
<li>
<code class="prettyprint lang-smt3">lambda</code>,
for function (λ) abstraction
(<code class="prettyprint lang-smt3">(lambda ((<i>x₁ τ₁</i>) ⋅⋅⋅ (<i>x<sub>n</sub> τ<sub>n</sub></i>)) <i>t</i>)</code>).
</li>
</ul>
The
<code class="prettyprint lang-smt3">let</code>
binder is the same as in Version 2 with the addition that now it can be used
to define higher-order variables.
The <code class="prettyprint lang-smt3">lambda</code>
binder is an extension to functions of the corresponding binder of Version 2.7.