N-step code for fibonacci OCAML - algorithm

So I'm trying to code something for my class that will output an int list of the first k terms in an n-step fibonacci sequence.
So for those of you that don't know, an n step fibonacci sequence is when you add the n numbers before it to get the next one,
so for n=1 it'd be 1,1,1,1,1,...
n=2, it'd be 1,1,2,3,5,...
n=3 it'd be 1,1,2,4,7...
My approach was to start of with a base case, so
let rec n_step n k=
if k=1 then [1] else
if n=1 then 1::nacci n k-1 else
but now I'm stuck here. I know I need to iterate through and add up the terms in the list, but I'm not sure how to accomplish this.
I made a helper function sum
let rec sum lst =
match lst with
| [] -> 0
| h::t -> h + sum t
I was trying to make it selectively add the last n numbers of the list to get the next value but I got stuck on that as well
Thanks in advance!

This is homework so I'll only suggest some steps, not a complete solution:
if you come from an imperative background, try first an imperative solution such as a loop that prints the result instead of building a list and tying the recursion at once. You can store the required state in a global and gradually change that to pass parameters.
start with n=2, using a tuple instead of a list. It will be considerably easier to do that first, manually extend to fixed n=3 and fixed n=4 before using a list.
Applying these two pieces of advice, a first step might be:
let print_fib_2 () =
let previous_ref = ref (1, 1) in
for i = 0 to 10 do
let (a, b) = !previous_ref in
let next = a + b in
previous_ref := (next, a);
Printf.printf "%d\n" next
done
I'd first generalize to using changing n=2 to n=3: what happens to the pairs (a, b) and (next, a)? what does it mean in terms of lists?
By following baby steps from a working example you should be able to work to a solution.

I've figured it out using many helper functions.
So I've made a sum function that would sum up the values in a list
A gather function that would only take the n values from the entire list
and then in my original function, I used pattern matching for the k's such that if k=1, it would yield one and otherwise it would recurse. If it wasn't one I appended the next value using the helper

Related

Sorting Algorithm: Insertion sort - Pseudocode given in lectures seems wrong

I'm attending a basic class called Algorithms. We are studying the sorting algorithms; we were given the following pseudocode as an example of the insertion sort algorithm. However I think it's wrong.
For i in {2,..,n}:
For j in {i,..,2}:
If a(j)<a(j-1), swap a(j) and a(j-1)
Else, Break
You can also see it here in the lecture notes, in this screenshot:
I understand the first line - it starts from 2 because the first card is "already ordered", since it is the only card so far.
Is the second line a mistake? How can it be that we use j from i to 2? Of course this cannot hold true in the future. Also, shouldn't the break be less indented? So only one tab away instead of 2?
Edit
Here is the "main idea" of the algorithm. As you see the range of index j seems wrong from here.
Edit2
So here I try to write what happens in my mind, reading this pseudocode:
Suppose I have the list (5,3,8,7,2,4,1,6). I will write | to separate the "hand" from the deck, also I'll write 5_ to emphasize which element I'm looking at. So here we go:
i = 1, (5|3,8,7,2,4,1,6)
i = 2, (5,3|8,7,2,4,1,6), now j in {2}, so we only have j = 2, a(j=2)=3 < a(j=1)=5, hence swap 3 with 5
i = 3, (3,5,8|7,2,4,1,6), j in {2,3}, so j=2 gives a(j=2)=5 !< a(j=1)=3 SO WE BREAK!
i = 4, (3,5,8,7|2,4,1,6), j in {2,3,4}, so j = 2 gives a(j=2)=5 !< a(j=1)=3, SO WE BREAK
and as you see this will always happen from now on because we start from 2 and because we break it! So even though the set of integers for j increases, we can't go further 2, because we just violate the condition
If you make the following assumptions, the code is valid:
An array of length N has indices 1..N
For loops cover the specified range regardless of the direction; thus, for x in {a,...,b} will go through a, a+1, a+2, ..., b-1, b if a <= b, but go through a, a-1, a-2, ..., b+1 b if a >= b.
The second line isn't a mistake because you trying to take the i-th element(running on the outer loop) and insert into the partition before it. You then have to compare this element with the partition before it to make it sorted.
this SO post has a good visualization:
Insertion Sort vs. Selection Sort

Optimal way to compute permutations in julia

Consider a list [1,1,1,...,1,0,0,...,0] (an arbitrary list of zeros and ones). We want the whole possible permutations in this array, there'll be binomial(l,k) permutations (l stands for the length of the list and k for the number of ones in the list).
Right now, I have tested three different algorithms to generate the whole possible permutations, one that uses a recurrent function, one that calculates
the permutations via calculating the interval number [1,...,1,0,0,...,0]
to [0,0,...0,1,1,...,1] (since this can be seen as a binary number interval), and one that calculates the permutations using lexicographic order.
So far, the first two approaches fail in performance when the permutations are
approx. 32. The lexicographic technique works still pretty nice (only a few miliseconds to finish).
My question is, specifically for julia, which is the best way to calculate
permutations as I described earlier? I don't know too much in combinatorics, but I think a descent benchmark would be to generate all permutations from the total binomial(l,l/2)
As you have mentioned yourself in the comments, the case where l >> k is definitely desired. When this is the case, we can substantially improve performance by not handling vectors of length l until we really need them, and instead handle a list of indexes of the ones.
In the RAM-model, the following algorithm will let you iterate over all the combinations in space O(k^2), and time O(k^2 * binom(l,k))
Note however, that every time you generate a bit-vector from an index combination, you incur an overhead of O(l), in which you will also have the lower-bound (for all combinations) of Omega(l*binom(l,k)), and the memory usage grows to Omega(l+k^2).
The algorithm
"""
Produces all `k`-combinations of integers in `1:l` with prefix `current`, in a
lexicographical order.
# Arguments
- `current`: The current combination
- `l`: The parent set size
- `k`: The target combination size
"""
function combination_producer(l, k, current)
if k == length(current)
produce(current)
else
j = (length(current) > 0) ? (last(current)+1) : 1
for i=j:l
combination_producer(l, k, [current, i])
end
end
end
"""
Produces all combinations of size `k` from `1:l` in a lexicographical order
"""
function combination_producer(l,k)
combination_producer(l,k, [])
end
Example
You can then iterate over all the combinations as follows:
for c in #task(combination_producer(l, k))
# do something with c
end
Notice how this algorithm is resumable: You can stop the iteration whenever you want, and continue again:
iter = #task(combination_producer(5, 3))
for c in iter
println(c)
if c[1] == 2
break
end
end
println("took a short break")
for c in iter
println(c)
end
This produces the following output:
[1,2,3]
[1,2,4]
[1,2,5]
[1,3,4]
[1,3,5]
[1,4,5]
[2,3,4]
took a short break
[2,3,5]
[2,4,5]
[3,4,5]
If you want to get a bit-vector out of c then you can do e.g.
function combination_to_bitvector(l, c)
result = zeros(l)
result[c] = 1
result
end
where l is the desired length of the bit-vector.

Can someone explain how recursive insertion sort works?

Assuming A is an array, and n is the number of elements in A,
recursive_insertion_sort(A, n)
IF n > 1 THEN
recursive_insertion_sort(A, n-1)
key = A[n]
i = n - 1
DOWHILE A[i] > key AND i > 0
A[i+1] = A[i]
i = i - 1
ENDDO
A[i+1] = temp
ENDIF
END
Can someone explain how recursion works in this case? There are a few things I don't understand:
I don't understand why we have to call the function again if n > 1.
Why do we input (n-1) when we call the function again? Is it so that we start the entire process from n = 2, the first 2 elements?
How does recursion in general work? Like, once we call the function again, do we ignore the code from line 4 onwards, and jump straight into the second call? Or do we run the 2nd call in conjunction with the first call?
Before discussing the implementation, let's explain what this function does: it does not sort the entire array A, but only its initial n elements. You can pass the length of the array for n to sort the whole thing, but the fact that you pass the length separately is essential to understanding the rest of the answer.
I don't understand why we have to call the function again if n > 1.
Perhaps a better way to explain the meaning of this condition would be that we do not call this function again when n is one or less. This is called the base case of recursive algorithm, i.e. the case when you don't have to do anything. In case of sorting it means that an array of only one element is already sorted.
Why do we input (n-1) when we call the function again?
Since n is the number of elements that we need to sort, We pass n-1 to sort the front of the array. Once the function returns, we know that the portion A[1..n-1] is already sorted. All we need to do is to move A[n] to its right place. We do that in the DOWHILE loop that follows: we go backward one element at a time, moving elements that are bigger than A[n] to the right. Once the loop is over, we place A[n] to its new place. Now the range A[1..n] is sorted.
How does recursion in general work?
The function has two cases - the trivial base case, when everything is done, and a reduction step, when you use recursive invocation to solve a simpler problem, and then use the results of the simpler solution to construct your final solution.
once we call the function again, do we ignore the code from line 4 onwards, and jump straight into the second call?
No, once the function returns, we continue where we left. In your case, the function waits for the A[1..n-1] range to be sorted before placing A[n] to the right place.
Small example to understand how this works :
recursive_insertion_sort([1, 7, 5, 2], 4)
| recursive_insertion_sort([1, 7, 5, 2], 3)
| | recursive_insertion_sort([1, 7, 5, 2], 2)
| | | recursive_insertion_sort([1, 7, 5, 2], 1)
| | puts 7 in the right position between it's ORDERED left values [1] -> [1,7]
| puts 5 in the right position between it's ORDERED left values [1,7] -> [1,5,7]
puts 2 in the right position between it's ORDERED left values [1,5,7] -> [1,2,5,7]

Count ways to take atleast one stick

There are N sticks placed in a straight line. Bob is planning to take few of these sticks. But whatever number of sticks he is going to take, he will take no two successive sticks.(i.e. if he is taking a stick i, he will not take i-1 and i+1 sticks.)
So given N, we need to calculate how many different set of sticks he could select. He need to take at least stick.
Example : Let N=3 then answer is 4.
The 4 sets are: (1, 3), (1), (2), and (3)
Main problem is that I want solution better than simple recursion. Can their be any formula for it? As am not able to crack it
It's almost identical to Fibonacci. The final solution is actually fibonacci(N)-1, but let's explain it in terms of actual sticks.
To begin with we disregard from the fact that he needs to pick up at least 1 stick. The solution in this case looks as follows:
If N = 0, there is 1 solution (the solution where he picks up 0 sticks)
If N = 1, there are 2 solutions (pick up the stick, or don't)
Otherwise he can choose to either
pick up the first stick and recurse on N-2 (since the second stick needs to be discarded), or
leave the first stick and recurse on N-1
After this computation is finished, we remove 1 from the result to avoid counting the case where he picks up 0 sticks in total.
Final solution in pseudo code:
int numSticks(int N) {
return N == 0 ? 1
: N == 1 ? 2
: numSticks(N-2) + numSticks(N-1);
}
solution = numSticks(X) - 1;
As you can see numSticks is actually Fibonacci, which can be solved efficiently using for instance memoization.
Let the number of sticks taken by Bob be r.
The problem has a bijection to the number of binary vectors with exactly r 1's, and no two adjacent 1's.
This is solveable by first placing the r 1's , and you are left with exactly n-r 0's to place between them and in the sides. However, you must place r-1 0's between the 1's, so you are left with exactly n-r-(r-1) = n-2r+1 "free" 0's.
The number of ways to arrange such vectors is now given as:
(1) = Choose(n-2r+1 + (r+1) -1 , n-2r+1) = Choose(n-r+1, n-2r+1)
Formula (1) is deriving from number of ways of choosing n-2r+1
elements from r+1 distinct possibilities with replacements
Since we solved it for a specific value of r, and you are interested in all r>=1, you need to sum for each 1<=r<=n
So, the solution of the problem is given by the close formula:
(2) = Sum{ Choose(n-r+1, n-2r+1) | for each 1<=r<=n }
Disclaimer:
(A close variant of the problem with fixed r was given as HW in the course I am TAing this semester, main difference is the need to sum the various values of r.

Prolog; try to make fibonacci more effective?

This logic programming is really making a lap dance on my imperative programming skills. This is homework, so please just don't drop me the answer. This is what I have:
fibo(N,1) :-
N < 2,
!.
fibo(N,R) :-
N1 is N-1,
N2 is N-2,
fibo(N1,R1),
fibo(N2,R2),
R is R1+R2.
I'm suppose to make another function that looks like this; fib(N,Value,LastValue).
N is the n'th number, and value is the return value. I don't understand how I can rewrite this using accumulation. And since it counts backwards I don't see how it can "know" a last value before it calculates anything. :s Any input is appreciated.
I could post here the solution, but since that this is homework, it would be counter-productive. Instead, here's a lead:
The problem with the version of Fibonacci that you listed is that it is inefficient. Each call to fibo/2 causes another two calls, but some of these calls calculate the values of the same Fibonacci numbers. For example, in pseudo-code:
(a) fibo(4) -> fibo(3), fibo(2)
(b) fibo(3) -> fibo(2), fibo(1)
(c) fibo(2) -> fibo(1), fibo(0) % called from (a)
(d) fibo(2) -> fibo(1), fibo(0) % called from (b), redundant
To overcome this deficiency, you were asked to rephrase Fibonacci in terms of returning not just the last value, but the last two values, so that each call to fib/3 will cause only a single recursive call (hence calculate the Fibonacci series in linear time). You'll need to change the base cases to:
fib(1,1,0).
fib(2,1,1).
I'll leave the recursive case to you.
For the impatient
Here is the recursive case as well:
fib(N, Val, Last) :-
N > 2,
N1 is N - 1,
fib(N1, Last, Last1), % single call with two output arguments,
% instead of two calls with one output argument
Val is Last + Last1.
See the related discussion:
Generalizing Fibonacci sequence with SICStus Prolog
and consider ony's very good solution using finite domain constraints from there.
Perhaps using tail recursion is a good option
edit:
Instead of breaking fib(6) into fib(5)+fib(4) you might try something like fib(6) = fib(6,0,0) the first parameter is the count of steps, when it reaches 0 you stop, the second parameter the last value you calculated, and the third parameter is the value to calculate which is equal to the sum of current second and third parameters (with the exception of the first step, in which 0 + 0 will be 1)
So to calculate you set the second parameter at each call and acumulate in the third so fib(6,0,0) => fib(5,0,1) => fib(4,1,1) => fib(3,1,2) => fib(2,2,3) => fib(1,3,5) => fib(0,5,8) then you return 8
In that method you dont actually have to save in the stack the adress return, avoiding stack overflow
Remember that there is another way to calculate the Fibonacci sequence: starting from the base case and moving up.
Right now, to calculate fib(n), you add fib(n-1) and fib(n-2). Instead, flip that around and calculate fib(0) and fib(1) based on the definition of the Fibonacci sequence, and build up from that.
You almost already have it. Just rewrite:
fibo(N, Value) :-
N1 is N-1, N2 is N-2,
fibo(N1, LastValue),fibo(N2, SecondToLastValue),
Value is LastValue + SecondToLastValue.
in terms of
fibo2(N, Value, LastValue):- ...
I don't understand how I can rewrite
this using accumulation
Just don't, this is not needed (although it's possible to do so).

Resources