My julia ray tracer returns StackOverFlowError - julia

I'm trying to write a ray tracer in julia but my main function returns StackOverFlowError. Below is my main function:
function trace(ray::Ray, surfaces::Array{Any, 1}, depth::Int64, maxDepth::Int64)
material, t = findIntersection(ray, surfaces, Inf)
if typeof(material) == Empty
Vec3(0,0,0)
end
if depth > maxDepth
Vec3(0,0,0)
end
if material.isLight == true
material.emittance
end
normal = material.normal
ρ = material.reflectance
BRDF = ρ/3.14159
R = randHemi(normal)
cosθ = dot(R,normal)
newRay = Ray(ray.s + t*ray.d, R)
In = trace(newRay, surfaces, depth+1, maxDepth)
2.0*3.14159*BRDF*In
end
And here is my intersection function:
function findIntersection(ray::Ray, surfaces::Array{Any, 1}, tmin::Float64)
hitSurface = Empty(Vec3(0,0,0), Vec3(0,0,0), Vec3(0,0,0), false)
for surface in surfaces
t = intersect(surface, ray)
if t < tmin
hitSurface = surface
tmin = t
end
end
return hitSurface, tmin
end
But I receive this error:
StackOverflowError:
Stacktrace:
[1] findIntersection(::Ray, ::Array{Any,1}, ::Float64) at .\In[31]:10
[2] trace(::Ray, ::Array{Any,1}, ::Int64, ::Int64) at .\In[33]:2
[3] trace(::Ray, ::Array{Any,1}, ::Int64, ::Int64) at .\In[33]:18 (repeats
14493 times)
[4] top-level scope at In[35]:1
What is the cause of error?

Your problem is that you missed a return.
What you meant to have was
if depth > maxDepth
return Vec3(0,0,0)
end
Without the return, that line just allocates a Vec3, and the code continues looping.

Stackoverflow error usually occurs when there are too many recursive calls. In a nutshell, in most programming languages there is a limit on how many recursive calls you can make.
In your example, the trace functions calls itself recursively and it can cause an stack overflow. You have a parameters maxDepth that can limit that. Setting it to a lower value will probably solve this particular issue.

Related

LoadError: MethodError: "Method too new to be called from this world context." in Julia

Can someone explain in simple terms why this error occurs and how it can be avoided except not placing the code in main in a function?
Please refer to question Improving the performance of SymPy function generated from string in Julia for the function string_to_func.
Works:
using SymPy
function string_to_func(function_string)
func_lambdify = lambdify(SymPy.sympify(function_string), invoke_latest=false)
#eval func(x, y, z) = ($func_lambdify)(x, y, z)
return Nothing
end
function_string = "x + y + z"
string_to_func(function_string)
result = func(1, 2, 3)
Throws Error:
using SymPy
function string_to_func(function_string)
expr = lambdify(SymPy.sympify(function_string), invoke_latest=false)
#eval func(x, y, z) = ($expr)(x, y, z)
return Nothing
end
function main()
function_string = "x + y + z"
string_to_func(function_string)
result = func(1, 2, 3)
end
main()
Anonymized Error Message:
ERROR: LoadError: MethodError: no method matching func(::Int64, ::Int64, ::Int64)
The applicable method may be too new: running in world age 29676, while current world is 29678.
Closest candidates are:
func(::Any, ::Any, ::Any) at path_to_folder\test.jl:5 (method too new to be called from this world context.)
Stacktrace:
[1] main()
# Main path_to_folder\test.jl:12
[2] top-level scope
# path_to_folder\test.jl:15
in expression starting at path_to_folder\test.jl:15
You need to invoke func using Base.invokelatest, i.e.
function main()
function_string = "x + y + z"
string_to_func(function_string)
result = Base.invokelatest(func, 1, 2, 3)
end
See the manual for further details about world age and why invokelatest is needed here.
I should also mention GeneratedFunctions.jl that can avoid some of the overhead associated with invokelatest, although it has it is own caveats since its somewhat of a hack.

How to pass a list of parameters to workers in Julia Distributed

with Julia 1.5.3, I wanted to pass a list or parameters to the distributed workers.
I first tried in a non distributed way :
using Distributed
#everywhere begin
using SharedArrays
solve(a,b,c) = return (1,2,3)
d_rates = LinRange(0.01, 0.33, 5)
m_rates = LinRange(0.01, 0.25, 5)
population_size = 10^3
max_iterations_perloop = 10^3
nb_repeats = 2
nb_params = length(d_rates)*length(m_rates)*nb_repeats
para = enumerate(Base.product(d_rates, m_rates, population_size, max_iterations_perloop, 1:nb_repeats))
results = SharedArray{Tuple{Int, Int, Int}}(nb_params)
end
for (y , x) in para
results[y] = solve(x[1], x[2], x[3])
end
which worked fine. And then changed the final loop to:
#sync #distributed for (y , x) in para
results[y] = solve(x[1], x[2], x[3])
end
I then got an error (truncated):
ERROR: LoadError: TaskFailedException:
MethodError: no method matching firstindex(::Base.Iterators.Enumerate{Base.Iterators.ProductIterator{Tuple{LinRange{Float64},LinRange{Float64},Int64,Int64,UnitRange{Int64}}}})
Closest candidates are:
firstindex(::Cmd) at process.jl:638
firstindex(::Core.SimpleVector) at essentials.jl:599
firstindex(::Base64.Buffer) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.5/Base64/src/buffer.jl:18
...
Stacktrace:
[1] (::Distributed.var"#159#161"{var"#271#272",Base.Iterators.Enumerate{Base.Iterators.ProductIterator{Tuple{LinRange{Float64},LinRange{Float64},Int64,Int64,UnitRange{Int64}}}}})() at ./task.jl:332
Stacktrace:
[1] sync_end(::Channel{Any}) at ./task.jl:314
[2] top-level scope at task.jl:333
[3] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1088
[4] include_string(::Module, ::String, ::String) at ./loading.jl:1096
[5] invokelatest(::Any, ::Any, ::Vararg{Any,N} where N; kwargs::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}) at ./essentials.jl:710
[6] invokelatest(::Any, ::Any, ::Vararg{Any,N} where N) at ./essentials.jl:709
Is it possible to pass such a list, if so how?
I assume that all your workers are on a single server and that you have actually added some workers using the addprocs command. The first problem with your code is that you create the SharedArray on all workers. Rather than that the syntax of a SharedArray is the following:
help?> SharedArray
SharedArray{T}(dims::NTuple; init=false, pids=Int[])
SharedArray{T,N}(...)
Construct a SharedArray of a bits type T and size dims across the processes specified by pids - all of which have to be on the same host. (...)
This means that you create SharedArray only once from the master worker and you can specify the workers that are aware of it using the pids argument (if you do not specify pids all worker processes have the access).
Hence your code will look like this:
using Distributed, SharedArrays
addprocs(4)
#everywhere using SharedArrays
#everywhere solve(a,b,c) = return (1,2,3)
#(...) # your setup code without #everywhere
results = SharedArray{Tuple{Int, Int, Int}}(nb_params)
#sync #distributed for (y , x) in collect(para)
results[y] = solve(x[1], x[2], x[3])
end
Note that you will need collect because #distributed macro needs to know the size of the Vector and it does not work good with iterators.

InexactError: Int64(::Float64)

I am still learning the language Julia and i have this error. I am writing an mosquito population model and i am trying to run my main function a 100 times. This main function uses many other functions to calculate the subpopulation levels.
# Importing KNMI data
xf = XLSX.readxlsx("C:/Scriptie_mosquitoes/knmi_csv.xlsx")
sh = xf["knmi_csv"]
temperature = sh["B3:B368"]
precip = sh["F3:F368"]
subpopulation_amount = 100
imat_list1 = zeros(100,length(temperature))
imat_list = Array{Float64}(imat_list1)
adul_list1 = zeros(100,length(temperature))
adul_list = Array{Float64}(adul_list1)
egg_list1 = zeros(100,length(temperature))
egg_list = Array{Float64}(egg_list1)
diaegg_list1 = zeros(100,length(temperature))
diaegg_list = Array{Float64}(diaegg_list1)
imat_list[1] = 100.0
adul_list[1] = 1000.0
egg_list[1] = 100.0
diaegg_list[1] = 100.0
for counter = 1:1:subpopulation_amount
u = Distributions.Normal()
temp_change = rand(u)
tempa = temperature .+ temp_change
println(tempa)
e = Distributions.Normal()
precip_change = rand(e)
println("hallo", precip_change)
println(counter,tempa,precip,precip_change)
main(counter,tempa::Array{Float64,2},precip::Array{Any,2},precip_change::Float64,imat_list::Array{Float64,2},adul_list::Array{Float64,2},egg_list::Array{Float64,2},diaegg_list::Array{Float64,2})
end
However i get this error which i tried to fix with all the Float64 stuf. I doesn't work unfortunatly. I hope some of you guys see the problem or can help me with understanding the error message.
ERROR: InexactError: Int64(87.39533010546728)
Stacktrace:
[1] Int64 at .\float.jl:710 [inlined]
[2] convert at .\number.jl:7 [inlined]
[3] setindex! at .\array.jl:825 [inlined]
[4] main(::Int64, ::Array{Float64,2}, ::Array{Any,2}, ::Float64, ::Array{Float64,2}, ::Array{Float64,2}, ::Array{Float64,2}, ::Array{Float64,2}) at .\REPL[905]:19
[5] top-level scope at .\REPL[938]:10
You can check the documentation for InexactError by typing ?InexactError:
help?> InexactError
search: InexactError
InexactError(name::Symbol, T, val)
Cannot exactly convert val to type T in a method of function name.
I think that explains it nicely. There is no Int64 that represents the value 87.39533010546728.
You have a variety of options available. Check their help to learn more about them:
julia> trunc(Int, 87.39533010546728)
87
julia> Int(round(87.39533010546728))
87
julia> Int(floor(87.39533010546728))
87
We do not see the code of main. However it seems that you are using values of one of the Arrays that you have as its argument to use for indexing some vector in your code. And since vector indices need to be integers it fails. Most likely some variable is in wrong place in your main - look around [] operators.
When debugging you could also try to change your Arrays to Int elements and see which change causes the problem to stop. E.g. round.(Int, tempa) etc.
The problem is just what it says: you cannot exactly represent a decimal number (87.39) as an integer.
You need to decide what you want to do here - one option is to just round() your decimal number before converting it to an integer.
It's hard to say from the code you posted where exactly the error occurs, but one potentially less obvious way for this to happen is if you try to index into an array (e.g. my_array[i]), and your calculations lead to i having a non-integer value.

Getting the whole AST of the file / complex code

Julia manual states:
Every Julia program starts life as a string:
julia> prog = "1 + 1"
"1 + 1"
I can easily get the AST of the simple expression, or even a function with the help of quote / code_*, or using Meta.parse / Meta.show_sexpr if I have the expression in a string.
The question: Is there any way to get the whole AST of the codepiece, possibly including several atomic expressions? Like, read the source file and convert it to AST?
If you want to do this from Julia instead of FemtoLisp, you can do
function parse_file(path::AbstractString)
code = read(path, String)
Meta.parse("begin $code end")
end
This takes in a file path, reads it and parses it to a big expression that can be evaluated.
This comes from #NHDaly's answer, here:
https://stackoverflow.com/a/54317201/751061
If you already have your file as a string and don’t want to have to read it again, you can instead do
parse_all(code::AbstractString) = Meta.parse("begin $code end")
It was pointed out on Slack by Nathan Daly and Taine Zhao that this code won't work for modules:
julia> eval(parse_all("module M x = 1 end"))
ERROR: syntax: "module" expression not at top level
Stacktrace:
[1] top-level scope at REPL[50]:1
[2] eval at ./boot.jl:331 [inlined]
[3] eval(::Expr) at ./client.jl:449
[4] |>(::Expr, ::typeof(eval)) at ./operators.jl:823
[5] top-level scope at REPL[50]:1
This can be fixed as follows:
julia> eval_all(ex::Expr) = ex.head == :block ? for e in ex eval_all(e) end : eval(e);
julia> eval_all(ex::Expr) = ex.head == :block ? eval.(ex.args) : eval(e);
julia> eval_all(parse_all("module M x = 1 end"));
julia> M.x
1
Since the question asker is not convinced that the above code produces a tree, here is a graph representation of the output of parse_all, clearly showing a tree structure.
In case you're curious, those leaves labelled #= none:1 =# are line number nodes, indicating the line on which each following expression takes place.
As suggested in the comments, one can also apply Meta.show_sexpr to an Expr object to get a more "lispy" representation of the AST without all the pretty printing julia does by default:
julia> (Meta.show_sexpr ∘ Meta.parse)("begin x = 1\n y = 2\n z = √(x^2 + y^2)\n end")
(:block,
:(#= none:1 =#),
(:(=), :x, 1),
:(#= none:2 =#),
(:(=), :y, 2),
:(#= none:3 =#),
(:(=), :z, (:call, :√, (:call, :+, (:call, :^, :x, 2), (:call, :^, :y, 2))))
)
There's jl-parse-file in the FemtoLisp implementation of the Julia parser. You can call it from the Lisp REPL (julia --lisp), and it returns an S-expression for the whole file. Since Julia's Expr is not much different from Lisp S-expressions, that might be enough for you purposes.
I still wonder how one would access the result of this from within Julia. If I understand correctly, the Lisp functions are not exported from libjulia, so there's no direct way to just use a ccall. But maybe a variant of jl_parse_eval_all can be implemented.

JuMP variable declaration: MethodError

I'm following the quickstart guide on JuMP.
My julia version is 0.7, the code is this:
using JuMP
m = Model()
l = zeros(10)
u = ones(10)
##variable(m, x)
##variable(m, 0 <= x[1:10] <= 1)
#variable(m, l<=x[1:10]<=u)
The first two variable macros (commented out) work fine, but the last one produces an error.
MethodError: no method matching constructvariable!(::Model, ::getfield(JuMP, Symbol("#_error#107")){Tuple{Symbol,Expr}}, ::Array{Float64,1}, ::Array{Float64,1}, ::Symbol, ::String, ::Float64)
Closest candidates are:
constructvariable!(::Model, ::Function, !Matched::Number, !Matched::Number, ::Symbol, ::AbstractString, ::Number; extra_kwargs...) at /home/lhk/.julia/packages/JuMP/Xvn0n/src/macros.jl:968
constructvariable!(::Model, ::Function, !Matched::Number, !Matched::Number, ::Symbol, !Matched::Number, !Matched::Array{T,1} where T, !Matched::Array{Float64,1}, !Matched::AbstractString, !Matched::Number; extra_kwargs...) at /home/lhk/.julia/packages/JuMP/Xvn0n/src/macros.jl:961
Stacktrace:
[1] top-level scope at /home/lhk/.julia/packages/JuMP/Xvn0n/src/macros.jl:1259
[2] top-level scope at In[18]:7
How can I have different bounds for each entry in a vector valued variable ?
Argh, this is actually really easy:
l = zeros(10)
u = ones(10)
#variable(m, l[idx] <= x[idx = 1:10] <= u[idx])

Resources