Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ TupleTools = "9d95972d-f1c8-5527-a6e0-b4b365fa01f6"
TypeParameterAccessors = "7e5a90cf-f82e-492e-a09b-e3e26432c138"

[weakdeps]
BlockSparseArrays = "2c9a651f-6452-4ace-a6ac-809f4280fbb4"
GradedUnitRanges = "e2de450a-8a67-46c7-b59c-01d5a3d041c5"

[extensions]
TensorAlgebraGradedUnitRangesExt = "GradedUnitRanges"
TensorAlgebraBlockSparseArraysGradedUnitRangesExt = ["BlockSparseArrays", "GradedUnitRanges"]

[compat]
ArrayLayouts = "1.10.4"
BlockArrays = "1.2.0"
BlockSparseArrays = "0.3.6"
EllipsisNotation = "1.8.0"
GradedUnitRanges = "0.1.0"
LinearAlgebra = "1.10.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module TensorAlgebraBlockSparseArraysGradedUnitRangesExt

using BlockArrays: Block, blocksize
using BlockSparseArrays: BlockSparseMatrix, @view!
using GradedUnitRanges: AbstractGradedUnitRange, dual, tensor_product
using Random: AbstractRNG
using TensorAlgebra: TensorAlgebra, random_unitary!

function TensorAlgebra.:⊗(a1::AbstractGradedUnitRange, a2::AbstractGradedUnitRange)
return tensor_product(a1, a2)
end

function TensorAlgebra.square_zero_map(
elt::Type, ax::Tuple{AbstractGradedUnitRange,Vararg{AbstractGradedUnitRange}}
)
return BlockSparseArray{elt}(undef, (dual.(ax)..., ax...))
end

function TensorAlgebra.random_unitary!(
rng::AbstractRNG,
a::BlockSparseMatrix{
<:Any,<:Any,<:Any,<:Tuple{AbstractGradedUnitRange,Vararg{AbstractGradedUnitRange}}
},
)
# TODO: Define and use `blockdiagindices`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something worth considering: in this function we are not guaranteed the user inputted a square matrix, in which case this function would still work, but spit out a random left- or right- isometry. I think if we call the function unitary, we probably want to check for this, either by an explicit checksquare, or some other means.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I had that in mind but forgot to add that check. We should definitely check it is square (and more specifically, the blocks are the same and the codomain is the dual of the domain).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is definitely that it is unitary in a strict sense, in that it literally maps the space back to itself.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After adding this check, I realized there is a crucial thing missing from this PR, which is specifying that the codomain and domain are duals of each other. That will require a separate PR to fusedims to support that, though @ogauthe is reworking fusedims/splitdims to accommodate FusionTensors so I'll hold off on that for now.

# or `blockdiaglength`.
for i in 1:blocksize(a, 1)
a[Block(i, i)] = random_unitary!(rng, @view!(a[Block(i, i)]))
end
return a
end

end

This file was deleted.

2 changes: 0 additions & 2 deletions src/fusedims.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ function fusedims(::ReshapeFusion, a::AbstractArray, axes::AbstractUnitRange...)
return reshape(a, axes)
end

dual(x) = x

⊗(a::AbstractUnitRange) = a
function ⊗(a1::AbstractUnitRange, a2::AbstractUnitRange, as::AbstractUnitRange...)
return ⊗(a1, ⊗(a2, as...))
Expand Down
39 changes: 21 additions & 18 deletions src/random_unitary.jl
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
using Random: Random, AbstractRNG
using MatrixAlgebraKit: qr_full!
using Random: Random, AbstractRNG, randn!

function random_unitary(
rng::AbstractRNG, elt::Type, ax::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}
)
ax_fused = ⊗(ax...)
a_fused = random_unitary(rng, elt, ax_fused)
return splitdims(a_fused, dual.(ax), ax)
function square_zero_map(elt::Type, ax::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}})
return zeros(elt, (ax..., ax...))
end

# Copy of `Base.to_dim`:
# https://github.com/JuliaLang/julia/blob/1431bec1bcd205f181ca2a3f1c314247b64076df/base/array.jl#L439-L440
to_dim(d::Integer) = d
to_dim(d::Base.OneTo) = last(d)

# Matrix version.
function random_unitary(rng::AbstractRNG, elt::Type, ax::Tuple{AbstractUnitRange})
return random_unitary(rng, elt, map(to_dim, ax))
using EllipsisNotation: : .. function random_unitary!(rng::AbstractRNG, a::AbstractArray)
@assert iseven(ndims(a))
ndims_codomain = ndims(a) ÷ 2
biperm = blockedperm(ntuple(identity, ndims(a)), (ndims_codomain, ndims_codomain))
a_mat = fusedims(a, biperm)
r_mat = random_unitary!(rng, a_mat)
splitdims!(a, r_mat, biperm)
return a
end

using MatrixAlgebraKit: qr_full!
function random_unitary(rng::AbstractRNG, elt::Type, dims::Tuple{Integer})
Q, _ = qr_full!(randn(rng, elt, (dims..., dims...)); positive=true)
function random_unitary!(rng::AbstractRNG, a::AbstractMatrix)
a_r = randn!(rng, a)
Q, _ = qr_full!(randn!(rng, a); positive=true)
return Q
end

function random_unitary(
rng::AbstractRNG, elt::Type, ax::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}
)
return random_unitary!(rng, square_zero_map(elt, ax))
end

# Canonicalizing other kinds of inputs.
function random_unitary(
rng::AbstractRNG, elt::Type, dims::Tuple{Vararg{Union{AbstractUnitRange,Integer}}}
Expand Down
1 change: 1 addition & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[deps]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"
BlockSparseArrays = "2c9a651f-6452-4ace-a6ac-809f4280fbb4"
EllipsisNotation = "da5c29d0-fa7d-589e-88eb-ea29b0a81949"
GradedUnitRanges = "e2de450a-8a67-46c7-b59c-01d5a3d041c5"
JLArrays = "27aeb0d3-9eb9-45fb-866b-73c2ecf80fcb"
Expand Down
Loading