I am moving from Julia 0.7 to 1.0. It seems that Julia's rule for the scope of variables changed from 0.7 to 1.0. For example, I want to run a simple loop like this:
num = 0
for i = 1:5
if i == 3
num = num + 1
end
end
print(num)
In Julia 0.7 (and in most of other languages), we could expect num = 1 after the loop. However, it will incur UndefVarError: num not defined in Julia 1.0. I know that by using let I can do this
let
num = 0
for i = 1:5
if i == 3
num = num + 1
end
end
print(num)
end
It will print out 1. But I do want to get the num = 1 outside the loop and the let block. Some answers suggest putting all code in a let block, but it will incur other problems including UndefVarError while testing line-by-line. Is there any way instead of using let blocking? Thanks!
This is discussed here.
Add global as shown below inside the loop for the num variable.
num = 0
for i = 1:5
if i == 3
global num = num + 1
end
end
print(num)
Running in the Julia 1.0.0 REPL:
julia> num = 0
0
julia> for i = 1:5
if i == 3
global num = num + 1
end
end
julia> print(num)
1
Edit
For anyone coming here new to Julia, the excellent comment made in the answer below by vasja, should be noted:
Just remember that inside a function you won't use global, since the scope rules inside a function are as you would expect:
See that answer for a good example of using a function for the same code without the scoping problem.
Just remember that inside a function you won't use global, since the scope rules inside a function are as you would expect:
function testscope()
num = 0
for i = 1:5
if i == 3
num = num + 1
end
end
return num
end
julia> t = testscope()
1
The unexpected behaviour is only in REPL.
More on this here
Related
I'm working with Julia 1.8.2 on the Advent of Code day 6 and noticed some strange performance difference between while and for loops.
I had written an implementation with a for loop, but realized that I did not need to go over each index, and I could skip indices in certain cases, but when I rewrote my code with a while loop it took ~10x as long to run. Both the for and the while loop code give the correct answer.
Then I added a small basic while vs for loop test to see if it was my code or the actual loops, and the results were even more dramatic. The while test took ~0.5s while the for test completed almost instantly.
My full code is given below, see AoC day6 for the data.
My question is why is the while loop so much slower? Does the Julia interpreter have a hard time optimizing while loops for some reason?
using BenchmarkTools
function parse_data()
open(joinpath(dirname(#__FILE__), "data/day6.txt")) do f
while !eof(f)
line = readline(f)
return line
end
end
end
function test_for(data)
tot = 0
for i = 1:length(data) * 100
tot += 1
end
return tot
end
function test_while(data)
tot = 0
i = 1
while i <= length(data) * 100
tot += 1
i += 1
end
return tot
end
function solve_problem_for(data)
marker_length = 14
for i = 1:length(data)
repeat = false
for (j, item) in enumerate(view(data, i:i+marker_length - 1))
repeat = repeat || occursin(item, view(data, i + j:i + marker_length - 1))
if repeat
break
end
end
if !repeat
return i + marker_length - 1
end
end
end
function solve_problem_while(data)
marker_length = 14
i = 1
while i <= length(data)
repeat = false
for (j, item) in enumerate(view(data, i:i+marker_length - 1))
repeat = repeat || occursin(item, view(data, i + j:i + marker_length - 1))
if repeat
i += j - 1
break
end
end
if !repeat
return i + marker_length - 1
end
i += 1
end
end
function main()
data = parse_data()
#time sol = solve_problem_while(data)
#time sol = solve_problem_while(data)
println(sol)
#time sol = test_while(data)
#time sol = test_while(data)
#time sol = solve_problem_for(data)
#time sol = solve_problem_for(data)
println(sol)
#time sol = test_for(data)
#time sol = test_for(data)
end
main()
The code below returns "Arithmetic", "Geometric" if the input array is an arithmetic and geometric series respectively and -1 if it is neither.
Although the code works fine, when I change
if s = arr.length - 1
to
if s == arr.length - 1
in the while loop, the code is not working properly anymore.
I do not understand why. Shouldn't == work instead of =?
def ArithGeo(arr)
# code goes here
len = arr.length
difference = arr[len-1] - arr[len-2]
ratio = arr[len-1]/arr[len-2]
k = 0
s = k + 1
while (arr[s] - arr[k]) == difference && s < arr.length
if s = arr.length - 1
return "Arithmetic"
end
k += 1
end
k = 0
while arr[s] / arr[k] == ratio && s < arr.length
if s = arr.length - 1
return "Geometric"
end
k += 1
end
return -1
end
You're never changing the value of s which I think you want to do. You should do that at the point that you increment k
k += 1
s = k + 1
Also, at the point where you reinitialize k for the geometric test, you want to reset s as well...
k = 0
s = k + 1
You could also get rid of the variable s completely and make it a method... add these three lines at the top of the code
def s(k)
k + 1
end
And remove all the lines where you assign a value to s and use s(k)... s(k) will be a method that always returns the next higher value to k
The difference between those two statements is that variable s is set for the first statement but not for the second. The first if statement has thus a side effect of setting s to arr.length - 1
if s = arr.length - 1 # s => arr.length - 1
if s == arr.length - 1 # s => undefined
Because the if statement is inside a while loop which uses s in its expression the change of the statement changes the behavior of the programm.
If you put == the statement will try to check if they are equals , with just = the statement work properly because your are only setting the value to a value , so this is always true.
If it's different compare something to equals than just set a variable , that can be always true.
I'm trying to implement Smith-Waterman alignment in parallel using Julia (see: Figure 1 of http://www.cs.virginia.edu/~rl6sf/paper_dump/2011:12:33:22.pdf), but the algorithm is running much slower in Julia than the serial version. I'm using shared arrays to do this and figure I am doing something silly that is making the code run slow. Could someone take a look and see if my code is optimized as possible? The parallel version should run faster than in serial….
The basic concept of it is to compute the anti-diagonal elements of a matrix in parallel from the upper left to lower right corner and to update them. I'm trying to use 32 cores on a shared array machine to do this. I have a SharedArray matrix that I am using to do this and am computing the elements of each anti-diagonal in parallel as shown below. The while loops in the spSW function submit tasks to workers in sync for each anti-diagonal using the helper function shared_get_score(). The main goal of this function is to fill in each element in the shared arrays "matrix" and "path".
function spSW(seq1,seq2,p)
indel = -1
match = 2
seq1 = "^$seq1"
seq2 = "^$seq2"
col = length(seq1)
row = length(seq2)
wl = workers()
matrix,path = shared_initialize_path(seq1,seq2)
for j = 2:col
jcol = j
irow = 2
#sync begin
count = 0
while jcol > 1 && irow < row + 1
#println(j," ",irow," ",jcol)
if seq1[jcol] == seq2[irow]
equal = true
else
equal = false
end
w = wl[(count % p) + 1]
#async remotecall_wait(w,shared_get_score!,matrix,path,equal,indel,match,irow,jcol)
jcol -= 1
irow += 1
count += 1
end
end
end
for i = 3:row
jcol = col
irow = i
#sync begin
count = 0
while irow < row+1 && jcol > 1
#println(j," ",irow," ",jcol)
if seq1[jcol] == seq2[irow]
equal = true
else
equal = false
end
w = wl[(count % p) + 1]
#async remotecall_wait(w,shared_get_score!,matrix,path,equal,indel,match,irow,jcol)
jcol -= 1
irow += 1
count += 1
end
end
end
return matrix,path
end
The other helper functions are:
function shared_initialize_path(seq1,seq2)
col = length(seq1)
row = length(seq2)
matrix = convert(SharedArray,fill(0,(row,col)))
path = convert(SharedArray,fill(0,(row,col)))
return matrix,path
end
#everywhere function shared_get_score!(matrix,path,equal,indel,match,i,j)
pathvalscode = ["-","|","M"]
pathvals = [1,2,3]
scores = []
push!(scores,matrix[i,j-1]+indel)
push!(scores,matrix[i-1,j]+indel)
if equal
push!(scores,matrix[i-1,j-1]+match)
else
push!(scores,matrix[i-1,j-1]+indel)
end
val,ind = findmax(scores)
if val < 0
matrix[i,j] = 0
else
matrix[i,j] = val
end
path[i,j] = pathvals[ind]
end
Does anyone see an obvious way to make this run faster? Right now it's about 10 times slower than the serial version.
I am taking a lesson on codecademy in which I am currently stuck do not know how to proceed - it is regarding return values.
The instructions are:
Write a method that takes an integer as an argument, and returns that integer times ten. Call times_ten in your code after you define it and print out its return value.
What is given in the script is:
def times_ten(integer)
# your code here
end
# call times_ten here
This is the example it gives but I am having a hard time understanding:
def first_squares(number_of_squares)
squares = []
idx = 0
while idx < number_of_squares
squares.push(idx * idx)
idx = idx + 1
end
return squares
end
puts("How many square numbers do you want?")
number_of_squares = gets.to_i
squares = first_squares(number_of_squares)
idx = 0
while idx < squares.length
puts(squares[idx])
idx = idx + 1
end
Thanks for your help
It should be:
def ten_times(n)
n*10 # you don't have to use 'return' explicitly
end
ten_times(n) -- but put in an actual integer instead of n (or maybe you have to puts or print it, depending on what they want)
Your example is not really related to your outcome.
The example script should be like this:
def ten_times(integer)
# integer * 10 #for implicit return
return integer * 10 #for explicit return
end
print ten_times(any number you want goes in here)
You can run the following code at www.rubyplus.biz:
Implicit return:
def times_ten(integer)
integer * 10
end
p times_ten(1)
Explicit return:
def times_ten(integer)
return integer * 10
end
p times_ten(2)
This loop does not terminate after I type x. I'm really new to Ruby, and so far, it is so much different than what I learned before - quite interesting,
total = 0
i = 0
while ((number = gets) != "x")
total += number.to_i
i += 1
end
puts "\nAverage: " + (total / i).to_s
Any help is greatly appreciated.
Because gets gives you the newline as well. You need to chomp it.
Try:
while ((number = gets.chomp) != "x")
and you'll see it starts working:
pax> ruby testprog.rb
1
5
33
x
Average: 13