Functional programming in Dafny Exercise: Making Change Will Sonnex and Sophia Drossopoulou These exercises are also about specification and verification of functional programming. They are a bit more demanding than those on lists. In particular, we now look at proofs involving universal and existential quantifiers. Definitions are in the provided file “Change.dfy”. The subject of this exercise is making change from a given list of units for a given amount. Correct change for a given amount is defined as: predicate correct_change( units: list<int>, amount: nat, change: list<int>) { All_nat(units) && subset(change, units) && sum(change) == amount } For example, the following assertions hold: correct_change( [3,4,8], 16, [4,4,8]) and correct_change( [3,4,8], 16, [3,3,3,3,4]) But the following assertions do not hold correct_change( [3,4,8], 16, [3,3,3,3,3]) and correct_change( [3,4,8], 16, [5,5,3,3]). (We have used the notation [..,..,…] to indicate lists.) Question 0 Preliminaries Look at the definitions of subsequence and subset. Which of the following properties are true? Give a counter-example for those which are false. ∀𝑥𝑠: 𝑙𝑖𝑠𝑡〈𝑇〉, 𝑥𝑠: 𝑙𝑖𝑠𝑡〈𝑇〉, 𝑦𝑠: 𝑙𝑖𝑠𝑡〈𝑇〉, 𝑧𝑠: 𝑙𝑖𝑠𝑡〈𝑇〉. a. b. c. d. 𝑠𝑢𝑏𝑠𝑒𝑞𝑢𝑒𝑛𝑐𝑒(𝑥𝑠, 𝑦𝑠) ⟹ 𝑠𝑢𝑏𝑠𝑒𝑡(𝑥𝑠, 𝑦𝑠). 𝑠𝑢𝑏𝑠𝑒𝑡(𝑥𝑠, 𝑦𝑠) ⟹ 𝑠𝑢𝑏𝑠𝑒𝑞𝑢𝑒𝑛𝑐𝑒(𝑥𝑠, 𝑦𝑠) 𝑠𝑢𝑏𝑠𝑒𝑞𝑢𝑒𝑛𝑐𝑒(𝑥𝑠, 𝑦𝑠) ∧ 𝑠𝑢𝑏𝑠𝑒𝑞𝑢𝑒𝑛𝑐𝑒(𝑦𝑠, 𝑧𝑠) ⟹ 𝑠𝑢𝑏𝑠𝑒𝑞𝑢𝑒𝑛𝑐𝑒(𝑥𝑠, 𝑧𝑠) 𝑠𝑢𝑏𝑠𝑒𝑡(𝑥𝑠, 𝑦𝑠) ∧ 𝑠𝑢𝑏𝑠𝑒𝑡(𝑦𝑠, 𝑧𝑠) ⟹ 𝑠𝑢𝑏𝑠𝑒𝑡(𝑥𝑠, 𝑧𝑠) Question 1 Which of the following properties are true? Give a counter-example for those that are false. ∀𝑐: 𝑖𝑛𝑡, 𝑐𝑠: 𝑙𝑖𝑠𝑡〈𝑖𝑛𝑡〉, 𝑛: 𝑛𝑎𝑡, 𝑐ℎ𝑔: 𝑙𝑖𝑠𝑡〈𝑖𝑛𝑡〉. e. f. g. h. 𝑒𝑙𝑒𝑚(𝑐, 𝑐𝑠) ∧ 𝑐𝑜𝑟𝑟𝑒𝑐𝑡_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛, 𝑐ℎ𝑔) ⟹ 𝑒𝑙𝑒𝑚(𝑐, 𝑐ℎ𝑔) 𝑒𝑙𝑒𝑚(𝑐, 𝑐ℎ𝑔) ∧ 𝑐𝑜𝑟𝑟𝑒𝑐𝑡_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛, 𝑐ℎ𝑔) ⟹ 𝑒𝑙𝑒𝑚(𝑐, 𝑐𝑠) 𝑐𝑜𝑟𝑟𝑒𝑐𝑡_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛, 𝑐ℎ𝑔) ⟹ 𝑠𝑢𝑏𝑠𝑒𝑡(𝑐𝑠, 𝑐ℎ𝑔) 𝑠𝑢𝑏𝑠𝑒𝑡(𝑐𝑠, 𝑐𝑠 ′ ) ∧ 𝑐𝑜𝑟𝑟𝑒𝑐𝑡_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛, 𝑐ℎ𝑔) ⟹ 𝑐𝑜𝑟𝑟𝑒𝑐𝑡_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠 ′ , 𝑛, 𝑐ℎ𝑔) i. 𝑠𝑢𝑚(𝑐𝑠) ≤ 𝑠𝑢𝑚(𝑐ℎ𝑔) ∧ 𝑐𝑜𝑟𝑟𝑒𝑐𝑡_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛, 𝑐ℎ𝑔) ⟹ 𝑙𝑒𝑛(𝑐𝑠) ≤ 𝑙𝑒𝑛(𝑐ℎ𝑔) j. 𝑐𝑜𝑟𝑟𝑒𝑐𝑡_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛, 𝑟𝑒𝑝𝑒𝑎𝑡(1, 𝑛)) k. 𝑐𝑜𝑟𝑟𝑒𝑐𝑡_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛, 𝑐ℎ𝑔) ⟹ 𝑙𝑒𝑛(𝑐𝑠) > 0 Question 2 Within the provided “Change.dfy” we have defined a simple algorithm for making change from a given set of units. It does not always terminate, and so Dafny will not compile it. Alter its preconditions so that it does always terminate, such that Dafny can prove termination and hence compile the function. function make_change(units: list<int>, amount: nat): list<int> requires all_nat(units); Calculate the value of make_change( [2,3], 6) and the value of make_change( [2,3], 6). Question 3 Which of the following properties are true? Give a counter-example for those that are false. Any calls to 𝑚𝑎𝑘𝑒_𝑐ℎ𝑎𝑛𝑔𝑒 automatically enforce any pre-conditions you added in the previous question. Definitions of functions and predicates can be found in “Change.dfy”. ∀𝑐: 𝑖𝑛𝑡, 𝑐𝑠: 𝑙𝑖𝑠𝑡〈𝑖𝑛𝑡〉, 𝑛: 𝑛𝑎𝑡, 𝑐ℎ𝑔: 𝑙𝑖𝑠𝑡〈𝑖𝑛𝑡〉. 𝑒𝑙𝑒𝑚(𝑐, 𝑐𝑠) ∧ 𝑐 < 𝑛 ⟹ 𝑒𝑙𝑒𝑚(𝑐, 𝑚𝑎𝑘𝑒_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛)) 𝑒𝑙𝑒𝑚(𝑐, 𝑚𝑎𝑘𝑒_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛)) ⟹ 𝑒𝑙𝑒𝑚(𝑐, 𝑐𝑠) 𝑐ℎ𝑎𝑛𝑔𝑒_𝑒𝑥𝑖𝑠𝑡𝑠(𝑐𝑠, 𝑛) ⟹ 𝑐𝑜𝑟𝑟𝑒𝑐𝑡_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛, 𝑚𝑎𝑘𝑒_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛)) 𝑠𝑢𝑏𝑠𝑒𝑡(𝑐𝑠, 𝑐𝑠 ′ ) ⟹ 𝑠𝑢𝑏𝑠𝑒𝑡(𝑚𝑎𝑘𝑒_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛), 𝑚𝑎𝑘𝑒_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠 ′ , 𝑛)) 𝑒𝑙𝑒𝑚(𝑐, 𝑚𝑎𝑘𝑒_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛)) ⟹ 𝑐 < 𝑛 𝑠𝑢𝑏𝑠𝑒𝑞𝑢𝑒𝑛𝑐𝑒(𝑐𝑠, 𝑚𝑎𝑘𝑒_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛)) 𝑠𝑢𝑏𝑠𝑒𝑡(𝑐𝑠, 𝑐𝑠 ′ ) ∧ 𝑐𝑜𝑟𝑟𝑒𝑐𝑡_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛, 𝑚𝑎𝑘𝑒_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛)) ⟹ 𝑐𝑜𝑟𝑟𝑒𝑐𝑡_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠 ′ , 𝑛, 𝑚𝑎𝑘𝑒_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠 ′ , 𝑛)) h. 𝑠𝑢𝑏𝑠𝑒𝑡(𝑐𝑠, 𝑐𝑠 ′ ) ∧ 𝑐ℎ𝑎𝑛𝑔𝑒_𝑒𝑥𝑖𝑠𝑡𝑠(𝑐𝑠, 𝑛) ⟹ 𝑐ℎ𝑎𝑛𝑔𝑒_𝑒𝑥𝑖𝑠𝑡𝑠(𝑐𝑠 ′ , 𝑛) a. b. c. d. e. f. g. Question 4 a. Our simple algorithm “make_change” will not always produce correct change. Design a simple predicate good_units for the input list of units such that it does: predicate good_units(cs: list<int>) The following property should therefore be valid (you don’t need to prove this yet…): ∀𝑐𝑠, 𝑛. 𝑔𝑜𝑜𝑑_𝑛𝑖𝑡𝑠(𝑐𝑠)𝑢 ⟹ 𝑐𝑜𝑟𝑟𝑒𝑐𝑡_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛, 𝑚𝑎𝑘𝑒_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛)) It should be the case that the following holds: 𝑔𝑜𝑜𝑑_𝑢𝑛𝑖𝑡𝑠([20,1,5,10,2]). b. Check in Dafny that your good_units predicate ensures change exists for any amount: ∀𝑐𝑠, 𝑛. 𝑔𝑜𝑜𝑑_𝑢𝑛𝑖𝑡𝑠(𝑐𝑠) ⟹ 𝑐ℎ𝑎𝑛𝑔𝑒_𝑒𝑥𝑖𝑠𝑡𝑠(𝑐𝑠, 𝑛) ghost method prop_good_units_make_change(cs: list<int>, n: nat) requires good_units(cs); ensures change_exists(cs, n); 𝑐ℎ𝑎𝑛𝑔𝑒_𝑒𝑥𝑖𝑠𝑡𝑠(𝑐𝑠, 𝑛) is defined as ∃𝑐ℎ𝑔. 𝑐𝑜𝑟𝑟𝑒𝑐𝑡_𝑐ℎ𝑎𝑛𝑔𝑒(𝑐𝑠, 𝑛, 𝑐ℎ𝑔). To construct this existential provide any value for 𝑐ℎ𝑔 such that 𝑐𝑜𝑟𝑟𝑒𝑐𝑡_𝑐ℎ𝑔(𝑐𝑠, 𝑛, 𝑐ℎ𝑔) holds, viz. show the following for some 𝑐ℎ𝑔: assert correct_change(cs, n, chg); You will probably need to prove some auxiliary lemmas. Hint: We have defined some functions for you which we haven’t used yet. c. Informally explain in words why it is impossible to invent a 𝑚𝑎𝑔𝑖𝑐_𝑢𝑛𝑖𝑡𝑠 predicate satisfying the property in a., but which also satisfies: ∀𝑐𝑠, 𝑛. (𝑐ℎ𝑎𝑛𝑔𝑒_𝑒𝑥𝑖𝑠𝑡𝑠(𝑐𝑠, 𝑛) ⟹ 𝑚𝑎𝑔𝑖c_𝑢𝑛𝑖𝑡𝑠(𝑐𝑠)) d. (Hard) If your definition for good units is strong enough it will also satisfy: ∀𝑐𝑠. (∀𝑛. 𝑐ℎ𝑎𝑛𝑔𝑒_𝑒𝑥𝑖𝑠𝑡𝑠(𝑐𝑠, 𝑛)) ⟹ 𝑔𝑜𝑜𝑑_𝑢𝑛𝑖𝑡𝑠(𝑐𝑠) State this property in Dafny. The prove it. Question 5 Prove the correctness of make_change in Dafny, i.e. that the property from the previous question holds, by giving a body to prop_make_change. ghost method prop_make_change(cs: list<int>, n: nat) requires good_units(cs); ensures correct_change(cs, n, make_change(cs, n));