Neat way to define arbitraly order Tensor in Julia - julia

I want to define an arbitrary order Tensor-like type in Julia. Here, Tensor-like means something like Vector{Vector{Vector{T}}. My trial was the code below:
function Tensor(N::Int, T::DataType)
N==0 && return eval(T)
return Tensor(N-1, eval(Expr(:curly, :Vector, T)))
end
And declaration would be data = Tensor(3, Float64)[]. Regarding this, I have two questions. 1) Is there a neater way to do this? 2) I prefer declaration using braces like data = Tensor{3, Float64}[] rather than using parentheses. How can I do this maybe by means of metaprogramming?

Assuming that you know the size of tensor.
Let
d = (4,3,2)
be the size of your tensor. You can create it in two ways:
Arrays of zeros
Use zeros() - see the example below:
julia> zeros(Float64,d)
4×3×2 Array{Float64,3}:
[:, :, 1] =
0.0 0.0 0.0
0.0 0.0 0.0
0.0 0.0 0.0
0.0 0.0 0.0
[:, :, 2] =
0.0 0.0 0.0
0.0 0.0 0.0
0.0 0.0 0.0
0.0 0.0 0.0
Not initialized (faster, note the garbage values)
Use Array type constructor:
julia> x = Array{Float64,length(d)}(undef,d)
4×3×2 Array{Float64,3}:
[:, :, 1] =
5.34466e-316 5.34466e-316 5.34467e-316
5.34466e-316 5.34467e-316 5.34467e-316
5.34466e-316 5.34467e-316 5.34467e-316
5.34466e-316 1.51858e-316 5.34468e-316
[:, :, 2] =
1.51858e-316 5.34487e-316 0.0
1.51858e-316 5.34487e-316 0.0
1.51858e-316 5.34429e-316 0.0
1.51858e-316 5.16938e-316 0.0

Related

How can I efficiently turn a vector of 1-dim array into a 2-dim array(matrix) in Julia?

As mentioned I have a vector of 1D matrice, such as:
P_predefined = [[.3 .4 .2 .1], [.2 .3 .5 0.], [.1 0. .8 .1], [.4 0. 0. .6]]
I would like to turn it into a matrix of 2D, I tried to use vcat, for which I expected to behave like vstack in Python, but it doesn't work.
vcat(algorithm.predefinedP)
It still returns a vector
[[0.3 0.4 0.2 0.1], [0.2 0.3 0.5 0.0], [0.1 0.0 0.8 0.1], [0.4 0.0 0.0 0.6]] #Vector{Matrix{Float64}}
How should I do it in the right way?
Julia 1.9 has stack, which can be used on earlier Julia versions via the package Compat.
julia> using Compat
julia> P_predefined = vec.([[.3 .4 .2 .1], [.2 .3 .5 0.], [.1 0. .8 .1], [.4 0. 0. .6]])
4-element Vector{Vector{Float64}}:
[0.3, 0.4, 0.2, 0.1]
[0.2, 0.3, 0.5, 0.0]
[0.1, 0.0, 0.8, 0.1]
[0.4, 0.0, 0.0, 0.6]
julia> stack(P_predefined)
4×4 Matrix{Float64}:
0.3 0.2 0.1 0.4
0.4 0.3 0.0 0.0
0.2 0.5 0.8 0.0
0.1 0.0 0.1 0.6
julia> stack(P_predefined; dims=1)
4×4 Matrix{Float64}:
0.3 0.4 0.2 0.1
0.2 0.3 0.5 0.0
0.1 0.0 0.8 0.1
0.4 0.0 0.0 0.6
Note: your P_predefined is a vector of 1xn matrices, instead of vectors. I've used vec here to convert them to vectors.
vcat(A...)
Concatenate along dimension 1. To efficiently concatenate a large
vector of arrays, use reduce(vcat, x).
julia> reduce(vcat, P_predefined)
4×4 Matrix{Float64}:
0.3 0.4 0.2 0.1
0.2 0.3 0.5 0.0
0.1 0.0 0.8 0.1
0.4 0.0 0.0 0.6
Since you mention efficiency, a comprehension will be 2X faster than vcat.
m, n = length(P_predefined), length(P_predefined[1])
#btime mat = [$P_predefined[i][j] for i=1:$m, j=1:$n]
#btime mat = reduce(vcat, $P_predefined)
# 29.347 ns (1 allocation: 192 bytes)
# 72.131 ns (1 allocation: 192 bytes)

What causes `AssertionError` when asserting a diagonalized vector in Julia?

I've been doing some exercises in julia, and I am currently trying to #assert a vector that has been diagonalized into a matrix against a "solution matrix" given in the exercise notebook. However, I get an AssertionError when asserting my code against the provided solution. Example of my code:
julia> using LinearAlgebra
julia> A =
[
140 97 74 168 131
97 106 89 131 36
74 89 152 144 71
168 131 144 54 142
131 36 71 142 36
]
5×5 Matrix{Int64}:
140 97 74 168 131
97 106 89 131 36
74 89 152 144 71
168 131 144 54 142
131 36 71 142 36
julia> A_eigv = eigen(A).values
5-element Vector{Float64}:
-128.49322764802145
-55.887784553057
42.752167279318854
87.16111477514494
542.4677301466137
julia> A_diag = Diagonal(A_eigv)
5×5 Diagonal{Float64, Vector{Float64}}:
-128.493 ⋅ ⋅ ⋅ ⋅
⋅ -55.8878 ⋅ ⋅ ⋅
⋅ ⋅ 42.7522 ⋅ ⋅
⋅ ⋅ ⋅ 87.1611 ⋅
⋅ ⋅ ⋅ ⋅ 542.468
julia> #assert A_diag == [-128.493 0.0 0.0 0.0 0.0;
0.0 -55.8878 0.0 0.0 0.0;
0.0 0.0 42.7522 0.0 0.0;
0.0 0.0 0.0 87.1611 0.0;
0.0 0.0 0.0 0.0 542.468]
AssertionError: A_diag == [-128.493 0.0 0.0 0.0 0.0; 0.0 -55.8878 0.0 0.0 0.0; 0.0 0.0 42.7522 0.0 0.0; 0.0 0.0 0.0 87.1611 0.0; 0.0 0.0 0.0 0.0 542.468]
Stacktrace:
[1] top-level scope
# In[90]:1
[2] eval
# ./boot.jl:360 [inlined]
[3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
# Base ./loading.jl:1094
My inital assumption was that a difference in number of decimals was the cause of the error. I therefore replaced == with ≈ (\approx). However, as the code example below shows, the error persists:
julia> #assert A_diag ≈ #\approx
[-128.493 0.0 0.0 0.0 0.0;
0.0 -55.8878 0.0 0.0 0.0;
0.0 0.0 42.7522 0.0 0.0;
0.0 0.0 0.0 87.1611 0.0;
0.0 0.0 0.0 0.0 542.468]
AssertionError: A_diag ≈ [-128.493 0.0 0.0 0.0 0.0; 0.0 -55.8878 0.0 0.0 0.0; 0.0 0.0 42.7522 0.0 0.0; 0.0 0.0 0.0 87.1611 0.0; 0.0 0.0 0.0 0.0 542.468]
Stacktrace:
[1] top-level scope
# In[97]:1
[2] eval
# ./boot.jl:360 [inlined]
[3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
# Base ./loading.jl:1094
I've been reading through my code multiple times now, and I am at a loss. The values in my diagonal matrix (A_diag) are seemingly identical to the solution matrix. Furthermore, setting the statement to approximately equal (\approx) renders the same error, so I assume I can count out decimal error.
My main question is: What causes the AssertionError?
No, the dots are treated as 0 for the purpose of testing equality.
julia> Diagonal(1:2) == [1 0; 0 2]
true
Your problem is that your arrays are actually not equal; -128.49322764802145 is not the same as -128.493. (The pretty-printed version of the array truncates floats for display, but that's not the true underlying value!).
[Edit:]
Using ≈ (\approx) will also fail in this case. The reason for this is explained in the documentation for isapprox()
The binary operator ≈ is equivalent to isapprox with the default arguments,
if an atol > 0 is not specified, rtol defaults to the square root of eps of the type of x or y, whichever is bigger (least precise).
Essentially, what this means is that ≈ will test for approximate equality with a relative tolerance of √eps() which is approximately equal to 1.5e-8, or 0.0000015%. This tolerance is waaay too low, and increasing the tolerance will resolve the issue. E.g.:
# Option 1: Absolute tolerance. Set to a reasonable max deviation:
julia> isapprox(A_diag, sol_mat, atol = 1e-3)
true
# Option 2: Relative tolerance. Setting rtol = 1e-n, n is the number of significant digits in either matrices will work in most cases.
julia> isapprox(A_diag, sol_mat, rtol = 1e-6)
true
Since the solution matrix provides the values in six significant digits, another alternative is to round the values in A_diag to this number og digits and test for equality. E.g.:
julia> round.(A_diag, RoundNearestTiesUp, sigdigits=6) ==
[-128.493 0.0 0.0 0.0 0.0;
0.0 -55.8878 0.0 0.0 0.0;
0.0 0.0 42.7522 0.0 0.0;
0.0 0.0 0.0 87.1611 0.0;
0.0 0.0 0.0 0.0 542.468]
true

I want to make a matrix from 1D Arrays in Julia

I am new to Julia and need some help.
I have a list of 1D Arrays, I want to produce a matrix like this
g = [ 2.0 -1.0 0.0 0.0;
-1.0 2.0 -1.0 0.0;
0.0 -1.0 2.0 -1.0;
0.0 0.0 -1.0 3.0]
I am able to follow simple examples given on docs, but how do I achieve this using loops?
Cheers,
Ayush
with loops you can create a matrix and then fill it.
with loops
horizontally:
julia> arr = [[2.0,-1.0,0.0,0.0],[-1.0,2.0,-1.0,0.0],[0.0,-1.0,2.0,-1.0],[0.0,0.0,-1.0,3.0],[1.,1.,1.,1.]]
5-element Array{Array{Float64,1},1}:
[2.0, -1.0, 0.0, 0.0]
[-1.0, 2.0, -1.0, 0.0]
[0.0, -1.0, 2.0, -1.0]
[0.0, 0.0, -1.0, 3.0]
[1.0, 1.0, 1.0, 1.0]
julia> function make_matrix(input::Vector{<:Vector})
element_type = eltype(eltype(input))
if (length(input) == 0)
return Array{element_type,2}(undef,0,0)
end
height,width = length(input[1]), length(input)
for col in input
(height == length(col)) ? nothing : throw("inconsistent array size")
end
output = Array{element_type}(undef,height,width)
for i in 1:width
output[:,i] = input[i]
end
return output
end
make_matrix (generic function with 1 method)
julia> make_matrix(arr)
4×5 Array{Float64,2}:
2.0 -1.0 0.0 0.0 1.0
-1.0 2.0 -1.0 0.0 1.0
0.0 -1.0 2.0 -1.0 1.0
0.0 0.0 -1.0 3.0 1.0
vertically:
julia> function vmake_matrix(input::Vector{<:Vector})
element_type = eltype(eltype(input))
if (length(input) == 0)
return Array{element_type,2}(undef,0,0)
end
height,width = length(input),length(input[1])
for col in input
(width == length(col)) ? nothing : throw("inconsistent array size")
end
output = Array{element_type}(undef,height,width)
for i in 1:height
output[i,:] = input[i]
end
return output
end
vmake_matrix (generic function with 1 method)
julia> vmake_matrix(arr)
5×4 Array{Float64,2}:
2.0 -1.0 0.0 0.0
-1.0 2.0 -1.0 0.0
0.0 -1.0 2.0 -1.0
0.0 0.0 -1.0 3.0
1.0 1.0 1.0 1.0
without loops
without loops you can use vcat or hcat depending on the direction you want to concatenate the arrays in.
julia> H_arr = [ [ 2.0 -1.0 0.0 0.0],[-1.0 2.0 -1.0 0.0],[0.0 -1.0 2.0 -1.0],[0.0 0.0 -1.0 3.0] ]
4-element Array{Array{Float64,2},1}:
[2.0 -1.0 0.0 0.0]
[-1.0 2.0 -1.0 0.0]
[0.0 -1.0 2.0 -1.0]
[0.0 0.0 -1.0 3.0]
julia> vcat(H_arr...)
4×4 Array{Float64,2}:
2.0 -1.0 0.0 0.0
-1.0 2.0 -1.0 0.0
0.0 -1.0 2.0 -1.0
0.0 0.0 -1.0 3.0
julia> V_arr = [[2.0,-1.0,0.0,0.0],[-1.0,2.0,-1.0,0.0],[0.0,-1.0,2.0,-1.0],[0.0,0.0,-1.0,3.0]]
4-element Array{Array{Float64,1},1}:
[2.0, -1.0, 0.0, 0.0]
[-1.0, 2.0, -1.0, 0.0]
[0.0, -1.0, 2.0, -1.0]
[0.0, 0.0, -1.0, 3.0]
julia> hcat(V_arr...)
4×4 Array{Float64,2}:
2.0 -1.0 0.0 0.0
-1.0 2.0 -1.0 0.0
0.0 -1.0 2.0 -1.0
0.0 0.0 -1.0 3.0

Create a submatrix of UpperTriangularMatrix in Julia

Given a list of columns and rows, I want to produce a submatrix of a cholesky factorization. Example:
julia> A = rand(10,10)
julia> R = chol(A'*A)
julia> ind = [1,3,6,8,9]
julia> R[ind,ind]
However, this results in an error:
ERROR: BoundsError: attempt to access 5x5
UpperTriangular{Float64,Array{Float64,2}}:
1.28259 0.0 0.0 0.0 0.0
0.0 6.51646e-314 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
at index [2,1]
in _unsafe_getindex at multidimensional.jl:197
in getindex at abstractarray.jl:483
I understand that this would work for a typical matrix, but the UpperTriangular type obviously requires something different... I can't find documentation on this.
Looks like Triangular matrices haven't been updated to take advantage of fallback non-scalar indexing in 0.4 (this was a missing method error in 0.3).
Easiest ways around this for now are conversion to a full array before you index:
julia> full(R)[ind,ind]
5x5 Array{Float64,2}:
2.2261 1.28096 1.69087 1.26135 1.50703
0.0 1.03681 0.115735 0.559855 0.70766
0.0 0.0 0.702936 -0.111155 -0.61263
0.0 0.0 0.0 0.661491 0.33661
0.0 0.0 0.0 0.0 0.159691
Or by using a SubArray, which creates a view into the original data (so modifications will propagate):
julia> sub(R, ind, ind)
5x5 SubArray{Float64,2,UpperTriangular{Float64,Array{Float64,2}},Tuple{Array{Int64,1},Array{Int64,1}},0}:
2.2261 1.28096 1.69087 1.26135 1.50703
0.0 1.03681 0.115735 0.559855 0.70766
0.0 0.0 0.702936 -0.111155 -0.61263
0.0 0.0 0.0 0.661491 0.33661
0.0 0.0 0.0 0.0 0.159691

How to get more info on julia array bounds error?

I'd coded a Julia function with an array bounds error:
function wrong()
alphas = [ 0.5, 1, 1.25, 2.0 ] ;
theta = 0:0.02:1 * pi ;
U = zeros( length(theta), 4 ) ;
i = 1 ;
j = 1 ;
for a = alphas
kd = pi * a ;
for t = theta
v = (cos( kd * cos( t ) ) - cos( kd ))/sin( t ) ;
U[i, j] = v ;
i = i + 1 ;
end
j = j + 1 ;
end
end
Here i=1 should be in the loop. I get:
julia> wrong()
ERROR: BoundsError()
in setindex! at array.jl:308 (repeats 2 times)
Is there any way to get the julia interpreter to give more detailed information about exceptions when they are hit, or ways to debug into the failing statement and see what's going on? For example, knowing what the index values that were caused the bounds error when this occurred would have been helpful to debug this.
Bounds error reporting has improved in julia v0.4 via this pull request https://github.com/JuliaLang/julia/pull/9534. In julia 0.4 the array as well as the index you were trying to access get printed by default:
julia> wrong()
ERROR: BoundsError: attempt to access 158x4 Array{Float64,2}:
NaN 0.0 0.0 0.0
0.0157085 0.0 0.0 0.0
0.0314201 0.0 0.0 0.0
0.047138 0.0 0.0 0.0
0.0628651 0.0 0.0 0.0
0.0786045 0.0 0.0 0.0
0.094359 0.0 0.0 0.0
0.110131 0.0 0.0 0.0
0.125924 0.0 0.0 0.0
0.141739 0.0 0.0 0.0
⋮
0.127183 0.0 0.0 0.0
0.111388 0.0 0.0 0.0
0.0956143 0.0 0.0 0.0
0.0798585 0.0 0.0 0.0
0.064118 0.0 0.0 0.0
0.04839 0.0 0.0 0.0
0.0326715 0.0 0.0 0.0
0.0169595 0.0 0.0 0.0
0.00125087 0.0 0.0 0.0
at index [159,2]
in wrong at none:15
I don't know if you can backport the changes to your julia version, but switching to 0.4 should solve your problem.

Resources