Trouble creating a real-valued vector out of elements of multiple complex arrays

Now for some utility functions

"""Expand vector to include padded matrices"""
function ExpandVector(x::Vector; nm=2, nr=2, nc=2, nre=3, nce=3)
    vec(PaddedView(0,reshape(x,(2,nr,nc,nm)),(2,nre,nce,nm)))
end

"""Expand vector to include padded matrices and append parameters"""
function ExpandVectorWithParams(x::Vector; params...)
    [ExpandVector(x;params...); collect(values(params))]
end

"""Extract matrices from vector"""
function VectorToMatrices(x::Vector; nm=2, nr=2, nc=2)
    x = reshape(x,(2,nr,nc,nm))
    x = x[1,:,:,:] + x[2,:,:,:,]*im
    ntuple(i->x[:,:,i],size(x,3))
end

"""Extract expanded matrices from vectors"""
function VectorToExpandedMatrices(x::Vector; nm=2, nre=3, nce=3, args...)
    VectorToMatrices(x; nm=nm, nr=nre, nc=nce)
end

"""Convert matrices back to vector form"""
function MatricesToVector(args...)
    X = cat(dims=3,args...)
    X = cat(dims=4,real.(X),imag.(X))
    X = permutedims(X,(4,1,2,3))
    vec(X)
end

One version if we are allowed to define the functions with known parameters is as follows:

params = (nm=2, nr=2, nc=2, nre=3, nce=3)
Initializer(x::Vector) = ExpandVector(x; params...)
Create(x::Vector) = VectorToExpandedMatrices(x; params...)
Create(x) = Create( collect(x) )


julia> X0 = Initializer( collect(1:16) )
36-element reshape(PaddedView(0, ::Array{Int64,4}, (Base.OneTo(2), Base.OneTo(3), Base.OneTo(3), Base.OneTo(2))), 36) with eltype Int64:
  1
  2
  3
  4
  0
  0
  5
  6
  7
  8
  ⋮
 16
  0
  0
  0
  0
  0
  0
  0
  0

julia> Ae,Be = Create(X0)
(Complex{Int64}[1 + 2im 5 + 6im 0 + 0im; 3 + 4im 7 + 8im 0 + 0im; 0 + 0im 0 + 0im 0 + 0im], Complex{Int64}[9 + 10im 13 + 14im 0 + 0im; 11 + 12im 15 + 16im 0 + 0im; 0 + 0im 0 + 0im 0 + 0im])

julia> Ae
3×3 Array{Complex{Int64},2}:
 1+2im  5+6im  0+0im
 3+4im  7+8im  0+0im
 0+0im  0+0im  0+0im

julia> Be
3×3 Array{Complex{Int64},2}:
  9+10im  13+14im  0+0im
 11+12im  15+16im  0+0im
  0+0im    0+0im   0+0im


Alternatively, let’s say we don’t know the parameters when defining Create:

"""Create with unknown params"""
param_keys = (:nm, :nr, :nc, :nre, :nce)
CreateUnknownParams(x::Vector) = VectorToExpandedMatrices(x[1:end-5]; ( ; zip(param_keys, x[end-4:end]) ... ) ... )

"""Initialize with known params encoded in vector"""
params = (nm=2, nr=2, nc=2, nre=3, nce=3)
InitializeWithParams(x::Vector) = ExpandVectorWithParams(x; params...)

julia> X0 = InitializeWithParams( collect(1:16) )
41-element Array{Int64,1}:
 1
 2
 3
 4
 0
 0
 5
 6
 7
 8
 ⋮
 0
 0
 0
 0
 2
 2
 2
 3
 3

julia> Ae,Be = CreateUnknownParams(X0)
(Complex{Int64}[1 + 2im 5 + 6im 0 + 0im; 3 + 4im 7 + 8im 0 + 0im; 0 + 0im 0 + 0im 0 + 0im], Complex{Int64}[9 + 10im 13 + 14im 0 + 0im; 11 + 12im 15 + 16im 0 + 0im; 0 + 0im 0 + 0im 0 + 0im])

julia> Ae
3×3 Array{Complex{Int64},2}:
 1+2im  5+6im  0+0im
 3+4im  7+8im  0+0im
 0+0im  0+0im  0+0im

julia> Be
3×3 Array{Complex{Int64},2}:
  9+10im  13+14im  0+0im
 11+12im  15+16im  0+0im
  0+0im    0+0im   0+0im

I hope that helps.

3 Likes

Thank you so much, this is exactly what I was looking for, you have helped tremendously. I feel I am finally getting the hang of programming this sort of linear algebra manipulation through this explanation.

I would really suggest leveraging the reinterpret function here:

Instead of

do

function vec2mat(x::Vector{T}; nm=2, nr=2, nc=2) where {T<:Real}
	z = reshape(reinterpret(Complex{T}, x), nr, nc, nm)
	return ntuple(i->z[:,:,i], nm)
end

And instead of

do

function mat2vec(z::AbstractArray{Complex{T}, 2}...) where {T}
	x = vec.(reinterpret.(T, z))
	return vcat(x...)
end

The reinterpret versions are 15-20 times faster (even more if you use view), and, imho, nicer.

2 Likes