#### 99 lines 3.7 KiB Coq Raw Normal View History

 2020-12-11 11:32:54 -08:00 `Require Import Coq.ZArith.Int.` `Require Import Coq.Lists.ListSet.` `Require Import Coq.Vectors.VectorDef.` `Require Import Coq.Vectors.Fin.` ``` ``` `Module DayEight (Import M:Int).` ` (* We need to coerce natural numbers into integers to add them. *)` ` Parameter nat_to_t : nat -> t.` ` (* We need a way to convert integers back into finite sets. *)` ` Parameter clamp : forall {n}, t -> option (Fin.t n).` ``` ``` ` Definition fin := Fin.t.` ` ` ` (* The opcode of our instructions. *)` ` Inductive opcode : Type :=` ` | add` ` | nop` ` | jmp.` ``` ``` ``` (* The result of running a program is either the accumulator ``` ` or an infinite loop error. In the latter case, we return the` ` set of instructions that we tried. *)` ` Inductive run_result {n : nat} : Type :=` ` | Ok : t -> run_result` ` | Fail : set (fin n) -> run_result.` ``` ``` ` Definition state n : Type := (fin (S n) * set (fin n) * t).` ``` ``` ` (* An instruction is a pair of an opcode and an argument. *)` ` Definition inst : Type := (opcode * t).` ` (* An input is a bounded list of instructions. *)` ` Definition input (n : nat) := VectorDef.t inst n.` ``` (* 'indices' represents the list of instruction ``` ` addresses, which are used for calculating jumps. *)` ` Definition indices (n : nat) := VectorDef.t (fin n) n.` ``` ``` ` (* Compute the destination jump index, an integer. *)` ` Definition jump_t {n} (pc : fin n) (off : t) : t :=` ` M.add (nat_to_t (proj1_sig (to_nat pc))) off.` ``` ``` ``` (* Compute a destination index that's valid. ``` ` Not all inputs are valid, so this may fail. *)` ` Definition valid_jump_t {n} (pc : fin n) (off : t) : option (fin (S n)) := @clamp (S n) (jump_t pc off).` ``` ``` ` Definition weaken_one {n} (f : fin n) : fin (S n).` ` Proof.` ` apply (@cast (n + 1)).` ` + apply L. apply f.` ` + rewrite <- plus_n_Sm. rewrite <- plus_n_O. reflexivity.` ` Defined.` ``` ``` ` Inductive step_noswap {n} : input n -> state n -> state n -> Prop :=` ` | step_noswap_acc : forall inp pc' v acc t,` ` nth inp pc' = (add, t) ->` ` ~ set_mem Fin.eq_dec pc' v = true ->` ` step_noswap inp (weaken_one pc', v, acc) (FS pc', set_add Fin.eq_dec pc' v, M.add acc t)` ` | step_noswap_nop : forall inp pc' v acc t,` ` nth inp pc' = (nop, t) ->` ` ~ set_mem Fin.eq_dec pc' v = true ->` ` step_noswap inp (weaken_one pc', v, acc) (FS pc', set_add Fin.eq_dec pc' v, acc)` ` | step_noswap_jmp : forall inp pc' pc'' v acc t,` ` nth inp pc' = (jmp, t) ->` ` ~ set_mem Fin.eq_dec pc' v = true ->` ` valid_jump_t pc' t = Some pc'' ->` ` step_noswap inp (weaken_one pc', v, acc) (pc'', set_add Fin.eq_dec pc' v, acc).` ``` ``` ` Fixpoint nat_to_fin (n : nat) : fin (S n) :=` ` match n with` ` | O => F1` ` | S n' => FS (nat_to_fin n')` ` end.` ``` ``` ` Inductive run_noswap {n} : input n -> state n -> state n -> Prop :=` ` | run_noswap_ok : forall inp v acc,` ` run_noswap inp (nat_to_fin n, v, acc) (nat_to_fin n, v, acc)` ` | run_noswap_fail : forall inp pc' v acc,` ` set_mem Fin.eq_dec pc' v = true ->` ` run_noswap inp (weaken_one pc', v, acc) (weaken_one pc', v, acc)` ` | run_noswap_trans : forall inp st st' st'',` ` step_noswap inp st st' -> run_noswap inp st' st'' -> run_noswap inp st st''.` ``` ``` ` Inductive valid_inst {n} : inst -> fin n -> Prop :=` ` | valid_inst_add : forall t f, valid_inst (add, t) f` ` | valid_inst_nop : forall t f f',` ` valid_jump_t f t = Some f' -> valid_inst (nop, t) f` ` | valid_inst_jmp : forall t f f',` ` valid_jump_t f t = Some f' -> valid_inst (jmp, t) f.` ``` ``` ` (* An input is valid if all its instructions are valid. *)` ` Definition valid_input {n} (inp : input n) : Prop := forall (pc : fin n),` ` valid_inst (nth inp pc) pc.` ``` ``` ` Theorem valid_input_terminates : forall n (inp : input n) st,` ` valid_input inp -> exists st', run_noswap inp st st'.` ` Proof.` ` (* Stoppped here. *)` ` Admitted.` `End DayEight.`