How to prove time complexity of bubble sort using dafny? - time-complexity

Is there a way in dafny to create an invariant specific to a single loop iteration? Below I'm trying to create a dafny program to upper bound the number of swaps of bubble sort. That value is stored in variable n. So I'd like to upper bound n by (a.Length * (a.Length - 1))/2. The reason being is that the maximum number of swaps that can occur is if the array is in the opposite order so then there must be n swaps on the first iteration of the inside loop and then n-1 swaps of the second iteration of the inside loop, etc. until the array is sorted. This is equivalent to 1+2+3+...+n-1+n = n(n-1)/2, which is precisely what I'm trying to show. I'm wondering if there's a method in dafny to upper bound the value of i-j or n in the code below based on the iteration of the inner loop. Is there such a way?
If not is there another method to upper bound this n value given the explanation provided above? Perhaps additional invariants I'm not thinking of?
method BubbleSort(a: array<int>) returns (n: nat)
modifies a
requires a != null
ensures n <= (a.Length * (a.Length - 1))/2
{
var i := a.Length - 1;
n := 0;
while (i > 0)
invariant 0 < a.Length ==> 0 <= i < a.Length;
decreases i;
{
var j := 0;
while (j < i)
invariant i - j <= old(i) - old(j);
invariant i < 0 && j < 0 ==> 0 <= n <= a.Length;
decreases i - j;
{
if(a[j] > a[j+1])
{
a[j], a[j+1] := a[j+1], a[j];
n := n + 1;
}
j := j + 1;
}
i := i -1;
}
}

I don't think you need to "create an invariant specific to a single loop iteration", but instead to rephrase your loop invariants in a way that they apply to all iterations.
Your English argument for why the complexity is bounded is a good one.
the maximum number of swaps that can occur is if [there are] n swaps on the first iteration of the inside loop and then n-1 swaps of the second iteration of the inside loop, etc. until the array is sorted. This is equivalent to 1+2+3+...+n-1+n = n(n-1)/2
All you need to do is to formalize this argument into Dafny. I suggest introducing a function for "the sum of all integers between a and b" and then using that function to phrase your loop invariants.

Related

Prove that the time complexity of a function is O(n^3)

public void function2(long input) {
long s = 0;
for (long i = 1; i < input * input; i++){
for(long j = 1; j < i * i; j++){
s++;
}
}
}
l'm pretty certain that the time complexity of this function is n^3, however if someone could provide a line by line explanation of this, that would be great.
First of all, you need to define what n is if you write something like O(n^3), otherwise it doesn't make any sense. Let's say n is the value (as opposed to e.g. the bit-length) of input, so n = input.
The outer loop has k iterations, where k = n^2. The inner loop has 1^2, 2^2, 3^2, ... up to k^2 iterations, so summing up everything you get O(k^3) iterations (since the sum of the p-th powers of the first m integers is always O(m^(p+1))).
Hence the overall time complexity is O(n^6).

Nested loops with time complexity log(log n)

Can there be an algorithm with two loops (nested) such that the overall time complexity is O(log(log n))
This arised after solving the following :
for(i=N; i>0; i=i/2){
for(j=0; j<i; j++){
print "hello world"
}
}
The above code has time complexity of N. (Using concept of Geometric Progression). Can there exists similar loop with time complexity O(log(log n)) ?
For a loop to iterate O(log log n) times, where the loop index variable counts up to n, then the index variable has to grow like the inverse function of log log k where k is the number of iterations; i.e. it has to grow like 2^2^k, or some other base than 2.
One way to achieve this is by starting at 2 and repeatedly squaring until you reach n - if the index variable is (((2^2)^2)...^2) with k squarings, then this equals 2^2^k as required:
for(int i = 2; i < n; i = i*i) {
//...
}
This loop iterates O(log log n) times, as required. If you absolutely must do it with nested loops, we can trivially add an extra loop which iterates O(1) times, leaving the total number of iterations asymptotically the same:
for(int i = 2; i < n; i = i*i) {
for(int j = 0; j < 10; j++) {
// ...
}
}

determine the time complexity of the algorithems

I have just started to learn time complexity, but I don't really get the idea, could you help with those questions and explain the way of thinking:
int Fun1(int n)
{
for (i = 0; i < n; i += 1) {
for (j = 0; j < i; j += 1) {
for (k = j; k < i; i += 1) {
// do something
}
}
}
}
void Fun2(int n){
i=o
while(i<n){
for (j = 0; j < i; j += 1) {
k=n
while(k>j){
k=k/2
}
k=j
while(k>1){
k=k/2
}
}
}
int Fun3(int n){
for (i = 0; i < n; i += 1) {
print("*")
}
if(n<=1){
print("*")
return
}
if (n%2 != 0){
Fun3(n-1)
}
else{
Fun3(n/2)
}
}
for function 1, I think its Theta(n^3) because it runs at most
n*n*n times but I am not sure how to prove this.
for the second I think its Theta (n^2log(n))
I am not sure
Could you help, please?
First a quick note, in Fun2(n) there should be a i++ before closing the while loop, anyway, time complexity is important in order to understand the efficiency of your algorithms. In this case you have these 3 functions:
Fun1(n)
In this function you have three nested for loops, each for loops iterates n times over a given input, we know that the complexity of this iteration is O(n). Since there are three nested for loops, the second for loop will iterate n times over each iteration of the outer for loop. The same will do the most inner loop. The resulting complexity, as you correctly said, is O(n) * O(n) * O(n) = O(n^3)
Fun2(n)
This function has a while loop that iterates n times over a given input. So the outer loop complexity is O(n). Same as before we have an inner for loop that iterates n times on each cycle of the outer loop. So far we have O(n) * O(n) which is O(n^2) as complexity. Inside the for loop we have a while loop, that differs from the other loops, since does not iterate on each element in a specific range, but it divides the range by 2 at each iteration. For example from 0 to 31 we have 0-31 -> 0-15 -> 0-7 -> 0-3 -> 0-1
As you know the number of iteration is the result of the logarithmic function, log(n), so we end up with O(n^2) * O(log(n)) = O(n^2(log(n)) as time complexity
Fun3(n)
In this function we have a for loop with no more inner loops, but then we have a recursive call. The complexity of the for loop as we know is O(n), but how many times will this function be called?
If we take a small number (like 6) as example we have a first loop with 6 iteration, then we call again the function with n = 6-1 since 6 mod 2 = 0
Now we have a call to Fun3(5), we do 5 iteration and the recursively we call Fun3(2) since 5 mod 2 != 0
What are we having here? We having a recursive call that in the worst case will call itself n times
The complexity result is O(n!)
Note that when we calculate time complexity we ignore the coefficients since are not relevant, usually the function we consider, especially in CS, are:
O(1), O(n), O(log(n)), O(n^a) with a > 1, O(n!)
and we combine and simplify them in order to know who has the best (lowest) time complexity to have an idea of which algorithm could be used

Code for factorials in objective C

Using only for or while statements, I'm trying to come up with a program to generate and print a table of the first 10 factorials. Here's my code:
for (count = 1; count<=10; ++count)
{
n = count;
while (n > 0){
count *= (count-1);
n -= 1;
}
NSLog(#" %2g %3g", count, factorial);
}
I don't understand why this is not working. It never gets out of the loop and goes on forever. What's the correction? Thank you!
The reason:
count *= (count-1);
Since count starts at 1, it will always be reset to 0, so the count <= 10 condition of the outer loop will always be true, hence the infinite looping.
And you're overcomplicating it anyway.
for (int i = 1; i <= 10; i++) {
int r = 1, n = i;
while (n)
r *= n--;
printf("%d! = %d\n", i, r);
}
In Math, n! is the same thing as Γ(n+1) (see: http://en.wikipedia.org/wiki/Gamma_function)
So just use:
-(float)factorial:(float)number1 {
return tgammaf(++number1);
}
This will even work for floats and negative numbers,
other solutions posted are long and extraneous and only work with
positive integers.
During the first loop iteration count is 1 and so also n is 1, then you enter the while and you set count to zero (count-1), and decrease n which becomes zero and you exit the while. So during the second loop iteration count will be zero. You keep decreasing count and it never gets increased, so you never exit the loop until a numeric overflow occurs.
You're doing it harder that what it is (and also inefficient) . Is enough that you keep multiplying n for count to get the factorial:
int n=1;
for (count = 1; count<=10; ++count)
{
n*= count;
NSLog(#"%d",n);
}

Objective C, difference between n++ and ++n

In Objective-C, is there any difference between n++ and ++n (eg. used in a for loop)?
++n; increments the value of n before the expression is evaluated.
n++; increments the value of n after the expression is evaluated.
So compare the results of this
int n = 41;
int o = ++n; //n = 42, o = 42
with the results of this:
int n = 41;
int o = n++; //n = 42, o = 41
In the case of loops:
for (int i = 0; i < j; i++) {/*...*/}
however it doesn't make any difference, unless you had something like this:
for (int i = 0; i < j; x = i++) {/*...*/}
or this:
for (int i = 0; i < j; x = ++i) {/*...*/}
One could say:
It doesn't matter whether to use n++ or ++n as long as no second (related) variable is modified (based on n) within the same expression.
The same rules apply to --n; and n--;, obviously.
++n increments the value before it's used (pre-increment) and n++ increments after (post-increment).
In the context of a for loop, there is no observable difference, as the increment is applied after the code in the loop has been executed.
++n and n++ differ in what the expression evaluates to. An example:
int n = 0;
NSLog(#"%d", n); // 0
NSLog(#"%d", n++); // still 0, increments afterwards
NSLog(#"%d", n); // 1
NSLog(#"%d", ++n); // 2, because it increments first
NSLog(#"%d", n); // 2
In a loop it wont make a difference. Some people say ++n is faster though
In Scott Meyers "More Effective C++" Book he makes a very rational case for preferring prefix increment to postfix increment. In a nutshell, in that language due to operator overloading facilities prefix increment is almost always faster. Objective C doesn't support overloaded operators but if you have or ever will do any C++ or Objective-C++ programming then preferring prefix increment is a good habit to get into.
Remember that most of the time ++n looks like:
n = n + 1
[do something with n]
Whereas n++ looks like (if used as intended):
register A = n; // copy n
[do something with n]
n = A + 1;
As you can see the postfix case has more instructions. In simple for loops most compilers are smart enough to avoid the copy if it's obvious that the pre-increment n isn't going to be used but that case devolves to the prefix case.
I Hope this makes sense. In summary you should use prefix unless you really want the "side-effect" behavior of evaluate then increment that you get from the postfix version.
As stated above,
--n decrements the value of n before the expression is evaluated.
n--; decrements the value of n after the expression is evaluated.
The thing here to note is when using while loops
For example:
n = 5
while(n--) #Runs the loop 5 times
while(--n) #Runs the loop 4 times
As in n-- the loop runs extra time while n = 1
But in --n 1 is first decremented to 0, and then evaluated. This causes the while loop to break.