diff --git a/130-tri.dfy b/130-tri.dfy new file mode 100644 index 0000000..2b10914 --- /dev/null +++ b/130-tri.dfy @@ -0,0 +1,34 @@ +function tri(n: nat): nat + decreases if n % 2 == 0 then 0 else n +{ + if n == 1 then 3 + else if n % 2 == 0 then 1 + n / 2 + else tri(n - 1) + tri(n - 2) + tri(n + 1) +} + +method Tribonacci(n: nat) returns (result: seq) + ensures |result| == n + 1 + ensures forall i :: 0 <= i <= n ==> result[i] == tri(i) +{ + if n == 0 { + result := [1]; + } else { + result := [1, 3]; + var i := 2; + while i <= n + invariant 0 <= i <= n + 1 + invariant |result| == i + invariant forall j :: 0 <= j < i ==> result[j] == tri(j) + { + if i % 2 == 0 { + result := result + [1 + i / 2]; + } else { + assert result[i - 2] == tri(i - 2); + assert result[i - 1] == tri(i - 1); + assert (i + 3) / 2 == tri(i + 1); + result := result + [result[i - 2] + result[i - 1] + (i + 3) / 2]; + } + i := i + 1; + } + } +} diff --git a/139-special_factorial.dfy b/139-special_factorial.dfy new file mode 100644 index 0000000..67624c3 --- /dev/null +++ b/139-special_factorial.dfy @@ -0,0 +1,31 @@ +function factorial(n: nat): nat + decreases n +{ + if n == 0 then 1 else n * factorial(n - 1) +} + +function special_factorial_rec(n: nat): nat + decreases n +{ + if n == 0 then 1 else factorial(n) * special_factorial_rec(n - 1) +} + +method special_factorial(n: nat) returns (result: nat) + requires n > 0 + ensures result == special_factorial_rec(n) +{ + result := 1; + var fact := 1; + + var i := 0; + while i < n + invariant 0 <= i <= n + invariant result == special_factorial_rec(i) + invariant fact == factorial(i) + decreases n - i + 1 + { + i := i + 1; + fact := fact * i; + result := result * fact; + } +} \ No newline at end of file diff --git a/148-bf.dfy b/148-bf.dfy new file mode 100644 index 0000000..7cf6e25 --- /dev/null +++ b/148-bf.dfy @@ -0,0 +1,67 @@ +datatype Planet = Mercury | Venus | Earth | Mars | Jupiter | Saturn | Uranus | Neptune +datatype Option = Some(value: T) | None + +function PlanetFromString(name: string): Option + ensures PlanetFromString(name).Some? ==> 0 <= PlanetIndex(PlanetFromString(name).value) <= 7 +{ + match name + case "Mercury" => Some(Mercury) + case "Venus" => Some(Venus) + case "Earth" => Some(Earth) + case "Mars" => Some(Mars) + case "Jupiter" => Some(Jupiter) + case "Saturn" => Some(Saturn) + case "Uranus" => Some(Uranus) + case "Neptune" => Some(Neptune) + case _ => None +} + +function PlanetIndex(p: Planet): int +{ + match p + case Mercury => 0 + case Venus => 1 + case Earth => 2 + case Mars => 3 + case Jupiter => 4 + case Saturn => 5 + case Uranus => 6 + case Neptune => 7 +} + +function GetPlanetsBetween(planet1: string, planet2: string): seq + ensures |GetPlanetsBetween(planet1, planet2)| <= 6 +{ + var p1 := PlanetFromString(planet1); + var p2 := PlanetFromString(planet2); + if p1.None? || p2.None? then + [] + else + var i1 := PlanetIndex(p1.value); + var i2 := PlanetIndex(p2.value); + if i1 < i2 then + GetPlanetsBetweenIndices(i1 + 1, i2 - 1) + else if i1 > i2 then + GetPlanetsBetweenIndices(i2 + 1, i1 - 1) + else + [] +} + +function GetPlanetsBetweenIndices(start: int, end: int): seq + requires 0 <= start <= 7 && 0 <= end <= 7 + ensures |GetPlanetsBetweenIndices(start, end)| <= (if start <= end then end - start + 1 else 0) + decreases if start <= end then end - start + 1 else 0 +{ + if start > end then + [] + else + match start + case 0 => ["Mercury"] + GetPlanetsBetweenIndices(1, end) + case 1 => ["Venus"] + GetPlanetsBetweenIndices(2, end) + case 2 => ["Earth"] + GetPlanetsBetweenIndices(3, end) + case 3 => ["Mars"] + GetPlanetsBetweenIndices(4, end) + case 4 => ["Jupiter"] + GetPlanetsBetweenIndices(5, end) + case 5 => ["Saturn"] + GetPlanetsBetweenIndices(6, end) + case 6 => ["Uranus"] + GetPlanetsBetweenIndices(7, end) + case 7 => ["Neptune"] +} \ No newline at end of file diff --git a/150-x_or_y.dfy b/150-x_or_y.dfy new file mode 100644 index 0000000..26110f0 --- /dev/null +++ b/150-x_or_y.dfy @@ -0,0 +1,16 @@ +predicate IsPrime(n: nat) +{ + n > 1 && + forall k :: 2 <= k < n ==> n % k != 0 +} + +method x_or_y(n: nat, x: int, y: int) returns (result: int) + ensures IsPrime(n) ==> result == x + ensures !IsPrime(n) ==> result == y +{ + if IsPrime(n) { + return x; + } else { + return y; + } +} \ No newline at end of file diff --git a/152-compare.dfy b/152-compare.dfy index 91c5bf3..5611fe1 100644 --- a/152-compare.dfy +++ b/152-compare.dfy @@ -1,27 +1,22 @@ method Compare(scores: array, guesses: array) returns (result: array) requires scores.Length == guesses.Length ensures result.Length == scores.Length - ensures forall i :: 0 <= i < result.Length ==> - result[i] == if scores[i] == guesses[i] then 0 else abs(scores[i] - guesses[i]) + ensures forall i :: 0 <= i < result.Length ==> result[i] == abs(scores[i] - guesses[i]) { result := new int[scores.Length]; var i := 0; while i < scores.Length invariant 0 <= i <= scores.Length invariant result.Length == scores.Length - invariant forall k :: 0 <= k < i ==> - result[k] == if scores[k] == guesses[k] then 0 else abs(scores[k] - guesses[k]) + invariant forall k :: 0 <= k < i ==> result[k] == abs(scores[k] - guesses[k]) { - if scores[i] == guesses[i] { - result[i] := 0; - } else { - result[i] := abs(scores[i] - guesses[i]); - } + result[i] := abs(scores[i] - guesses[i]); i := i + 1; } } function abs(x: int): int + ensures 0 <= abs(x) { if x < 0 then -x else x -} \ No newline at end of file +} diff --git a/153-Strongest_Extension.dfy b/153-Strongest_Extension.dfy new file mode 100644 index 0000000..b499a59 --- /dev/null +++ b/153-Strongest_Extension.dfy @@ -0,0 +1,59 @@ +class Extension { + var name: string + var strength: int + + constructor(n: string) + ensures name == n + ensures strength == CalculateStrength(n) + { + name := n; + strength := CalculateStrength(n); + } + + static function CalculateStrength(s: string): int + { + CountUpperCase(s) - CountLowerCase(s) + } + + static function CountUpperCase(s: string): int + { + if |s| == 0 then 0 + else (if 'A' <= s[0] <= 'Z' then 1 else 0) + CountUpperCase(s[1..]) + } + + static function CountLowerCase(s: string): int + { + if |s| == 0 then 0 + else (if 'a' <= s[0] <= 'z' then 1 else 0) + CountLowerCase(s[1..]) + } +} + +method Strongest_Extension(className: string, extensions: seq) returns (result: string) + requires |extensions| > 0 + ensures |result| > |className| + ensures result[..|className|] == className + ensures result[|className|] == '.' + ensures var extName := result[|className| + 1..]; + extName in extensions + ensures var extName := result[|className| + 1..]; + forall i :: 0 <= i < |extensions| ==> Extension.CalculateStrength(extName) >= Extension.CalculateStrength(extensions[i]) +{ + var strongestExt := new Extension(extensions[0]); + ghost var strongestIndex := 0; + + for i := 1 to |extensions| + invariant 0 <= strongestIndex < |extensions| + invariant strongestExt.name == extensions[strongestIndex] + invariant strongestExt.strength == Extension.CalculateStrength(extensions[strongestIndex]) + invariant forall j :: 0 <= j < i ==> strongestExt.strength >= Extension.CalculateStrength(extensions[j]) + invariant forall j :: 0 <= j < i ==> Extension.CalculateStrength(extensions[strongestIndex]) >= Extension.CalculateStrength(extensions[j]) + { + var currentExt := new Extension(extensions[i]); + if currentExt.strength > strongestExt.strength { + strongestExt := currentExt; + strongestIndex := i; + } + } + + result := className + "." + strongestExt.name; +} diff --git a/154-cycpattern_check.dfy b/154-cycpattern_check.dfy new file mode 100644 index 0000000..5450c78 --- /dev/null +++ b/154-cycpattern_check.dfy @@ -0,0 +1,27 @@ +predicate IsSubstring(s: string, sub: string) +{ + |s| >= |sub| && exists i {:trigger s[i..i+|sub|]} :: 0 <= i <= |s| - |sub| && s[i..i+|sub|] == sub +} + +function RotateString(s: string, n: nat): string + requires 0 <= n <= |s| +{ + s[n..] + s[..n] +} + +method CycpatternCheck(word: string, pattern: string) returns (result: bool) + ensures result ==> exists i :: 0 <= i <= |pattern| && IsSubstring(word, RotateString(pattern, i)) + ensures !result ==> forall i :: 0 <= i <= |pattern| ==> !IsSubstring(word, RotateString(pattern, i)) +{ + var i := 0; + while i <= |pattern| + invariant 0 <= i <= |pattern| + 1 + invariant forall j :: 0 <= j < i ==> !IsSubstring(word, RotateString(pattern, j)) + { + if IsSubstring(word, RotateString(pattern, i)) { + return true; + } + i := i + 1; + } + return false; +} \ No newline at end of file diff --git a/README.md b/README.md index 609e391..4b0adf8 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ Current status: - [ ] 127. intersection - [ ] 128. prod_signs - [ ] 129. minPath -- [ ] 130. tri +- [x] 130. tri - [ ] 131. digits - [ ] 132. is_nested - [ ] 133. sum_squares @@ -141,7 +141,7 @@ Current status: - [ ] 136. largest_smallest_integers - [ ] 137. compare_one - [ ] 138. is_equal_to_sum_even -- [ ] 139. special_factorial +- [x] 139. special_factorial - [ ] 140. fix_spaces - [ ] 141. file_name_check - [ ] 142. sum_squares @@ -150,13 +150,13 @@ Current status: - [ ] 145. order_by_points - [ ] 146. specialFilter - [ ] 147. get_max_triples -- [ ] 148. bf +- [x] 148. bf - [ ] 149. sorted_list_sum -- [ ] 150. x_or_y +- [x] 150. x_or_y - [ ] 151. double_the_difference - [x] 152. compare -- [ ] 153. Strongest_Extension -- [ ] 154. cycpattern_check +- [x] 153. Strongest_Extension +- [x] 154. cycpattern_check - [ ] 155. even_odd_count - [ ] 156. int_to_mini_roman - [x] 157. right_angle_triangle diff --git a/flake.nix b/flake.nix index e51215c..7aa92ae 100644 --- a/flake.nix +++ b/flake.nix @@ -10,7 +10,7 @@ flake-parts.lib.mkFlake { inherit inputs; } { systems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin" ]; perSystem = { pkgs, ... }: { - packages = rec { + packages = { dafny-check = pkgs.writeShellScriptBin "dafny-check" '' DIR=''${1:-.} for f in "$DIR"/*.dfy