@@ -209,70 +209,6 @@ function half_newton_polytope(basis::SA.ExplicitBasis, newton::NewtonFilter)
209
209
return post_filter (gram_monos, monos)
210
210
end
211
211
212
- # If `mono` is such that there is no other way to have `mono^2` by multiplying
213
- # two different monomials of `monos` and `mono` is not in `X` then, the corresponding
214
- # diagonal entry of the Gram matrix will be zero hence the whole column and row
215
- # will be zero hence we can remove this monomial.
216
- # See [Proposition 3.7, CLR95], [Theorem 2, L09] or [Section 2.4, BKP16].
217
-
218
- # [CLR95] Choi, M. D. and Lam, T. Y. and Reznick, B.
219
- # *Sum of Squares of Real Polynomials*.
220
- # Proceedings of Symposia in Pure mathematics (1995)
221
- #
222
- # [L09] Lofberg, Johan.
223
- # *Pre-and post-processing sum-of-squares programs in practice*.
224
- # IEEE transactions on automatic control 54.5 (2009): 1007-1011.
225
- #
226
- # [BKP16] Sabine Burgdorf, Igor Klep, and Janez Povh.
227
- # *Optimization of polynomials in non-commuting variables*.
228
- # Berlin: Springer, 2016.
229
- function post_filter (monos, X)
230
- num = Dict (mono => 1 for mono in X)
231
- function _increase (mono)
232
- return num[mono] = get (num, mono, 0 ) + 1
233
- end
234
- function _decrease (mono)
235
- value = num[mono] - 1
236
- if iszero (value)
237
- delete! (num, mono)
238
- else
239
- num[mono] = value
240
- end
241
- return iszero (value)
242
- end
243
- for a in monos
244
- for b in monos
245
- if a != b
246
- _increase (a * b)
247
- end
248
- end
249
- end
250
- back = Dict {eltype(monos),Int} ()
251
- keep = ones (Bool, length (monos))
252
- function _delete (i)
253
- keep[i] = false
254
- a = monos[i]
255
- for (j, b) in enumerate (monos)
256
- if keep[j] && a != b
257
- for w in [a * b, b * a]
258
- if _decrease (w) && haskey (back, w)
259
- _delete (back[w])
260
- end
261
- end
262
- end
263
- end
264
- end
265
- for (i, mono) in enumerate (monos)
266
- w = mono^ 2
267
- if haskey (num, w)
268
- back[w] = i
269
- else
270
- _delete (i)
271
- end
272
- end
273
- return monos[findall (keep)]
274
- end
275
-
276
212
struct DegreeBounds{M}
277
213
mindegree:: Int
278
214
maxdegree:: Int
@@ -305,7 +241,6 @@ function min_degree(p::SA.AlgebraElement, v)
305
241
return mapreduce (Base. Fix2 (min_degree, v), min, SA. supp (p))
306
242
end
307
243
min_degree (p:: MB.Polynomial{MB.Monomial} , v) = MP. degree (p. monomial, v)
308
- minus_min_degree (p, v) = - min_degree (p, v)
309
244
310
245
function _monomial (vars, exps)
311
246
if any (Base. Fix2 (isless, 0 ), exps)
@@ -389,13 +324,21 @@ function _interval(a, b)
389
324
end
390
325
end
391
326
327
+ function _gram_shift_min (d_g, d_s, g:: SA.AlgebraElement )
328
+ if _is_monomial_basis (typeof (g))
329
+ return d_g + 2 minimum (d_s)
330
+ else
331
+ return 0
332
+ end
333
+ end
334
+
392
335
function deg_range (deg, p, gs, gram_deg, truncation)
393
336
d_max = min (deg (p), truncation)
394
337
sign = deg_sign (deg, p, d_max)
395
338
for g in gs
396
339
d_g, sign_g = deg_sign (deg, g)
397
340
d_s = gram_deg (g)
398
- if isempty (d_s) || d_g + 2 minimum ( d_s) > truncation
341
+ if isempty (d_s) || _gram_shift_min ( d_g, d_s, g ) > truncation
399
342
continue
400
343
end
401
344
d = d_g + 2 maximum (d_s)
429
372
430
373
# deg_range(deg, p, gs, gram_deg, range)
431
374
#
432
- # Maximum value of `deg(s_0 = p - sum s_i g_i for g in gs ) in range` where
375
+ # Maximum value of `deg(s_0 = p - sum s_i g_i for i in eachindex(gs) ) in range` where
433
376
# `s_0, s_i` are SOS and `deg(s_i) <= gram_deg(g)`.
434
377
# Note that `range` should be in increasing order.
435
378
function deg_range (deg, p, gs, gram_deg, range:: UnitRange )
@@ -451,6 +394,40 @@ _maxdegree(a::SA.AlgebraElement) = maximum(_maxdegree, SA.supp(a))
451
394
_mindegree (p:: MB.Polynomial{MB.Monomial} ) = MP. mindegree (p. monomial)
452
395
_maxdegree (p:: MB.Polynomial{MB.Monomial} ) = MP. maxdegree (p. monomial)
453
396
397
+ _is_monomial_basis (:: Type{<:SA.AlgebraElement{<:MB.Algebra{BT,B}}} ) = true
398
+ _is_monomial_basis (:: Type{<:SA.AlgebraElement} ) = false
399
+
400
+ # Minimum degree of a gram basis for a gram matrix `s`
401
+ # such that the minimum degree of `s * g` is at least `mindegree`.
402
+ function _multiplier_mindegree (
403
+ mindegree,
404
+ g:: SA.AlgebraElement ,
405
+ )
406
+ if _is_monomial_basis (typeof (g))
407
+ return _min_half (min_shift (mindegree, _mindegree (g)))
408
+ else
409
+ # For instance, with `Chebyshev` a square already produces
410
+ # a monomial of degree 0 so let's just give up here
411
+ # The Chebyshev Newton polytope of the product of polynomials
412
+ # with Chebyshev Newton polytope `N1` and `N2` is a subset
413
+ # of `(N1 + N2 - R_+^n) ∩ R_+^n` so we compute
414
+ # `σ(y, cheby(N1) + cheby(N2))` as `σ(max.(y, 0), N1 + N2)`
415
+ return 0
416
+ end
417
+ end
418
+
419
+ # Maximum degree of a gram basis for a gram matrix `s`
420
+ # such that the maximum degree of `s * g` is at most `maxdegree`.
421
+ # Here, we assume that the degree of `*(a::MB.Polynomial, b::MB.Polynomial)`
422
+ # is bounded by the sum of the degree of `a` and `b` for any basis.
423
+ function _multiplier_maxdegree (maxdegree, g:: SA.AlgebraElement )
424
+ return _max_half (maxdegree - _maxdegree (g))
425
+ end
426
+
427
+ function _multiplier_deg_range (range, g:: SA.AlgebraElement )
428
+ return _multiplier_mindegree (minimum (range), g): _multiplier_maxdegree (maximum (range), g)
429
+ end
430
+
454
431
function putinar_degree_bounds (
455
432
p:: SA.AlgebraElement ,
456
433
gs:: AbstractVector{<:SA.AlgebraElement} ,
@@ -459,13 +436,11 @@ function putinar_degree_bounds(
459
436
)
460
437
mindegree = 0
461
438
# TODO homogeneous case
462
- mindeg (g) = _min_half (min_shift (mindegree, _mindegree (g)))
463
- maxdeg (g) = _max_half (maxdegree - _maxdegree (g))
464
- degrange (g) = mindeg (g): maxdeg (g)
465
- minus_degrange (g) = - maxdeg (g): - mindeg (g)
439
+ degrange (g) = _multiplier_deg_range (mindegree: maxdegree, g)
440
+ minus_degrange (g) = (- ). (degrange (g))
466
441
# The multiplier will have degree `0:2fld(maxdegree - _maxdegree(g), 2)`
467
442
mindegree =
468
- - deg_range (p -> - _mindegree (p) , p, gs, minus_degrange, - maxdegree: 0 )
443
+ - deg_range (( - ) ∘ _mindegree, p, gs, minus_degrange, - maxdegree: 0 )
469
444
if isnothing (mindegree)
470
445
return
471
446
end
@@ -474,13 +449,17 @@ function putinar_degree_bounds(
474
449
return
475
450
end
476
451
vars_mindeg = map (vars) do v
477
- return - deg_range (
478
- Base. Fix2 (minus_min_degree, v),
479
- p,
480
- gs,
481
- minus_degrange,
482
- - maxdegree: 0 ,
483
- )
452
+ return if _is_monomial_basis (eltype (gs))
453
+ - deg_range (
454
+ (- ) ∘ Base. Fix2 (min_degree, v),
455
+ p,
456
+ gs,
457
+ minus_degrange,
458
+ - maxdegree: 0 ,
459
+ )
460
+ else
461
+ 0
462
+ end
484
463
end
485
464
if any (isnothing, vars_mindeg)
486
465
return
@@ -501,29 +480,24 @@ function putinar_degree_bounds(
501
480
)
502
481
end
503
482
504
- function multiplier_basis (g:: SA.AlgebraElement , bounds:: DegreeBounds )
483
+ function multiplier_basis (g:: SA.AlgebraElement{<:MB.Algebra{BT,B}} , bounds:: DegreeBounds ) where {BT,B}
505
484
shifted = minus_shift (bounds, g)
506
485
if isnothing (shifted)
507
486
halved = nothing
508
487
else
509
488
halved = _half (shifted)
510
489
end
511
- basis = MB. FullBasis {MB.Monomial ,MP.monomial_type(typeof(g))} ()
490
+ basis = MB. FullBasis {B ,MP.monomial_type(typeof(g))} ()
512
491
if isnothing (halved)
513
- # TODO add `MB.empty_basis` to API
514
- return MB. maxdegree_basis (
515
- basis,
516
- MP. variables (bounds. variablewise_mindegree),
517
- - 1 ,
518
- )
492
+ return MB. empty_basis (MB. explicit_basis_type (typeof (basis)))
519
493
else
520
494
return maxdegree_gram_basis (basis, halved)
521
495
end
522
496
end
523
497
524
498
function half_newton_polytope (
525
- p:: MP.AbstractPolynomialLike ,
526
- gs:: AbstractVector{<:MP.AbstractPolynomialLike } ,
499
+ p:: SA.AlgebraElement ,
500
+ gs:: AbstractVector{<:SA.AlgebraElement } ,
527
501
vars,
528
502
maxdegree,
529
503
:: NewtonDegreeBounds ,
@@ -554,10 +528,10 @@ function half_newton_polytope(
554
528
gs:: AbstractVector{<:SA.AlgebraElement} ,
555
529
vars,
556
530
maxdegree,
557
- :: NewtonFilter{<:NewtonDegreeBounds} ,
531
+ filter :: NewtonFilter{<:NewtonDegreeBounds} ,
558
532
)
559
533
bounds = putinar_degree_bounds (p, gs, vars, maxdegree)
560
- bases = [ multiplier_basis (g, bounds) for g in gs]
534
+ bases = half_newton_polytope (p, gs, vars, maxdegree, filter . outer_approximation)
561
535
push! (
562
536
bases,
563
537
maxdegree_gram_basis (
@@ -604,6 +578,7 @@ function Base.:+(c::SignCount, a::SignChange{Missing})
604
578
@assert c. unknown >= - a. Δ
605
579
return SignCount (c. unknown + a. Δ, c. positive, c. negative)
606
580
end
581
+
607
582
function Base.:+ (c:: SignCount , a:: SignChange{<:Number} )
608
583
if a. sign > 0
609
584
@assert c. positive >= - a. Δ
@@ -642,6 +617,29 @@ function increase(cache, counter, generator_sign, monos, mult)
642
617
end
643
618
end
644
619
620
+ # If `mono` is such that there is no other way to have `mono^2` by multiplying
621
+ # two different monomials of `monos` and `mono` is not in `X` then, the corresponding
622
+ # diagonal entry of the Gram matrix will be zero hence the whole column and row
623
+ # will be zero hence we can remove this monomial.
624
+ # See [Proposition 3.7, CLR95], [Theorem 2, L09] or [Section 2.4, BKP16].
625
+
626
+ # This is generalized here to the case with constraints as detailed in [L23].
627
+
628
+ # [CLR95] Choi, M. D. and Lam, T. Y. and Reznick, B.
629
+ # *Sum of Squares of Real Polynomials*.
630
+ # Proceedings of Symposia in Pure mathematics (1995)
631
+ #
632
+ # [L09] Löfberg, Johan.
633
+ # *Pre-and post-processing sum-of-squares programs in practice*.
634
+ # IEEE transactions on automatic control 54.5 (2009): 1007-1011.
635
+ #
636
+ # [BKP16] Sabine Burgdorf, Igor Klep, and Janez Povh.
637
+ # *Optimization of polynomials in non-commuting variables*.
638
+ # Berlin: Springer, 2016.
639
+ #
640
+ # [L23] Legat, Benoît
641
+ # *Exploiting the Structure of a Polynomial Optimization Problem*
642
+ # SIAM Conference on Applications of Dynamical Systems, 2023
645
643
function post_filter (poly:: SA.AlgebraElement , generators, multipliers_gram_monos)
646
644
counter = MB. algebra_element (
647
645
zero (MP. polynomial_type (MP. monomial_type (typeof (SA. basis (poly))), SignCount)),
737
735
function _sub (basis:: SubBasis{B} , I) where {B}
738
736
return SubBasis {B} (basis. monomials[I])
739
737
end
740
-
741
- function half_newton_polytope (a:: SA.AlgebraElement , args... )
742
- @assert SA. basis (a) isa MB. SubBasis{MB. Monomial}
743
- half_newton_polytope (SA. coeffs (a, MB. FullBasis {MB.Monomial,MP.monomial_type(typeof(a))} ()), args... )
744
- end
0 commit comments