Julia: adding anonymous functions together - recursion

If I define some anonymous functions a(x) and b(x) as
a = x -> x^2
b = x -> 2x
it would be helpful for recursive problems to add them together, say over the duration of some loop:
for i=1:5
a = x -> a(x) + b(x)
end
where the goal would be to have this represented internally each loop iteration as
a = x -> x^2 + 2x
a = x -> x^2 + 2x + x^2 + 2x
a = x -> x^2 + 2x + x^2 + 2x + x^2 + 2x
...
But, this fails and returns some error. I'm assuming it's because calling the new a(x) is interpreted as: a(2) = 2 -> x^2 + x^2 + ... + x^2 + 2x
julia> a(2)
ERROR: StackOverflowError:
in (::##35#36)(::Int64) at ./REPL[115]:0
in (::##35#36)(::Int64) at ./REPL[115]:1 (repeats 26666 times)
Is there any way around this?

You can do exactly what you're looking for using the let keyword:
a = x -> x^2
b = x -> 2x
for i=1:5
a = let a = a; x -> a(x) + b(x); end
end
a(2) # returns 24
Explanation
The let keyword allows you to create a block with local scope, and return the last statement in the block back to its caller scope. (contrast that with the begin keyword for instance, which does not introduce new scope).
If you pass a sequence of "assignments" to the let keyword, these become variables local to the block (allowing you, therefore, to re-use variable names that already exist in your workspace). The declaration let a = a is perfectly valid and means "create a local variable a which is initialised from the a variable of the outer scope" --- though if we wanted to be really clear, we could have written it like this instead:
for i=1:5
a = let a_old = a
x -> a_old(x) + b(x);
end
end
then again, if you were willing to use an a_old variable, you could have just done this instead:
for i=1:5; a_old = a; a = x-> a_old(x) + b(x); end
let is a very useful keyword: it's extremely handy for creating on-the-spot closures; in fact, this is exactly what we did here: we have returned a closure, where the "local variable a" essentially became a closed variable.
PS. Since matlab was mentioned, what you're doing when you evaluate a = # (x) a(x) + b(x) in matlab is essentially creating a closure. In matlab you can inspect all the closed variables (i.e. the 'workspace' of the closure) using the functions command
PPS. The Dr Livingstone, I presume?

Using Polynomials package could be a way. This would go:
julia> using Polynomials # install with Pkg.add("Polynomials")
julia> x = Poly([0,1])
Poly(x)
julia> a = x^2
Poly(x^2)
julia> b = 2x
Poly(2*x)
julia> a = a+b
Poly(2*x + x^2)
julia> a(2.0)
8.0
The reason this works is because essentially the behavior you want is symbolic manipulation of functions. Julia does not work this way (it's a compiler - or ahead-of-time (AOT) compiler), but it is flexible. If fancier functions than polynomials are required, maybe a symbolic math package would help (there is SymPy, but I haven't used it).

This:
a = x -> a(x) + b(x)
is a recursive call with no stopping condition. It has nothing to do with Julia. As soon as you define this the previous definition (x^2) was overridden, and will have nothing to to with the stack or your result. It doesn't exist anymore. What you're trying to do is:
a(2) = a(2)+2*2 = (a(2)+2*2)+2*2 = ((a(2)+2*2)+2*2)+2*2 = ...
etc. The 2*2 will not even be substituted, I just wrote it to be clear. You probably want to define
c = x -> a(x) + b(x)
EDIT
I see now coming from MATLAB you're expecting the syntax to mean something else. What you wrote in nearly all languages is a recursive call, which you do not want. What you do want is something like:
concatFuncs => f1,f2 -> (x->f1(x)+f2(x))
This piece of code will take any to functions accepting an x and generate a + between the resulting calls. This will work with anything that '+' works with. So:
summed = concatFuncs(a,b)
is the function you need.

Related

How to calculate complex functions in Fortran which are not easy to separate into real and imaginary components?

I need to calculate a complex function for different x values, something like
(i+1) exp(i * x) / x
I see that my option is to expand it in terms of sin and cos, and then separate out real and imaginary parts manually by hand, to be able to calculate them individually in code, and then define my complex function. This is a relatively simple function, but I have some bigger ones, not so easy to segregate manually into two components.
Am I missing something or this is the only way?
EDIT : I am pasting the sample code which works after helpful comments from everyone below, hope it's useful :
program complex_func
IMPLICIT NONE
Real(8) x
complex CF
x = 0.7
call complex_example(x, CF)
write(*,*) CF
end program complex_func
Subroutine complex_example(y, my_CF)
Implicit None
Real(8) y
Complex my_CF
complex, parameter :: i = (0, 1) ! sqrt(-1)
my_CF = (i+1) * exp(i*y) / y
!my_CF = cmplx(1, 1) * exp(cmplx(0.0, y)) / y !!THIS WORKS, TOO
write(*,*) my_CF
return
end Subroutine complex_example

how to correctly pass a value to an included function?

I have 2 julia files, alpha.jl and beta.jl.
in alpha.jl, there are 2 functions:
der that returns a derivative using Zygote,
derPlot that plots the function as well as the derivative:
function der(f, x)
y = f'(x)
return y
end
function derPlt(der,z)
plot(f, aspect_ratio=:equal, label="f(x)")
g(f,x₀) = (x -> f(x₀) + f'(x₀)*(x-x₀))
plot!(g(f,x), label="dy",color="magenta")
xlims!(-z,z)
ylims!(-z,z)
end
everything comes out fine when i call these 2 functions in beta.jl, after including the files:
include("alpha.jl")
f(x)=-x^2+2
x = -1.3
derPlt(der(f, x), 6)
However, if i directly enter in a value for the function, the plotted derivative line doesnt update; i.e, if i enter 2.0 instead of passing in some variable named x,
derPlt(der(f, 2.0), 6)
no change is reflected on the plot. New to Julia, trying to understand and fix it.
I think it's because in your derPlt function, you call
plot!(g(f,x),...)
on x instead of the z argument. The problem is then that you define a x = -1.3, the value of which is used inside of derPlt, regardless of what z argument you feed it.
Maybe replace that line with
plot!(g(f,z),...)
and you should be fine.
Seeing as this is a follow up to a question I answered previously I thought I'd have to respond: Benoit is broadly speaking correct, you are running into a scoping issue here, but a few more changes are in order.
Note that your function signature is derPlot(der, z) but then:
You never actually use the der argument in your function body; and
You construct your tangent line as g(f,x₀) = (x -> f(x₀) + f'(x₀)*(x-x₀)) - note that there's no z in there, only an x
Now where does that x come from? In the absence of any x argument being passed to your function, Julia will look for it in the global scope (outside your function). Here, you define x = -1.3, and when you then call derPlt, that's the x that will be used to construct your tangent, irrespective of the z argument you're passing.
Here's a cleaned up and working version:
using Plots, Zygote
function derPlt(f,z)
plot(f, label="f(x)", aspect_ratio = :equal,
xlims = (-5,5), ylims = (-5,5))
g(f,x₀) = (z -> f(x₀) + f'(x₀)*(z-x₀))
plot!(i -> g(f, z)(i), label="dy",color="magenta")
end
f(x)=-x^2+2
derPlt(f, -1.5)
I would encourage you to read the relevant manual section on Scope of Variables to ensure you get an understanding of what's happening in your code - good luck!

plotting a line tangent to a function at a point

Heres a block of code that plots a function over a range, as well as the at a single input :
a = 1.0
f(x::Float64) = -x^2 - a
scatter(f, -3:.1:3)
scatter!([a], [f(a)])
i would like to plot the line, tangent to the point, like so:
Is there a pattern or simple tool for doing so?
That depends on what you mean by "pattern or simple tool" - the easiest way is to just derive the derivative by hand and then plot that as a function:
hand_gradient(x) = -2x
and then add plot!(hand_gradient, 0:0.01:3) to your plot.
Of course that can be a bit tedious with more complicated functions or when you want to plot lots of gradients, so another way would be to utilise Julia's excellent automatic differentiation capabilities. Comparing all the different options is a bit beyond the scope of this answer, but check out https://juliadiff.org/ if you're interested. Here, I will be using the widely used Zygote library:
julia> using Plots, Zygote
julia> a = 1.0;
julia> f(x) = -x^2 - a;
[NB I have slightly amended your f definition to be in line with the plot you posted, which is an inverted parabola]
note that here I am not restricting the type of input argument x to f - this is crucial for automatic differentiation to work, as it is implemented by runnning a different number type (a Dual) through your function. In general, restricting argument types in this way is an anti-pattern in Julia - it does not help performance, but makes your code less interoperable with other parts of the ecosystem, as you can see here if you try to automatically differentiate through f(x::Float64).
Now let's use Zygote to provide gradients for us:
julia> f'
#43 (generic function with 1 method)
as you can see, running f' now returns an anonymous function - this is the derivative of f, as you can verify by evaluating it at a specific point:
julia> f'(2)
-4.0
Now all we need to do is leverage this to construct a function that itself returns a function which traces out the line of the gradient:
julia> gradient_line(f, x₀) = (x -> f(x₀) + f'(x₀)*(x-x₀))
gradient_line (generic function with 1 method)
this function takes in a function f and a point x₀ for which we want to get the tangent, and then returns an anonymous function which returns the value of the tangent at each value of x. Putting this to use:
julia> default(markerstrokecolor = "white", linewidth = 2);
julia> scatter(f, -3:0.1:3, label = "f(x) = -x² - 1", xlabel = "x", ylabel = "f(x)");
julia> scatter!([1], [f(1)], label = "", markersize = 10);
julia> plot!(gradient_line(f, 1), 0:0.1:3, label = "f'(1)", color = 2);
julia> scatter!([-2], [f(-2)], label = "", markersize = 10, color = 3);
julia> plot!(gradient_line(f, -2), -3:0.1:0, label = "f'(-2)", color = 3)
It is overkill for this problem, but you could use the CalculusWithJulia package which wraps up a tangent operator (along with some other conveniences) similar to what is derived in the previous answers:
using CalculusWithJulia # ignore any warnings
using Plots
f(x) = sin(x)
a, b = 0, pi/2
c = pi/4
plot(f, a, b)
plot!(tangent(f,c), a, b)
Well, the tool is called high school math :)
You can simply calculate the slope (m) and intersect (b) of the tanget (mx + b) and then plot it. To determine the former, we need to compute the derivative of the function f in the point a, i.e. f'(a). The simplest possible estimator is the difference quotient (I assume that it would be cheating to just derive the parabola analytically):
m = (f(a+Δ) - f(a))/Δ
Having the slope, our tanget should better go through the point (a, f(a)). Hence we have to choose b accordingly as:
b = f(a) - m*a
Choosing a suitably small value for Δ, e.g. Δ = 0.01 we obtain:
Δ = 0.01
m = (f(a+Δ) - f(a))/Δ
b = f(a) - m*a
scatter(f, -3:.1:3)
scatter!([a], [f(a)])
plot!(x -> m*x + b, 0, 3)
Higher order estimators for the derivative can be found in FiniteDifferences.jl and FiniteDiff.jl for example. Alternatively, you could use automatic differentiation (AD) tools such as ForwardDiff.jl to obtain the local derivative (see Nils answer for an example).

1D integration with multivariable function input

To demonstrate, let's start with a simple multi-variable function f(x,y) = xy^2.
I am trying to find a command that would allow me to numerically integrate f(2, y) = 2y^2 from y = 0 to y = 2. (i.e. the original function is multi-variable, but only one variable remains when actually doing the integration)
I needed to define the function that way as I need to obtain the results using different values of x. (probably going to involve for-loop, but that is another story)
I have tried to walk through Cubature's user guide but apparently did not find anything useful. Maybe I have missed it
Can anyone help?
In such case it is simplest to use an anonymous function wrapper:
using QuadGK
f(x,y) = x*y^2
intf(x) = quadgk(y -> f(x, y), 0, 2)
if the anonymous function would be longer you could write:
intf(x) = quadgk(0, 2) do y
f(x, y)
end
This is an exact equivalent of the latter but do syntax allows you to write longer bodies of an anonymous function.
Now you can write e.g.:
julia> intf(1)
(2.6666666666666665, 4.440892098500626e-16)
julia> intf(2)
(5.333333333333333, 8.881784197001252e-16)
julia> intf(3)
(8.0, 0.0)

How does SML evaluate the arguments passed into currying function?

I write two different pieces of code trying to figure out the substitution v.s. evaluation order SML uses with respect to function arguments. But the results confused me a lot.
The toy function is as below
fun pow x y = if y=0 then 1 else x * (pow x y-1));
It only works as I expected when I surround the expression, i.e. y-1 with parens. So I augment it with a simple print statement to track what's going on.
fun pow x y = (print("y is: "^ Int.toString(y)^"\n");
if y = 0 then 1 else x * (pow x y-1))
It runs like value y remains the same every time the function is called( Apparently y-1 is not properly evaluated or parsed as a whole here.)
However, another dummy code I wrote below works perfectly out of my expectation, though.
fun foo x y= x+y;
val res= foo 2 3-9
res = -4 which does not run in the same logic as above.
Any insights on this will be appreciated!!
(I have read some simple illustration about adding parens allows to determine where the argument ends, but it's not so convincing)
pow x y - 1 is equivalent to (pow x y) - 1. The same is true for your foo example, but 2 + (3 - 9) and (2 + 3) - 9 actually have the same result, which is why you don't see a difference.

Resources