Julia UndefVarError on Metaprogramming - julia

I'm trying to do a solver for equations. When I run the code the X variable appears to be undefined, but it prints out perfectly. What am I missing?
I should give the program some numbers, than operations as Macros and it should create an outer product matrix of the operations applied.
function msu()
print("Insert how many values: ")
quantity = parse(Int64, readline())
values = []
for i in 1:quantity
println("x$i")
num1 = parse(Float64, readline())
push!(values, num1)
end
println(values)
print("How many operations? ")
quantity = parse(Int64, readline())
ops = []
for i in 1:quantity
push!(ops, Meta.parse(readline()))
end
mat = zeros((quantity, quantity))
for i in 1:length(mat)
sum = 0
for j in 1:length(values)
# here begins problems, the following prints are for debugging purpose
print(length(values))
func = Meta.parse("$(ops[convert(Int64, ceil(j / quantity))]) * $(ops[convert(Int64, j % quantity)])")
print(func)
x = values[j]
println(x)
sum += eval(func)
end
mat[i] = sum
end
println(mat)
end
msu()
The original code was in Spanish, if you find any typo it's probably because I skipped a translation.

Related

ST-HOSVD in Julia

I am trying to implement ST-HOSVD algorithm in Julia because I could not found library which contains ST-HOSVD.
See this paper in Algorithm 1 in page7.
https://people.cs.kuleuven.be/~nick.vannieuwenhoven/papers/01-STHOSVD.pdf
I cannot reproduce input (4,4,4,4) tensor by approximated tensor whose tucker rank is (2,2,2,2).
I think I have some mistake in indexes of matrix or tensor elements, but I could not locate it.
How to fix it?
If you know library of ST-HOSVD, let me know.
ST-HOSVD is really common way to reduce information. I hope the question helps many Julia user.
using TensorToolbox
function STHOSVD(A, reqrank)
N = ndims(A)
S = copy(A)
Sk = undef
Uk = []
for k = 1:N
if k == 1
Sk = tenmat(S, k)
end
Sk_svd = svd(Sk)
U1 = Sk_svd.U[ :, 1:reqrank[k] ]
V1t = Sk_svd.V[1:reqrank[k], : ]
Sigma1 = diagm( Sk_svd.S[1:reqrank[k]] )
Sk = Sigma1 * V1t
push!(Uk, U1)
end
X = ttm(Sk, Uk[1], 1)
for k=2:N
X = ttm(X, Uk[k], k)
end
return X
end
A = rand(4,4,4,4)
X = X_STHOSVD(A, [2,2,2,2])
EDIT
Here, Sk = tenmat(S, k) is mode n matricization of tensor S.
S∈R^{I_1×I_2×…×I_N}, S_k∈R^{I_k×(Π_{m≠k}^{N} I_m)}
The function is contained in TensorToolbox.jl. See "Basis" in Readme.
The definition of mode-k Matricization can be seen the paper in page 460.
It works.
I have seen 26 page in this slide
using TensorToolbox
using LinearAlgebra
using Arpack
function STHOSVD(T, reqrank)
N = ndims(T)
tensor_shape = size(T)
for i = 1 : N
T_i = tenmat(T, i)
if reqrank[i] == tensor_shape[i]
USV = svd(T_i)
else
USV = svds(T_i; nsv=reqrank[i] )[1]
end
T = ttm( T, USV.U * USV.U', i)
end
return T
end

Julia - generate an array of functions programmatically

I want to generate an array of functions programmatically, with a loop so that each successive function depends on the previous.
For example in pseudo-code:
f_array = [f1, f2, f3]
with:
f1(x) = x
f2(x) = 3 * f1(x)
f3(x) = 3 * f2(x)
so that I could call:
f_array[3](x)
and get the result of f3(x)
Here is what I have tried:
# create simple function just to initialize
f(x)=x
# initialize array of functions
N = 3
f_array = fill(f, N)
# now we update each function
for i in 2:N
f_array[i] = (f(x)= 3 * f_array[i-1](x))
end
I get an error:
ERROR: MethodError: Cannot convert an object of type getfield(Main,
Symbol("#f#15")){Int64} to an object of type typeof(f)
I cannot find a solution at the moment. Any help would be appreciated.
When you use fill with f it sets expected type for the elements of f_array to f, in the code below I am switching to abstract type to make it possible to have any function in the array
# create simple function just to initialize
f(x)=x
# initialize array of functions
N = 3
f_array = Array{Function}(undef, N);
f_array[1] = f;
# now we update each function
for i in 2:N
f_array[i] = x -> 3 * f_array[i-1](x)
end
print(f_array[3](2))
which produces a value of 18
In the mean time, I also found a way using metaprogramming. I post this here as it could be useful for others:
f1(x) = x
for i in 2:N
prog = "f$i(x) = 3 * f$(i-1)(x)"
exp = Meta.parse(prog)
eval(exp)
end
f3(2)
# 18
I'd write Yegor's answer as
f_array = Function[identity]
for i in 2:3
push!(f_array, x -> 3f_array[i-1](x))
end
But more importantly, this is a well known pattern: iterated function application. And it is already implemented, not in Base, but for example in IterTools.jl, by which you should be able to write:
f_array(start, N) = collect(Iterators.take(iterated(x -> 3x, start), N))
(I didn't test this, though.)

Scilab - Finding the average of randomly generated numbers with different indices

Say I have a function that generates random integers between say (1,10).
Then, I define a (for loop) which has 5 iterations.
This (for loop) calls the function defined above, and then it checks the value of the integer generated by the function. Depending on the value of the integer, the variable "cost" is decided.
function integer = UniformInt(a, b)
integer = min( floor( rand()*(b-a) ) + a , b);
endfunction
for i=1:5
x(i) = UniformInt(1,10);
if (x(i)<4) then
cost(i) = 15;
elseif (4<=x(i) && x(i)<=8) then
cost(i) = 27;
else
cost(i) = 35;
end
end
Now, when I run that and find x, say the values generated are:
5.
9.
5.
2.
2.
And so, the different cost values will be:
27.
35.
27.
15.
15.
This is all good so far. Now, what I want to do with these results is:
Check how many times each value of x appeared. I can do this via Scilab's tabul function:
9. 1.
5. 2.
2. 2.
Now, what I really want to code is:
x=9 only showed up once, so, the average of cost is 35/1 = 35.
x=5 showed up twice, so, the average of cost is (27+27)/2 = 27.
x=2 showed up twice, so, the average of cost is (15+15)/2 = 15.
How would I do that?
For posterity, a code in which the answer provided by user #Stéphane Mottelet would be useful (because my code above is trivial) is as follows:
function integer = UniformInt(a, b)
integer = min( floor( rand()*(b-a) ) + a , b);
endfunction
for i=1:5
x(i) = UniformInt(1,10);
if (x(i)<4) then
cost(i) = 15*rand();
elseif (4<=x(i) && x(i)<=8) then
cost(i) = 27*rand();
else
cost(i) = 35*rand();
end
end
Now the cost values are multiplied by a random number, and so,
if the value of say x=10 showed up 2 times, the average cost when x=10 will not simply be (35+35)/2.
I would do like this, but the answer is quite trivial since for now the value of cost is the same for a given x value (I suppose your real application draws random values of cost)
t = tabul(x);
for k = 1:size(t,1)
avg(k) = mean(cost(x == t(k)));
end

Parallelize two (or more) functions in julia

I am trying to solve some wave equation problem (related to my Phd) using finite difference method. For this, I have translated (line by line) a fortran code (link below): (https://github.com/geodynamics/seismic_cpml/blob/master/seismic_CPML_2D_anisotropic.f90)
Inside these code and within the time loop, there are four main loops that are independent. In fact, I could arrange them into four functions.
As I have to run this code about a hundred times, it would be nice to speed up the process. In this sense, I am turning my eyes toward parallelization. See below, as an example:
function main()
...some common code...
for time=1:N
function fun1() # I want this function to run parallel...
function fun2() # ..this function to run parallel with 1,3,4
function fun3() # ..This function to run parallel with 2,3,4
function fun4() # ..This function to run parallel with 1,2,3
end
... more code here...
return
end
So,
1) Is it possible to do what I mention before?
2) Will this approach speed up my code?
3) Is there a better way to think this problem?
A minimal working example could be like this:
function fun1(t)
for i=1:1000
for j=1:1000
t+=(0.5)^t+(0.3)^(t-1);
end
end
return t
end
function fun2(t)
for i=1:1000
for j=1:1000
t+=(0.5)^t;
end
end
return t
end
function fun3(r)
for i=1:1000
for j=1:1000
r = (r + rand())/r;
end
end
return r
end
function main()
a = 2;
b = 2.5;
c = 3.0;
for i=1:100
a = fun1(a);
b = fun2(b);
c = fun3(c);
end
return;
end
So, As can be seen, non of the three functions above (fun1, fun2 & fun3) depend from any ohter, so they can sure run parallel. can these be achieved?, will it bust my computational speed?
Edited:
Hi #BogumiłKamiński I have altered the finite-Diff-eq in order to implement a "loop" (as you sugested) over the inputs and outputs of my functions. If there is no much trouble, I would like your opinion over the parellelization design of the code:
Key elements
1) I have packed all inputs in 4 tuples: sig_xy_in and sig_xy_cros_in (for the 2 sigma functions) and vel_vx_in and vel_vy_in (for 2 velocity functions). I then packed the 4 tuples into 2 vectors for "looping" purposes...
2) I packed the 4 functions in 2 vectors for "looping" purposes...
3) I run the first parallel loop and then unpack its output tuple...
4) I run the second parallel loop(for velocities) and then unpack its output tuple...
5) finally, I packed the outputed elements into the inputs tuples and continue the time loop until finish..
...code
l = Threads.SpinLock()
arg_in_sig = [sig_xy_in,sig_xy_cros_in]; # Inputs tuples x sigma funct
arg_in_vel = [vel_vx_in, vel_vy_in]; # Inputs tuples x velocity funct
func_sig = [sig_xy , sig_xy_cros]; # Vector with two sigma functions
func_vel = [vel_vx , vel_vy]; # Vector with two velocity functions
for it = 1:NSTEP # time steps
#------------------------------------------------------------
# Compute sigma functions
#------------------------------------------------------------
Threads.#threads for j in 1:2 # Star parallel of two sigma functs
Threads.lock(l);
Threads.unlock(l);
arg_in_sig[j] = func_sig[j](arg_in_sig[j]);
end
# Unpack tuples for sig_xy and sig_xy_cros
# Unpack tuples for sig_xy
sigxx = arg_in_sig[1][1]; # changed by sig_xy
sigyy = arg_in_sig[1][2]; # changed by sig_xy
m_dvx_dx = arg_in_sig[1][3]; # changed by sig_xy
m_dvy_dy = arg_in_sig[1][4]; # changed by sig_xy
vx = arg_in_sig[1][5]; # unchanged by sig_xy
vy = arg_in_sig[1][6]; # unchanged by sig_xy
delx_1 = arg_in_sig[1][7]; # unchanged by sig_xy
dely_1 = arg_in_sig[1][8]; # unchanged by sig_xy
...more unpacking...
# Unpack tuples for sig_xy_cros
sigxy = arg_in_sig[2][1]; # changed by sig_xy_cros
m_dvy_dx = arg_in_sig[2][2]; # changed by sig_xy_cros
m_dvx_dy = arg_in_sig[2][3]; # changed by sig_xy_cros
vx = arg_in_sig[2][4]; # unchanged by sig_xy_cros
vy = arg_in_sig[2][5]; # unchanged by sig_xy_cros
...more unpacking....
#--------------------------------------------------------
# velocity
#--------------------------------------------------------
Threads.#threads for j in 1:2 # Start parallel ot two velocity funct
Threads.lock(l)
Threads.unlock(l)
arg_in_vel[j] = func_vel[j](arg_in_vel[j])
end
# Unpack tuples for vel_vx
vx = arg_in_vel[1][1]; # changed by vel_vx
m_dsigxx_dx = arg_in_vel[1][2]; # changed by vel_vx
m_dsigxy_dy = arg_in_vel[1][3]; # changed by vel_vx
sigxx = arg_in_vel[1][4]; # unchanged changed by vel_vx
sigxy = arg_in_vel[1][5];....
# Unpack tuples for vel_vy
vy = arg_in_vel[2][1]; # changed changed by vel_vy
m_dsigxy_dx = arg_in_vel[2][2]; # changed changed by vel_vy
m_dsigyy_dy = arg_in_vel[2][3]; # changed changed by vel_vy
sigxy = arg_in_vel[2][4]; # unchanged changed by vel_vy
sigyy = arg_in_vel[2][5]; # unchanged changed by vel_vy
.....
...more unpacking...
# ensamble new input variables
sig_xy_in = (sigxx,sigyy,
m_dvx_dx,m_dvy_dy,
vx,vy,....);
sig_xy_cros_in = (sigxy,
m_dvy_dx,m_dvx_dy,
vx,vy,....;
vel_vx_in = (vx,....
vel_vy_in = (vy,.....
end #time loop
Here is a simple way to run your code in multithreading mode:
function fun1(t)
for i=1:1000
for j=1:1000
t+=(0.5)^t+(0.3)^(t-1);
end
end
return t
end
function fun2(t)
for i=1:1000
for j=1:1000
t+=(0.5)^t;
end
end
return t
end
function fun3(r)
for i=1:1000
for j=1:1000
r = (r + rand())/r;
end
end
return r
end
function main()
l = Threads.SpinLock()
a = [2.0, 2.5, 3.0]
f = [fun1, fun2, fun3]
Threads.#threads for i in 1:3
for j in 1:4
Threads.lock(l)
println((thread=Threads.threadid(), iteration=j))
Threads.unlock(l)
a[i] = f[i](a[i])
end
end
return a
end
I have added locking - just as an example how you can do it (in Julia 1.3 you would not have to do this as IO is thread safe there).
Also note that rand() is sharing data among threads prior to Julia 1.3 so it would be not safe to run these functions if all of them used rand() (again in Julia 1.3 it would be safe to do so).
To run this code first set the maximum number of threads you want to use e.g. like this on Windows: set JULIA_NUM_THREADS=4 (in Linux you should export). Here is an example of this code run (I have reduced the number of iterations done in order to shorten the output):
julia> main()
(thread = 1, iteration = 1)
(thread = 3, iteration = 1)
(thread = 2, iteration = 1)
(thread = 3, iteration = 2)
(thread = 3, iteration = 3)
(thread = 3, iteration = 4)
(thread = 2, iteration = 2)
(thread = 1, iteration = 2)
(thread = 2, iteration = 3)
(thread = 2, iteration = 4)
(thread = 1, iteration = 3)
(thread = 1, iteration = 4)
3-element Array{Float64,1}:
21.40311930108456
21.402807510451463
1.219028489573526
Now one smal cautionary note - while it is relatively easy to make code multithreaded in Julia (and in Julia 1.3 it will be even simpler) you have to be careful when you do it as you have to take care of race conditions.

Neat representation of results in Julia after a loop

I have created a small code in Julia that is able to use function iteration to solve a simple non-linear problem.
The code is the following:
"""
Problem: find the root of f(x) = exp(-x) - x
using the fixed point iteration
(aka function iteration)
Solution: f(x) = exp(-x) - x = 0
x = exp(-x)
"""
i = 0; # initialize first iteration
x = 0; # initialize solution
error = 1; # initialize error bound
xvals = x; # initialize array of iterates
tic()
while error >= 1e-10
y = exp(-x);
xvals = [xvals;y]; # It is not needed actually
error = abs(y-x);
x = y;
i = i + 1;
println(["Solution", x', "Error:", error', "Iteration no:", i'])
end
toc()
In the above code the results are not neat for there are many decimal numbers. To my understanding, using println may not be a good idea and instead #printf or sprintf must be used, however, I was not able to put everything in one line.
Is it possible to do that?
The syntax for printf is (roughly) the same for all languages,
but it is indeed arcane.
You can use %f for floats, %e for floats in scientific notation,
%d for integers, %s for strings.
The numbers between the % and the letter are
the number of digits (or characters) before and after the comma.
i = 0
x = 0
error = Inf
while error >= 1e-10
x, previous = exp(-x), x
error = abs( x - previous )
i += 1
#printf(
"Value: %1.3f Error: %1.3e Iteration: %3d\n",
x, error, i
)
end
You could also have tried round or signif,
but since round decimal numbers cannot always be represented exactly as floats,
that does not work reliably.

Resources