Skip to content

Commit 78d26ce

Browse files
authored
Use StarAlgebras.QuadraticForm (#391)
* Use StarAlgebras.QuadraticForm * Update branch * Fix format * Fixes * Fix format * Fix * Back to `StarAlgebras#main` * Fix * Fixes * Fix format * Remove useless lines * Missing star * Fix format
1 parent aabcab2 commit 78d26ce

File tree

6 files changed

+95
-134
lines changed

6 files changed

+95
-134
lines changed

docs/src/tutorials/Symmetry/cyclic.jl

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -90,18 +90,6 @@ model = Model(solver)
9090
@variable(model, t)
9191
@objective(model, Max, t)
9292
pattern = Symmetry.Pattern(G, action)
93-
basis = MB.explicit_basis(MB.algebra_element(poly - t))
94-
using SymbolicWedderburn
95-
summands = SymbolicWedderburn.symmetry_adapted_basis(
96-
Float64,
97-
pattern.group,
98-
pattern.action,
99-
basis,
100-
semisimple = true,
101-
)
102-
103-
gram_basis = SumOfSquares.Certificate.Symmetry._gram_basis(pattern, basis, Float64)
104-
10593
con_ref = @constraint(model, poly - t in SOSCone(), symmetry = pattern)
10694
optimize!(model)
10795
@test termination_status(model) == MOI.OPTIMAL #src

src/Bridges/Constraint/sos_polynomial_in_semialgebraic_set.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ function MOI.Bridges.Constraint.bridge_constraint(
6363
λ_constraints = UMCT[]
6464
preprocessed =
6565
Certificate.preprocessed_domain(set.certificate, set.domain, p)
66+
implicit_basis = MB.implicit_basis(set.basis)
67+
cache = zero(MOI.ScalarAffineFunction{T}, MB.algebra(implicit_basis))
6668
for index in Certificate.preorder_indices(set.certificate, preprocessed)
6769
λ, λ_variable, λ_constraint, λ_basis = lagrangian_multiplier(
6870
model,
@@ -79,14 +81,15 @@ function MOI.Bridges.Constraint.bridge_constraint(
7981
# `Float64` when used with JuMP and the coefficient type is often `Int` if
8082
# `set.domain.V` is `FullSpace` or `FixedPolynomialSet`.
8183
g = Certificate.generator(set.certificate, index, preprocessed)
84+
MA.operate_to!(cache, +, λ)
8285
# TODO replace with `MA.sub_mul` when it works.
8386
p = MA.operate!(
8487
SA.UnsafeAddMul(*),
8588
p,
86-
λ,
89+
cache,
8790
MB.algebra_element(
8891
MB.sparse_coefficients(-one(T) * similar(g, T)),
89-
MB.FullBasis{MB.Monomial,MP.monomial_type(g)}(),
92+
implicit_basis,
9093
),
9194
)
9295
end

src/Bridges/Variable/kernel.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ function MOI.Bridges.Variable.bridge_constrained_variable(
1212
) where {T,M}
1313
variables = Vector{MOI.VariableIndex}[]
1414
constraints = MOI.ConstraintIndex{MOI.VectorOfVariables}[]
15-
acc = zero(
16-
MOI.ScalarAffineFunction{T},
17-
MB.algebra(MB.implicit_basis(set.basis)),
18-
)
15+
algebra = MB.algebra(MB.implicit_basis(set.basis))
16+
acc = zero(MOI.ScalarAffineFunction{T}, algebra)
17+
cache = zero(MOI.ScalarAffineFunction{T}, algebra)
1918
for (gram_basis, weight) in zip(set.gram_bases, set.weights)
2019
gram, vars, con = SOS.add_gram_matrix(model, M, gram_basis, T)
2120
push!(variables, vars)
2221
push!(constraints, con)
23-
MA.operate!(SA.UnsafeAddMul(*), acc, gram, weight)
22+
MA.operate_to!(cache, +, gram)
23+
MA.operate!(SA.UnsafeAddMul(*), acc, cache, weight)
2424
end
2525
MA.operate!(SA.canonical, SA.coeffs(acc))
2626
return KernelBridge{T,M}(

src/Certificate/ideal.jl

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ function _combine_with_gram(
2020
weights,
2121
) where {B,M}
2222
p = zero(_NonZero, MB.algebra(MB.FullBasis{B,M}()))
23+
cache = zero(_NonZero, MB.algebra(MB.FullBasis{B,M}()))
2324
for mono in basis
2425
MA.operate!(
2526
SA.UnsafeAddMul(*),
@@ -29,12 +30,12 @@ function _combine_with_gram(
2930
)
3031
end
3132
for (gram, weight) in zip(gram_bases, weights)
32-
MA.operate!(
33-
SA.UnsafeAddMul(*),
34-
p,
33+
MA.operate_to!(
34+
cache,
35+
+,
3536
GramMatrix{_NonZero}((_, _) -> _NonZero(), gram),
36-
weight,
3737
)
38+
MA.operate!(SA.UnsafeAddMul(*), p, cache, weight)
3839
end
3940
MA.operate!(SA.canonical, SA.coeffs(p))
4041
return MB.SubBasis{B}(keys(SA.coeffs(p)))

src/Certificate/newton_polytope.jl

Lines changed: 32 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,9 @@ Base.copy(s::SignChange) = s
567567
Base.iszero(::SignChange) = false
568568
MA.scaling_convert(::Type, s::SignChange) = s
569569
Base.:*(s::SignChange, α::Real) = SignChange(s.sign * α, s.Δ)
570+
Base.:*::Real, s::SignChange) = SignChange* s.sign, s.Δ)
571+
#Base.convert(::Type{SignChange{T}}, s::SignChange) where {T} = SignChange{T}(s.sign, s.Δ)
572+
#Base.:+(a::SignChange, b::SignChange) = convert(SignCount, a) + b
570573

571574
struct SignCount
572575
unknown::Int
@@ -586,6 +589,9 @@ function _sign(c::SignCount)
586589
return missing
587590
end
588591
end
592+
function Base.show(io::IO, c::SignCount)
593+
return print(io, "[$(c.unknown)|$(c.positive)|$(c.negative)]")
594+
end
589595

590596
function Base.:*(α, a::SignCount)
591597
if α > 0
@@ -630,26 +636,16 @@ end
630636

631637
Base.convert(::Type{SignCount}, Δ::SignChange) = SignCount() + Δ
632638

633-
function increase(cache, counter, generator_sign, monos, mult)
634-
for a in monos
635-
for b in monos
636-
MA.operate_to!(
637-
cache,
638-
*,
639-
MB.algebra_element(mult),
640-
MB.algebra_element(a),
641-
MB.algebra_element(b),
642-
)
643-
MA.operate!(
644-
SA.UnsafeAddMul(*),
645-
counter,
646-
_term_constant_monomial(
647-
SignChange((a != b) ? missing : generator_sign, 1),
648-
mult,
649-
),
650-
cache,
651-
)
652-
end
639+
struct SignGram{T,B}
640+
sign::T
641+
basis::B
642+
end
643+
SA.basis(g::SignGram) = g.basis
644+
function Base.getindex(g::SignGram, i, j)
645+
if i == j
646+
return SignChange(g.sign, 1)
647+
else
648+
return SignChange(missing, 1)
653649
end
654650
end
655651

@@ -715,38 +711,33 @@ function post_filter(
715711
_DictCoefficients(Dict{MP.monomial_type(typeof(poly)),SignCount}()),
716712
MB.implicit_basis(SA.basis(poly)),
717713
)
718-
algebra = MB.algebra(MB.implicit_basis(SA.basis(poly)))
719-
cache = zero(Float64, algebra)
720-
cache3 = zero(SignCount, algebra)
721-
cache4 = zero(SignCount, algebra)
714+
cache = zero(SignCount, MB.algebra(MB.implicit_basis(SA.basis(poly))))
715+
cache2 = zero(SignCount, MB.algebra(MB.implicit_basis(SA.basis(poly))))
722716
for (mono, v) in SA.nonzero_pairs(SA.coeffs(poly))
723717
MA.operate!(
724-
SA.UnsafeAddMul(*),
718+
SA.UnsafeAdd(),
725719
counter,
726720
_term(SignChange(_sign(v), 1), SA.basis(poly)[mono]),
727721
)
728722
end
729723
for (mult, gram_monos) in zip(generators, multipliers_gram_monos)
730-
for (mono, v) in SA.nonzero_pairs(SA.coeffs(mult))
731-
increase(
732-
cache,
733-
counter,
734-
-_sign(v),
735-
gram_monos,
736-
SA.basis(mult)[mono],
737-
)
738-
end
724+
MA.operate_to!(
725+
cache,
726+
+,
727+
SA.QuadraticForm{SA.star}(SignGram(-1, gram_monos)),
728+
)
729+
MA.operate!(SA.UnsafeAddMul(*), counter, mult, cache)
739730
end
740731
function decrease(sign, a, b, generator)
741732
MA.operate_to!(
742-
cache3,
733+
cache,
743734
*,
744735
_term(SignChange(sign, -1), a),
745736
MB.algebra_element(b),
746737
)
747-
MA.operate_to!(cache4, *, cache3, generator)
748-
MA.operate!(SA.UnsafeAddMul(*), counter, cache4)
749-
for mono in SA.supp(cache4)
738+
MA.operate_to!(cache2, *, cache, generator)
739+
MA.operate!(SA.UnsafeAdd(), counter, cache2)
740+
for mono in SA.supp(cache2)
750741
count = SA.coeffs(counter)[SA.basis(counter)[mono]]
751742
count_sign = _sign(count)
752743
# This means the `counter` has a sign and it didn't have a sign before
@@ -781,16 +772,16 @@ function post_filter(
781772
for i in eachindex(generators)
782773
for (j, mono) in enumerate(multipliers_gram_monos[i])
783774
MA.operate_to!(
784-
cache3,
775+
cache,
785776
*,
786777
# Dummy coef to help convert to `SignCount` which is the `eltype` of `cache`
787778
_term(SignChange(1, 1), mono),
788779
MB.algebra_element(mono),
789780
)
790781
# The `eltype` of `cache` is `SignCount`
791782
# so there is no risk of term cancellation
792-
MA.operate_to!(cache4, *, cache3, generators[i])
793-
for w in SA.supp(cache4)
783+
MA.operate_to!(cache2, *, cache, generators[i])
784+
for w in SA.supp(cache2)
794785
if ismissing(_sign(SA.coeffs(counter)[SA.basis(counter)[w]]))
795786
push!(get!(back, w, Tuple{Int,Int}[]), (i, j))
796787
else

src/gram_matrix.jl

Lines changed: 48 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ function MP.similar_type(
9090
return GramMatrix{S,B,US,MS}
9191
end
9292

93+
SA.basis(g::GramMatrix) = g.basis
9394
MB.implicit_basis(g::GramMatrix) = MB.implicit_basis(g.basis)
9495

9596
# When taking the promotion of a GramMatrix of JuMP.Variable with a Polynomial JuMP.Variable, it should be a Polynomial of AffExpr
@@ -137,76 +138,13 @@ function GramMatrix(Q::AbstractMatrix, monos::AbstractVector)
137138
return GramMatrix(Q, MB.SubBasis{MB.Monomial}(sorted_monos), σ)
138139
end
139140

140-
# `_gram_operate!` is a temporary workaround waiting for a cleaner solution
141-
# in https://github.com/JuliaAlgebra/StarAlgebras.jl/pull/62
142-
143-
function _gram_operate!(
144-
op,
145-
p,
146-
α,
147-
row::MB.Polynomial,
148-
col::MB.Polynomial,
149-
args::Vararg{Any,N},
150-
) where {N}
151-
return MA.operate!(
152-
op,
153-
p,
154-
MB.term_element(true, row), # TODO `*` shouldn't be defined for group elements so this is a hack
155-
MB.term_element(α, col),
156-
args...,
157-
)
158-
end
159-
160-
function _gram_operate!(
161-
op,
162-
p,
163-
α,
164-
row::SA.AlgebraElement,
165-
col::SA.AlgebraElement,
166-
args::Vararg{Any,N},
167-
) where {N}
168-
return MA.operate!(
169-
op,
170-
p,
171-
true * row, # TODO `*` shouldn't be defined for group elements so this is a hack
172-
α * col,
173-
args...,
174-
)
175-
end
176-
177-
function _gram_operate!(
178-
op,
179-
p,
180-
α,
181-
row::MB.SemisimpleElement,
182-
col::MB.SemisimpleElement,
183-
args::Vararg{Any,N},
184-
) where {N}
185-
for (r, c) in zip(row.elements, col.elements)
186-
_gram_operate!(op, p, α, r, c, args...)
187-
end
188-
end
189-
190141
function MA.operate!(
191142
op::SA.UnsafeAddMul{typeof(*)},
192143
p::SA.AlgebraElement,
193144
g::GramMatrix,
194145
args::Vararg{Any,N},
195146
) where {N}
196-
for row in eachindex(g.basis)
197-
row_star = SA.star(g.basis[row])
198-
for col in eachindex(g.basis)
199-
_gram_operate!(
200-
op,
201-
p,
202-
g.Q[row, col],
203-
row_star,
204-
g.basis[col],
205-
args...,
206-
)
207-
end
208-
end
209-
return p
147+
return MA.operate!(op, p, SA.QuadraticForm{SA.star}(g), args...)
210148
end
211149

212150
"""
@@ -320,6 +258,51 @@ end
320258
# convert(PT, MP.polynomial(p))
321259
#end
322260

261+
function MA.operate_to!(a::SA.AlgebraElement, ::typeof(+), g::GramMatrix)
262+
return MA.operate_to!(a, +, SA.QuadraticForm{SA.star}(g))
263+
end
264+
265+
function MA.operate!(op::SA.UnsafeAdd, a::SA.AlgebraElement, g::GramMatrix)
266+
return MA.operate!(op, a, SA.QuadraticForm{SA.star}(g))
267+
end
268+
269+
function MA.operate!(
270+
op::SA.UnsafeAdd,
271+
a::SA.AlgebraElement,
272+
g::BlockDiagonalGramMatrix,
273+
)
274+
for block in g.blocks
275+
MA.operate!(op, a, block)
276+
end
277+
return a
278+
end
279+
280+
function MA.operate_to!(
281+
a::SA.AlgebraElement,
282+
::typeof(+),
283+
g::BlockDiagonalGramMatrix,
284+
)
285+
MA.operate!(zero, a)
286+
MA.operate!(SA.UnsafeAdd(), a, g)
287+
MA.operate!(SA.canonical, a)
288+
return a
289+
end
290+
291+
function MB.algebra_element(
292+
p::Union{GramMatrix{T,B,U},BlockDiagonalGramMatrix{T,B,U}},
293+
) where {T,B,U}
294+
return MB.algebra_element(p, U)
295+
end
296+
297+
function MB.algebra_element(
298+
g::Union{GramMatrix,BlockDiagonalGramMatrix},
299+
::Type{T},
300+
) where {T}
301+
a = zero(T, MB.algebra(MB.implicit_basis(g)))
302+
MA.operate_to!(a, +, g)
303+
return a
304+
end
305+
323306
function MP.polynomial(
324307
p::Union{GramMatrix{T,B,U},BlockDiagonalGramMatrix{T,B,U}},
325308
) where {T,B,U}
@@ -330,10 +313,5 @@ function MP.polynomial(
330313
g::Union{GramMatrix,BlockDiagonalGramMatrix},
331314
::Type{T},
332315
) where {T}
333-
p = zero(T, MB.algebra(MB.implicit_basis(g)))
334-
MA.operate!(SA.UnsafeAddMul(*), p, g)
335-
MA.operate!(SA.canonical, SA.coeffs(p))
336-
return MP.polynomial(
337-
SA.coeffs(p, MB.FullBasis{MB.Monomial,MP.monomial_type(g)}()),
338-
)
316+
return MP.polynomial(MB.algebra_element(g, T))
339317
end

0 commit comments

Comments
 (0)