INTRODUCTION TO
Larch
- Larch is a family of Languages that supports a two tiered, definitional
style of specification.
- An abstract specification is a way to describe results without describing
how to achieve them.
- A definitional specification explicitly lists properties that an
implementation must exhibit.
- It will not tell us "how to"!
- Example: Specification of an Integer Square Root Procedure
int squareRoot (int x) {
requires x >= 0;
modifies nothing;
ensures forall i:int
abs(x - (result * result)) <= abs(x -(i*i)));
}
NOTES:
- The lectures on Larch are based on Larch: Language And Tools
for Formal Specification by John V. Guttag and James J Horning, Springer-Verlag.
- There are many web sites for Larch:
- Also of interest are:
- Operational specification gives a recipe that has the required
property. Operational specification shows how to compute the specification.
A program would be an operational specification.
- Example:
int sqrt(int x)
requires x >= 0
effects
i = 0;
while i*i < x
i = i+1 end
if abs(i*i - x) > abs ((i-1) * (i-1) -x)
then return i - 1 else return i
Larch: Slide 2
Role of Specification
- Writing specifications can serve to clarify and deepen the designers'
understanding of what is being specified
- focuses attention on inconsistences, missing parts and ambiguities
- Provide "logical firewalls" by documenting mutual obligations
- Used in generating test data
- Aid in maintenance
- By recording the preserved properties
- Delimiting the changes that might affect clients
- Makes it possible to completely hide
- the implementation of an abstraction from a client
- the uses made by the client from the implementor
Larch: Slide 3
Two Tiered Specification Language
- Each specification has components written in 2 languages
- Larch Shared Language
- Larch Interface Language
- An additional tool:
- LP (Larch Prover) is a tool which is a proof assistant/proof debugger.
Larch: Slide 4
Larch Shared Language
- "*.lsl"
- Independent of any language
- Provides the semantic meaning for the Larch Interface Language.
- Used to define specialized vocabularies.
- LSL specifications are more likely to be reuseable than Larch Interface
Languages.
- LSL has a simplier underlying semantics than most programming languages
(and therefore Larch Interface Languages).
- Less likely to make mistakes.
- Easier to find mistakes.
- Easier to make and check assertions about semantic properties of
an LSL specification than that of the Interface specification.
Larch: Slide 5
Larch Interface Language
- Designed for specific programming languages
- Ada (penelope)
- C(lcl)
- Modula 3
- Smalltalk
- C++
- Provides information to programs that implement the specification.
- Deals with what can be observed by a client program.
- Provides a way to write assertions about program states.
- Incorporates programming language specific notations for features
such as side effects, exception handling, iterators and concurrency.
Larch: Slide 6
- The underlying formalism of the Larch family of Languages is Multisorted
first-order logic.
- Therefore we will revisit Logic and add some more concepts.
Larch: Slide 7
Basic concepts of logic
- ()A logical language consists
of a set of sorts and operators (function symbols).
- Sorts are like programming language types.
- Operators represent a map from tuples of values to a value.
- An operator's signature is a tuple of sorts for the operator.
- Example: for the operator "+" the signature could be
Int, Int -> Int
- The domain sort is the tuple of sorts for the arguments.
- The range sort is the sort for the result.
- A relational operator is a binary operator with a range sort
of Bool.
- An application consists of an operator and a tuple of terms
that whose domain has the same sort as the domain of the operator.
- The sort of the application is the same as the operator's range
sort.
- A variable is an identifier which represents an arbitary
value of some sort.
- A term is a variable, application or a parenthesized term
- () An equation is a term of sort Bool written
as a pair of same-sort terms joined by the equality operator =
- A predicate (formula) is a term of sort Bool
- An interpretation (structure) determines the value of predicate
based on the sort and operator.
- Example: SquareRoot(5) = 2
- Is false if SquareRoot is the usual function over the real numbers.
- Is true if SquareRoot is interpreted as the greatest-integer-less-than-
or-equal-to-the-square-root.
- Our set of usual connectives.
- Set of operators whose meanings are fixed a priori.
- equality operator for each sort.
- <=>
- ~
- /\
- \/
- =>
- Quantifiers
- forall
- exist
- A variable is bound in a predicate if it is in the scope of a quantifier.
Otherwise the variable is free.
- "First order" has to do with what you are allowed to use
when you quantify. We are are only quantifying variables of a Sort.
Larch: Slide 8
- A predicate is valid or a tautology if it is true
in all interpretations (structures) under all assignments to its free variables.
- A predicate is satisfiable if there exists an interpretation and
an assignment to its free variables, in which it is true.
- () A sentence is a predicate with no free
variables.
By convention, a free standing predicate with free variables stands
for a sentence obtained by universally quantifying (forall)
it's free variable at the outer level.
- If a sentence is true in an interpretation (structure) we say that
the structure is a model of the sentence.
- When each member of a set of sentences is true under an interpretation,
that interpretation is a model of that set.
Larch: Slide 9
Example of a model of a set of sentences:
Let E be a non-Bool sort with one operator $,
let x, y, and z be variables of sort E.
Consider the following set of sentences:
{forall x:E ~(x $ x),
forall x:E
forall y:E
forall z:E (( x $ y /\ y $ z) => x $ z )}
Give a model of this set of sentences.
NOTES 9:
Normally you would see the sentences written with the symbol < instead
of $.
Larch: Slide 10
- If E is the sort Int and $ is interpreted as being the operation
< then this interpretation is a model for the set of sentences given
in slide 9.
- If E is the sort Int and $ is interpreted as being the operation
=< then this interpretation is NOT a model for the set of sentences
given in slide 9.
- Any interpretation that is a model of the set of sentences in Slide
9 is commonly known as a strict partial order. This set of sentences
are called axioms for strict partial orders.
Larch: Slide 11
A few more definitions (semantic description):
- A sentence S is a logical consequence of a set T of sentences
if every model of T is also a model of S.
- Example:
forall x:E forall y:E ~( x $ y /\ y $ x)
is a logical consequence of the set of sentences in Slide 9.
(Any model for a strict partial order will also model the above).
- A set of sentences is closed under logical consequences if
it contains all its logical consequences.
- A Theory is a closed set of sentences.
- A theory is complete if for every sentence S either S or
~S is in the theory.
- A set of sentences is consistent if it has a model.
- A theory is consistent if and only if it does not contain
a contradiction (i.e. the sentence true = false).
Larch: Slide 12
Proof and consequences -- Syntactic Characterization
- A formal deduction system consists of set of sentences, called
logical axioms, together with a set of deduction rules that
map finite sets of sentences ( the premises of a deduction) to a
conclusion.
P, P => Q
---------
Q
A proof based on a set T of sentences is a finite sequence
of sentences each of which is either
- a logical axiom,
- a member of T
- or the conclusion of a deduction rule applied to a set of sentences
occurring earlier in the proof.
A sentence S is a theorem of T if it occurs in some proof
based on T.
Three desirable properties :
- A system is sound if for any T, all proofs yield theorems
of T which are true.
- A system is complete if, for any T, all theorems of T that
are true are provable as theorems in T.
- A system is effective if, for any computable set T of sentences,
the set of proofs based on T is also computable.
Larch: Slide 13
- LP (Larch prover) uses a system of deduction which is sound and
effective.
- Completeness of its deduction system matters less--since we are
often dealing with incomplete theories.
Larch:Slide 14
LSL: The Larch Shared Language :
A discussion using examples.
What is a table?
Larch: Slide 15
Table: trait
%Specification of Tables that store values in indexed places.
introduces
new: -> Tab
add: Tab, Ind, Val->Tab
__ \in __: Ind, Tab->Val
lookup: Tab, Ind->Bool
isEmpty: Tab->Bool
size: Tab->Int
0,1: ->Int
__ + __: Int, Int->Int
asserts
forall i, i1: Ind, val: Val, t:Tab
~(i \in new)
i \in add(t, i1, val) == i = i1 \/ i \in t;
lookup(add(t, i, val), i1) ==
if i = i1 then val else lookup(t, i1);
size(new) == 0;
size(add(t, i, val))
= if i \in t then size(t) else size(t) + 1;
isEmpty(t) == size(t) = 0
Larch: Slide 16
Explanation of reserved words in LSL on Slide 15
- LSL's basic unit of specification is a trait.
- A trait can be referred to by its name.
- A well formed trait defines a theory in multisorted first-ordered
logic with equality.
- Each trait should be consistent. It must not define an equation
containing true == false.
- introduces
declares a list of operators each with a signature.
- Every operator must be declared.
- Signatures are used to sort-check terms.
- Double underscore indicates
that the operator will be used in "mixfix" form.
- __ + __
- [ __ ]
- if __ then __ else __
- The body of the specification contains:
- following the reserve word asserts,
Notes 16
~(i \in new)
is an abbreviation for
~(i \in new) == true
Larch: Slide 17
Precedence scheme: most tightly to least tightly binding
- postfix operator consisting of . (dot) followed by an identifier
- other user-defined operators and ~ (negation)
- built-in equality operators (= and ~=)
- built-in propostional connectives (\/, /\, =>)
- built-in if __ then __ else __
- ==
Example:
v == x + w.a.b = y \/ z
is equivalent to
v = (((x + ((w.a).b)) = y) \/ z)
Larch: Slide 18
For specifying an abstract type a theory stronger than equational
theory is often needed.
- The constructs generated by and partitioned by
are provided.
- A generated by clause
asserts that a list of operators is a complete set of generators for a
sort.
- Each value of the sort can be written as a finite number of applications
of this list of operators.
- Therefore an induction schema can be used to prove
things about the sort.
- A partioned by
clause asserts that a list of operators constitutes a complete set of observers
for a sort.
- All distinct values of the sort can be distinguished only by using
this list of operators.
- Can be used to add deduction rules
Larch: Slide 19
The table specification including the use of partitioned by
and generated by.
Table: trait
%Specification of Tables
%that store values in
%indexed places.
introduces
new: -> Tab
add: Tab, Ind, Val->Tab
__ \in __: Ind, Tab->Val
lookup: Tab, Ind->Bool
isEmpty: Tab->Bool
size: Tab->Int
0,1: ->Int
__ + __: Int, Int->Int
asserts
Tab generated by new, add
Tab partitioned by \in, lookup
forall i, i1: Ind, val: Val, t:Tab
~(i \in new)
i \in add(t, i1, val) == i = i1 \/ i \in t;
lookup(add(t, i, val), i1) ==
if i = i1 then val else lookup(t, i1);
size(new) == 0;
size(add(t, i, val)) ==
if i \in t then size(t) else size(t) + 1;
isEmpty(t) == size(t) = 0
Larch: Slide 20
Using generated by
a list of operations to prove
forall t:Tab, i:Ind (i \in t => size (t) > 0)
forall i:Ind (i \in new => size(new) > 0)
forall t:Tab, i1:Ind, v1:Val
(forall i:Ind ( i \in t => size(t) > 0)
=> (forall i:Ind ( i \in add(t,i1,v1)
=> size (add(t,i1,v1)) > 0))
- Additional deduction rule for Table
allowed because of the additional axioms in the partition by clause.
forall i1:Ind (i1 \in t1 = i1 \in t2),
forall i1:Ind (lookup(t1, i1) = lookup(t2,i1))
--------------------------------------------------
t1 = t2
- In order to prove the commutativity of add of the same
value, i.e.
forall t:Tab, i,i1:Ind, v:Val
(add(add(t,i,v), i1,v)
= add(add(t,i1,v) i,v) )
- one discharges the two subgoals
forall i2:Ind
(i2 \in add(add(t,i,v), i1,v) = i2 \in add(add(t,i1,v), i,v))
forall i2:Ind
(lookup(add(add(t,i,v) i1,v),i2)
= lookup(add(add(t,i1,v),i,v),i2))
Larch: Slide 21
Combining Traits:
- Table uses three operators that it does not
define: 0,1 and +.
(0 and 1 are considered constant operators.)
- Since 0,1 and + exists in a trait named Integer we can just make
an external reference to it in Table:
Larch: Slide 22
Table: trait
%Specification of Tables that store values in indexed places.
includes Integer
introduces
new: -> Tab
add: Tab, Ind, Val->Tab
__ \in __: Ind, Tab->Val
lookup: Tab, Ind->Bool
isEmpty: Tab->Bool
size: Tab->Int
0,1: ->Int
__ + __: Int, Int->Int
asserts
Tab generated by new, add
Tab partitioned by \in, lookup
forall i, i1: Ind, val: Val, t:Tab
~(i \in new)
i \in add(t, i1, val) == i = i1 \/ i \in t;
lookup(add(t, i, val), i1) ==
if i = i1 then val else lookup(t, i1);
size(new) == 0;
size(add(t, i, val)) ==
if i \in t then size(t) else size(t) + 1;
isEmpty(t) == size(t) = 0
Larch: Slide 23
Another Example of includes:Given Specifications
of relations,
reflexive: trait
introduces __ \rel __ : T, T -> Bool
asserts forall x:T x \rel x
symmetric: trait
introduces __ \rel __ : T, T -> Bool
asserts forall x, y:T x \rel y == y \rel x
transitive: trait
introduces __ \rel __ : T, T -> Bool
asserts forall x, y, z:T
(x \rel y /\ y \rel z) => x \rel z
We can specify equivalence as:
equivalence1: trait
includes reflexive, symmetric, transitive
Which has the same associated theory as:
equivalence2: trait
introduces __ \rel __ : T, T -> Bool
asserts forall x, y, z:T
x \rel x;
x \rel y == y \rel x;
(x \rel y /\ y \rel z) => x \rel z
See Slide 24 to see how
to rename the operator.
Larch: Slide 24
Renaming: Any sort or operator can be renamed when the trait is referenced
in another trait.
equivalence: trait
includes
(reflexive, symmetric, transitive)
( \equiv for \rel )
A convenient way to rename sorts:
Given a header for a trait as follows:
SArr (Val, Arr): trait
Then
include SArr(Int, IntArr)
would be equivalent to
includes SArr(Int for Val, IntArr for Arr)
to Slide 25
NOTES 24:
Two specifications of sparse arrays:
SArr: trait
includes Table(Arr for Tab,
defined for \in,
assign for add,
__[__] for lookup,
Int for Ind)
SArrExpanded: trait
introduces
new: -> Arr
assign: Arr, Int, Val->Arr
defined: Int, Arr->Val
__[__]: Arr, Int->Bool
isEmpty: Arr->Bool
size: Arr->Int
0,1: ->Int
__ + __: Int, Int->Int
asserts forall i,i1:Int,val:Val,t:Arr
~defined(i, new)
defined (i, assign(t, i1, val)) ==
i = i1 \/ defined(i, t);
assign(t, i, val)[i1] ==
if i = i1 then val
else t[i1];
size(new) == 0;
size(assign(t, i, val)) ==
if defined(i, t) then size(t)
else size(t) + 1;
isEmpty(t) == size(t) = 0
Larch: Slide 25
- The checkable properties of LSL are
- consistency
- check that no theory contains false == true
- theory containment
- The specification can be augmented with redundant information that
can be used to help in locating errors in the specification.
- Check that the redundant claims follow from the axioms.
- Implies clause
makes claims about theory containment.
- Although LSL does not require that each trait define a complete
theory. (One in which every sentence is true or false.)
- However within a trait one can include specific checkable claims
about completeness.
- Converts clause is used to check
claims about completeness.
Larch: Slide 26
- Given the SArray trait below:
SArray: trait
introduces
new: -> Arr
assign: Arr, Int, Val->Arr
defined: Int, Arr->Val
__[__]: Arr, Int->Bool
isEmpty: Arr->Bool
size: Arr->Int
0,1: ->Int
__ + __: Int, Int->Int
asserts forall i,i1:Int,val:Val,t:Arr
~defined(i, new)
defined (i, assign(t, i1, val)) ==
i = i1 \/ defined(i, t);
assign(t, i, val)[i1] ==
if i = i1
then val else t[i1];
size(new) == 0;
size(assign(t, i, val)) ==
if defined(i, t)
then size(t)
else size(t) + 1;
isEmpty(t) == size(t) = 0
Suppose we think that a consequence of the
assertions of SArray is no array with a defined element is empty.
To formalize this we add the following implies clause:
implies forall a: Arr, i:Int
defined(i, a)=> ~isEmpty(a)
Larch: Slide 27
implies converts isEmpty
says the trait's axioms fully define isEmpty.
Adding a stronger claim:
implies converts isEmpty, __[__]
However, the meaning of terms of the form:
new[i]
is not defined by the trait. Later we discuss how to get around this.
Larch: Slide 28
More Examples:
- Specification for a container:
InsertGenerated(E,C): trait
% C's contains finitely many E's
introduces
empty: -> C
insert: E, C -> C
asserts
C generated by empty, insert
Container(E,C): trait
% head and tail enumerate contents of a C
includes InsertGenerated, Integer
introduces
isEmpty: C -> Bool
count: E,C -> Int
__ \in __: E,C -> Bool
head: C -> E
tail: C -> C
asserts
C partitioned by isEmpty, head, tail
forall e, e1:E, c: C
isEmpty(empty);
~isEmpty(insert(e,c));
count(e, empty) == 0;
count(e, insert(e1,c)) ==
count(e,c) + (if e=e1 then 1 else 0);
e \in c == count(e,c) > 0;
~isEmpty(c) =>
count(e,insert(head(c),tail(c))) = count(e,c)
implies
forall c:C ~isEmpty(c) => count(head(c), c) > 0;
converts isEmpty, count, \in
Notes: 28
When specifying abstract data types you should add assertions for how
to generate the data and how to observe the data. (ie Include assertions
on generate by and partition by.)
Larch: Slide 29
- Some more properties of relational operators:
Irreflexive ( \rel ): trait
introduces __ \rel __: T, T -> Bool
asserts forall x: T ~(x \rel x)
Transitive ( \rel ): trait
introduces __ \rel __: T, T -> Bool
asserts forall x, y, z: T
(x \rel y /\ y \rel z) => x \rel z
Asymmetric ( \rel ): trait
introduces __ \rel __: T, T -> Bool
asserts forall x, y: T
(x \rel y ) => ~(y \rel x)
Larch: Slide 30
- Using the traits in slide 29 we give the specification for Strict
Partial Order discussed in slide
9.
StrictPartialOrder ( <, T) :trait
includes Irreflexive(<), Transitive(<)
implies
Asymmetric (<)
forall x, y, z: T
~(x < x);
(x < y /\ y < z) => x < z
Notes 30:
Check out LSL
Handbook of Table of Contents web page for more examples of LSL specifications.