Skip to content

Commit

Permalink
Review files 000 and 001 (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
jesyspa authored Sep 30, 2024
1 parent f67ed37 commit ea4d330
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 63 deletions.
30 changes: 11 additions & 19 deletions 000-has_close_elements.dfy
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
method abs(val : int) returns (res : int)
ensures val < 0 ==> res == -val
ensures val >= 0 ==> res == val
function abs(val : real): real
{
if (val < 0) {
res := -val;
} else {
res := val;
}
}

function abs1(x : int, threshold : int): bool
{
x >= threshold || x <= -threshold
if (val < 0.0) then
-val
else
val
}

method has_close_elements(numbers: seq<int>, threshold: int) returns (flag : bool)
method has_close_elements(numbers: seq<real>, threshold: real) returns (flag : bool)
// pre-conditions-start
requires threshold > 0
requires threshold > 0.0
// pre-conditions-end
// post-conditions-start
ensures flag == (exists i: int, j: int :: i >= 0 && j >= 0 && i < |numbers| && j < |numbers| && i != j && !abs1(numbers[i] - numbers[j], threshold))
ensures flag == (exists i: int, j: int :: i >= 0 && j >= 0 && i < |numbers| && j < |numbers| && i != j && abs(numbers[i] - numbers[j]) < threshold)
// post-conditions-end
{
// impl-start
Expand All @@ -28,20 +20,20 @@ method has_close_elements(numbers: seq<int>, threshold: int) returns (flag : boo
while (i < |numbers|)
// invariants-start
invariant 0 <= i && i <= |numbers|
invariant flag == (exists i1: int, j1: int :: i1 >= 0 && j1 >= 0 && i1 < i && j1 < |numbers| && i1 != j1 && !abs1(numbers[i1] - numbers[j1], threshold))
invariant flag == (exists i1: int, j1: int :: i1 >= 0 && j1 >= 0 && i1 < i && j1 < |numbers| && i1 != j1 && abs(numbers[i1] - numbers[j1]) < threshold)
// invariants-end
{
var j: int := 0;
while (j < |numbers|)
// invariants-start
invariant 0 <= i && i < |numbers|
invariant 0 <= j && j <= |numbers|
invariant flag == (exists i1: int, j1: int :: i1 >= 0 && j1 >= 0 && ((i1 < i && j1 < |numbers|) || (i1 == i && j1 < j)) && i1 != j1 && !abs1(numbers[i1] - numbers[j1], threshold))
invariant flag == (exists i1: int, j1: int :: i1 >= 0 && j1 >= 0 && ((i1 < i && j1 < |numbers|) || (i1 == i && j1 < j)) && i1 != j1 && abs(numbers[i1] - numbers[j1]) < threshold)
// invariants-end
{
if (i != j)
{
var distance: int := abs(numbers[i] - numbers[j]);
var distance: real := abs(numbers[i] - numbers[j]);
if (distance < threshold)
{
flag := true;
Expand Down
149 changes: 105 additions & 44 deletions 001-separate-paren-groups.dfy
Original file line number Diff line number Diff line change
@@ -1,59 +1,104 @@
function IsValidParentheses(s: string, i: int, depth: int): bool
decreases |s| - i
requires 0 <= i && i <= |s|
function ParenthesesDepth(s: string, i: int, j: int): int
decreases j - i
requires 0 <= i <= j <= |s|
{
if i == |s| then
depth >= 0
else if depth < 0 then
false
if i == j then
0
else if s[i] == '(' then
IsValidParentheses(s, i + 1, depth + 1)
ParenthesesDepth(s, i+1, j) + 1
else if s[i] == ')' then
depth > 0 && IsValidParentheses(s, i + 1, depth - 1)
ParenthesesDepth(s, i+1, j) - 1
else
IsValidParentheses(s, i + 1, depth)
ParenthesesDepth(s, i+1, j)
}

function IsValidParentheses2(s: string, i: int, depth: int): bool
decreases |s| - i
requires 0 <= i && i <= |s|
predicate InnerDepthsPositive(s: string)
{
if i == |s| then
depth == 0
else if depth < 0 then
false
else if s[i] == '(' then
IsValidParentheses2(s, i + 1, depth + 1)
else if s[i] == ')' then
if depth > 0 then IsValidParentheses2(s, i + 1, depth - 1) else false
else
IsValidParentheses2(s, i + 1, depth)
forall i :: 0 < i < |s| ==> ParenthesesDepth(s, 0, i) > 0
}

function IsValidParentheses1(s: string, i: int, depth: int): bool
decreases |s| - i
requires 0 <= i && i <= |s|
predicate InnerDepthsNonnegative(s: string)
{
if i == |s| then
depth == 0
else if (depth <= 0 && i != 0) then
false
else if s[i] == '(' then
IsValidParentheses1(s, i + 1, depth + 1)
else if s[i] == ')' then
depth > 0 && IsValidParentheses1(s, i + 1, depth - 1)
else
IsValidParentheses1(s, i + 1, depth)
forall i :: 0 < i < |s| ==> ParenthesesDepth(s, 0, i) >= 0
}

lemma ParenthesesDepthSum(s: string, i: int, j: int, k: int)
decreases j - i
requires 0 <= i <= j <= k <= |s|
ensures ParenthesesDepth(s, i, k) == ParenthesesDepth(s, i, j) + ParenthesesDepth(s, j, k)
{
if i != j {
ParenthesesDepthSum(s, i+1, j, k);
}
}

lemma ParenthesesSuffixEq(s: string, i: int, j: int)
decreases j -i
requires 0 <= i <= j <= |s|
ensures ParenthesesDepth(s, i, j) == ParenthesesDepth(s[..j], i, j)
{
if i != j {
ParenthesesSuffixEq(s, i+1, j);
}
}

lemma ParenthesesPrefixEq(s: string, i: int, j: int)
decreases j -i
requires 0 <= i <= j <= |s|
ensures ParenthesesDepth(s, i, j) == ParenthesesDepth(s[i..], 0, j-i)
{ }

lemma ParenthesesSubstring(s: string, i: int, j: int)
decreases j - i
requires 0 <= i <= j <= |s|
ensures ParenthesesDepth(s, i, j) == ParenthesesDepth(s[i..j], 0, j-i)
{
assert ParenthesesDepth(s, i, j) == ParenthesesDepth(s[..j], i, j)
by { ParenthesesSuffixEq(s, i, j); }
assert ParenthesesDepth(s[..j], i, j) == ParenthesesDepth(s[i..j], 0, j-i)
by { ParenthesesPrefixEq(s[..j], i, j); }
}

lemma ParenthesesCommonSegment(s: string, t: string, i: int, j: int)
requires 0 <= i <= j <= |s|
requires 0 <= i <= j <= |t|
requires s[i..j] == t[i..j]
ensures ParenthesesDepth(s, i, j) == ParenthesesDepth(t, i, j)
{
ParenthesesSubstring(s, i, j);
ParenthesesSubstring(t, i, j);
}

lemma ParenthesesDepthAppend(s: string, c: char)
ensures ParenthesesDepth(s + [c], 0, |s|+1) == ParenthesesDepth(s, 0, |s|) + ParenthesesDepth([c], 0, 1)
{
ParenthesesSubstring(s + [c], 0, |s|);
ParenthesesSubstring(s + [c], |s|, |s| + 1);
ParenthesesDepthSum(s + [c], 0, |s|, |s| + 1);
}

lemma InnerDepthsPositiveAppendDecompose(s: string, c: char)
requires InnerDepthsPositive(s)
requires ParenthesesDepth(s, 0, |s|) > 0
ensures InnerDepthsPositive(s + [c])
{
forall i: int | 0 < i < |s| + 1
ensures ParenthesesDepth(s + [c], 0, i) > 0
{
if (i <= |s|) {
ParenthesesCommonSegment(s, s + [c], 0, i);
}
}
}

method separate_paren_groups(paren_string: string) returns (res : seq<string>)
// pre-conditions-start
requires forall i :: i >= 0 && i < |paren_string| ==> paren_string[i] == '(' || paren_string[i] == ')'
requires forall i :: 0 <= i <= |paren_string| ==> IsValidParentheses(paren_string, i, 0)
requires IsValidParentheses2(paren_string, 0, 0)
requires ParenthesesDepth(paren_string, 0, |paren_string|) == 0
requires InnerDepthsNonnegative(paren_string)
// pre-conditions-end
// post-conditions-start
ensures |res| > 0 ==> forall i :: 0 <= i < |res| ==> IsValidParentheses1(res[i], 0, 0)
ensures forall k :: 0 <= k < |res| ==> ParenthesesDepth(res[k], 0, |res[k]|) == 0
ensures forall k :: 0 <= k < |res| ==> InnerDepthsPositive(res[k])
// post-conditions-end
{
// impl-start
Expand All @@ -65,13 +110,29 @@ method separate_paren_groups(paren_string: string) returns (res : seq<string>)

while (i < |paren_string|)
// invariants-start
invariant 0 <= i && i <= |paren_string|
invariant 0 <= i && i < |paren_string| ==> paren_string[i] in {'(', ')'}
invariant |res| > 0 ==> (forall i1 :: 0 <= i1 < |res| ==> IsValidParentheses1(res[i1], 0, 0))
invariant IsValidParentheses(paren_string, i, 0)
invariant 0 <= i <= |paren_string|
invariant forall k :: 0 <= k < |res| ==> ParenthesesDepth(res[k], 0, |res[k]|) == 0
invariant forall k :: 0 <= k < |res| ==> InnerDepthsPositive(res[k])
invariant ParenthesesDepth(paren_string, 0, |paren_string|) == 0
invariant InnerDepthsNonnegative(paren_string)
invariant ParenthesesDepth(paren_string, i, |paren_string|) + current_depth == 0
invariant ParenthesesDepth(paren_string, 0, i) == current_depth
invariant ParenthesesDepth(current_string, 0, |current_string|) == current_depth
invariant InnerDepthsPositive(current_string)
invariant current_string == "" || current_depth > 0
invariant current_depth >= 0
// invariants-end
{
var c: char := paren_string[i];

// lemma-use-start
ParenthesesDepthAppend(current_string, c);
ParenthesesDepthSum(paren_string, 0, i, i+1);
if (current_string != "") {
InnerDepthsPositiveAppendDecompose(current_string, c);
}
// lemma-use-end

if (c == '(')
{
current_depth := current_depth + 1;
Expand Down

0 comments on commit ea4d330

Please sign in to comment.