Built with Alectryon, running Coq+SerAPI v8.19.0+0.19.3. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑Ctrl+↓ to navigate, Ctrl+🖱️ to focus. On Mac, use ⌘ instead of Ctrl.
(* This file demonstrates coinduction through the example of automata equivalence. We explore three different ways to define equivalence between automaton states and prove they are all equivalent. *)Require Import List.Import ListNotations.(* An automaton over an alphabet Sigma consists of: - A state type (i.e., a set of states) - A predicate identifying accepting states - A transition function delta that takes a state and input symbol and returns the next state *)Recordaut (Sigma : Type) := {
state : Type;
accept : state -> Prop;
delta : state -> Sigma -> state
}.(* Make the record fields available without explicitly mentioning Sigma *)Arguments state {_}.Arguments accept {_}.Arguments delta {_}.(* Define states for our example automaton *)Inductivestates1 := sA | sB | sC | sD | sE | sF.(* Example automaton that takes boolean inputs. States B, D, and E are accepting states. The transition function defines how states change based on boolean inputs. *)Definitionaut1 : aut bool := {|
state := states1;
accept s := match s with
| sA | sB | sF => False
| sC | sD | sE => Trueend;
delta s x := match s, x with
| sA, false => sB
| sA, true => sC
| sB, false => sA
| sB, true => sD
| sC, false => sE
| sC, true => sF
| sD, false => sE
| sD, true => sF
| sE, false => sE
| sE, true => sF
| sF, _ => sF
end;
|}.(* First definition of language acceptance: A state accepts a list of inputs if following those inputs leads to an accepting state *)Inductiveaccepts {Sigma} (A : aut Sigma) : list Sigma -> state A -> Prop :=
| acc_nil : foralls, accept A s -> accepts A [] s
| acc_cons : forallsxxs, accepts A xs (delta A s x) -> accepts A (x :: xs) s.(* First definition of state equivalence: Two states are equivalent if they accept exactly the same input sequences *)Definitionequiv1 {Sigma} (A : aut Sigma) (s1s2 : state A) :=
forallxs, accepts A xs s1 <-> accepts A xs s2.
a: bool xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB
accepts aut1 (a :: xs) sA <->
accepts aut1 (a :: xs) sB
a: bool xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB
accepts aut1 (a :: xs) sA -> accepts aut1 (a :: xs) sB
a: bool xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB
accepts aut1 (a :: xs) sB -> accepts aut1 (a :: xs) sA
a: bool xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB
accepts aut1 (a :: xs) sA -> accepts aut1 (a :: xs) sB
a: bool xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H: accepts aut1 (a :: xs) sA
accepts aut1 (a :: xs) sB
a: bool xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs (delta aut1 sA a)
accepts aut1 (a :: xs) sB
a: bool xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs (if a then sC else sB)
accepts aut1 (a :: xs) sB
a: bool xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs (if a then sC else sB)
accepts aut1 xs (delta aut1 sB a)
a: bool xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs (if a then sC else sB)
accepts aut1 xs (if a then sD else sA)
xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs sC
accepts aut1 xs sD
xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs sB
accepts aut1 xs sA
xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs sC
accepts aut1 xs sD
xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs sC
accepts aut1 xs sC
auto.
xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs sB
accepts aut1 xs sA
xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs sB
accepts aut1 xs sB
auto.
a: bool xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB
accepts aut1 (a :: xs) sB -> accepts aut1 (a :: xs) sA
a: bool xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H: accepts aut1 (a :: xs) sB
accepts aut1 (a :: xs) sA
a: bool xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs (delta aut1 sB a)
accepts aut1 (a :: xs) sA
a: bool xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs (if a then sD else sA)
accepts aut1 (a :: xs) sA
a: bool xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs (if a then sD else sA)
accepts aut1 xs (delta aut1 sA a)
a: bool xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs (if a then sD else sA)
accepts aut1 xs (if a then sC else sB)
xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs sD
accepts aut1 xs sC
xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs sA
accepts aut1 xs sB
xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs sD
accepts aut1 xs sC
xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs sD
accepts aut1 xs sD
auto.
xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs sA
accepts aut1 xs sB
xs: list bool IHxs: accepts aut1 xs sA <-> accepts aut1 xs sB H0: accepts aut1 xs sA
accepts aut1 xs sA
auto.Qed.(* Example: states A and F are not equivalent *)
~ equiv1 aut1 sA sF
~ equiv1 aut1 sA sF
Admitted.(* Second definition of equivalence using bisimulation: A relation R is a bisimulation if related states: 1) agree on acceptance 2) transition to related states on any input *)Definitionbisim {Sigma} (A : aut Sigma) (R : state A -> state A -> Prop) :=
foralls1s2, R s1 s2 -> (accept A s1 <-> accept A s2) /\ forallx, R (delta A s1 x) (delta A s2 x).(* Two states are equivalent if there exists a bisimulation relating them *)Definitionequiv2 {Sigma} (A : aut Sigma) (s1s2 : state A) :=
existsR, bisim A R /\ R s1 s2.
Sigma: Type aut: lec22_coinduction.aut Sigma
bisim aut (equiv1 aut)
Sigma: Type aut: lec22_coinduction.aut Sigma
bisim aut (equiv1 aut)
Admitted.(* The first and second definitions of equivalence are equivalent *)
Sigma: Type aut: lec22_coinduction.aut Sigma s1, s2: state aut
equiv1 aut s1 s2 -> equiv2 aut s1 s2
Sigma: Type aut: lec22_coinduction.aut Sigma s1, s2: state aut
equiv1 aut s1 s2 -> equiv2 aut s1 s2
Admitted.
Sigma: Type aut: lec22_coinduction.aut Sigma s1, s2: state aut
equiv2 aut s1 s2 -> equiv1 aut s1 s2
Sigma: Type aut: lec22_coinduction.aut Sigma s1, s2: state aut
equiv2 aut s1 s2 -> equiv1 aut s1 s2
Admitted.(* Third definition using coinduction: Two states are equivalent if: 1) they agree on acceptance 2) their transitions are equivalent for all inputs This is similar to bisimulation but uses Coq's built-in coinduction *)CoInductiveequiv3 {Sigma} (A : aut Sigma) (s1s2 : state A) : Prop := {
accept_eq : accept A s1 <-> accept A s2;
delta_eq : forallx, equiv3 A (delta A s1 x) (delta A s2 x);
}.(* Reflexivity of equiv3 *)
Sigma: Type aut: lec22_coinduction.aut Sigma s: state aut
equiv3 aut s s
Sigma: Type aut: lec22_coinduction.aut Sigma s: state aut
equiv3 aut s s
Sigma: Type aut: lec22_coinduction.aut Sigma
foralls : state aut, equiv3 aut s s
Sigma: Type aut: lec22_coinduction.aut Sigma IH: foralls : state aut, equiv3 aut s s
foralls : state aut, equiv3 aut s s
Sigma: Type aut: lec22_coinduction.aut Sigma IH: foralls : state aut, equiv3 aut s s s: state aut
equiv3 aut s s
Sigma: Type aut: lec22_coinduction.aut Sigma IH: foralls : state aut, equiv3 aut s s s: state aut
accept aut s <-> accept aut s
Sigma: Type aut: lec22_coinduction.aut Sigma IH: foralls : state aut, equiv3 aut s s s: state aut
forallx : Sigma,
equiv3 aut (delta aut s x) (delta aut s x)
Sigma: Type aut: lec22_coinduction.aut Sigma IH: foralls : state aut, equiv3 aut s s s: state aut
accept aut s <-> accept aut s
reflexivity.
Sigma: Type aut: lec22_coinduction.aut Sigma IH: foralls : state aut, equiv3 aut s s s: state aut
forallx : Sigma,
equiv3 aut (delta aut s x) (delta aut s x)
Sigma: Type aut: lec22_coinduction.aut Sigma IH: foralls : state aut, equiv3 aut s s s: state aut x: Sigma
equiv3 aut (delta aut s x) (delta aut s x)
apply IH.Qed.(* Example: states E and D are equivalent *)
equiv3 aut1 (if x then sF else sE)
(if x then sF else sE)
destruct x; apply equiv3_refl.Qed.(* The second and third definitions are equivalent *)
Sigma: Type aut: lec22_coinduction.aut Sigma s1, s2: state aut
equiv2 aut s1 s2 -> equiv3 aut s1 s2
Sigma: Type aut: lec22_coinduction.aut Sigma s1, s2: state aut
equiv2 aut s1 s2 -> equiv3 aut s1 s2
Sigma: Type aut: lec22_coinduction.aut Sigma s1, s2: state aut R: state aut -> state aut -> Prop bisim_R: bisim aut R R_s1_s2: R s1 s2
equiv3 aut s1 s2
Sigma: Type aut: lec22_coinduction.aut Sigma R: state aut -> state aut -> Prop bisim_R: bisim aut R
foralls1s2 : state aut, R s1 s2 -> equiv3 aut s1 s2
Sigma: Type aut: lec22_coinduction.aut Sigma R: state aut -> state aut -> Prop bisim_R: bisim aut R IH: foralls1s2 : state aut,
R s1 s2 -> equiv3 aut s1 s2
foralls1s2 : state aut, R s1 s2 -> equiv3 aut s1 s2
Sigma: Type aut: lec22_coinduction.aut Sigma R: state aut -> state aut -> Prop bisim_R: bisim aut R IH: foralls1s2 : state aut,
R s1 s2 -> equiv3 aut s1 s2 s1, s2: state aut R_s1_s2: R s1 s2
equiv3 aut s1 s2
Sigma: Type aut: lec22_coinduction.aut Sigma R: state aut -> state aut -> Prop bisim_R: bisim aut R IH: foralls1s2 : state aut,
R s1 s2 -> equiv3 aut s1 s2 s1, s2: state aut R_s1_s2: R s1 s2
accept aut s1 <-> accept aut s2
Sigma: Type aut: lec22_coinduction.aut Sigma R: state aut -> state aut -> Prop bisim_R: bisim aut R IH: foralls1s2 : state aut,
R s1 s2 -> equiv3 aut s1 s2 s1, s2: state aut R_s1_s2: R s1 s2
forallx : Sigma,
equiv3 aut (delta aut s1 x) (delta aut s2 x)
Sigma: Type aut: lec22_coinduction.aut Sigma R: state aut -> state aut -> Prop bisim_R: bisim aut R IH: foralls1s2 : state aut,
R s1 s2 -> equiv3 aut s1 s2 s1, s2: state aut R_s1_s2: R s1 s2
accept aut s1 <-> accept aut s2
Sigma: Type aut: lec22_coinduction.aut Sigma R: state aut -> state aut -> Prop bisim_R: bisim aut R IH: foralls1s2 : state aut,
R s1 s2 -> equiv3 aut s1 s2 s1, s2: state aut R_s1_s2: R s1 s2 H: accept aut s1 <-> accept aut s2 H0: forallx : Sigma,
R (delta aut s1 x) (delta aut s2 x)
accept aut s1 <-> accept aut s2
auto.
Sigma: Type aut: lec22_coinduction.aut Sigma R: state aut -> state aut -> Prop bisim_R: bisim aut R IH: foralls1s2 : state aut,
R s1 s2 -> equiv3 aut s1 s2 s1, s2: state aut R_s1_s2: R s1 s2
forallx : Sigma,
equiv3 aut (delta aut s1 x) (delta aut s2 x)
Sigma: Type aut: lec22_coinduction.aut Sigma R: state aut -> state aut -> Prop bisim_R: bisim aut R IH: foralls1s2 : state aut,
R s1 s2 -> equiv3 aut s1 s2 s1, s2: state aut R_s1_s2: R s1 s2 x: Sigma
equiv3 aut (delta aut s1 x) (delta aut s2 x)
Sigma: Type aut: lec22_coinduction.aut Sigma R: state aut -> state aut -> Prop bisim_R: bisim aut R IH: foralls1s2 : state aut,
R s1 s2 -> equiv3 aut s1 s2 s1, s2: state aut R_s1_s2: R s1 s2 x: Sigma
R (delta aut s1 x) (delta aut s2 x)
Sigma: Type aut: lec22_coinduction.aut Sigma R: state aut -> state aut -> Prop bisim_R: bisim aut R IH: foralls1s2 : state aut,
R s1 s2 -> equiv3 aut s1 s2 s1, s2: state aut R_s1_s2: R s1 s2 x: Sigma H: accept aut s1 <-> accept aut s2 H0: forallx : Sigma,
R (delta aut s1 x) (delta aut s2 x)
R (delta aut s1 x) (delta aut s2 x)
auto.Qed.(* equiv3 itself forms a bisimulation *)
Sigma: Type aut: lec22_coinduction.aut Sigma
bisim aut (equiv3 aut)
Sigma: Type aut: lec22_coinduction.aut Sigma
bisim aut (equiv3 aut)
Sigma: Type aut: lec22_coinduction.aut Sigma s1, s2: state aut accept_eq: accept aut s1 <-> accept aut s2 delta_eq: forallx : Sigma,
equiv3 aut (delta aut s1 x)
(delta aut s2 x)
(accept aut s1 <-> accept aut s2) /\
(forallx : Sigma,
equiv3 aut (delta aut s1 x) (delta aut s2 x))
eauto.Qed.(* Complete the equivalence between definitions 2 and 3 *)
Sigma: Type aut: lec22_coinduction.aut Sigma s1, s2: state aut
equiv3 aut s1 s2 -> equiv2 aut s1 s2
Sigma: Type aut: lec22_coinduction.aut Sigma s1, s2: state aut
equiv3 aut s1 s2 -> equiv2 aut s1 s2
Sigma: Type aut: lec22_coinduction.aut Sigma s1, s2: state aut Hequiv: equiv3 aut s1 s2
equiv2 aut s1 s2
Sigma: Type aut: lec22_coinduction.aut Sigma s1, s2: state aut Hequiv: equiv3 aut s1 s2
existsR : state aut -> state aut -> Prop,
bisim aut R /\ R s1 s2
Sigma: Type aut: lec22_coinduction.aut Sigma s1, s2: state aut Hequiv: equiv3 aut s1 s2
bisim aut (equiv3 aut) /\ equiv3 aut s1 s2
Sigma: Type aut: lec22_coinduction.aut Sigma s1, s2: state aut Hequiv: equiv3 aut s1 s2