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.
Related
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!
I'm trying to create a loop that will evaluate this equation.
10
y = ∑X^j
j=0
When x = 5. I am trying to use this code
y=0 # initialize y to 0
x = 5
for(i in 1:5){y[i] = (exp(x[0:10]))}
print(y)
but I can't seem to even get the exponents right, let alone the summation. Anyone know how to use a for loop to evaluate this sum?
The code is mixing a for loop with a sequence which is likely not going to produce the results you want. Also, the error that "number of items to replace is not a multiple of replacement length" shows there is a problem with the sequence and trying to index a single value.
x <- 5
y <- 0
for (i in 0:10) {
y <- y + x ^ i
}
Comparing the results to the most succint way listed above shows the results are the same.
> setequal(y, sum(x^(0:10)))
[1] TRUE
Background
I read here that newton method fails on function x^(1/3) when it's inital step is 1. I am tring to test it in julia jupyter notebook.
I want to print a plot of function x^(1/3)
then I want to run code
f = x->x^(1/3)
D(f) = x->ForwardDiff.derivative(f, float(x))
x = find_zero((f, D(f)),1, Roots.Newton(),verbose=true)
Problem:
How to print chart of function x^(1/3) in range eg.(-1,1)
I tried
f = x->x^(1/3)
plot(f,-1,1)
I got
I changed code to
f = x->(x+0im)^(1/3)
plot(f,-1,1)
I got
I want my plot to look like a plot of x^(1/3) in google
However I can not print more than a half of it
That's because x^(1/3) does not always return a real (as in numbers) result or the real cube root of x. For negative numbers, the exponentiation function with some powers like (1/3 or 1.254 and I suppose all non-integers) will return a Complex. For type-stability requirements in Julia, this operation applied to a negative Real gives a DomainError. This behavior is also noted in Frequently Asked Questions section of Julia manual.
julia> (-1)^(1/3)
ERROR: DomainError with -1.0:
Exponentiation yielding a complex result requires a complex argument.
Replace x^y with (x+0im)^y, Complex(x)^y, or similar.
julia> Complex(-1)^(1/3)
0.5 + 0.8660254037844386im
Note that The behavior of returning a complex number for exponentiation of negative values is not really different than, say, MATLAB's behavior
>>> (-1)^(1/3)
ans =
0.5000 + 0.8660i
What you want, however, is to plot the real cube root.
You can go with
plot(x -> x < 0 ? -(-x)^(1//3) : x^(1//3), -1, 1)
to enforce real cube root or use the built-in cbrt function for that instead.
plot(cbrt, -1, 1)
It also has an alias ∛.
plot(∛, -1, 1)
F(x) is an odd function, you just use [0 1] as input variable.
The plot on [-1 0] is deducted as follow
The code is below
import numpy as np
import matplotlib.pyplot as plt
# Function f
f = lambda x: x**(1/3)
fig, ax = plt.subplots()
x1 = np.linspace(0, 1, num = 100)
x2 = np.linspace(-1, 0, num = 100)
ax.plot(x1, f(x1))
ax.plot(x2, -f(x1[::-1]))
ax.axhline(y=0, color='k')
ax.axvline(x=0, color='k')
plt.show()
Plot
That Google plot makes no sense to me. For x > 0 it's ok, but for negative values of x the correct result is complex, and the Google plot appears to be showing the negative of the absolute value, which is strange.
Below you can see the output from Matlab, which is less fussy about types than Julia. As you can see it does not agree with your plot.
From the plot you can see that positive x values give a real-valued answer, while negative x give a complex-valued answer. The reason Julia errors for negative inputs, is that they are very concerned with type stability. Having the output type of a function depend on the input value would cause a type instability, which harms performance. This is less of a concern for Matlab or Python, etc.
If you want a plot similar the above in Julia, you can define your function like this:
f = x -> sign(x) * abs(complex(x)^(1/3))
Edit: Actually, a better and faster version is
f = x -> sign(x) * abs(x)^(1/3)
Yeah, it looks awkward, but that's because you want a really strange plot, which imho makes no sense for the function x^(1/3).
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.
how would I write a function which chooses between two functions depending on whether the argument is larger or smaller zero and writes the generated values into a y vector so that one can plot(x,y). Can you please tell me whether this is the right ansatz or not:
x <- runif(20,-20,20)
y <- numeric()
f <- function(x){
if(x>0){y <- c(y,x^2)}
if(x<0){y <- c(y,x^3)}
}
for(i in x){f(x)}
plot(x,y)
As I can see, there are few problems with your code:
Your function f does not return any meaningful values. The assignment to y
is not global and remains in the scope of the function.
Many operations in R are vectorized (i.e. they are performed on the whole vectors instead of individual elements), and this is an important feature of a good R code, but your code does not take advantage of that. To give a gist, when you do x > 0, and x is a vector, it will return a boolean vector where condition is checked for every element of x. When you do x^2, it returns a numeric vector where every element is a square of the corresponding element in x. ifelse is also a vectorized operator, so it also checks the condition for every element in the vector. By knowing that, you can get rid of your function and loop and do y <- ifelse(x<0,x^3,x^2).
You don't need the loop, and in this case it is not even necessary to define f(x) and to store the output in a vector y.
Something like
x <- runif(20,-20,20)
plot(x,ifelse(x<0,x^3,x^2))
should do. The second argument can take several versions, as discussed in the comments.
If you want to store the function and the data for later use, try
x <- runif(20,-20,20)
f <- function(x) ifelse (x < 0, x^3, x^2)
y <- f(x)
plot (x,y)
Here is another option...
x <- runif(20,-20,20)
y <- x^2*(x>0)+x^3*(x<=0)
plot(x,y)
R will interpret (x > 0) as a boolean (T or F) and then automatically transform it to 1 and 0.