Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add numerical simple_projection + try_harder kwarg #41

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
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
99 changes: 99 additions & 0 deletions src/direct_summands.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,102 @@ function SparseArrays.droptol!(
droptol!(image_basis(ds), tol)
return ds
end

function simple_projection(
ds::SymbolicWedderburn.DirectSummand,
G::Group,
hom::SymbolicWedderburn.InducedActionHomomorphism;
atol=eps(eltype(ds))*max(size(ds)...)
)
issimple(ds) && return ds
@assert degree(ds) > 1
@assert rem(size(ds, 1), degree(ds)) == 0
@assert multiplicity(ds) == size(ds, 1)÷degree(ds)

# ds is a projection onto subspace of dimension m·d
# where m=multiplicity(ds), d = degreee(ds)
# here we separate the image into m orthogonal (simple) subspaces
# each of dimension d

Uπ = SymbolicWedderburn.image_basis(ds)
T = eltype(ds)
@assert T == Float64
subspaces = Vector{typeof(Uπ)}()
qrs = LinearAlgebra.QRCompactWY{T, Matrix{T}}[]
sizehint!(subspaces, multiplicity(ds))
sizehint!(qrs, multiplicity(ds))

@assert isapprox(Uπ*Uπ', I, atol=atol)

for (i, b) in enumerate(eachrow(Uπ))
b_orth = if isempty(subspaces)
b
else
b_orth = b - sum(_orth_proj(V, b, QR) for (V, QR) in zip(subspaces, qrs))
end
norm(b_orth, 2) < atol && continue

# we found a new subspace!
# zero_small!(b_orth, atol=atol)
b_orth ./= norm(b_orth, 2)
# seach subspace is of dimension degree(ds)
orbit_subspace = Matrix{T}(undef, length(b_orth), degree(ds))
orbit_subspace[:, 1] .= b_orth

dim = 1
# cached qrfact to be reused when b_orth is already in the orbit_subspace
qrfact = qr(@view orbit_subspace[:, 1:dim])
for g in G
isone(g) && continue
k = action(hom, g, b_orth)
@assert isapprox(norm(k, 2), 1.0, atol=atol) "Norm of translated vector should be ≈ 1.0, got $(norm(k, 2))"

# check if we've seen this one
for c in eachcol(orbit_subspace)
isapprox(k, c, atol=atol) && continue
end
# or maybe it's already in the span of others?
residual = k - _orth_proj(@view(orbit_subspace[:, 1:dim]), k, qrfact)
(rnorm = norm(residual, 2)) < atol && continue
if !isempty(subspaces)
before_norm = norm(residual, 2)
residual = residual - sum(_orth_proj(V, residual, QR) for (V, QR) in zip(subspaces, qrs))
@info "norms" before_norm after_norm=norm(residual, 2)
(rnorm = norm(residual, 2)) < atol && continue
end

# ok, it's not so we found a new vector in the subspace!
dim += 1
orbit_subspace[:, dim] .= residual ./ norm(residual, 2)
qrfact = qr(@view orbit_subspace[:, 1:dim])

if dim == degree(ds)
@info orbit_subspace' * orbit_subspace
@assert isapprox(orbit_subspace' * orbit_subspace, I, atol=atol)
push!(subspaces, orbit_subspace)
push!(qrs, qrfact)
break
end
end
# check that we exited via break, i.e. found all vectors in the subspace
@assert dim == degree(ds)
end
# and that we found exactly the right number of subspaces
@assert length(subspaces) == multiplicity(ds) "Expected $(multiplicity(ds)) subspaces, found $(length(subspaces))"

# as the projection we take the average of all vectors in the subspace
# new_Uπ = typeof(Uπ)(transpose(reduce(hcat, sum.(subspaces, dims=2))))
# new_Uπ ./= degree(ds)
# TODO: math says the the first one would be equally fine
new_Uπ = typeof(Uπ)(transpose(reduce(
hcat,
(@view(s[:, 1]) for s in subspaces)
)))

return SymbolicWedderburn.DirectSummand(
new_Uπ,
degree(ds),
multiplicity(ds),
true
)
end
5 changes: 5 additions & 0 deletions src/wedderburn_decomposition.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ function WedderburnDecomposition(
basis_half,
S = Rational{Int};
semisimple = false,
try_harder = false,
)
basis = StarAlgebras.Basis{UInt32}(basis_full)
invariants = invariant_vectors(G, action, basis)
Expand All @@ -24,6 +25,10 @@ function WedderburnDecomposition(
sa_basis = symmetry_adapted_basis(T, tbl, ehom; semisimple = semisimple)
end

if try_harder
Uπs .= simple_projection.(Uπs, Ref(G), Ref(ehom))
end

return WedderburnDecomposition(basis, invariants, Uπs, ehom)
end

Expand Down