Compare commits

..

No commits in common. "f53c65fb0d6710af758378f875d32035ad8ec718" and "c3a12cbf59b667282c7a1fbb2c24c8e6b1be4472" have entirely different histories.

2 changed files with 49 additions and 121 deletions

View File

@ -1,60 +0,0 @@
require "advent"
raw = input(2020, 14).lines
input = [] of {UInt64, UInt64, Array(Int32), UInt64, UInt64}
and_mask = (2_u64**63) + (2_u64**63-1)
or_mask = 0_u64
floats = [] of Int32
raw.each do |line|
if data = line.match(/^mask = (.+)$/)
new_mask = data[1]
and_mask = (2_u64**63) + (2_u64**63-1)
or_mask = 0_u64
floats = [] of Int32
new_mask.reverse.chars.each_with_index do |c, i|
floats << i if c == 'X'
or_mask = or_mask | (1_u64 << i) if c == '1'
and_mask = and_mask & ~(1_u64 << i) if c == '0'
end
elsif data = line.match(/^mem\[(\d+)\] = (\d+)$/)
input << {and_mask, or_mask, floats, data[1].to_u64, data[2].to_u64}
else
raise "Invalid line"
end
end
def part1(input)
memory = {} of UInt64 => UInt64
input.each do |i|
and_mask, or_mask, floats, addr, v = i
memory[addr] = (v & and_mask) | or_mask
end
memory.values.sum
end
def generate_possible(indices, index, n, &block : UInt64 -> _)
if index == indices.size
yield n
return
end
float_addr = indices[index]
no = n | (1_u64 << float_addr)
generate_possible(indices, index+1, no, &block)
nz = n & ~(1_u64 << float_addr)
generate_possible(indices, index+1, nz, &block)
end
def part2(input)
memory = {} of UInt64 => UInt64
input.each do |i|
_, or_mask, floats, addr, v = i
generate_possible(floats, 0, addr | or_mask) do |addr|
memory[addr] = v
end
end
memory.values.sum
end
puts part1(input)
puts part2(input)

110
day8.v
View File

@ -41,17 +41,13 @@ Module DayEight (Import M:Int).
Definition indices (n : nat) := VectorDef.t (fin n) n. Definition indices (n : nat) := VectorDef.t (fin n) n.
(* Change a jump to a nop, or a nop to a jump. *) (* Change a jump to a nop, or a nop to a jump. *)
Definition swap (i : inst) : inst := Definition replace (i : inst) : inst :=
match i with match i with
| (add, t) => (add, t) | (add, t) => (add, t)
| (nop, t) => (jmp, t) | (nop, t) => (jmp, t)
| (jmp, t) => (nop, t) | (jmp, t) => (nop, t)
end. end.
Inductive swappable : inst -> Prop :=
| swap_nop : forall t, swappable (nop, t)
| swap_jmp : forall t, swappable (jmp, t).
(* Compute the destination jump index, an integer. *) (* Compute the destination jump index, an integer. *)
Definition jump_t {n} (pc : fin n) (off : t) : t := Definition jump_t {n} (pc : fin n) (off : t) : t :=
M.add (nat_to_t (proj1_sig (to_nat pc))) off. M.add (nat_to_t (proj1_sig (to_nat pc))) off.
@ -100,14 +96,20 @@ Module DayEight (Import M:Int).
(* One modification: we really want to use 'allowed' addresses, (* One modification: we really want to use 'allowed' addresses,
a set that shrinks as the program continues, rather than 'visited' a set that shrinks as the program continues, rather than 'visited'
addresses, a set that increases as the program continues. *) addresses, a set that increases as the program continues. *)
Inductive step_noswap {n} : inst -> (fin n * t) -> (fin (S n) * t) -> Prop := Inductive step_noswap {n} : input n -> state n -> state n -> Prop :=
| step_noswap_add : forall pc acc t, | step_noswap_add : forall inp pc' v acc t,
step_noswap (add, t) (pc, acc) (FS pc, M.add acc t) nth inp pc' = (add, t) ->
| step_noswap_nop : forall pc acc t, set_In pc' v ->
step_noswap (nop, t) (pc, acc) (FS pc, acc) step_noswap inp (weaken_one pc', v, acc) (FS pc', set_remove Fin.eq_dec pc' v, M.add acc t)
| step_noswap_jmp : forall pc pc' acc t, | step_noswap_nop : forall inp pc' v acc t,
valid_jump_t pc t = Some pc' -> nth inp pc' = (nop, t) ->
step_noswap (jmp, t) (pc, acc) (pc', acc). set_In pc' v ->
step_noswap inp (weaken_one pc', v, acc) (FS pc', set_remove Fin.eq_dec pc' v, acc)
| step_noswap_jmp : forall inp pc' pc'' v acc t,
nth inp pc' = (jmp, t) ->
set_In pc' v ->
valid_jump_t pc' t = Some pc'' ->
step_noswap inp (weaken_one pc', v, acc) (pc'', set_remove Fin.eq_dec pc' v, acc).
Inductive done {n} : input n -> state n -> Prop := Inductive done {n} : input n -> state n -> Prop :=
| done_prog : forall inp v acc, done inp (nat_to_fin n, v, acc). | done_prog : forall inp v acc, done inp (nat_to_fin n, v, acc).
@ -119,35 +121,8 @@ Module DayEight (Import M:Int).
Inductive run_noswap {n} : input n -> state n -> state n -> Prop := Inductive run_noswap {n} : input n -> state n -> state n -> Prop :=
| run_noswap_ok : forall inp st, done inp st -> run_noswap inp st st | run_noswap_ok : forall inp st, done inp st -> run_noswap inp st st
| run_noswap_fail : forall inp st, stuck inp st -> run_noswap inp st st | run_noswap_fail : forall inp st, stuck inp st -> run_noswap inp st st
| run_noswap_trans : forall inp pc pc' v acc acc' st', | run_noswap_trans : forall inp st st' st'',
set_In pc v -> step_noswap inp st st' -> run_noswap inp st' st'' -> run_noswap inp st st''.
step_noswap (nth inp pc) (pc, acc) (pc', acc') ->
run_noswap inp (pc', set_remove Fin.eq_dec pc v, acc') st' ->
run_noswap inp (weaken_one pc, v, acc) st'.
Inductive run_swap {n} : input n -> state n -> state n -> Prop :=
| run_swap_normal : forall inp pc pc' v acc acc' st',
set_In pc v ->
~ swappable (nth inp pc) ->
step_noswap (nth inp pc) (pc, acc) (pc', acc') ->
run_swap inp (pc', set_remove Fin.eq_dec pc v, acc') st' ->
run_swap inp (weaken_one pc, v, acc) st'
| run_swap_swapped_ok : forall inp pc pc' v acc acc' st',
set_In pc v ->
swappable (nth inp pc) ->
step_noswap (swap (nth inp pc)) (pc, acc) (pc', acc') ->
run_noswap inp (pc', set_remove Fin.eq_dec pc v, acc') st' ->
done inp st' ->
run_swap inp (weaken_one pc, v, acc) st'
| run_swap_swapped_next : forall inp pc pc'w pc'n v acc acc'w acc'n st'w st'n,
set_In pc v ->
swappable (nth inp pc) ->
step_noswap (swap (nth inp pc)) (pc, acc) (pc'w, acc'w) ->
run_noswap inp (pc'w, set_remove Fin.eq_dec pc v, acc'w) st'w ->
stuck inp st'w ->
step_noswap (nth inp pc) (pc, acc) (pc'n, acc'n) ->
run_swap inp (pc'n, set_remove Fin.eq_dec pc v, acc'n) st'n ->
run_swap inp (weaken_one pc, v, acc) st'n.
Inductive valid_inst {n} : inst -> fin n -> Prop := Inductive valid_inst {n} : inst -> fin n -> Prop :=
| valid_inst_add : forall t f, valid_inst (add, t) f | valid_inst_add : forall t f, valid_inst (add, t) f
@ -165,16 +140,19 @@ Module DayEight (Import M:Int).
Variable inp : input n. Variable inp : input n.
Hypothesis Hv : valid_input inp. Hypothesis Hv : valid_input inp.
Theorem valid_input_can_step : forall pc acc, exists pc' acc', (* If the current address, which is not the end of the array, is
step_noswap (nth inp pc) (pc, acc) (pc', acc'). present in the "allowed" set, the program can continue. *)
Lemma step_if_possible : forall pcs v acc,
set_In pcs v ->
exists pc' acc', step_noswap inp (weaken_one pcs, v, acc) (pc', set_remove Fin.eq_dec pcs v, acc').
Proof. Proof.
intros pc acc. intros pcs v acc Hin.
destruct (nth inp pc) eqn:Hop. remember (nth inp pcs) as instr. destruct instr as [op t]. destruct op.
destruct o. + exists (FS pcs). exists (M.add acc t). apply step_noswap_add; auto.
- exists (FS pc). exists (M.add acc t0). apply step_noswap_add. + exists (FS pcs). exists acc. apply step_noswap_nop with t; auto.
- exists (FS pc). exists acc. eapply step_noswap_nop. + unfold valid_input in Hv. specialize (Hv pcs).
- specialize (Hv pc). rewrite Hop in Hv. inversion Hv; subst. rewrite <- Heqinstr in Hv. inversion Hv; subst.
exists f'. exists acc. eapply step_noswap_jmp. apply H0. exists f'. exists acc. apply step_noswap_jmp with t; auto.
Qed. Qed.
(* A program is either done, stuck (at an invalid/visited address), or can step. *) (* A program is either done, stuck (at an invalid/visited address), or can step. *)
@ -183,7 +161,7 @@ Module DayEight (Import M:Int).
(exists pcs, pc = weaken_one pcs /\ (exists pcs, pc = weaken_one pcs /\
((~ set_In pcs v /\ stuck inp (pc, v, acc)) \/ ((~ set_In pcs v /\ stuck inp (pc, v, acc)) \/
(exists pc' acc', set_In pcs v /\ (exists pc' acc', set_In pcs v /\
step_noswap (nth inp pcs) (pcs, acc) (pc', acc')))). step_noswap inp (pc, v, acc) (pc', set_remove Fin.eq_dec pcs v, acc')))).
Proof. Proof.
intros pc v acc. intros pc v acc.
(* Have we reached the end? *) (* Have we reached the end? *)
@ -196,8 +174,8 @@ Module DayEight (Import M:Int).
destruct (set_In_dec Fin.eq_dec pcs v). destruct (set_In_dec Fin.eq_dec pcs v).
- (* It is. *) - (* It is. *)
right. right.
destruct (valid_input_can_step pcs acc) as [pc' [acc' Hstep]]. destruct (step_if_possible pcs v acc) as [pc' [acc' Hstep]]; auto.
exists pc'; exists acc'; auto. exists pc'. exists acc'. split; auto.
- (* It is not. *) - (* It is not. *)
left. split; auto. apply stuck_prog; auto. left. split; auto. apply stuck_prog; auto.
Qed. Qed.
@ -208,19 +186,30 @@ Module DayEight (Import M:Int).
{ measure (length v) }: { measure (length v) }:
(exists pc', run_noswap inp (pc, v, acc) pc') := (exists pc', run_noswap inp (pc, v, acc) pc') :=
match valid_input_progress pc v acc with match valid_input_progress pc v acc with
| or_introl (conj Heq Hdone) => _ | or_introl (conj Heq Hdone) =>
inhabited_sig_to_exists
(inhabits
(@exist (state n)
(fun x => run_noswap inp (pc, v, acc) x) (pc, v, acc) (run_noswap_ok _ _ Hdone)))
| or_intror (ex_intro _ pcs (conj Hw w)) => | or_intror (ex_intro _ pcs (conj Hw w)) =>
match w with match w with
| or_introl (conj Hnin Hstuck) => _ | or_introl (conj Hnin Hstuck) =>
inhabited_sig_to_exists
(inhabits
(@exist (state n)
(fun x => run_noswap inp (pc, v, acc) x) (pc, v, acc) (run_noswap_fail _ _ Hstuck)))
| or_intror (ex_intro _ pc' (ex_intro _ acc' (conj Hin Hst))) => | or_intror (ex_intro _ pc' (ex_intro _ acc' (conj Hin Hst))) =>
match valid_input_terminates pc' (set_remove Fin.eq_dec pcs v) acc' (set_remove_nodup Fin.eq_dec pcs Hnd) with match valid_input_terminates pc' (set_remove Fin.eq_dec pcs v) acc' (set_remove_nodup Fin.eq_dec pcs Hnd) with
| ex_intro _ pc'' Hrun => _ | ex_intro _ pc'' Hrun =>
inhabited_sig_to_exists
(inhabits
(@exist (state n)
(fun x => run_noswap inp (pc, v, acc) x) pc''
(run_noswap_trans _ _ (pc', set_remove Fin.eq_dec pcs v, acc') _ Hst Hrun)))
end end
end end
end. end.
Obligation 1. eexists. apply run_noswap_ok. assumption. Qed. Obligation 1.
Obligation 2. eexists. apply run_noswap_fail. assumption. Qed.
Obligation 3.
clear Heq_anonymous. clear valid_input_terminates. clear Hst. clear Heq_anonymous. clear valid_input_terminates. clear Hst.
induction v. induction v.
- inversion Hin. - inversion Hin.
@ -231,6 +220,5 @@ Module DayEight (Import M:Int).
specialize (IHv H2 H). specialize (IHv H2 H).
simpl. rewrite Heq_dec. simpl. lia. simpl. rewrite Heq_dec. simpl. lia.
Qed. Qed.
Obligation 4. eexists. eapply run_noswap_trans; auto. apply Hst. apply Hrun. Qed.
End ValidInput. End ValidInput.
End DayEight. End DayEight.