"Not defined variable" in a 'while loop' in Julia - while-loop

I am trying to do a sensitivity analysis in Julia using JuMP. Here is my code:
using JuMP, Plots, Gurobi
m=Model(with_optimizer(Gurobi.Optimizer))
#variable(m, x>=0)
#variable(m, y>=0)
#variable(m, k>=0)
k = 0
while k<=1
φ(x,y,k)=3*x+k*y
#objective(m, Max, φ(x,y,k))
#constraint(m, 2*x-4>=0)
#constraint(m, y-0.5*x>=0)
pl=optimize!(m)
k=k+0.2
end
The problem is that I get an error:
UndefVarError: k not defined
What am I missing?

julia> k =0
0
julia> while k<10
k=k+1
end
ERROR: UndefVarError: k not defined
Stacktrace:
[1] top-level scope at ./REPL[11]:2
In julia if we are operating with loops the variables we initialise outside our loop can not be directly accessed within a loop on default. To do that we have to set those variable on to global use as on default they are considered to be local
julia> while k<10
global k=k+1
end
Now this works fine

Disclaimer: This is an alternative solution, that it was suggested by a member of Julia Discorse
In a discussion at Julia Discourse, it is suggested to wrap the code in a function in order to increase speed and to avoid the global issue:
function run_code()
model = Model(with_optimizer(Gurobi.Optimizer))
#variable(model, x >= 0)
#variable(model, y >= 0)
#constraint(model, 2x - 4 >= 0)
k = 0
while k <= 1
#objective(model, Max, 3x + k * y)
optimize!(model)
k = k + 0.2
end
end
run_code()

Related

Model exists relation in a linear program (PuLP)

I'm trying to implement an exists relation as part of an LP using PuLP. I'd like to check whether there is a j for which x_ij + x_kj = 2.
for i in range(g):
for k in range(g):
prob += lp.lpSum((x[(i, j)] + x[(k, j)] == 2) for j in range(t)) == y[(i, k)]
The variables are all binary. I tried to model it using a sum of boolean expressions, which should result in 1 if y_ik is 1 and 0 otherwise. However, this approach doesn't work.

My program in Julia sees syntax error where there is none

I have a problem with this bit of code. Every time I try to run it it says that I have "Unexpected" end. For me everything is on point and I cant figure it out can someone help me find solution? Full error code and program code below.
Program:
function mbisekcji(f, a::Float64, b::Float64, delta::Float64, epsilon::Float64)
e = b-a
u = f(a)
v = f(b)
err = 0
iterator = 0
if sign(u) == sign(v)
err = 1
return err
end
while true
e = e/2
c = a+e
w = f(c)
if (norm(e) < delta) || (norm(w) < epsilon)
return w, f(w), iterator, err
end
if sign(w) == sign(u)
b = c
v = w
else
a = c
u = w
end
iterator++
end
end
Error:
LoadError: [91msyntax: unexpected "end"[39m
while loading C:\Users\username\Desktop\Study\zad1.jl, in expression starting on line 60
include_string(::String, ::String) at loading.jl:522
include_string(::Module, ::String, ::String) at Compat.jl:84
(::Atom.##112#116{String,String})() at eval.jl:109
withpath(::Atom.##112#116{String,String}, ::String) at utils.jl:30
withpath(::Function, ::String) at eval.jl:38
hideprompt(::Atom.##111#115{String,String}) at repl.jl:67
macro expansion at eval.jl:106 [inlined]
(::Atom.##110#114{Dict{String,Any}})() at task.jl:80
Also, just to make thing easier, line 60 is second end from the back. The one closing while loop.
In order to increment a variable by 1 in Julia you have to write
iterator += 1
Julia does not support ++ to increment a variable.
But, for example, you could define a macro to do almost what you want:
julia> macro ++(x)
esc(:($x += 1))
end
#++ (macro with 1 method)
julia> x = 1
1
julia> #++x
2
julia> x
2

How to add a column of simple moving average of another column to a Julia data frame

I have a Julia data frame where one column is called 'close' and I want to add another column to the data frame called 'sma' which is a simple moving average of 'close'. Thanks to anyone who can help!
I noticed a problem in the code amrod. It doesn't account for the first length of SMA that doesn't have enough previous data points for a good SMA and also gives double the SMA that is asked for. I changed it to input zeros up to that point, I also changed the variable names when I was figuring out how it works.
function makeSMA(data, SMA)
len = length(data)
y = Vector{Float64}(len)
for i in 1:SMA-1
y[i] = NaN
end
for i in SMA:len
y[i] = mean(data[i-(SMA-1):i])
end
return y
end
check this:
function ma{T <: Real}(x::Vector{T}, wind::Int)
len = length(x)
y = Vector{Float64}(len)
for i in 1:len
lo = max(1, i - wind)
hi = min(len, i + wind)
y[i] = mean(x[lo:hi])
end
return y
end
x = collect(1:100)
y = ma(x, 4)
then you can hcat(x, y).
EDIT:
If you want a backwards-looking MA you can use something like
function ma{T <: Real}(x::Vector{T}, wind::Int)
len = length(x)
y = Vector{Float64}(len)
for i in 1:len
if i < wind
y[i] = NaN
else
y[i] = mean(x[i - wind + 1:i])
end
end
return y
end

Iterating over multidimensional Numpy array

What is the fastest way to iterate over all elements in a 3D NumPy array? If array.shape = (r,c,z), there must be something faster than this:
x = np.asarray(range(12)).reshape((1,4,3))
#function that sums nearest neighbor values
x = np.asarray(range(12)).reshape((1, 4,3))
#e is my element location, d is the distance
def nn(arr, e, d=1):
d = e[0]
r = e[1]
c = e[2]
return sum(arr[d,r-1,c-1:c+2]) + sum(arr[d,r+1, c-1:c+2]) + sum(arr[d,r,c-1]) + sum(arr[d,r,c+1])
Instead of creating a nested for loop like the one below to create my values of e to run the function nn for each pixel :
for dim in range(z):
for row in range(r):
for col in range(c):
e = (dim, row, col)
I'd like to vectorize my nn function in a way that extracts location information for each element (e = (0,1,1) for example) and iterates over ALL elements in my matrix without having to manually input each locational value of e OR creating a messy nested for loop. I'm not sure how to apply np.vectorize to this problem. Thanks!
It is easy to vectorize over the d dimension:
def nn(arr, e):
r,c = e # (e[0],e[1])
return np.sum(arr[:,r-1,c-1:c+2],axis=2) + np.sum(arr[:,r+1,c-1:c+2],axis=2) +
np.sum(arr[:,r,c-1],axis=?) + np.sum(arr[:,r,c+1],axis=?)
now just iterate over the row and col dimensions, returning a vector, that is assigned to the appropriate slot in x.
for row in <correct range>:
for col in <correct range>:
x[:,row,col] = nn(data, (row,col))
The next step is to make
rows = [:,None]
cols =
arr[:,rows-1,cols+2] + arr[:,rows,cols+2] etc.
This kind of problem has come up many times, with various descriptions - convolution, smoothing, filtering etc.
We could do some searches to find the best, or it you prefer, we could guide you through the steps.
Converting a nested loop calculation to Numpy for speedup
is a question similar to yours. There's only 2 levels of looping, and sum expression is different, but I think it has the same issues:
for h in xrange(1, height-1):
for w in xrange(1, width-1):
new_gr[h][w] = gr[h][w] + gr[h][w-1] + gr[h-1][w] +
t * gr[h+1][w-1]-2 * (gr[h][w-1] + t * gr[h-1][w])
Here's what I ended up doing. Since I'm returning the xv vector and slipping it in to the larger 3D array lag, this should speed up the process, right? data is my input dataset.
def nn3d(arr, e):
r,c = e
n = np.copy(arr[:,r-1:r+2,c-1:c+2])
n[:,1,1] = 0
n3d = np.ma.masked_where(n == nodata, n)
xv = np.zeros(arr.shape[0])
for d in range(arr.shape[0]):
if np.ma.count(n3d[d,:,:]) < 2:
element = nodata
else:
element = np.sum(n3d[d,:,:])/(np.ma.count(n3d[d,:,:])-1)
xv[d] = element
return xv
lag = np.zeros(shape = data.shape)
for r in range(1,data.shape[1]-1): #boundary effects
for c in range(1,data.shape[2]-1):
lag[:,r,c] = nn3d(data,(r,c))
What you are looking for is probably array.nditer:
a = np.arange(6).reshape(2,3)
for x in np.nditer(a):
print(x, end=' ')
which prints
0 1 2 3 4 5

Fortran Error Meanings

I have been following books and PDFs on writing in FORTRAN to write an integration program. I compile the code with gfortran and get several copies of the following errors.
1)Unexpected data declaration statement at (1)
2)Unterminated character constant beginning at (1)
3)Unclassifiable statement at (1)
4)Unexpected STATEMENT FUNCTION statement at (1)
5)Expecting END PROGRAM statement at (1)
6)Syntax error in data declaration at (1)
7)Statement function at (1) is recursive
8)Unexpected IMPLICIT NONE statement at (1)
I do not know hat they truly mean or how to fix them, google search has proven null and the other topics on this site we about other errors. for Error 5) i put in Program main and end program main like i might in C++ but still got the same result. Error 7) makes no sense, i am trying for recursion in the program. Error 8) i read implicit none was to prevent unnecessary decelerations.
Ill post the code itself but i am more interested in the compiling errors because i still need to fine tune the array data handling, but i cant do that until i get it working.
Program main
implicit none
real, dimension(:,:), allocatable :: m, oldm
real a
integer io, nn
character(30) :: filename
real, dimension(:,:), allocatable :: alt, temp, nue, oxy
integer locationa, locationt, locationn, locationo, i
integer nend
real dz, z, integral
real alti, tempi, nuei, oxyi
integer y, j
allocate( m(0, 0) ) ! size zero to start with?
nn = 0
j = 0
write(*,*) 'Enter input file name: '
read(*,*) filename
open( 1, file = filename )
do !reading in data file
read(1, *, iostat = io) a
if (io < 0 ) exit
nn = nn + 1
allocate( oldm( size(m), size(m) ) )
oldm = m
deallocate( m )
allocate( m(nn, nn) )
m = oldm
m(nn, nn) = a ! The nnth value of m
deallocate( oldm )
enddo
! Decompose matrix array m into column arrays [1,n]
write(*,*) 'Enter Column Number for Altitude'
read(*,*) locationa
write(*,*) 'Enter Column Number for Temperature'
read(*,*) locationt
write(*,*) 'Enter Column Number for Nuetral Density'
read(*,*) locationn
write(*,*) 'Enter Column Number for Oxygen density'
read(*,*) locationo
nend = size(m, locationa) !length of column #locationa
do i = 1, nend
alt(i, 1) = m(i, locationa)
temp(i, 1) = log(m(i, locationt))
nue(i, 1) = log(m(i, locationn))
oxy(i, 1) = log(m(i, locationo))
enddo
! Interpolate Column arrays, Constant X value will be array ALT with the 3 other arrays
!real dz = size(alt)/100, z, integral = 0
!real alti, tempi, nuei, oxyi
!integer y, j = 0
dz = size(alt)/100
do z = 1, 100, dz
y = z !with chopped rounding alt(y) will always be lowest integer for smooth transition.
alti = alt(y, 1) + j*dz ! the addition of j*dz's allow for all values not in the array between two points of the array.
tempi = exp(linear_interpolation(alt, temp, size(alt), alti))
nuei = exp(linear_interpolation(alt, nue, size(alt), alti))
oxyi = exp(linear_interpolation(alt, oxy, size(alt), alti))
j = j + 1
!Integration
integral = integral + tempi*nuei*oxyi*dz
enddo
end program main
!Functions
real function linear_interpolation(x, y, n, x0)
implicit none
integer :: n, i, k
real :: x(n), y(n), x0, y0
k = 0
do i = 1, n-1
if ((x0 >= x(i)) .and. (x0 <= x(i+1))) then
k = i ! k is the index where: x(k) <= x <= x(k+1)
exit ! exit loop
end if
enddo
if (k > 0) then ! compute the interpolated value for a point not in the array
y0 = y(k) + (y(k+1)-y(k))/(x(k+1)-x(k))*(x0-x(k))
else
write(*,*)'Error computing the interpolation !!!'
write(*,*) 'x0 =',x0, ' is out of range <', x(1),',',x(n),'>'
end if
! return value
linear_interpolation = y0
end function linear_interpolation
I can provide a more detailed description of the exact errors, i was hoping that the error name would be enough since i have a few of each type.
I think I can spot a few serious errors in your code sample. The syntax error is that you have unbalanced parentheses in the exp(... statements. They should be like this:
tempi = exp(linear_interpolation(alt, temp, size(alt), alti) ) ! <- extra ")"
nuei = exp(linear_interpolation(alt, nue, size(alt), alti) )
oxyi = exp(linear_interpolation(alt, oxy, size(alt), alti) )
It's precisely things like this that can produce long strings of confusing errors like you're getting; therefore the advice Dave and Jonathan have given can't be repeated often enough.
Another error (the "unclassifiable statement") applies to your loops:
do(i=1, nend)
! ...
do(z=1, 100, dz)
! ...
These should be written without parentheses.
The "data declaration error" stems from your attempt to declare and initialise multiple variables like
real dz = size(alt)/100, z, integral = 0
Along with being positioned incorrectly in the code (as noted), this can only be done with the double colon separator:
real :: dz = size(alt)/100, z, integral = 0
I personally recommend always writing declarations like this. It must be noted, though, that initialising variables like this has the side effect of implicitly giving them the save attribute. This has no effect in a main program, but is important to know; you can avoid it by putting the initialisations on a separate line.