diff --git a/049-modp.dfy b/049-modp.dfy new file mode 100644 index 0000000..0613916 --- /dev/null +++ b/049-modp.dfy @@ -0,0 +1,22 @@ +function modp_rec(n: int, p: int): int + requires p > 0 + requires n >= 0 +{ + if n == 0 then 1 % p else (modp_rec(n - 1, p) * 2) % p +} + +method modp(n: int, p: int) returns (r: int) + requires p > 0 + requires n >= 0 + ensures r == modp_rec(n, p) +{ + r := 1 % p; + var i := 0; + while i < n + invariant 0 <= i <= n + invariant r == modp_rec(i, p) + { + r := (r * 2) % p; + i := i + 1; + } +} \ No newline at end of file diff --git a/073-smallest_change.dfy b/073-smallest_change.dfy new file mode 100644 index 0000000..c033bc9 --- /dev/null +++ b/073-smallest_change.dfy @@ -0,0 +1,19 @@ +method smallest_change(s: seq) returns (c: int) + ensures c == |set i {:trigger s[i]} | 0 <= i < |s| / 2 && s[i] != s[|s| - 1 - i]| +{ + ghost var pos := {}; + c := 0; + + var i := 0; + while i < |s| / 2 + invariant 0 <= i <= |s| / 2 + invariant pos == set j {:trigger s[j]} | 0 <= j < i && s[j] != s[|s| - 1 - j] + invariant c == |pos| + { + if s[i] != s[|s| - 1 - i] { + pos := pos + {i}; + c := c + 1; + } + i := i + 1; + } +} \ No newline at end of file diff --git a/081-numerical_letter_grade.dfy b/081-numerical_letter_grade.dfy new file mode 100644 index 0000000..f9e893c --- /dev/null +++ b/081-numerical_letter_grade.dfy @@ -0,0 +1,67 @@ +method numerical_letter_grade(grades: seq) returns (letters: seq) + requires forall i :: 0 <= i < |grades| ==> 0.0 <= grades[i] <= 4.0 + ensures |letters| == |grades| + ensures forall i :: 0 <= i < |grades| && grades[i] == 4.0 ==> letters[i] == "A+" + ensures forall i :: 0 <= i < |grades| && grades[i] < 4.0 && grades[i] > 3.7 ==> letters[i] == "A" + ensures forall i :: 0 <= i < |grades| && grades[i] <= 3.7 && grades[i] > 3.3 ==> letters[i] == "A-" + ensures forall i :: 0 <= i < |grades| && grades[i] <= 3.3 && grades[i] > 3.0 ==> letters[i] == "B+" + ensures forall i :: 0 <= i < |grades| && grades[i] <= 3.0 && grades[i] > 2.7 ==> letters[i] == "B" + ensures forall i :: 0 <= i < |grades| && grades[i] <= 2.7 && grades[i] > 2.3 ==> letters[i] == "B-" + ensures forall i :: 0 <= i < |grades| && grades[i] <= 2.3 && grades[i] > 2.0 ==> letters[i] == "C+" + ensures forall i :: 0 <= i < |grades| && grades[i] <= 2.0 && grades[i] > 1.7 ==> letters[i] == "C" + ensures forall i :: 0 <= i < |grades| && grades[i] <= 1.7 && grades[i] > 1.3 ==> letters[i] == "C-" + ensures forall i :: 0 <= i < |grades| && grades[i] <= 1.3 && grades[i] > 1.0 ==> letters[i] == "D+" + ensures forall i :: 0 <= i < |grades| && grades[i] <= 1.0 && grades[i] > 0.7 ==> letters[i] == "D" + ensures forall i :: 0 <= i < |grades| && grades[i] <= 0.7 && grades[i] > 0.0 ==> letters[i] == "D-" + ensures forall i :: 0 <= i < |grades| && grades[i] == 0.0 ==> letters[i] == "E" +{ + letters := []; + var i := 0; + while i < |grades| + invariant 0 <= i <= |grades| + invariant |letters| == i + invariant forall j :: 0 <= j < i && grades[j] == 4.0 ==> letters[j] == "A+" + invariant forall j :: 0 <= j < i && grades[j] < 4.0 && grades[j] > 3.7 ==> letters[j] == "A" + invariant forall j :: 0 <= j < i && grades[j] <= 3.7 && grades[j] > 3.3 ==> letters[j] == "A-" + invariant forall j :: 0 <= j < i && grades[j] <= 3.3 && grades[j] > 3.0 ==> letters[j] == "B+" + invariant forall j :: 0 <= j < i && grades[j] <= 3.0 && grades[j] > 2.7 ==> letters[j] == "B" + invariant forall j :: 0 <= j < i && grades[j] <= 2.7 && grades[j] > 2.3 ==> letters[j] == "B-" + invariant forall j :: 0 <= j < i && grades[j] <= 2.3 && grades[j] > 2.0 ==> letters[j] == "C+" + invariant forall j :: 0 <= j < i && grades[j] <= 2.0 && grades[j] > 1.7 ==> letters[j] == "C" + invariant forall j :: 0 <= j < i && grades[j] <= 1.7 && grades[j] > 1.3 ==> letters[j] == "C-" + invariant forall j :: 0 <= j < i && grades[j] <= 1.3 && grades[j] > 1.0 ==> letters[j] == "D+" + invariant forall j :: 0 <= j < i && grades[j] <= 1.0 && grades[j] > 0.7 ==> letters[j] == "D" + invariant forall j :: 0 <= j < i && grades[j] <= 0.7 && grades[j] > 0.0 ==> letters[j] == "D-" + invariant forall j :: 0 <= j < i && grades[j] == 0.0 ==> letters[j] == "E" + { + if grades[i] == 4.0 { + letters := letters + ["A+"]; + } else if grades[i] > 3.7 { + letters := letters + ["A"]; + } else if grades[i] > 3.3 { + letters := letters + ["A-"]; + } else if grades[i] > 3.0 { + letters := letters + ["B+"]; + } else if grades[i] > 2.7 { + letters := letters + ["B"]; + } else if grades[i] > 2.3 { + letters := letters + ["B-"]; + } else if grades[i] > 2.0 { + letters := letters + ["C+"]; + } else if grades[i] > 1.7 { + letters := letters + ["C"]; + } else if grades[i] > 1.3 { + letters := letters + ["C-"]; + } else if grades[i] > 1.0 { + letters := letters + ["D+"]; + } else if grades[i] > 0.7 { + letters := letters + ["D"]; + } else if grades[i] > 0.0 { + letters := letters + ["D-"]; + } else { + letters := letters + ["E"]; + } + + i := i + 1; + } +} diff --git a/089-encrypt.dfy b/089-encrypt.dfy new file mode 100644 index 0000000..ed54b85 --- /dev/null +++ b/089-encrypt.dfy @@ -0,0 +1,30 @@ +function rot_sym(c: char): char + requires 'a' <= c <= 'z' + ensures 'a' <= rot_sym(c) <= 'z' +{ + var alph := c as int - 'a' as int; + ((alph + 2 * 2) % 26 + 'a' as int) as char +} + +method encrypt(s: string) returns (r: string) + requires forall i :: 0 <= i < |s| ==> 'a' <= s[i] <= 'z' + ensures |r| == |s| + ensures forall i :: 0 <= i < |s| ==> r[i] == rot_sym(s[i]) +{ + r := ""; + var i := 0; + while i < |s| + invariant 0 <= i <= |s| + invariant |r| == i + invariant forall j :: 0 <= j < i ==> r[j] == rot_sym(s[j]) + { + r := r + [rot_sym(s[i])]; + i := i + 1; + } +} + +method Main() { + var s := "asdfghjkl"; + var r := encrypt(s); + assert r == "ewhjklnop"; +} \ No newline at end of file diff --git a/108-count_nums.dfy b/108-count_nums.dfy new file mode 100644 index 0000000..7eec499 --- /dev/null +++ b/108-count_nums.dfy @@ -0,0 +1,32 @@ +method count_nums(s: seq) returns (cnt: nat) + ensures cnt == |set i | 0 <= i < |s| && digits_sum(s[i]) > 0| +{ + ghost var found := {}; + + cnt := 0; + var i := 0; + while i < |s| + invariant 0 <= i <= |s| + invariant found == set j | 0 <= j < i && digits_sum(s[j]) > 0 + invariant cnt == |found| + { + if digits_sum(s[i]) > 0 { + found := found + {i}; + cnt := cnt + 1; + } + i := i + 1; + } +} + +function digits_sum(x: int): int + decreases abs(x) +{ + if abs(x) < 10 then x else x % 10 + digits_sum(x / 10) +} + +function abs(x: int): int + ensures abs(x) >= 0 + ensures abs(x) == x || abs(x) == -x +{ + if x >= 0 then x else -x +} \ No newline at end of file diff --git a/114-minSubArraySum.dfy b/114-minSubArraySum.dfy new file mode 100644 index 0000000..93f3826 --- /dev/null +++ b/114-minSubArraySum.dfy @@ -0,0 +1,28 @@ +function Sum(a: seq, s: int, t: int): int + requires 0 <= s <= t <= |a| +{ + if s == t then 0 else Sum(a, s, t-1) + a[t-1] +} + +method minSubArraySum(a: seq) returns (s: int) + ensures forall p,q :: 0 <= p <= q <= |a| ==> Sum(a, p, q) >= s + ensures exists k, m :: 0 <= k <= m <= |a| && s == Sum(a, k, m) +{ + var k, m := 0, 0; + s := 0; + var n := 0; + var c, t := 0, 0; + while n < |a| + invariant 0 <= c <= n <= |a| && t == Sum(a, c, n) + invariant forall b :: 0 <= b <= n ==> Sum(a, b, n) >= Sum(a, c, n) + invariant 0 <= k <= m <= n && s == Sum(a, k, m) + invariant forall p,q :: 0 <= p <= q <= n ==> Sum(a, p, q) >= Sum(a, k, m) + { + t, n := t + a[n], n + 1; + if t > 0 { + c, t := n, 0; + } else if s > t { + k, m, s := c, n, t; + } + } +} diff --git a/128-prod_signs.dfy b/128-prod_signs.dfy new file mode 100644 index 0000000..68e44f8 --- /dev/null +++ b/128-prod_signs.dfy @@ -0,0 +1,71 @@ +function abs(x: int): int + ensures abs(x) >= 0 + ensures abs(x) == x || abs(x) == -x + ensures x >= 0 ==> abs(x) == x + ensures x < 0 ==> abs(x) == -x +{ + if x >= 0 then x else -x +} + +function sum_abs(s: seq) : int + ensures sum_abs(s) >= 0 +{ + if |s| == 0 then 0 else abs(s[0]) + sum_abs(s[1..]) +} + +lemma sum_prop(s: seq) + requires |s| > 0 + ensures sum_abs(s) == sum_abs(s[..|s| - 1]) + abs(s[|s| - 1]) +{ + if (|s| > 1) { + assert (s[1..][..|s[1..]| - 1]) == s[1..|s| - 1]; + } +} + +method prod_signs(numbers: seq) returns (s: int) + ensures abs(s) == sum_abs(numbers) + ensures |set i | 0 <= i < |numbers| && numbers[i] < 0| % 2 == 1 ==> s <= 0 + ensures |set i | 0 <= i < |numbers| && numbers[i] < 0| % 2 == 0 ==> s >= 0 +{ + s := 0; + var i := 0; + while (i < |numbers|) + invariant 0 <= i <= |numbers| + invariant s == sum_abs(numbers[..i]) + { + s := s + abs(numbers[i]); + assert sum_abs(numbers[..i + 1]) == sum_abs(numbers[..i]) + abs(numbers[i]) by { + assert numbers[..i+1][..i] == numbers[..i]; + sum_prop(numbers[..i + 1]); + } + i := i + 1; + } + + assert numbers == numbers[..|numbers|]; + + i := 0; + ghost var negatives := {}; + var cnt := 0; + while (i < |numbers|) + invariant 0 <= i <= |numbers| + invariant cnt == |negatives| + invariant negatives == set j | 0 <= j < i && numbers[j] < 0 + { + if (numbers[i] < 0) { + negatives := negatives + {i}; + cnt := cnt + 1; + } + i := i + 1; + } + assert negatives == set i | 0 <= i < |numbers| && numbers[i] < 0; + + if (cnt % 2 == 1) { + s := -s; + } +} + +method Main() { + var nums := [1, 2, 2, -4]; + var s := prod_signs(nums); + print s; +} \ No newline at end of file diff --git a/README.md b/README.md index f1c0526..5d28ac6 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Current status: - [x] 46. fib4 - [ ] 47. median - [x] 48. is_palindrome -- [ ] 49. modp +- [x] 49. modp - [ ] 50. encode_shift - [x] 51. remove_vowels - [x] 52. below_threshold @@ -75,7 +75,7 @@ Current status: - [x] 70. strange_sort_list - [ ] 71. ~triangle_area~ -- requires real square root - [x] 72. will_it_fly -- [ ] 73. smallest_change +- [x] 73. smallest_change - [x] 74. total_match - [x] 75. is_multiply_prime - [x] 76. is_simple_power @@ -83,7 +83,7 @@ Current status: - [x] 78. hex_key - [ ] 79. decimal_to_binary - [x] 80. is_happy -- [ ] 81. numerical_letter_grade +- [x] 81. numerical_letter_grade - [x] 82. prime_length - [x] 83. starts_one_ends - [ ] 84. solve @@ -91,7 +91,7 @@ Current status: - [ ] 86. anti_shuffle - complex strings - [ ] 87. get_row - sorting - [x] 88. sort_array - sorting -- [ ] 89. encrypt +- [x] 89. encrypt - [ ] 90. next_smallest - nullable - [ ] 91. is_bored - complex strings - [x] 92. any_int @@ -110,7 +110,7 @@ Current status: - [x] 105. by_length - sorting - [x] 106. f - [ ] 107. even_odd_palindrome -- [ ] 108. count_nums +- [x] 108. count_nums - [ ] 109. move_one_ball - [x] 110. exchange - [ ] 111. histogram @@ -130,7 +130,7 @@ Current status: - [ ] 125. split_words - complex strings - [x] 126. is_sorted - [x] 127. intersection -- [ ] 128. prod_signs +- [x] 128. prod_signs - [ ] 129. minPath - [x] 130. tri - [ ] 131. digits diff --git a/REMAINING.md b/REMAINING.md index 9a141ad..642b432 100644 --- a/REMAINING.md +++ b/REMAINING.md @@ -9,21 +9,16 @@ Current status: - [ ] 38. encode_cyclic - [ ] 44. change_base - [ ] 47. median -- [ ] 49. modp - [ ] 50. encode_shift - [ ] 56. correct_bracketing - [ ] 61. correct_bracketing - [ ] 65. circular_shift -- [ ] 73. smallest_change - [ ] 79. decimal_to_binary -- [ ] 81. numerical_letter_grade - [ ] 84. solve -- [ ] 89. encrypt - [ ] 90. next_smallest - nullable - [ ] 93. encode - [ ] 103. rounded_avg - [ ] 107. even_odd_palindrome -- [ ] 108. count_nums - [ ] 109. move_one_ball - [ ] 111. histogram - [ ] 112. reverse_delete @@ -32,7 +27,6 @@ Current status: - [ ] 119. match_parens - [ ] 121. solution - sum - [ ] 124. valid_date -- [ ] 128. prod_signs - [ ] 129. minPath - [ ] 131. digits - [ ] 132. is_nested