Accessing values in expression using a macro - julia

I'm wondering whether it's possible to define a macro that can modify the values of an expression only if the values are of a specific type?
Here's a minimal example:
type Special
x::Int
end
f1(s, n::Special) = println("f1", s, n)
f2(s, n::Special) = println("f2", s, n)
x1 = Special(3)
x2 = Special(5)
expr = :(
f1("this is f1", x1),
f2("this is f2", x2)
)
Now a macro might be able to examine the values of the arguments to the functions, determine that x1 and x2 are of type Special, run some function to modify their values, say by changing 3 to 4 and 5 to 2 (it might involve comparing two values), then pass the expression back to the caller. The final result would be equivalent to calling:
f1("this is f1", 4)
f2("this is f2", 2)
I found that it's possible to access the values in a macro via:
eval(eval(filter(x -> typeof(eval(x)) == Special, expr.args[1].args))[1]).x
=> 3
but although this works it looks wrong, and I'm might either be doing it wrong or trying to do something too way out...

No, you should never try to check types or values inside macros. Using eval to figure out the type or value of something in a macro may work in very limited situations, but it'll break in almost every real use. Instead, just have the macro insert a call to a generic function — that's where Julia excels at picking apart types (as method dispatch) and values (within the method):
munge_special(x::Special) = Special(x.x + 42)
munge_special(x) = x
macro do_something_special(x)
return :(munge_special($(esc(x))))
end
julia> #do_something_special Special(2)
Special(44)
julia> #do_something_special 3
3

Related

Creating an array of `nothing` of any size in Julia

In Julia it is possible to create arrays of any size using the functions zeros(.) or ones(.). Is there a similar function to create an array that is filled with nothing at initialization but also accepts floats? I mean a function like in this example:
a = array_of_nothing(3)
# a = [nothing,nothing,nothing]
a[1] = 3.14
# a = [3.14,nothing,nothing]
I tried to find information on internet, but without success... Sorry, I am a beginner in Julia.
The fill function can be used to create arrays of arbitrary values, but it's not so easy to use here, since you want a Vector{Union{Float64, Nothing}}. Two options come to mind:
A comprehension:
a = Union{Float64, Nothing}[nothing for _ in 1:3];
a[2] = 3.14;
>> a
3-element Array{Union{Nothing, Float64},1}:
nothing
3.14
nothing
Or ordinary array initialization:
a = Vector{Union{Float64, Nothing}}(undef, 3)
fill!(a, nothing)
a[2] = 3.14
It seems that when you do Vector{Union{Float64, Nothing}}(undef, 3) the vector automatically contains nothing, but I wouldn't rely on that, so fill! may be necessary.
I think you are looking for the Base.fill — Function.
fill(x, dims)
This creates an array filled with value x.
println(fill("nothing", (1,3)))
You can also pass a function Foo() like fill(Foo(), dims) which will return an array filled with the result of evaluating Foo() once.

How can I interpret user input as a function in Julia?

I've been using the following function to take in user input for something I'm writing in Julia:
function input(prompt::AbstractString = "")
println(prompt * " ")
chomp(readline())
end
In my particular case, the input that I'm taking in is in the form of equations such as "y = x^2". After the input() function passes it to me as an ASCIIString, I then use the parse() function to convert it to an Expression:
:(y = x^2)
As an Expression, I can use the .args attribute to do things like counting the number of variables and returning the unique variables, all of which has worked fine. Now, I need to be able to evaluate the right side of the expression as the Function f(x) = x^2. To do so, I began writing the following function (which has some pretty major flaws):
function evalExpression()
L = [1,2,3,4]
equation = parse(input("Enter an equation"))
f = equation.args[2].args[2]
for i in L
x = i
value = eval(f)
println(value)
end
end
This function has two problems that I haven't been able to resolve. The first is that it gives me an UndefVarError for x when I try to run it right now; that's more or less expected. The second is that unless I knew that the user would input a function of only x, I would have no way of figuring out what the variables I needed to assign were. I wrote a recursive function that can take in an expression and return all its variables in the form of [:x, :y, etc.], but I cannot assign :x to a number to evaluate the function--I need to assign it just to x, and I cannot figure out how to access that. Is there anything that I can use to access the variables I need? Or a different approach I could take?
Thank you!
When I run the following:
function evalExpression()
L = [1,2,3,4]
equation = parse(input("Enter an equation"))
global x
for i in L
x = i
f = equation.args[2].args[2]
value = eval(f)
println(value)
end
end
and then putting y = x*x I get
evalExpression()
Enter an equation
y = x*x
1
2
3
4
What is missing, at least for x as a variable, is declaring it globally. When you eval parsed statements, these parsed statements only access global variables
So what you probably need to do after you've invented your recursive function to correctly fetch variables, is to create them globally. Maybe
eval(parse("$variable = 0"))
will do

Julia: show body of function (to find lost code)

In the R-language I am able to declare a function and to see the body of the function like so:
> megafoobar = function(x){ return(x + 10000 )}
> body(megafoobar)
{
return(x + 10000)
}
Is something like this also possible in Julia? I wrote a function that was very useful and it is still in memory/callable but I forgot how I wrote it. I am hoping such a method exists in Julia so I can find out how I wrote it.
For functions defined in a package, you can use less or #less.
The former, takes a function name (and returns the first definition,
which need not be the one you want), the latter, a function call.
less(less) # First definition of less,
# with signature (String,Integer)
#less less(less) # Definition of less(f::Callable)
But this will not work with functions you defined yourself in the REPL.
For those, you can use code_typed, but it only returns the AST (abstract
syntax tree) of your code, which is less readable.
You also need to provide the type of the arguments,
because there can be several functions with the same name:
you can get them with methods.
f(x::Number) = x + 1
f(x::AbstractArray) = length(x)
methods(f)
# 2 methods for generic function "f":
# f(x::Number) at none:1
# f(x::AbstractArray{T,N}) at none:1
code_typed(f,(Number,)) # Give the argument types as a tuple
# 1-element Array{Any,1}:
# :($(Expr(:lambda, {:x}, {{},{{:x,Number,0}},{}}, :(begin # none, line 1:
# return x::Number + 1
# end))))
the answers said above are already good.
I personally use the good old ctrl+r in the REPL and write the name of the function as you define it to find the block of code when you define your function.

Passing constant arguments to a multidimensional rootfinder in Sage

I have a five-dimensional rootfinding problem I'd like to solve from within a Sage notebook, but the functions I wish to solve depend on other parameters that shouldn't be varied during the rootfinding. Figuring out how to set up a call to, say, scipy.optimize.newton_krylov has got me stumped. So let's say I have (with a,b,c,d,e the parameters I want to vary, F1,F2,F3,F4,F5 the five expressions I which to solve to be equal to F1Val,F2Val,F3Val,F4Val,F5Val, values I already know, and posVal another known parameter)
def func(a, b, c, d, e, F1Val, F2Val, F3Val, F4Val, F5Val, posVal):
F1.subs(x1=a,x2=b,x3=c,x4=d,x5=e,position=posVal)
F2.subs(x1=a,x2=b,x3=c,x4=d,x5=e,position=posVal)
F3.subs(x1=a,x2=b,x3=c,x4=d,x5=e,position=posVal)
F4.subs(x1=a,x2=b,x3=c,x4=d,x5=e,position=posVal)
F5.subs(x1=a,x2=b,x3=c,x4=d,x5=e,position=posVal)
return (F1-F1Val, F2-F2Val, F3-F3Val, F4-F4Val, F5-F5Val)
and now I want to pass this to a rootfinding function to yield func = (0,0,0,0,0). I want to pass an initial guess (a0, b0, c0, d0, e0) vector and a set of arguments (F1Val, F2Val, F3Val, F4Val, F5Val, posVal) for the evaluation, but I can't figure out how to do this. Is there a standard technique for this sort of thing? The multidimensional rootfinders in scipy seem to be lacking the args=() variable that the 1D rootfinders offer.
Best,
-user2275987
Well, I'm still not sure how to actually employ the Newton-Raphson method here, but using fsolve works, for functions that accept a vector of variables and a vector of constant arguments. I'm reproducing my proof of concept here
def tstfunc(xIn, constIn):
x = xIn[0]
y = xIn[1]
a = constIn[0]
b = constIn[1]
out = [x+2*y+a]
out.append(a*x*y+b)
return out
from scipy.optimize import fsolve
ans = fsolve(tstfunc, x0=[1,1], args=[0.3, 2.1])
print ans

Pari/GP: user defined functions

I have defined a couple of functions of arity 1, say func1(-) and func2(-). I have tested them and seen that they actually do what they are supposed to.
I wish to define a third function, say func3(-), that outputs the difference of func1(-) and func2(-). This is what I do
func3(k) = {j=func1(k)-func2(k); print(j)}
Nevertheless, it doesn't return what it ought to. Let us suppose that func1(5) outputs 10 and func2(5) outputs 2. Then, func3(5) ought to output an 8, right? It returns instead the output of func1(5) in one row, the output of func2(2) in another row, and then a zero (even though the difference of the corresponding outputs is not 0).
Do you know what's wrong with the definition of func3(-)?
A GP user function returns the last evaluated value. Here, it's the resut of
the 'print(j)' command, which prints j (side effect) and returns 'void',
which is typecast to 0 when it must be given a value, as here.
f1(x) = 10
f2(x) = 2
f3(x) = f1(x) - f2(x)
correctly returns 8. You didn't give the code for your func1 / func2
functions, but I expect you included a 'print' statement, maybe expecting it
to return a value. That's why you get outputs on different rows, before the 0.
If you don't like this 'return-last-evaluation-result' behaviour, you can use
explicit 'return (result)' statements.

Resources