F# tricky recursive algorithm - list

I have this code in VBA (looping through the array a() of type double):
bm = 0 'tot
b = 0 'prev
For i = 24 To 0 Step -1
BP = b 'prevprev = prev
b = bm 'prev = tot
bm = T * b - BP + a(i) 'tot = a(i) + T * prev - prevprev
Next
p = Exp(-xa * xa) * (bm - BP) / 4 '* (tot - prevprev)/4
I'm putting this in F#. Clearly I could use an array and mutable variables to recreate the VBA. And maybe this is an example of the right time to use mutable that I've seen hinted at. But why not try to do it the most idiomatic way?
I could write a little recursive function to replicate the loop. But it kind of feels like littering to hang out a little sub-loop that has no meaning on its own as a standalone, named function.
I want to do it with List functions. I have a couple ideas, but I'm not there yet. Anyone get this in a snap??
The two vague ideas I have are: 1. I could make two more lists by chopping off one (and two) elements and adding zero-value element(s). And combine those lists. 2. I'm wondering if a list function like map can take trailing terms in the list as arguments. 3. As a general question, I wonder if this might be a case where an experienced person would say that this problem screams for mutable values (and if so does that dampen my enthusiasm for getting on the functional boat).
To give more intuition for the code: The full function that this is excerpted from is a numerical approximation for the cumulative normal distribution. I haven't looked up the math behind this one. "xa" is the absolute value of the main function argument "x" which is the number of standard deviations from zero. Without working through the proof, I don't think there's much more to say than: it's just a formula. (Oh and maybe I should change the variable names--xa and bm etc are pretty wretched. I did put suggestions as comments.)

It's just standard recursion. You make your exit condition and your recur condition.
let rec calc i prevPrev prev total =
if i = 0 then // exit condition; do your final calc
exp(-xa * xa) * (total - prevPrev) / 4.
else // recur condition, call again
let newPrevPrev = prev
let newPrev = total
let newTotal = (T * newPrev - newPrevPrev + a i)
calc (i-1) newPrevPrev newPrev newTotal
calc 24 initPrevPrev initPrev initTotal
or shorter...
let rec calc i prevPrev prev total =
if i = 0 then
exp(-xa * xa) * (total - prevPrev) / 4.
else
calc (i-1) prev total (T * total - prev + a i)

Here's my try at pulling the loop out as a recursive function. I'm not thrilled about the housekeeping to have this stand alone, but I think the syntax is neat. Aside from an error in the last line, that is, where the asterisk in (c * a.Tail.Head) gets the red squiggly for float list not matching type float (but I thought .Head necessarily returned float not list):
let rec RecurseIt (a: float list) c =
match a with
| []-> 0.0
| head::[]-> a.Head
| head::tail::[]-> a.Head + (c * a.Tail) + (RecurseIt a.Tail c)
| head::tail-> a.Head + (c * a.Tail.Head) - a.Tail.Tail.Head + (RecurseIt a.Tail c)
Now I'll try list functions. It seems like I'm going to have to iterate by element rather than finding a one-fell-swoop slick approach.
Also I note in this recursive function that all my recursive calls are in tail position I think--except for the last one which will come one line earlier. I wonder if this creates a stack overflow risk (ie, prevents the compiler from treating the recursion as a loop (if that's the right description), or if I'm still safe because the algo will run as a loop plus just one level of recursion).
EDIT:
Here's how I tried to return a list instead of the sum of the list (so that I could use the 3rd to last element and also sum the elements), but I'm way off with this syntax and still hacking away at it:
let rec RecurseIt (a: float list) c =
match a with
| []-> []
| head::[]-> [a.Head]
| head::tail::[]-> [a.Head + (c * a.Tail)] :: (RecurseIt a.Tail c)
| head::tail-> [a.Head + (c * a.Tail.Head) - a.Tail.Tail.Head] :: (RecurseIt a.Tail c)

Here's my try at a list function. I think the problem felt more complicated than it was due to confusing myself. I just had some nonsense with List.iteri here. Hopefully this is closer to making sense. I hoped some List. function would be neat. Didn't manage. For loop not so idiomatic I think. :
for i in 0 .. a.Length - 1 do
b::
a.Item(i) +
if i > 0 then
T * b.Item(i-1) -
if i > 1 then
b.Item(i-2)
else
0
else
0

Related

How to iterate over objective function

I want to potentiate certain terms in my objective function.
model.addConstr(KW == quicksum(I[t] *(1.05**(-i)) for t in Tst + Z[t]
* (1.05**(-j)) for t in T)
model.setObjective(KW,GRB.MAXIMIZE)
model.optimize()
The variable i should run from 1 to the number of elements in Tst and T
respectively.
So if t in Tst is [2020,2021,2022], I[2020] gets multiplied by 1.05**
(-1)
I[2021] by 1.05**(-2) and I[2022] by 1.05**(-3).
Same with Z[t], only that the list of T is larger than Tst.
for i in range(1,len(Tst)+1):
model.addConstr(KW == quicksum(I[t] * (1.05**(-i)))
However KW is always 0 then, which it shouldnt be. What am i missing?
I just created a 2nd dictionary
Expo = {}
i=1
for t in T:
Expo[t] = i
i = i + 1
If I do:
model.addConstr(KW == quicksum(I[t] *(1.05**(Expo[t])) for t in Tst + Z[t]
* (1.05**(Expo[t])) for t in T)
model.setObjective(KW,GRB.MAXIMIZE)
model.optimize()
it does what i want. But I dont think its a very good solution :P

Psum not accumulating (Polymorphic Higher order function) without forcing a type

New to OCaml and Functional Programming as a whole so I was having some problems with keeping the type ambiguous. I'm trying to make a function which takes in a symbol accum(which looks like (+) or (-.) or (*) etc.) and a function f. My current implementation is below and if let's say I passed in (** f (x) = 3x^2 + 5x + 6 **) but I always get '6' instead of '276' because in the else part I'm not summing adding the results of the previous rounds so I just get the final value of '6'.
I get type errors because of the + so when I throw floats in it breaks. How can I overcome this (let partial accept floats or ints but actually accumulate the answer)?
let rec powerSum(sign )(f):'a =
fun x ->
if x = 0 then
f (x)
else if x < 0 then
raise(Failure "Error arg isn't '+'")
else
powerSum sign f (x-1);
Hint: you should use accum at some point.

One simple 'if' statement in Julia increases the run-time of my prime sieve by a factor of 15 – why?

I've been experimenting with various prime sieves in Julia with a view to finding the fastest. This is my simplest, if not my fastest, and it runs in around 5-6 ms on my 1.80 GHz processor for n = 1 million. However, when I add a simple 'if' statement to take care of the cases where n <= 1 or s (the start number) > n, the run-time increases by a factor of 15 to around 80-90 ms.
using BenchmarkTools
function get_primes_1(n::Int64, s::Int64=2)::Vector{Int64}
#=if n <= 1 || s > n
return []
end=#
sieve = fill(true, n)
for i = 3:2:isqrt(n) + 1
if sieve[i]
for j = i ^ 2:i:n
sieve[j]= false
end
end
end
pl = [i for i in s - s % 2 + 1:2:n if sieve[i]]
return s == 2 ? unshift!(pl, 2) : pl
end
#btime get_primes_1(1_000_000)
Output with the 'if' statement commented out, as above, is:
5.752 ms (25 allocations: 2.95 MiB)
Output with the 'if' statement included is:
86.496 ms (2121646 allocations: 35.55 MiB)
I'm probably embarrassingly ignorant or being terminally stupid, but if someone could point out what I'm doing wrong it would be very much appreciated.
The problem of this function is with Julia compiler having problems with type inference when closures appear in your function. In this case the closure is a comprehension and the problem is that if statement makes sieve to be only conditionally defined.
You can see this by moving sieve up:
function get_primes_1(n::Int64, s::Int64=2)::Vector{Int64}
sieve = fill(true, n)
if n <= 1 || s > n
return Int[]
end
for i = 3:2:isqrt(n) + 1
if sieve[i]
for j = i ^ 2:i:n
sieve[j]= false
end
end
end
pl = [i for i in s - s % 2 + 1:2:n if sieve[i]]
return s == 2 ? unshift!(pl, 2) : pl
end
However, this makes sieve to be created also when n<1 which you want to avoid I guess :).
You can solve this problem by wrapping sieve in let block like this:
function get_primes_1(n::Int64, s::Int64=2)::Vector{Int64}
if n <= 1 || s > n
return Int[]
end
sieve = fill(true, n)
for i = 3:2:isqrt(n) + 1
if sieve[i]
for j = i ^ 2:i:n
sieve[j]= false
end
end
end
let sieve = sieve
pl = [i for i in s - s % 2 + 1:2:n if sieve[i]]
return s == 2 ? unshift!(pl, 2) : pl
end
end
or avoiding an inner closure for example like this:
function get_primes_1(n::Int64, s::Int64=2)::Vector{Int64}
if n <= 1 || s > n
return Int[]
end
sieve = fill(true, n)
for i = 3:2:isqrt(n) + 1
if sieve[i]
for j = i ^ 2:i:n
sieve[j]= false
end
end
end
pl = Int[]
for i in s - s %2 +1:2:n
sieve[i] && push!(pl, i)
end
s == 2 ? unshift!(pl, 2) : pl
end
Now you might ask how can you detect such problems and make sure that some solution solves them? The answer is to use #code_warntype on a function. In your original function you will notice that sieve is Core.Box which is an indication of the problem.
See https://github.com/JuliaLang/julia/issues/15276 for details. In general this is in my perception the most important issue with performance of Julia code which is easy to miss. Hopefully in the future the compiler will be smarter with this.
Edit: My suggestion actually doesn't seem to help. I missed your output annotation, so the return type appears to be correctly inferred after all. I am stumped, for the moment.
Original answer:
The problem isn't that there is an if statement, but that you introduce a type instability inside that if statement. You can read about type instabilities in the performance section of the Julia manual here.
An empty array defined like this: [], has a different type than a vector of integers:
> typeof([1,2,3])
Array{Int64,1}
> typeof([])
Array{Any,1}
The compiler cannot predict what the output type of the function will be, and therefore produces defensive, slow code.
Try to change
return []
to
return Int[]

Trouble in Making an isPrime Function

This is a homework. OCaml seems to be made by a psychopath.
let prime : int -> bool
= fun n ->
if n > 2 then
let a = n - 1 in
let rec divisor n a =
if a > 1 && n mod a = 0 then false
else if a = 2 && n mod a <> 0 then true
else divisor n a-1 ;;
else if n = 2 then true
else if n = 1 then false
I am not good at coding and I know that my isPrime algorithm is wrong.
But I wonder where in my code is the mistake that produces the syntax error.
Also is there any way to define the isPrime function in a recursive form?
Example:
let rec prime n = ~
You'll get better responses from experts if you don't gratuitously insult their language :-) But I'm an easygoing guy, so I'll take a stab at your syntax error.
There are quite a few problems in this code. Here are 3 that I see right off:
The symbol ;; is used to tell the interpreter that you've entered a full expression that you want it to evaluate. It's definitely out of place in the middle of a function declaration.
Your second let doesn't have an associated in. Every let must have an in after it. The only exception is for defining values at the top level of a module (like your prime function).
The expression divisor n a-1 is parsed as (divisor n a) - 1. You want parentheses like this: divisor a (n - 1).

OCaml: retain value of variable with control statements

I'm very new to OCaml / functional programming, and I'm confused about the implementation of some things that are relatively simple other languages I know. I could use any and all help.
Chiefly: in a program I'm working on, I either increment or decrement a variable based on a certain parameter. Here's something representative of what I have:
let tot = ref 0 in
for i = 0 to s do
if test_num > 0 then
tot := !tot + other_num
else
tot := !tot - other_num
done;;
This is obviously not the way to go about it, because even if the else statement is never taken, the code acts as if it is, each and every time, presumably because it's closer to the bottom of the program? I know OCaml has pretty sophisticated pattern matching, but within this level of coed I need access to a handful of lists I've already created, and, as far as I understand, I can't access those lists from a top-level function without passing them all as parameters.
I know I'm going about this the wrong way, but I have no idea how to do this idiomatically.
Suggestions? Thanks.
edit
Here's a more concise example:
let ex_list = [1; -2; 3; -4] in
let max_mem = ref 0 in
let mem = ref 0 in
let () =
for i = 0 to 3 do
let transition = List.nth ex_list i in
if transition > 0 then (
mem := (!mem + 10);
) else
mem := (!mem - 1);
if (!mem > !max_mem) then (max_mem := !mem);
done;
print_int !max_mem; print_string "\n";
in !mem;
At the end, when I print max_mem, I get 19, though this value should be (0 + 10 - 1 + 10 - 1 = 18). Am I doing the math wrong, or does the problem come from somewhere else?
Your code looks fine to me. It doesn't make a lot of sense as actual code, but I think you're just trying to show a general layout. It's also written in imperative style, which I usually try to avoid if possible.
The if in OCaml acts just like it does in other languages, there's no special thing about being near the bottom of the program. (More precisely, it acts like the ? : ternary operator from C and related languages; i.e., it's an expression.)
Your code doesn't return a useful value; it always returns () (the quintessentially uninteresting value known as "unit").
If we replace your free variables (ones not defined in this bit of code) by constants, and change the code to return a value, we can run it:
# let s = 8 in
let other_num = 7 in
let test_num = 3 in
let tot = ref 0 in
let () =
for i = 0 to s do
if test_num > 0 then
tot := !tot + other_num
else
tot := !tot - other_num
done
in
!tot;;
- : int = 63
#
If you're trying to learn to write in a functional style (i.e., without mutable variables), you would write this loop as a recursive function and make tot a parameter:
# let s = 8 in
let other_num = 7 in
let test_num = 3 in
let rec loop n tot =
if n > s then
tot
else
let tot' =
if test_num > 0 then tot + other_num else tot - other_num
in
loop (n + 1) tot'
in
loop 0 0;;
- : int = 63
It would probably be easier to help if you gave a (edited to add: small :-) self-contained problem that you're trying to solve.
The other parts of your question aren't clear enough to give any advice on. One thing that I might point out is that it's completely idiomatic to use pattern matching when processing lists.
Also, there's nothing wrong with passing things as parameters. That's why the language is called "functional" -- your code consists of functions, which have parameters.
Update
I like to write let () = expr1 in expr2 instead of expr1; expr2. It's just a habit I got into, sorry if it's confusing. The essence is that you're evaluating the first expression just for its side effects (it has type unit), and then returning the value of the second expression.
If you don't have something after the for, the code will evaluate to (), as I said. Since the purpose of the code seems to be to compute the value of !tot, this is what I returned. At the very least, this lets you see the calculated value in the OCaml top level.
tot' is just another variable. If you calculate a new value straightforwardly from a variable named var, it's conventional to name the new value var'. It reads as "var prime".
Update 2
Your example code works OK, but it has the problem that it uses List.nth to traverse a list, which is a slow (quadratic) operation. In fact your code is naturally considered a fold. Here's how you might write it in a functional style:
# let ex_list = [1; -2; 3; -4] in
let process (tot, maxtot) transition =
let tot' = if transition > 0 then tot + 10 else tot - 1 in
(tot', max maxtot tot')
in
List.fold_left process (0, 0) ex_list;;
- : int * int = (18, 19)
#
In addition to Jeffrey's answer, let me second that this is not how you would usually write such code in Ocaml, since it is a very low-level imperative approach. A more functional version would look like this:
let high ex_list =
let deltas = List.map (fun x -> if x > 0 then 10 else -1) ex_list in
snd (List.fold_left (fun (n, hi) d -> (n+d, max (n+d) hi)) (0, 0) deltas)
let test = high [1; -2; 3; -4]