Why should the second invariant not hold on entry? - recursion

The idea is to reverse an array on site.
I have tried with several (recursive) definitions of reverse...getting different behaviors but not the right one...
method arr_reverse (a : array<int>)
modifies a
ensures a[..] == reverse (old(a[..]))
{var i : int, k : int ;
i, k := 0, a.Length ;
while k > i + 1
invariant 0 <= i <= k <= a.Length
invariant reverse (old(a[..])) == a[..i] + reverse (a[i..k]) + a[k..]
{
a[i], a[k-1] := a[k-1], a[i] ;
i, k := i+1, k-1 ;
}
}
function reverse (s : seq<int>) : seq<int>
decreases |s|
{if s == [] then s
else [s[|s|-1]] + reverse (s[..|s|-1])
}

To prove the invariant on entry, you need to give Dafny just one more hint:
assert a[i..k] == a[..];
I found it by trying to prove manually the invariant on entry, by adding several asserts until I found one that make the trick. I'm following the manual to debug verification when verification fails.
When I'm applying this methodology to the body of your while statement, I can write asserts from bottom to top and find this:
// 6) This was the original invariant. So, between 5 and 6, I just need to prove a result about reverse
assert reverse (old(a[..])) == a[..i] + reverse (a[i..k]) + a[k..];
// 5) It might not be easy for Dafny, but we should get to this assert after moving equality
assert reverse(old(a[..])) == a[..i] + ([a[k-1]] + reverse (a[i+1..k-1]) + [a[i]]) + a[k..];
// 4) Now I move the assert up again
assert reverse(old(a[..])) == (a[..i] + [a[k-1]]) + reverse (a[i+1..k-1]) + ([a[i]] + a[k..]);
a[i], a[k-1] := a[k-1], a[i] ;
// 3) I do a bit of guessing to make "a[i]" and "a[k-1]" to appear
assert reverse(old(a[..])) == (a[..i] + [a[i]]) + reverse (a[i+1..k-1]) + ([a[k-1]] + a[k..]);
// 2) I use verification debugging to "move the assert up"
assert reverse(old(a[..])) == a[..i+1] + reverse (a[i+1..k-1]) + a[k-1..];
i, k := i+1, k-1 ;
// 1) I write the invariant
assert reverse(old(a[..])) == a[..i] + reverse (a[i..k]) + a[k..];
So the only thing that remain (besides maybe other lemmas of associativity you might have to invoke), is to prove the non-trivial lemma that reverse (a[i..k]) == [a[k-1]] + reverse (a[i+1..k-1]) + [a[i]]

Related

Quick Select in O(1) using tail recursion

I was doing a ZTM course there he said that Quick Select algo at worst case can be O(1) Space complexity using tail recursion as it only makes one recursive calls.
His Code was
const quickSelect = function (nums, left, right, indexToFind) {
const partitionIndex = getPartition(nums, left, right);
if (partitionIndex === indexToFind) {
return nums[partitionIndex];
} else if (indexToFind < partitionIndex) {
return quickSelect(nums, left, partitionIndex - 1, indexToFind);
} else {
return quickSelect(nums, partitionIndex + 1, right, indexToFind);
}
};
And here is the optimized version of Quick Sort from GFG article it looks like quickSelect and one recursive call each time.
Code:
def quickSort(arr, low, high)
{
while (low < high):
''' pi is partitioning index, arr[p] is now
at right place '''
pi = partition(arr, low, high);
# If left part is smaller, then recur for left
# part and handle right part iteratively
if (pi - low < high - pi):
quickSort(arr, low, pi - 1);
low = pi + 1;
# Else recur for right part
else:
quickSort(arr, pi + 1, high);
high = pi - 1;
}
Why can't this be O(1) Space complexity then using Tail rec?
Iterative version of quick select using Lomuto partition scheme. I don't know if python optimization handles tail recursion.
def quickselect(a, k):
lo = 0
hi = len(a)-1
while (lo < hi):
p = a[hi]; # Lomuto partition
i = lo;
for j in range(lo, hi):
if (a[j] < p):
a[i],a[j] = a[j],a[i]
i += 1
a[i],a[hi] = a[hi],a[i]
if (k == i): # if pivot == kth element, return it
return a[k]
if (k < i): # loop on partition with kth element
hi = i - 1
else:
lo = i + 1
return a[k] # sorted to kth elemement, return it
Iterative version of quick select using Hoare partition scheme, it has to loop until lo == hi, since the pivot and values equal to pivot can end up anywhere after a partition step. However, it is faster than Lomuto partition scheme (at least with Python).
def quickselect(a, k):
lo = 0
hi = len(a)-1
while (lo < hi):
p = a[(lo + hi) // 2] # Hoare partition
i = lo - 1
j = hi + 1
while(1):
while(1):
i += 1
if(a[i] >= p):
break
while(1):
j -= 1
if(a[j] <= p):
break
if(i >= j):
break
a[i],a[j] = a[j],a[i]
if (k <= j): # loop on partition with kth element
hi = j
else:
lo = j + 1
return a[k] # sorted to kth elemement, return it

Dynamic programming to solve the fibwords problem

Problem Statement: The Fibonacci word sequence of bit strings is defined as:
F(0) = 0, F(1) = 1
F(n − 1) + F(n − 2) if n ≥ 2
For example : F(2) = F(1) + F(0) = 10, F(3) = F(2) + F(1) = 101, etc.
Given a bit pattern p and a number n, how often does p occur in F(n)?
Input:
The first line of each test case contains the integer n (0 ≤ n ≤ 100). The second line contains the bit
pattern p. The pattern p is nonempty and has a length of at most 100 000 characters.
Output:
For each test case, display its case number followed by the number of occurrences of the bit pattern p in
F(n). Occurrences may overlap. The number of occurrences will be less than 2^63.
Sample input: 6 10 Sample output: Case 1: 5
I implemented a divide and conquer algorithm to solve this problem, based on the hints that I found on the internet: We can think of the process of going from F(n-1) to F(n) as a string replacement rule: every '1' becomes '10' and '0' becomes '1'. Here is my code:
#include <string>
#include <iostream>
using namespace std;
#define LL long long int
LL count = 0;
string F[40];
void find(LL n, char ch1,char ch2 ){//Find occurences of eiher "11" / "01" / "10" in F[n]
LL n1 = F[n].length();
for (int i = 0;i+1 <n1;++i){
if (F[n].at(i)==ch1&&F[n].at(i+1)==ch2) ++ count;
}
}
void find(char ch, LL n){
LL n1 = F[n].length();
for (int i = 0;i<n1;++i){
if (F[n].at(i)==ch) ++count;
}
}
void solve(string p, LL n){//Recursion
// cout << p << endl;
LL n1 = p.length();
if (n<=1&&n1>=2) return;//return if string pattern p's size is larger than F(n)
//When p's size is reduced to 2 or 1, it's small enough now that we can search for p directly in F(n)
if (n1<=2){
if (n1 == 2){
if (p=="00") return;//Return since there can't be two subsequent '0' in F(n) for any n
else find(n,p.at(0),p.at(1));
return;
}
if (n1 == 1){
if (p=="1") find('1',n);
else find('0',n);
return;
}
}
string p1, p2;//if the last character in p is 1, we can replace it with either '1' or '0'
//p1 stores the substring ending in '1' and p2 stores the substring ending in '0'
for (LL i = 0;i<n1;++i){//We replace every "10" with 1, "1" with 0.
if (p[i]=='1'){
if (p[i+1]=='0'&&(i+1)!= n1){
if (p[i+2]=='0'&&(i+2)!= n1) return;//Return if there are two subsequent '0'
p1.append("1");//Replace "10" with "1"
++i;
}
else {
p1.append("0");//Replace "1" with "0"
}
}
else {
if (p[i+1]=='0'&&(i+1)!= n1){//Return if there are two subsequent '0'
return;
}
p1.append("1");
}
}
solve(p1,n-1);
if (p[n1-1]=='1'){
p2 = p1;
p2.back() = '1';
solve(p2,n-1);
}
}
main(){
F[0] = "0";F[1] = "1";
for (int i = 2;i<38;++i){
F[i].append(F[i-1]);
F[i].append(F[i-2]);
}//precalculate F(0) to F(37)
LL t = 0;//NumofTestcases
int n; string p;
while (cin >> n >> p) {
count = 0;
solve(p,n);
cout << "Case " << ++t << ": " << count << endl;
}
}
The above program works fine, but with small inputs only. When i submitted the above program to codeforces i got an answer wrong because although i shortened the pattern string p and reduces n to n', the size of F[n'] is still very large (n'>=50). How can i modify my code to make it works in this case, or is there another approach (such as dynamic programming?). Many thanks for any advice.
More details about the problem can be found here: https://codeforces.com/group/Ir5CI6f3FD/contest/273369/problem/B
I don't have time now to try to code this up myself, but I have a suggested approach.
First, I should note, that while that hint you used is certainly accurate, I don't see any straightforward way to solve the problem. Perhaps the correct follow-up to that would be simpler than what I'm suggesting.
My approach:
Find the first two ns such that length(F(n)) >= length(pattern). Calculating these is a simple recursion. The important insight is that every subsequent value will start with one of these two values, and will also end with one of them. (This is true for all adjacent values -- for any m > n, F(m) will begin either with F(n) or with F(n - 1). It's not hard to see why.)
Calculate and cache the number of occurrences of the pattern in this these two Fs, but whatever index shifting technique makes sense.
For F(n+1) (and all subsequent values) calculate by adding together
The count for F(n)
The count for F(n - 1)
The count for those spanning both F(n) and F(n - 1). We can achieve that by testing every breakdown of pattern into (nonempty) prefix and suffix values (i.e., splitting at every internal index) and counting those where F(n) ends in prefix and F(n - 1) starts with suffix. But we don't have to have all of F(n) and F(n - 1) to do this. We just need the tail of F(n) and the head of F(n - 1) of the length of the pattern. So we don't need to calculate all of F(n). We just need to know which of those two initial values our current one ends with. But the start is always the predecessor, and the end oscillates between the previous two. It should be easy to keep track.
The time complexity then should be proportional to the product of n and the length of the pattern.
If I find time tomorrow, I'll see if I can code this up. But it won't be in C -- those years were short and long gone.
Collecting the list of prefix/suffix pairs can be done once ahead of time

Prove recursion: Show that M(n) >= 1/2 (n + 1) lg(n + 1)

I want to show that the recursion of quicksort run on best time time on n log n.
i got this recursion formula
M(0) = 1
M(1) = 1
M(n) = min (0 <= k <= n-1) {M(K) + M(n - k - 1)} + n
show that M(n) >= 1/2 (n + 1) lg(n + 1)
what i have got so far:
By induction hyposes
M(n) <= min {M(k) + M(n - k - 1} + n
focusing on the inner expresison i got:
1/2(k + 1)lg(k + 1) + 1/2(n - k)lg(n - k)
1/2lg(k + 1)^(k + 1) + 1/2lg(n - k)^(n - k)
1/2(lg(k + 1)^(k + 1) + lg(n - k)^(n - k)
1/2(lg((k + 1)^(k + 1) . (n - k)^(n - k))
But i think im doing something wrong. i think the "k" should be gonne but i cant see how this equation would cancel out all the "k". So, probably, im doing something wrong
You indeed want to get rid of k. To do this, you want to find the lower bound on the minimum of M(k) + M(n - k - 1). In general it can be arbitrarily tricky, but in this case the standard approach works: take derivative by k.
((k+1) ln(k+1) + (n-k) ln(n-k))' =
ln(k+1) + (k+1)/(k+1) - ln(n-k) - (n-k)/(n-k) =
ln((k+1) / (n-k))
We want the derivative to be 0, so
ln((k+1) / (n-k)) = 0 <=>
(k+1) / (n-k) = 1 <=>
k + 1 = n - k <=>
k = (n-1) / 2
You can check that it's indeed a local minimum.
Therefore, the best lower bound on M(k) + M(n - k - 1) (which we can get from the inductive hypothesis) is reached for k=(n-1)/2. Now you can just substitute this value instead of k, and n will be your only remaining variable.

Check if a point lies on a line vector

To get another point (r) on the line that passes through point p in the direction v we can use the following formula, and substitute any value for a:
To test if r is on the line, we must only find a value for a that satisfies. In my current implementation, I check if a is the same for each component of the vectors by reorganizing the equation for r to:
In code terms, this looks like the following:
boolean isPointOnLine(Vector2f r, Vector2f p, Vector2f v) {
return (p.x - r.x) / v.x == (p.y - r.y) / v.y;
}
However, this method does not work: If any component of v is 0, the fraction will evaluate to infinity. Hence we get an incorrect result.
How do I check if r is on the line correctly?
In 3D you do the following:
If a point r=(x,y,z) is on the line with p=(px,py,pz) another point on the line and v=(vx,vy,vz) the direction calculate the following
CROSS(v,r-p)=0
or by component
(py-ry)*vz - (pz-rz)*vy==0
(pz-rz)*vx - (px-rx)*vz==0
(px-rx)*vy - (py-ry)*vx==0
For the 2D version, make all z-components zero
(px-rx)*vy - (py-ry)*vx == 0
No division needed, no edge cases and simple fast multiplication.
Of course due to round-off the result will be never be exactly zero. So what you need is a formula for the minimum distance, and a check if the distance is within some tolerance
d = ((px-rx)*vy-(py-ry)*vx)/sqrt(vx*vx+vy*vy) <= tol
It turns out that the equation I had was in fact correct, the division by 0 is just an edge case that must be handled beforehand. The final function looks like this:
boolean isPointOnLine(Vector2f r, Vector2f p, Vector2f v) {
if (v.x == 0) {
return r.x == p.x;
}
if (v.y == 0) {
return r.y == p.y;
}
return (p.x - r.x) / v.x == (p.y - r.y) / v.y;
}

Pascal Quicksort - counting the total number of recursions

I am stuck on my quicksort program. I need to count the total number of times the sorting function calls itself.
procedure quick (first, last, counter: integer);
var i, k, x : integer;
begin
i := first;
k := last;
x := a[(i+k) div 2];
counter := counter + 1;
while i<=k do begin
while a[i] < x do
i:= i+1;
while a[k] > x do
k:= k-1;
if i<=k then begin
prohod(i,k);
i:=i+1;
k:=k-1;
end;
end;
if first<k then quick(first,k, counter);
if i<last then quick(i,last, counter);
P:= P + counter;
end;
I tried this, where P is global variable and counter is recursive variable, first called as 1 ( quick(1, n, 1) ) . Sadly did not work. I also set P:= 0; right before I called the sorting (quick) procedure (I am not quite sure if it is correct way to approach the problem but it's all I could come up with).
Any ideas how to make this correctly and / or why my counter is not working?
This looks overly complex. If you just remove the counter, initialize P with the value -1 (instead of 0) and replace P := P + counter with P := P + 1, it should work.

Resources