@@ -489,3 +489,58 @@ function distance_to_set(
489489 elements = [x[i] for i in eachindex (x) if ! (i in pairs[k])]
490490 return LinearAlgebra. norm (elements, 2 )
491491end
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