How many times does the for-loop run? - analysis

How many times does the for-loop run?
done <- false
n <- 0
while (n < a-1) and (done = false)
done <- true
for m <- a downto n
if list[m] < list[m - 1] then
tmp <- list[m]
list[m] <- list[m-1]
list[m - 1] <- tmp
done <- false
n <- n + 1
return list
In the worst case, is the answer (n ^ 2 + n) / 2 correct?. Does the while-loop run n+1 times?

If downto includes the value of n, then:
It will run for ((a+1)+a+(a-1)+(a-2)+...+1) times in the worst case. This equals ((a+1)*(a+2))/2.
If downto does not include the value of n, then:
It will run for (a+(a-1)+(a-2)+...+1) times in the worst case. This equals (a*(a+1))/2.
In both cases, the while loop will run a times.

Related

missing invariant in dafny code involving sequences

I am wondering if there is a reason why dafny is unable to verify my program?
https://rise4fun.com/Dafny/Ip1s
Am I missing some additional invariant?
The problem is that your definition of s and your construction of o go in "different directions". The recursive case of s defines s(i) in terms of
i[0] and what is "previously" defined by s(i[1..]). In contrast, the loop iteration defines the new o in terms of i[n] and the previous value of o. It would take an inductively proven lemma to establish the proof obligations in your current program, and Dafny does not invent such lemmas by itself.
For the record in this answer, here is what you started with:
function s(i: seq<int>): seq<int> {
if |i| == 0 then [] else
if i[0] == 42 then [i[0]] + s(i[1..])
else s(i[1..])
}
method q (i: seq<int>) returns (o: seq<int>)
ensures o == s(i)
{
var n := 0;
o := [];
while n < |i|
invariant n <= |i| && o == s(i[..n])
{
if i[n] == 42 {
o := o + [i[n]];
}
n := n + 1;
}
}
There are four ways out.
One way out is to define a different version of s, call it s', that recurses from the other end of the given sequence. Then, replace s by s' in your method specification and loop invariant. This is a fine solution, unless for some reason you really prefer s, not s', in your method specification.
A second way out is to define such an s' and to prove a lemma that s(i) and s'(i) return the same value. This will let you keep s in your method specification, at the cost of having two function definitions and having to write (and prove and use) a lemma.
A third way out is to change the loop to iterate "downward" instead of "upward". That is, start n at |i| and decrement n in the loop body. (As usual, an increment of n is typically best done at the end of the loop body (post-increment), whereas a decrement of n is typically best done at the beginning of the loop body (pre-decrement).)
A fourth way out is to change the way you write the loop invariant about o. Currently, the invariant speaks about what you already have computed, that is, o == s(i[..n]). You can instead write the invariant in terms of what is yet to be computed, as in o + s(i[n..]) == s(i), which you can read as "once I have added s(i[n..]) to o, I will have s(i)". Here is that version of q:
method q(i: seq<int>) returns (o: seq<int>)
ensures o == s(i)
{
var n := 0;
o := [];
while n < |i|
invariant n <= |i| && o + s(i[n..]) == s(i)
{
if i[n] == 42 {
o := o + [i[n]];
}
n := n + 1;
}
}
You may also be interested in watching this episode of Verification Corner on this subject.
Rustan

Why does this List comprehension take too long to evaluate on Erlang/OTP 20?

To find any 5 numbers whose sum = 100. This can be done in a loop but i was illustrating list comprehension to a friend only to realize this takes more than 30 mins on my Mac Book Pro,core i7, 2.2GHz
[[A,B,C,D,E] || A <- lists:seq(1,100),B <- lists:seq(1,100),C <- lists:seq(1,100),D <- lists:seq(1,100),E <- lists:seq(1,100),(A + B + C + D + E) == 100]
And if the question is changed to have the 5 numbers consecutive, the constructed list comprehension even takes much longer. If i am to solve this problem using a list comprehension, am i doing it right ? if yes, why does it take too long ? please provide a solution that may be faster, perhaps using a loop.
The multiple generators behave like nested loops over the lists, and each call to lists:seq() will be fully evaluated each time. This takes a very long time, and spends most of that time allocating list cells and garbage collecting them again. But since they all evaluate to the same constant list anyway, you can rewrite it as L = lists:seq(1,100), [[A,B,C,D,E] || A <- L,B <- L,C <- L,D <- L,E <- L,(A + B + C + D + E) == 100]. Also, running this in the shell will be a lot slower than in a compiled module. On my macbook, the compiled code finished in about 2 min 30 s. And that's just using a single core. Compiling with [native] makes it run in 60 seconds flat.
Because it "creates" all the elements of a 100^5 list of list of 5 elements before it makes the filter, that represents 50000000000 elements.
[edit]
I reviewed the answer from RichardC and Alexey Romanov and I decided to make some tests:
-module (testlc).
-export ([test/1]).
test(N) ->
F1 = fun() -> [{W,X,Y,Z}|| W <- lists:seq(1,N),X <- lists:seq(1,N),Y <- lists:seq(1,N),Z <- lists:seq(1,N), W+X+Y+Z == N] end,
F2 = fun() ->L = lists:seq(1,N), [{W,X,Y,Z}|| W <- L,X <- L,Y <- L,Z <- L, W+X+Y+Z == N] end,
F3 = fun() -> [{W,X,Y,Z}|| W <- lists:seq(1,N-3), X <- lists:seq(1,N-2-W),Y <- lists:seq(1,N-1-W-X),Z <- lists:seq(1,N-W-X-Y), W+X+Y+Z == N] end,
F4 = fun() -> [{W,X,Y,N-W-X-Y}|| W <- lists:seq(1,N-3),X <- lists:seq(1,N-2-W),Y <- lists:seq(1,N-1-W-X)] end,
F5 = fun() -> L = lists:seq(1,N), [{W,X,Y,N-W-X-Y}|| W <- L,
XM <- [N-2-W], X <- L, X =< XM,
YM <- [N-1-W-X], Y <- L, Y =< YM] end,
{T1,L1} = timer:tc(F1),
{T2,L2} = timer:tc(F2),
{T3,L3} = timer:tc(F3),
{T4,L4} = timer:tc(F4),
{T5,L5} = timer:tc(F5),
_L = lists:sort(L1),
_L = lists:sort(L2),
_L = lists:sort(L3),
_L = lists:sort(L4),
_L = lists:sort(L5),
{test_for,N,{t1,T1},{t2,T2},{t3,T3},{t4,T4},{t5,T5}}.
and the result:
1> c(testlc).
{ok,testlc}
2> testlc:test(50).
{test_for,50,
{t1,452999},
{t2,92999},
{t3,32000},
{t4,0},
{t5,0}}
3> testlc:test(100).
{test_for,100,
{t1,4124992},
{t2,1452997},
{t3,203000},
{t4,16000},
{t5,15000}}
4> testlc:test(150).
{test_for,150,
{t1,20312959},
{t2,7483985},
{t3,890998},
{t4,93000},
{t5,110000}}
5> testlc:test(200).
{test_for,200,
{t1,63874875},
{t2,24952951},
{t3,2921995},
{t4,218999},
{t5,265000}}
Preparing the list outside of the list comprehension has a big impact, but it is more efficient to limit drastically the number of useless intermediate lists generated before the filter works. So it is a balance to evaluate. In this example, the 2 enhancements can be used together (Thanks to Alexey) but it does not make a big difference.
Erlang strong when we use concurrence in programming, so you can also spawn 100 process to handle list of [1,...,100]. It can be easy for your laptop calculate. For example:
do()->
L100 = lists:seq(1,100),
[spawn(?MODULE, func, [self(), [A], L100, L100, L100, L100]) ||
A <- L100],
loop(100, []).
loop(0, Acc) -> Acc;
loop(N, Acc) ->
receive
{ok, Result} ->
loop(N - 1, Acc ++ Result)
end.
func(Pid, LA, LB, LC, LD, LE) ->
Result = [[A,B,C,D,E] ||
A <- LA,B <- LB,C <- LC,D <- LD,E <- LE,(A + B + C + D + E) == 100],
Pid ! {ok, Result}.
With solution above, my laptop with i3 2.1GHz can be easy calculate in 1 minute. You can also spawn more process for shorter calculate. Process in Erlang is light-weight process so It can be easy start then easy stop.
One option would be
[[A,B,C,D,100-A-B-C-D] || A <- lists:seq(1,100), B <- lists:seq(1,100-A), C <- lists:seq(1,100-A-B), D <- lists:seq(1,100-A-B-C), 100-A-B-C-D > 0]
Just not enumerating all possible Es when at most one will succeed should be 100 times faster (or more since there's less garbage produced). Also decreasing the sizes of lists for B, C, and D will improve even more.
But there is some code duplication there. Unfortunately, Erlang doesn't allow "local" variables in list comprehensions, but you can emulate them with one-element generators:
[[A,B,C,D,E] || A <- lists:seq(1,100),
BMax <- [100-A], B <- lists:seq(1,BMax),
CMax <- [BMax-B], C <- lists:seq(1,CMax),
DMax <- [CMax-C], D <- lists:seq(1,DMax),
E <- [100-A-B-C-D], E > 0]
Or to avoid repeated lists:seq calls, as #RichardC points out:
L = lists:seq(1, 100),
[[A,B,C,D,E] || A <- L,
BMax <- [100-A], B <- L, B =< BMax,
CMax <- [BMax-B], C <- L, C =< CMax,
DMax <- [CMax-C], D <- L, D =< DMax,
E <- [100-A-B-C-D], E > 0]

Pure pattern matching

I am building a function that counts of many times a character appears in a string after the nth position.
countCh ("aaabbbccc", 3, 'b')
val it: int = 2
In C, I would use an accumulator with a while loop. But I am trying to learn the F# functional face, where this approach is discouraged.
So I used guards to test few conditions and build the function:
let rec countCh (s:string, n:int, ch:char) =
match s, n, ch with
| (s, n, ch) when n > s.Length -> 0 //p1
| (s, n, ch) when n < 0 -> 0 //p2
| (s, n, ch) when s.[n] <> ch -> countCh(s, n + 1, ch) //p3
| (s, n, ch) when s.[n] = ch -> 1 + countCh(s, n + 1, ch) //p4
The coexistence of patterns 3 and 4 is problematic (impossible, I am afraid). Even if it compiles, I have not been able to make it work. How can this task functionally be handled?
First, the coexistence of these branches is not problematic. They don't conflict with each other. Why do you think that it's problematic? Is it because you get an "Incomplete pattern match" compiler warning? That warning does not tell you that the branches conflict, it tells you that the compiler can't prove that the four branches cover all possibilities. Or do you think that for some other reason? If you want your questions to be answered accurately, you'll have to ask them more clearly.
Second, you're abusing the pattern matching. Look: there are no patterns! The patterns in every branch are exactly the same, and trivial. Only guards are different. This looks very counterintuitively within a match, but would be plainly expressed with if..elif:
let rec countCh (s:string) n ch =
if n >= s.Length || n < 0 then 0
elif s.[n] = ch then 1 + countCh s (n + 1) ch
else countCh s (n + 1) ch
NOTE 1: see how I made the parameters curried? Always use curried form, unless there is a very strong reason to use tupled. Curried parameters are much more convenient to use on the caller side.
NOTE 2: your condition n > s.Length was incorrect: string indices go from 0 to s.Length-1, so the bail condition should be n >= s.Length. It is corrected in my code.
Finally, since this is an exercise, I must point out that the recursion is not tail recursion. Look at the second branch (in my code): it calls the function recursively and then adds one to the result. Since you have to do something with the result of the recursive call, the recursion can't be "tail". This means you risk stack overflow on very long inputs.
To make this into tail recursion, you need to turn the function "inside out", so to say. Instead of returning the result from every call, you need to pass it into every call (aka "accumulator"), and only return from the terminal case:
let rec countCh (s:string) n ch countSoFar =
if n >= s.Length || n < 0 then countSoFar
elif s.[n] = ch then countCh s (n+1) ch (countSoFar+1)
else countCh s (n+1) ch countSoFar
// Usage:
countCh "aaaabbbccc" 5 'b' 0
This way, every recursive call is the "last" call (i.e. the function doesn't do anything with the result, but passes it straight out to its own caller). This is called "tail recursion" and can be compiled to work in constant stack space (as opposed to linear).
I agree with the other answers, but I'd like to help you with your original question. You need to indent the function, and you have an off by one bug:
let rec countCh (s:string, n:int, ch:char) =
match s, n, ch with
| s, n, _ when n >= s.Length-1 -> 0 //p1
| s, _, _ when n < 0 -> 0 //p2
| s, n, ch when s.[n+1] <> ch -> countCh(s, n+2, ch) //p3
| s, n, ch when s.[n+1] = ch -> 1 + countCh(s, n+2, ch) //p4
I'd suggest to not write it yourself, but ask the library functions for help:
let countCh (s: string, n, c) =
s.Substring(n+1).ToCharArray()
|> Seq.filter ((=) c)
|> Seq.length
Or use Seq.skip, along with the fact that you can drop the conversion to character array:
let countCh (s: string, n, c) =
s
|> Seq.skip (n + 1)
|> Seq.filter ((=) c)
|> Seq.length

Issue With Factorial Function

I have been trying to write a program which prints out a factorial without actually using recursion.
Here is the code
let factorial x =
let mutable n = x
while n > 0 do
let result = n*(n-1)
n <- (n-1)
result
The issue is that when I try to run the code it tells me that the expected result is a unit, whereas the input is clearly an integer, which obviously results in an error. However, I have checked all my variables and the compiler interprets them as integers, so what is the issue
There are several issues with your code here, you must keep in mind indentation in f# is very important, for you want to do your code should be:
let factorial x =
let mutable n = x
let mutable result = 1
while n > 0 do
result <- n * (n-1)
n <- (n - 1)
result
You were declaring the result variable inside the while scope and returning it outside it. Your code however is incorrect, I took the liberty of modify it, here what I did:
let factorial x =
let mutable n = x
let mutable result = 1
while n >= 1 do
result <- result * n
n <- (n - 1)
result

Usage about Pattern matching

I thought these two function were the same, but it seems that I was wrong.
I define two function f and g in this way:
let rec f n k =
match k with
|_ when (k < 0) || (k > n) -> 0
|_ when k = n -> 100
|_ -> (f n (k+1)) + 1
let rec g n k =
match k with
|_ when (k < 0) || (k > n) -> 0
| n -> 100
|_ -> (g n (k+1)) + 1
let x = f 10 5
let y = g 10 5
The results are:
val x : int = 105
val y : int = 100
Could anyone tell me what's the difference between these two functions?
EDIT
Why does it work here?
let f x =
match x with
| 1 -> 100
| 2 -> 200
|_ -> -1
List.map f [-1..3]
and we get
val f : x:int -> int
val it : int list = [-1; -1; 100; 200; -1]
The difference is that
match k with
...
when k = n -> 100
is a case that matches when some particular condition is true (k = n). The n used in the condition refers to the n that is bound as the function parameter. On the other hand
match k with
...
n -> 100
is a case that only needs to match k against a pattern variable n, which can always succeed. The n in the pattern isn't the same n as the n passed into the function.
For comparison, try the code
let rec g n k =
match k with
|_ when (k < 0) || (k > n) -> 0
| n -> n
|_ -> (g n (k+1)) + 1
and you should see that when you get to the second case, the value returned is the value of the pattern variable n, which has been bound to the value of k.
This behavior is described in the Variable Patterns section of the MSDN F# Language Reference, Pattern Matching:
Variable Patterns
The variable pattern assigns the value being matched to a variable
name, which is then available for use in the execution expression to
the right of the -> symbol. A variable pattern alone matches any
input, but variable patterns often appear within other patterns,
therefore enabling more complex structures such as tuples and arrays
to be decomposed into variables. The following example demonstrates a
variable pattern within a tuple pattern.
let function1 x =
match x with
| (var1, var2) when var1 > var2 -> printfn "%d is greater than %d" var1 var2
| (var1, var2) when var1 < var2 -> printfn "%d is less than %d" var1 var2
| (var1, var2) -> printfn "%d equals %d" var1 var2
function1 (1,2)
function1 (2, 1)
function1 (0, 0)
The use of when is described in more depth in Match Expressions.
The first function is ok, it calls recursively itself n-k times and returns 100 when matches with the conditional where k = n. So, it returns all the calls adding 1 n-k times. with your example, with n=10 and k=5 it is ok the result had been 105.
The problem is the second function. I tested here. See I changed the pattern n->100 to z->100 and it still matches there and never calls itself recursively. So, it always returns 100 if it does not fail in the first conditional. I think F# don't allow that kind of match so it is better to put a conditional to get what you want.

Resources