@@ -489,3 +489,58 @@ function distance_to_set(
489
489
elements = [x[i] for i in eachindex (x) if ! (i in pairs[k])]
490
490
return LinearAlgebra. norm (elements, 2 )
491
491
end
492
+
493
+ function _reshape (x:: AbstractVector , set:: MOI.PositiveSemidefiniteConeSquare )
494
+ n = MOI. side_dimension (set)
495
+ return reshape (x, (n, n))
496
+ end
497
+
498
+ function _reshape (x:: AbstractVector , set:: MOI.PositiveSemidefiniteConeTriangle )
499
+ n = MOI. side_dimension (set)
500
+ X = zeros (eltype (x), n, n)
501
+ k = 1
502
+ for i in 1 : n
503
+ for j in 1 : i
504
+ X[j, i] = X[i, j] = x[k]
505
+ k += 1
506
+ end
507
+ end
508
+ return LinearAlgebra. Symmetric (X)
509
+ end
510
+
511
+ """
512
+ distance_to_set(
513
+ ::ProjectionUpperBoundDistance,
514
+ x::AbstractVector,
515
+ set::Union{
516
+ MOI.PositiveSemidefiniteConeSquare,
517
+ MOI.PositiveSemidefiniteConeTriangle,
518
+ },
519
+ )
520
+
521
+ Let ``X`` be `x` reshaped into the appropriate matrix. The returned distance is
522
+ ``||X - Y||_2^2`` where ``Y`` is the eigen decomposition of ``X`` with negative
523
+ eigen values removed.
524
+ """
525
+ function distance_to_set (
526
+ :: ProjectionUpperBoundDistance ,
527
+ x:: AbstractVector{T} ,
528
+ set:: Union {
529
+ MOI. PositiveSemidefiniteConeSquare,
530
+ MOI. PositiveSemidefiniteConeTriangle,
531
+ },
532
+ ) where {T<: Real }
533
+ _check_dimension (x, set)
534
+ # We should return the norm of `A` defined by:
535
+ # ```julia
536
+ # λ, U = LinearAlgebra.eigen(_reshape(x, set))
537
+ # λ_negative = LinearAlgebra.Diagonal(min.(zero(T), λ))
538
+ # A = LinearAlgebra.Symmetric(U * λ_negative * U')
539
+ # LinearAlgebra.norm(A, 2)
540
+ # ```
541
+ # The norm should correspond to `MOI.Utilities.set_dot` so it's the
542
+ # Frobenius norm, which is the Euclidean norm of the vector of eigenvalues.
543
+ eigvals = LinearAlgebra. eigvals (_reshape (x, set))
544
+ eigvals .= min .(zero (T), eigvals)
545
+ return LinearAlgebra. norm (eigvals, 2 )
546
+ end
0 commit comments