In the following example:
Fs = cell(2)
i = 1
for i = 1:2
local i # same as local i = i
Fs[i] = () -> i
end
println(Fs[1]()) # 1
println(Fs[2]()) # 2
println(i) # 1
Is it true that local i is the same as local i = i?
Why cannot I do the same for while loop as such?
Fs = cell(2)
i = 1
while i <= 2 #LoadError: UndefVarError: i not define
local i = i
Fs[i] = ()->i
i += 1
end
But have to use let:
Fs = cell(2)
i = 1
while i <= 2
let i = i
Fs[i] = ()->i
end
i += 1
end
println(Fs[1]()) # 1
println(Fs[2]()) # 2
When you introduce new variable, and try to get it's value before assignment, Julia throws an UndefVarError error, in the first example:
Fs = cell(2)
i = 1
for i = 1:2
local i # same as local i = i
Fs[i] = () -> i
end
println(Fs[1]()) # 1
println(Fs[2]()) # 2
println(i) # 1
For block introduces a new local i, adn for command itself assign it so the code successfully dose it's duty. But in the second example:
Fs = cell(2)
i = 1
while i <= 2 #LoadError: UndefVarError: i not define
local i = i
Fs[i] = ()->i
i += 1
end
A new i was introduced in while block, but before assignment you try to get it's value, and this produces an error.
In 3d one let command declare a new local block and a new i variable for it's block.
julia> function test3()
Fs = cell(2)
i = 1
while i <= 2
let i = 100
println(i)
end
i += 1
end
println(i)
end
test3 (generic function with 1 method)
julia> test3()
100
100
3# while block use the function's scope
Related
I have a set of integers that act as ids for other variables in my code. I wish to create a list of them, numbered from 1 to N:
i_counter = 0
i_counter = i_counter + 1
i_A = i_counter
i_counter = i_counter + 1
i_B = i_counter
...
Is there a way to write these in one line? I'd like to be able to rearrange the code line-by-line to change the order of the counters.
In Julia, each statement is also an expression, so you can just chain together statements to get what you want.
i_counter = 0
i_A = i_counter = i_counter + 1
i_B = i_counter = i_counter + 1
or more elegantly, as in Bogumil's comment
i_counter = 0
i_A = i_counter += 1
i_B = i_counter += 1
In other words, there is no need for anything analogous to Python's new "walrus" operator := in Julia, because every statement such as i_counter = i_counter + 1 is already an expression that returns a value.
I'm trying to implement the following code from here but it won't work correctly.
What I want is the shortest path distances from a source to all nodes and also the predecessors. Also, I want the input of the graph to be an adjacency matrix which contains all of the edge weights.
I'm trying to make it work in just one function so I have to rewrite it. If I'm right the original code calls other functions (from graph.jl for example).
I don't quite understand how to rewrite the for loop which calls the adj() function.
Also, I'm not sure if the input is correct in the way the code is for now.
function dijkstra(graph, source)
node_size = size(graph, 1)
dist = ones(Float64, node_size) * Inf
dist[source] = 0.0
Q = Set{Int64}() # visited nodes
T = Set{Int64}(1:node_size) # unvisited nodes
pred = ones(Int64, node_size) * -1
while condition(T)
# node selection
untraversed_nodes = [(d, k) for (k, d) in enumerate(dist) if k in T]
if minimum(untraversed_nodes)[1] == Inf
break # Break if remaining nodes are disconnected
end
node_ind = untraversed_nodes[argmin(untraversed_nodes)][2]
push!(Q, node_ind)
delete!(T, node_ind)
# distance update
curr_node = graph.nodes[node_ind]
for (neigh, edge) in adj(graph, curr_node)
t_ind = neigh.index
weight = edge.cost
if dist[t_ind] > dist[node_ind] + weight
dist[t_ind] = dist[node_ind] + weight
pred[t_ind] = node_ind
end
end
end
return dist, pred
end
So if I'm trying it with the following matrix
A = [0 2 1 4 5 1; 1 0 4 2 3 4; 2 1 0 1 2 4; 3 5 2 0 3 3; 2 4 3 4 0 1; 3 4 7 3 1 0]
and source 2 i would like to get the distances in a vector dist and the predeccessors in anothe vectore pred.
Right now I'm getting
ERROR: type Array has no field nodes
Stacktrace: [1] getproperty(::Any, ::Symbol) at .\sysimg.jl:18
I guess I have to rewrite it a bit more.
I m thankful for any help.
Assuming that graph[i,j] is a length of path from i to j (your graph is directed looking at your data), and it is a Matrix with non-negative entries, where 0 indicates no edge from i to j, a minimal rewrite of your code should be something like:
function dijkstra(graph, source)
#assert size(graph, 1) == size(graph, 2)
node_size = size(graph, 1)
dist = fill(Inf, node_size)
dist[source] = 0.0
T = Set{Int}(1:node_size) # unvisited nodes
pred = fill(-1, node_size)
while !isempty(T)
min_val, min_idx = minimum((dist[v], v) for v in T)
if isinf(min_val)
break # Break if remaining nodes are disconnected
end
delete!(T, min_idx)
# distance update
for nei in 1:node_size
if graph[min_idx, nei] > 0 && nei in T
possible_dist = dist[min_idx] + graph[min_idx, nei]
if possible_dist < dist[nei]
dist[nei] = possible_dist
pred[nei] = min_idx
end
end
end
end
return dist, pred
end
(I have not tested it extensively, so please report if you find any bugs)
for i=1:5
if(i==1)
z = i
end
println("i = $i, z = $z")
end
i = 1, z = 1
ERROR: UndefVarError: z not defined
Stacktrace:
[1] top-level scope at ./REPL[6]:5 [inlined]
[2] top-level scope at ./none:0
The behavior of the above script is puzzling to me. Can someone help me understand why the print works when i=1 but fails when i=2.
The answer by #Wookies-Will-Code is correct and here is the reason.
As the Julia manual explains here:
for loops, while loops, and Comprehensions have the following behavior: any new variables introduced in their body scopes are freshly allocated for each loop iteration
Which means that at the end each iteration z is forgotten.
In order to make sure the value of z is persistent across iterations (and also after for loop finishes) define z before the loop. For example like this:
function mytest()
local z
for i=1:5
if i==1
z = i
end
println("i = $i, z = $z")
end
end
and now you have:
julia> mytest()
i = 1, z = 1
i = 2, z = 1
i = 3, z = 1
i = 4, z = 1
i = 5, z = 1
Observe that the situation is different in global scope. Even if z is globally defined it is not reused by default:
julia> z = 100
100
julia> for i=1:5
if i==1
z = i
end
println("i = $i, z = $z")
end
i = 1, z = 1
ERROR: UndefVarError: z not defined
Stacktrace:
[1] top-level scope at .\REPL[7]:5 [inlined]
[2] top-level scope at .\none:0
The reason is that Julia treats z as local to the for loop, because z is assigned to inside the loop. This is a compile time feature check so even if the if condition always fails you will get this error:
julia> z = 100
100
julia> for i=1:5
if false
z = i
end
println("i = $i, z = $z")
end
ERROR: UndefVarError: z not defined
Stacktrace:
[1] top-level scope at .\REPL[18]:5 [inlined]
[2] top-level scope at .\none:0
You have to assign to z using global keyword to make it work:
julia> z = 100
100
julia> for i=1:5
if i==1
global z = i
end
println("i = $i, z = $z")
end
i = 1, z = 1
i = 2, z = 1
i = 3, z = 1
i = 4, z = 1
i = 5, z = 1
I do not use Julia, but here goes. I am not sure how to send the string that z is not defined, but here 2 different prinln based on the value of i, simplest way to do it, or else you have to check if z is defined, this is simpler.
for i=1:5
if(i==1)
z = i
println("i = $i, z = $z")
else
println("i = $i","z not defined")
end
end
I've made a code to calculate the result of divided differences method and lagrange method by interpolating points. I would also like to build a polynomial using symbolic variables but how can I accomplish this?
function dividedDifferences(X,Y,x)
ddMatrix = X'
ddMatrix(:,2) = Y'
for j=3:length(Y)+3
for i=1:length(Y)+2-j
ddMatrix(i,j) = (ddMatrix(i,j-1)-ddMatrix(i+1,j-1))/(ddMatrix(i,1)-ddMatrix(i+j-2,1))
end
end
disp(ddMatrix)
Px = 0
for j=2:length(Y)+1
prd = 1
for i=1:j-2
prd = prd * (x - ddMatrix(i,1))
end
Px = Px + ddMatrix(1,j)*prd
end
disp(Px)
endfunction
function lagrange(X,Y,x)
for i=1:length(Y)
l(i)=1
for j=1:length(Y)
if i~=j
l(i) = l(i)*(x-X(j))/(X(i)-X(j))
end
end
end
disp(l')
L=0
for i=1:length(Y)
L = L+Y(i)*l(i)
end
disp(L)
endfunction
//example instance
X = [0 1 5 8]
Y = [0 1 8 16.4]
x = 7
dividedDifferences(X,Y,x)
lagrange(X,Y,x)
To create a symbolic polynomial, initialize a symbolic variable with x = poly(0,"x") where x is the name of the variable to use in the polynomial. Then proceed to compute with it exactly as you did in the function lagrange. I essentially copied your function to symboliclagrange below, cutting out the numerical parameter and intermediate display:
function symboliclagrange(X,Y)
x = poly(0,"x")
for i=1:length(Y)
l(i)=1
for j=1:length(Y)
if i~=j
l(i) = l(i)*(x-X(j))/(X(i)-X(j))
end
end
end
L=0
for i=1:length(Y)
L = L+Y(i)*l(i)
end
disp(L)
endfunction
With your input X = [0 1 5 8], Y = [0 1 8 16.4] the output is 0.85x+0.15x2, which is the correct interpolating polynomial.
I'm reading Harper's Intro to SML and am a bit confused on reference cells. On p. 114, he gives the following example:
val r = ref 0
val s = ref 0
val _ = r := 3
val x = !s + !r
val t = r
val _ = t := 5
val y = !s + !r
val z = !t !r
"After execution of these bindings, x is bound to 3, y is bound to 5, and z is bound to 10."
Here's my trace of his code:
val r = ref 0 //allocates storage for r and sets to 0
val s = ref 0 //allocates storage for s and sets to 0
val _ = r := 3 //sets r = 3
val x = !s + !r //sets x = 0 + 3 = 3
val t = r //sets t = 3
val _ = t := 5 //sets t = 5
val y = !s + !r //sets y = 0 + 3 = 3
val z = !t !r //sets z = 5 + 3 = 8
My x is correct (3), but my y and z are both wrong (my y is 3 instead of 5 and my z is 5 instead of 10).
Where am I going wrong here?
Also, why is val _ = t := 5 necessary instead of simply t := 5?
Thanks,
bclayman
val t = r does not set t to 3. It sets t to be the same reference cell that r is.
Thus, when you do t := 5, you set both the contents of t and r to 5, since both contain the same reference cell.
As for your other question, t := 5 is a function call of the function := : 'a ref * 'a -> unit. Thus, t := 5 is an expression that evaluates to ().
val _ = t := 5 simply throws away the () and turns it into a declaration rather than an expression.
val t = r makes t an alias for r. They both refer to the same location in the store. Thus t := 5 has the side effect of changing the contents of the memory location that r refers to as well (since t and r refer to the same place). Hence
val y = !s + !t
sets y = 0 + 5 = 5.
You are correct that val _ = t := 5 is basically the same as t := 5, though the former suppresses output in the REPL (by discarding the value of the assignment expression).