

@ 26,7 +26,7 @@ let's write a helper function that, given a number `x`, tries to find another nu 



`y` such that `x + y = 2020`. In fact, rather than hardcoding the desired 



sum to `2020`, let's just use another argument called `total`. The code is quite simple: 







{{< codelines "Coq" "aoccoq/day1.v" 7 14 >}} 



{{< codelines "Coq" "aoc2020/day1.v" 11 18 >}} 







Here, `is` is the list of numbers that we want to search. 



We proceed by case analysis: if the list is empty, we can't 


@ 43,7 +43,7 @@ for our purposes when the argument being case analyzed is given first. 



We can now use `find_matching` to define our `find_sum` function, which solves part 1. 



Here's the code: 







{{< codelines "Coq" "aoccoq/day1.v" 16 24 >}} 



{{< codelines "Coq" "aoc2020/day1.v" 20 28 >}} 







For every `x` that we encounter in our input list `is`, we want to check if there's 



a matching number in the rest of the list. We only search the remainder of the list 


@ 72,13 +72,13 @@ formally as follows: 







And this is how we write it in Coq: 







{{< codelines "Coq" "aoccoq/day1.v" 26 27 >}} 



{{< codelines "Coq" "aoc2020/day1.v" 30 31 >}} 







The arrow, `>`, reads "implies". Other than that, I think this 



property reads pretty well. The proof, unfortunately, is a little bit more involved. 



Here are the first few lines: 







{{< codelines "Coq" "aoccoq/day1.v" 28 31 >}} 



{{< codelines "Coq" "aoc2020/day1.v" 32 35 >}} 







We start with the `intros is` tactic, which is akin to saying 



"consider a particular list of integers `is`". We do this without losing 


@ 157,7 +157,7 @@ is zero. This means we're done with the base case! 



The inductive case is the meat of this proof. Here's the corresponding part 



of the Coq source file: 







{{< codelines "Coq" "aoccoq/day1.v" 32 36 >}} 



{{< codelines "Coq" "aoc2020/day1.v" 36 40 >}} 







This time, the proof state is more complicated: 






@ 284,14 +284,14 @@ Coq proofs is to actually step through them in the IDE! 







First on the list is `find_matching_skip`. Here's the type: 







{{< codelines "Coq" "aoccoq/day1.v" 38 39 >}} 



{{< codelines "Coq" "aoc2020/day1.v" 42 43 >}} 







It reads: if we correctly find a number in a small list `is`, we can find that same number 



even if another number is prepended to `is`. That makes sense: _adding_ a number to 



a list doesn't remove whatever we found in it! I used this lemma to prove another, 



`find_matching_works`: 







{{< codelines "Coq" "aoccoq/day1.v" 49 50 >}} 



{{< codelines "Coq" "aoc2020/day1.v" 53 54 >}} 







This reads, if there _is_ an element `y` in `is` that adds up to `k` with `x`, then 



`find_matching` will find it. This is an important property. After all, if it didn't 


@ 310,7 +310,7 @@ that all lists from this Advent of Code puzzle are guaranteed to have two number 



add up to our goal, and that these numbers are not equal to each other. In Coq, 



we state this as follows: 







{{< codelines "Coq" "aoccoq/day1.v" 4 5 >}} 



{{< codelines "Coq" "aoc2020/day1.v" 8 9 >}} 







This defines a new property, `has_pair t is` (read "`is` has a pair of numbers that add to `t`"), 



which means: 


@ 323,7 +323,7 @@ which means: 



When making claims about the correctness of our algorithm, we will assume that this 



property holds. Finally, here's the theorem we want to prove: 







{{< codelines "Coq" "aoccoq/day1.v" 64 66 >}} 



{{< codelines "Coq" "aoc2020/day1.v" 68 70 >}} 







It reads, "for any total `k` and list `is`, if `is` has a pair of numbers that add to `k`, 



then `find_sum` will return a pair of numbers `x` and `y` that add to `k`". 


@ 335,7 +335,7 @@ we want to confirm that `find_sum` will find one of them. Finally, here is the p 



I will not be able to go through it in detail in this post, but I did comment it to 



make it easier to read: 







{{< codelines "Coq" "aoccoq/day1.v" 67 102 >}} 



{{< codelines "Coq" "aoc2020/day1.v" 71 106 >}} 







Coq seems happy with it, and so am I! The bug I mentioned earlier popped up on line 96. 



I had accidentally made `find_sum` return `None` if it couldn't find a complement 


