Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
aa:adt-formal [2016/12/09 10:19] pdmatei created |
aa:adt-formal [2018/12/12 11:30] (current) dmihai |
||
---|---|---|---|
Line 5: | Line 5: | ||
In mathematics, **algebraic structures** consist of a (carrier) set (say - the natural numbers) as well as operations on elements of the set, satisfying specific axioms (e.g. //commutativity// for addition). | In mathematics, **algebraic structures** consist of a (carrier) set (say - the natural numbers) as well as operations on elements of the set, satisfying specific axioms (e.g. //commutativity// for addition). | ||
- | Very similar to algebraic structures, an **abstract data type** consists in: | + | Very similar to algebraic structures, an **abstract data type** consists of: |
* **specification** of **a class of objects**, | * **specification** of **a class of objects**, | ||
* a **set of operations** which operate on such objects, | * a **set of operations** which operate on such objects, | ||
Line 94: | Line 94: | ||
While each of the above axioms describes sensible concatenation behaviour, the interesting questions are: | While each of the above axioms describes sensible concatenation behaviour, the interesting questions are: | ||
- | * **the axioms are sufficient** in order to describe correct concatenation behaviour? | + | * **are the axioms sufficient** in order to describe correct concatenation behaviour? |
* **are all axioms necessary**? | * **are all axioms necessary**? | ||
Line 197: | Line 197: | ||
The FIFO implementation has two issues which require attention: | The FIFO implementation has two issues which require attention: | ||
- | * a pair of lists **is not a unique FIFO representation**. For instance, $math[Enqueue(1,Enqueue(2,Empty))] can be interpreted by: $math[\langle 1:2:Void, Void \rangle] as well as by $math[\langle 1:2:Void, Void \rangle]. Thus, FIFO equality in the implementation requires the operation: $math[\langle l, r \rangle \equiv \langle l', r' \rangle =^{(def)} l ++ reverse(r) = l' ++ reverse(r') ] | + | * a pair of lists **is not a unique FIFO representation**. For instance, $math[Enqueue(1,Enqueue(2,Empty))] can be interpreted by: $math[\langle 1:2:Void, Void \rangle] as well as by $math[\langle 1:Void, 2:Void \rangle]. Thus, FIFO equality in the implementation requires the operation: $math[\langle l, r \rangle \equiv \langle l', r' \rangle =^{(def)} l ++ reverse(r) = l' ++ reverse(r') ] |
* A FIFO such as $math[\langle 1:2:Void, Void \rangle] is nonempty, however we cannot extract elements from the rightmost list, since it is empty. Hence, we require the operation: | * A FIFO such as $math[\langle 1:2:Void, Void \rangle] is nonempty, however we cannot extract elements from the rightmost list, since it is empty. Hence, we require the operation: | ||
- | * (N) $math[normalize(\langle l, r \rangle) = \langle Void, r ++ reverse(l) \rangle] | + | * (N) $math[normalize(\langle l, Void \rangle) = \langle Void, reverse(l) \rangle] |
- | The normalization procedure ensures that - if the FIFO is non-empty, there are still elements to be dequeued from the rightmost list. | + | The normalization procedure ensures that - if the FIFO is non-empty, there are still elements to be dequeued from the rightmost list. Note that the axiom is specified only for non-normalized FIFOs, which is a matter of convenience for our implementation proofs. |
==== Implementations ==== | ==== Implementations ==== | ||
- | * $math[Enqueue(e,\langle l, r\rangle) = \langle e:l, r\rangle] | + | In the implementation, we will assume the following invariant: all operations receive **normalised FIFOs** and return **normalised FIFOs**. |
- | * $math[Dequeue(\langle l, Void\rangle) = Dequeue(normalize(\langle l, Void))\rangle] | + | |
- | * $math[Dequeue(\langle l, e:r\rangle) = \langle l, r\rangle] | + | * $math[Enqueue(e,\langle Void, Void\rangle) = \langle Void, e:Void \rangle] |
+ | * $math[Enqueue(e,\langle l, e':r\rangle) = \langle e:l, e':r\rangle] | ||
+ | * $math[Dequeue(\langle l, e:Void\rangle) = normalize(\langle l, Void \rangle)] | ||
+ | * $math[Dequeue(\langle l, e:e':r\rangle) = \langle l, e':r\rangle] | ||
- | * $math[Top(\langle l, Void\rangle) = Top(normalize(\langle l, Void))\rangle] | ||
* $math[Top(\langle l, e:r\rangle) = e] | * $math[Top(\langle l, e:r\rangle) = e] | ||
==== Axioms are preserved ==== | ==== Axioms are preserved ==== | ||
- | We proceed to verify that the axioms for $math[Dequeue] are preserved by the implementation: | + | We proceed to verify that the axioms for $math[Dequeue] are preserved by the implementation. |
- | + | ||
- | First axiom, **left-hand side**: | + | |
- | * $math[Dequeue(Enqueue(e,\langle Void, Void \rangle)) =] | + | |
- | * $math[Dequeue(\langle e:Void, Void \rangle) =] | + | |
- | * $math[Dequeue(normalize(\langle e:Void, Void \rangle)) =] | + | |
- | * $math[Dequeue(\langle Void, e:Void \rangle) =] | + | |
- | * $math[Dequeue(\langle Void, Void \rangle)] | + | |
- | + | ||
- | which is equal to the right-hand side. | + | |
- | + | ||
- | Second axiom, **left-hand side**: | + | |
- | * $math[Dequeue(Enqueue(e,Enqueue(e',\langle l,r\rangle))) =] | + | |
- | * $math[Dequeue(\langle e:e':l,r\rangle))) ] | + | |
- | + | ||
- | Case 1: $math[r = Void] | + | |
- | * $math[Dequeue(\langle e:e':l,Void\rangle))) =] | + | |
- | * $math[Dequeue(normalize(\langle e:e':l,Void\rangle)))) =] | + | |
- | * $math[Dequeue(\langle Void, reverse(e:e':l)\rangle)))) =] | + | |
- | * $math[\langle Void, tail(reverse(e:e':l))\rangle))))] | + | |
- | + | ||
- | Case 1: **right-hand side** | + | |
- | * $math[Enqueue(e,Dequeue(Enqueue(e',\langle l,Void\rangle))) = ] | + | |
- | * $math[Enqueue(e,Dequeue(\langle e':l,Void\rangle)) = ] | + | |
- | * $math[Enqueue(e,Dequeue(normalize(\langle e':l,Void\rangle))) = ] | + | |
- | * $math[Enqueue(e,Dequeue(\langle Void,reverse(e':l)\rangle)) = ] | + | |
- | * $math[Enqueue(e,\langle Void,tail(reverse(e':l))\rangle) = ] | + | |
- | * $math[\langle e:Void,tail(reverse(e':l))\rangle] | + | |
- | + | ||
- | To check if the FIFOs are equal, we need to compare: | + | |
- | * $math[tail(reverse(e:e':l)) ++ Void] with $math[tail(reverse(e':l)) ++ e:Void]. We apply axioms (as well as one yet-unproved proposition) to each expression: | + | |
- | * $math[tail(reverse((e':l) ++ e:Void)] and $math[tail(reverse(e':l)) ++ e:Void] | + | |
- | The equality of the two expressions rests on the following property: | ||
- | * $math[l \neq Void \rightarrow tail(l++l')=tail(l)++l'] | ||
- | To prove this property, we need to examine a new technique called **structural induction**. | ||
- | We leave Case 2 of the proof as exercise. | ||
===== Conclusion ===== | ===== Conclusion ===== | ||
Line 256: | Line 223: | ||
ADTs offer an interface between object implementation and object behaviour. The FIFO example illustrates the power of ADTs: | ADTs offer an interface between object implementation and object behaviour. The FIFO example illustrates the power of ADTs: | ||
* A FIFO can be implemented as two lists, **irrespective of the list implementation choice** | * A FIFO can be implemented as two lists, **irrespective of the list implementation choice** | ||
- | * Once axioms are shown to hold in the implementation, **it is guaranteed to satisfy all properties of the ADT**. | + | * Once axioms are shown to hold in the implementation, **they are guaranteed to satisfy all properties of the ADT**. |