This is a follow up of a recent thread I made Sparse matrices copy arrays, do not view them
I sum up all the shared ideas, with 2 code examples. This is intended as a much clearer version and prosecution of that thread, using what we came up with.
I’m currently stuck with a simple iterative algorithm by the lack of manual deallocation of stuff.
This could be solved by using pointers, but I can’t find anything concrete regarding them.
I was lucky to find a guy (@foobar_lv2) which lead me to some pointer syntax (unsafe_wrap), but I can’t find any documentation on them and they still remain unclear to me.
The issue is that, written a sparse matrix A and used it in a function I will call H_super(), I need to create a new_A using A itself.
new_A is a matrix of different dimension than A and will be used in H_super() the next iteration.
I need to use A and new_A at the same time just when creating new_A.
Thus I split the loop into 2 sections which alternate at every loop iteration:
Odd iteration and even iteration.
This way I can call H_super(A) (iter 1), H_super(new_A) (iter 2), H_super(A) (iter 3)…
A and new_A are preallocated.
I wanted to view slices of them, but sparseArrays doesn’t have a built-in feature to do that. Thus the use of unsafe_wraps.
In additon I incur in an issue when trying to write new_A expression in its buffer.
A sparse matrix buffer consists in 3 arrays and I need to put the expression in these 3 arrays. To use the sparsematrix structure I need to call SparseMatrixCSC, but this only works for arrays that are not undef arrays, waiting to be filled.
In the following program i will call A as Sz and new_A as Sz_temp. It’s actually the Sz pauli matrix
using SparseArrays
using LinearAlgebra
using Kronecker
#Definition of constant
NIter::Int32 = 3
init_N::Int32 = 2 #inizial size of matrices
N::Int32 = init_N ^ NIter #final size of matrices
#sparsization of Sz
nzval_Sz = Vector{Float64}(undef, N)
nzval_Sz[1] = 0.5
nzval_Sz[2] = -0.5
rowval_Sz = Vector{UInt32}(undef, N)
rowval_Sz[1] = 1
rowval_Sz[2] = 2
colptr_Sz = Vector{UInt32}(undef, N+1)
colptr_Sz[1] = 1
colptr_Sz[2] = 2
colptr_Sz[3] = 3 #last one is tot_nnz+1
#definition of temporary arrays
nzval_Sz_temp = Vector{Float64}(undef, N)
rowval_Sz_temp = Vector{UInt32}(undef, N)
colptr_Sz_temp = Vector{UInt32}(undef, N+1)
for i = 1:NIter
m = 2^i
m_next = 2^(i+1)
if i%2 != 0
Sz = SparseMatrixCSC(m, m, unsafe_wrap(Array, pointer(colptr_Sz), (m+1,)) , unsafe_wrap(Array, pointer(rowval_Sz), (m,)) , unsafe_wrap(Array, pointer(nzval_Sz), (m,)))
#H_super(Sz)
Sz_temp = SparseMatrixCSC(m_next, m_next, unsafe_wrap(Array, pointer(colptr_Sz), (m_next+1,)) , unsafe_wrap(Array, pointer(rowval_Sz), (m_next,)) , unsafe_wrap(Array, pointer(nzval_Sz), (m_next,)))
#the line above gives error, as some values are still not allocated. what I want to do is to save teh sparse matrix below in the Sz_temp sparse matrix created by the temporary arrays preallocated.
Sz_temp .= kronecker(sparse(I, m, m), Sz) #I'm writing on Sz_temp arrays #that means that next Sz I need to use is Sz_temp
else
Sz_temp = SparseMatrixCSC(m, m, unsafe_wrap(Array, pointer(colptr_Sz), (m+1,)) , unsafe_wrap(Array, pointer(rowval_Sz), (m,)) , unsafe_wrap(Array, pointer(nzval_Sz), (m,)))
#H_super(Sz_temp)
Sz = SparseMatrixCSC(m_next, m_next, unsafe_wrap(Array, pointer(colptr_Sz), (m_next+1,)) , unsafe_wrap(Array, pointer(rowval_Sz), (m_next,)) , unsafe_wrap(Array, pointer(nzval_Sz), (m_next,)))
#This shares the same issue of the other condition, but with Sz and Sz_temp switched
Sz .= kronecker(sparse(I, m, m), Sz_temp) #I'm writing on Sz arrays #that means that next Sz I need to use is Sz
end
end
Another, much clearer version, is the following.
It requires to somehow delete some data (I still don’t know how it’s done on julia and can’t find anything regarding manual deallocation of stuff)
using SparseArrays
using LinearAlgebra
using Kronecker
#definition of constants
NIter::Int32 = 3
init_N::Int32 = 2
#sparsization of Sz
nzval_Sz = Vector{Float64}(undef, N)
nzval_Sz[1] = 0.5
nzval_Sz[2] = -0.5
rowval_Sz = Vector{UInt32}(undef, N)
rowval_Sz[1] = 1
rowval_Sz[2] = 2
colptr_Sz = Vector{UInt32}(undef, N+1)
colptr_Sz[1] = 1
colptr_Sz[2] = 2
colptr_Sz[3] = 3 #last one is tot_nnz+1
Sz = SparseMatrixCSC(init_N, init_N, colptr_Sz, rowval_Sz, nzval_Sz) #copy of Sz
for i = 1:NIter
m = 2^i
Sz_temp = Sz #copy of the data
#somehow delete Sz which is defined "globally"
#H_super(Sz_temp)
Sz = kronecker(sparse(I, m, m), Sz_temp) #definition of new Sz
#somehow delete Sz_temp
end