mirror of
https://github.com/kalmarek/PropertyT.jl.git
synced 2024-11-24 16:35:28 +01:00
Compare commits
6 Commits
f9f852439f
...
005ffc29cb
Author | SHA1 | Date | |
---|---|---|---|
005ffc29cb | |||
5b4a7f6804 | |||
150b5c2cba | |||
3f2be20152 | |||
132802feeb | |||
1a43a1b1be |
@ -83,26 +83,29 @@ Base.@propagate_inbounds function Base.getindex(
|
|||||||
return pos - neg
|
return pos - neg
|
||||||
end
|
end
|
||||||
|
|
||||||
struct NZPairsIter{T}
|
struct NZPairsIter{T,I}
|
||||||
m::ConstraintMatrix{T}
|
m::ConstraintMatrix{T,I}
|
||||||
end
|
end
|
||||||
|
|
||||||
Base.eltype(::Type{NZPairsIter{T}}) where {T} = Pair{Int,T}
|
Base.eltype(::Type{NZPairsIter{T}}) where {T} = Pair{Int,T}
|
||||||
Base.IteratorSize(::Type{<:NZPairsIter}) = Base.SizeUnknown()
|
Base.IteratorSize(::Type{<:NZPairsIter}) = Base.SizeUnknown()
|
||||||
|
|
||||||
# TODO: iterate over (idx=>val) pairs combining vals
|
# TODO: iterate over (idx=>val) pairs combining vals
|
||||||
function Base.iterate(itr::NZPairsIter, state::Tuple{Int,Int} = (1, 1))
|
function Base.iterate(
|
||||||
|
itr::NZPairsIter,
|
||||||
|
state::Tuple{Int,Nothing} = (1, nothing),
|
||||||
|
)
|
||||||
k = iterate(itr.m.pos, state[1])
|
k = iterate(itr.m.pos, state[1])
|
||||||
isnothing(k) && return iterate(itr, state[2])
|
isnothing(k) && return iterate(itr, (nothing, 1))
|
||||||
idx, st = k
|
idx, st = k
|
||||||
return idx => itr.m.val, (st, 1)
|
return idx => itr.m.val, (st, nothing)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.iterate(itr::NZPairsIter, state::Int)
|
function Base.iterate(itr::NZPairsIter, state::Tuple{Nothing,Int})
|
||||||
k = iterate(itr.m.neg, state[1])
|
k = iterate(itr.m.neg, state[2])
|
||||||
isnothing(k) && return nothing
|
isnothing(k) && return nothing
|
||||||
idx, st = k
|
idx, st = k
|
||||||
return idx => -itr.m.val, st
|
return idx => -itr.m.val, (nothing, st)
|
||||||
end
|
end
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -12,9 +12,10 @@ function reconstruct(
|
|||||||
n = __outer_dim(wbdec)
|
n = __outer_dim(wbdec)
|
||||||
res = sum(zip(Ms, SymbolicWedderburn.direct_summands(wbdec))) do (M, ds)
|
res = sum(zip(Ms, SymbolicWedderburn.direct_summands(wbdec))) do (M, ds)
|
||||||
res = similar(M, n, n)
|
res = similar(M, n, n)
|
||||||
res = _reconstruct!(res, M, ds, __group_of(wbdec), wbdec.hom)
|
res = _reconstruct!(res, M, ds)
|
||||||
return res
|
return res
|
||||||
end
|
end
|
||||||
|
res = average!(zero(res), res, __group_of(wbdec), wbdec.hom)
|
||||||
return res
|
return res
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -22,16 +23,14 @@ function _reconstruct!(
|
|||||||
res::AbstractMatrix,
|
res::AbstractMatrix,
|
||||||
M::AbstractMatrix,
|
M::AbstractMatrix,
|
||||||
ds::SymbolicWedderburn.DirectSummand,
|
ds::SymbolicWedderburn.DirectSummand,
|
||||||
G,
|
|
||||||
hom,
|
|
||||||
)
|
)
|
||||||
|
res .= zero(eltype(res))
|
||||||
|
if !iszero(M)
|
||||||
U = SymbolicWedderburn.image_basis(ds)
|
U = SymbolicWedderburn.image_basis(ds)
|
||||||
d = SymbolicWedderburn.degree(ds)
|
d = SymbolicWedderburn.degree(ds)
|
||||||
Θπ = (U' * M * U) .* d
|
res = (U' * M * U) .* d
|
||||||
|
end
|
||||||
res .= zero(eltype(res))
|
return res
|
||||||
Θπ = average!(res, Θπ, G, hom)
|
|
||||||
return Θπ
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function __droptol!(M::AbstractMatrix, tol)
|
function __droptol!(M::AbstractMatrix, tol)
|
||||||
@ -52,18 +51,18 @@ function average!(
|
|||||||
<:SymbolicWedderburn.ByPermutations,
|
<:SymbolicWedderburn.ByPermutations,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
res .= zero(eltype(res))
|
||||||
@assert size(M) == size(res)
|
@assert size(M) == size(res)
|
||||||
|
o = Groups.order(Int, G)
|
||||||
for g in G
|
for g in G
|
||||||
p = SymbolicWedderburn.induce(hom, g)
|
p = SymbolicWedderburn.induce(hom, g)
|
||||||
Threads.@threads for c in axes(res, 2)
|
Threads.@threads for c in axes(res, 2)
|
||||||
# note: p is a permutation,
|
|
||||||
# so accesses below are guaranteed to be disjoint
|
|
||||||
for r in axes(res, 1)
|
for r in axes(res, 1)
|
||||||
res[r^p, c^p] += M[r, c]
|
if !iszero(M[r, c])
|
||||||
|
res[r^p, c^p] += M[r, c] / o
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
o = Groups.order(Int, G)
|
|
||||||
res ./= o
|
|
||||||
return res
|
return res
|
||||||
end
|
end
|
||||||
|
@ -99,7 +99,7 @@ function invariant_constraint!(
|
|||||||
invariant_vec::SparseVector,
|
invariant_vec::SparseVector,
|
||||||
) where {K}
|
) where {K}
|
||||||
result .= zero(eltype(result))
|
result .= zero(eltype(result))
|
||||||
for i in SparseArrays.nonzeroinds(invariant_vec)
|
@inbounds for i in SparseArrays.nonzeroinds(invariant_vec)
|
||||||
g = basis[i]
|
g = basis[i]
|
||||||
A = cnstrs[g]
|
A = cnstrs[g]
|
||||||
for (idx, v) in nzpairs(A)
|
for (idx, v) in nzpairs(A)
|
||||||
@ -109,6 +109,25 @@ function invariant_constraint!(
|
|||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function invariant_constraint(basis, cnstrs, invariant_vec)
|
||||||
|
I = UInt32[]
|
||||||
|
J = UInt32[]
|
||||||
|
V = Float64[]
|
||||||
|
_M = first(values(cnstrs))
|
||||||
|
CI = CartesianIndices(_M)
|
||||||
|
@inbounds for i in SparseArrays.nonzeroinds(invariant_vec)
|
||||||
|
g = basis[i]
|
||||||
|
A = cnstrs[g]
|
||||||
|
for (idx, v) in nzpairs(A)
|
||||||
|
ci = CI[idx]
|
||||||
|
push!(I, ci[1])
|
||||||
|
push!(J, ci[2])
|
||||||
|
push!(V, invariant_vec[i] * v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return sparse(I, J, V, size(_M)...)
|
||||||
|
end
|
||||||
|
|
||||||
function isorth_projection(ds::SymbolicWedderburn.DirectSummand)
|
function isorth_projection(ds::SymbolicWedderburn.DirectSummand)
|
||||||
U = SymbolicWedderburn.image_basis(ds)
|
U = SymbolicWedderburn.image_basis(ds)
|
||||||
return isapprox(U * U', I)
|
return isapprox(U * U', I)
|
||||||
@ -175,8 +194,23 @@ function sos_problem_primal(
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
id_one = findfirst(invariant_vectors(wedderburn)) do v
|
||||||
|
b = basis(parent(elt))
|
||||||
|
return sparsevec([b[one(first(b))]], [1 // 1], length(v)) == v
|
||||||
|
end
|
||||||
|
|
||||||
|
prog = ProgressMeter.Progress(
|
||||||
|
length(invariant_vectors(wedderburn));
|
||||||
|
dt = 1,
|
||||||
|
desc = "Adding constraints: ",
|
||||||
|
enabled = show_progress,
|
||||||
|
barlen = 60,
|
||||||
|
showspeed = true,
|
||||||
|
)
|
||||||
|
|
||||||
feasibility_problem = iszero(orderunit)
|
feasibility_problem = iszero(orderunit)
|
||||||
|
|
||||||
|
# problem creation starts here
|
||||||
model = JuMP.Model()
|
model = JuMP.Model()
|
||||||
if !feasibility_problem # add λ or not?
|
if !feasibility_problem # add λ or not?
|
||||||
λ = JuMP.@variable(model, λ)
|
λ = JuMP.@variable(model, λ)
|
||||||
@ -190,58 +224,52 @@ function sos_problem_primal(
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
P = map(direct_summands(wedderburn)) do ds
|
# semidefinite constraints as described by wedderburn
|
||||||
|
Ps = map(direct_summands(wedderburn)) do ds
|
||||||
dim = size(ds, 1)
|
dim = size(ds, 1)
|
||||||
P = JuMP.@variable(model, [1:dim, 1:dim], Symmetric)
|
P = JuMP.@variable(model, [1:dim, 1:dim], Symmetric)
|
||||||
JuMP.@constraint(model, P in PSDCone())
|
JuMP.@constraint(model, P in PSDCone())
|
||||||
return P
|
return P
|
||||||
end
|
end
|
||||||
|
|
||||||
begin # preallocating
|
begin # Ms are preallocated for the constraints loop
|
||||||
T = eltype(wedderburn)
|
T = eltype(wedderburn)
|
||||||
Ms = [spzeros.(T, size(p)...) for p in P]
|
Ms = [spzeros.(T, size(p)...) for p in Ps]
|
||||||
M_orb = zeros(T, size(parent(elt).mstructure)...)
|
_eps = 10 * eps(T) * max(size(parent(elt).mstructure)...)
|
||||||
end
|
end
|
||||||
|
|
||||||
X = convert(Vector{T}, StarAlgebras.coeffs(elt))
|
X = StarAlgebras.coeffs(elt)
|
||||||
U = convert(Vector{T}, StarAlgebras.coeffs(orderunit))
|
U = StarAlgebras.coeffs(orderunit)
|
||||||
|
|
||||||
# defining constraints based on the multiplicative structure
|
# defining constraints based on the multiplicative structure
|
||||||
cnstrs = constraints(parent(elt); augmented = augmented)
|
cnstrs = constraints(parent(elt); augmented = augmented)
|
||||||
|
|
||||||
prog = ProgressMeter.Progress(
|
# adding linear constraints: one per orbit
|
||||||
length(invariant_vectors(wedderburn));
|
|
||||||
dt = 1,
|
|
||||||
desc = "Adding constraints: ",
|
|
||||||
enabled = show_progress,
|
|
||||||
barlen = 60,
|
|
||||||
showspeed = true,
|
|
||||||
)
|
|
||||||
|
|
||||||
for (i, iv) in enumerate(invariant_vectors(wedderburn))
|
for (i, iv) in enumerate(invariant_vectors(wedderburn))
|
||||||
ProgressMeter.next!(prog; showvalues = __show_itrs(i, prog.n))
|
ProgressMeter.next!(prog; showvalues = __show_itrs(i, prog.n))
|
||||||
|
augmented && i == id_one && continue
|
||||||
|
# i == 500 && break
|
||||||
|
|
||||||
x = dot(X, iv)
|
x = dot(X, iv)
|
||||||
u = dot(U, iv)
|
u = dot(U, iv)
|
||||||
|
|
||||||
M_orb = invariant_constraint!(M_orb, basis(parent(elt)), cnstrs, iv)
|
spM_orb = invariant_constraint(basis(parent(elt)), cnstrs, iv)
|
||||||
|
|
||||||
Ms = SymbolicWedderburn.diagonalize!(
|
Ms = SymbolicWedderburn.diagonalize!(
|
||||||
Ms,
|
Ms,
|
||||||
M_orb,
|
spM_orb,
|
||||||
wedderburn;
|
wedderburn;
|
||||||
trace_preserving = true,
|
trace_preserving = true,
|
||||||
)
|
)
|
||||||
# SparseArrays.droptol!.(Ms, 10 * eps(T) * max(size(M_orb)...))
|
for M in Ms
|
||||||
|
SparseArrays.droptol!(M, _eps)
|
||||||
# @info [nnz(m) / length(m) for m in Ms]
|
end
|
||||||
|
|
||||||
if feasibility_problem
|
if feasibility_problem
|
||||||
JuMP.@constraint(model, x == _dot(P, Ms))
|
JuMP.@constraint(model, x == _dot(Ps, Ms))
|
||||||
else
|
else
|
||||||
JuMP.@constraint(model, x - λ * u == _dot(P, Ms))
|
JuMP.@constraint(model, x - λ * u == _dot(Ps, Ms))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
ProgressMeter.finish!(prog)
|
ProgressMeter.finish!(prog)
|
||||||
return model, P
|
return model, Ps
|
||||||
end
|
end
|
||||||
|
@ -176,7 +176,7 @@ end
|
|||||||
wd;
|
wd;
|
||||||
upper_bound = UB,
|
upper_bound = UB,
|
||||||
halfradius = 2,
|
halfradius = 2,
|
||||||
optimizer = cosmo_optimizer(; accel = 50, alpha = 1.9),
|
optimizer = scs_optimizer(; accel = 50, alpha = 1.9),
|
||||||
)
|
)
|
||||||
@test status == JuMP.OPTIMAL
|
@test status == JuMP.OPTIMAL
|
||||||
@test !certified
|
@test !certified
|
||||||
|
Loading…
Reference in New Issue
Block a user