Mimer: Observational equivalence at work.Loki: Right. Not iffy at all.
The goal of this lecture note is to illustrate how to calculate implementations from complete specifications. The calculations are spelled out for Boolean functions (negation, conjunction, etc.). The resulting definitions only use conditional expressions.
These resulting definitions are discovered, not invented, and since their starting point and their calculation are correct, they are correct by construction.
Let us revisit Exercise 15 from Week 03. The following unit-test function is complete in that it enumerates the graph of the negation function:
let test_not candidate =
let b0 = (candidate true = false)
and b1 = (candidate false = true)
in b0 && b1;;
OCaml’s predefined negation function passes this unit test.
Our witness implementation mimicks this unit-test function the way a fake function would:
let witness_not b =
if b = true
then false
else (if b = false
then true
else undefined ());;
where undefined is summarily defined as a failed assertion:
let undefined () =
assert false;;
This witness implementation passes the unit test.
Our starting point distinguishes between the two possible arguments for negation, and uses witness_not to return the right result:
let not_v1 b =
if b
then witness_not true
else witness_not false;;
This implementation passes the unit test.
We then unfold the calls to witness_not and select the corresponding conditional branch:
let not_v2 b =
if b
then false
else true;;
This implementation passes the unit test, is self-contained, and only uses conditional expressions.
Let us revisit Exercise 02 from Week 04. The following unit-test function is complete in that it enumerates the graph of the conjunction function:
let test_and candidate =
let b0 = (candidate true true = true)
and b1 = (candidate true false = false)
and b2 = (candidate false true = false)
and b3 = (candidate false false = false)
in b0 && b1 && b2 && b3;;
OCaml’s predefined conjunction function passes this unit test.
Our witness implementation mimicks the unit-test function the way a fake function would:
let witness_and b1 b2 =
if b1 = true && b2 = true
then true
else (if b1 = true && b2 = false
then false
else (if b1 = false && b2 = true
then false
else (if b1 = false && b2 = false
then false
else undefined ())));;
Our starting point distinguishes between the four possible arguments for conjunction, and uses witness_and to return the right result:
let and_v1 b1 b2 =
if b1
then (if b2
then witness_and true true
else witness_and true false)
else (if b2
then witness_and false true
else witness_and false false);;
This implementation passes the unit test.
We then unfold the calls to witness_and and select the corresponding conditional branch:
let and_v2 b1 b2 =
if b1
then (if b2
then true
else false)
else (if b2
then false
else false);;
On the ground that
we simplify and_v2 into the final implementation:
let and_v3 b1 b2 =
if b1
then b2
else false;;
This implementation passes the unit test, is self-contained, and only uses conditional expressions.
Revisiting Exercise 03 from Week 04, calculate an implementation of boolean disjunction, based on the following unit-test function, which is complete:
let test_or candidate =
let b0 = (candidate true true = true)
and b1 = (candidate true false = true)
and b2 = (candidate false true = true)
and b3 = (candidate false false = false)
in b0 && b1 && b2 && b3;;
Revisiting Exercise 04 from Week 04, calculate an implementation of negated conjunction (a.k.a. the Sheffer stroke), based on the following unit-test function, which is complete:
let test_nand candidate =
let b0 = (candidate true true = false)
and b1 = (candidate true false = true)
and b2 = (candidate false true = true)
and b3 = (candidate false false = true)
in b0 && b1 && b2 && b3;;
Revisiting Exercise 05 from Week 04, calculate an implementation of negated disjunction (a.k.a. Peirce’s arrow), based on the following unit-test function, which is complete:
let test_nor candidate =
let b0 = (candidate true true = false)
and b1 = (candidate true false = false)
and b2 = (candidate false true = false)
and b3 = (candidate false false = true)
in b0 && b1 && b2 && b3;;
Revisiting Exercise 06 from Week 04, calculate an implementation of exclusive disjunction based on the following unit-test function, which is complete:
let test_xor candidate =
let b0 = (candidate true true = false)
and b1 = (candidate true false = true)
and b2 = (candidate false true = true)
and b3 = (candidate false false = false)
in b0 && b1 && b2 && b3;;
Calculate an implementation of boolean implication based on the following unit-test function, which is complete:
let test_implies candidate =
let b0 = (candidate true true = true) (* true implies true *)
and b1 = (candidate true false = false) (* true does not imply false *)
and b2 = (candidate false true = true) (* false implies anything *)
and b3 = (candidate false false = true) (* false implies anything *)
in b0 && b1 && b2 && b3;;
Calculate an implementation of boolean equivalence based on the following unit-test function, which is complete:
let test_equivalence candidate =
let b0 = (candidate true true = true) (* true and true are equivalent *)
and b1 = (candidate true false = false) (* true and false are not equivalent *)
and b2 = (candidate false true = false) (* false and true are not equivalent *)
and b3 = (candidate false false = true) (* false and false are equivalent *)
in b0 && b1 && b2 && b3;;
Confirm (in two distinct ways) or deny (with one counter-example) the following rumoured observational equivalences:
Confirm (in two distinct ways) or deny (with one counter-example) the following rumoured observational equivalences:
Confirm (in two distinct ways) or deny (with one counter-example) the following rumoured observational equivalences:
Confirm (in two distinct ways) or deny (with one counter-example) the following rumoured observational equivalences:
Created [10 Jan 2023]