Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 62 additions & 4 deletions src/Utilities/distance_to_set.jl
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ function _reshape(
MOI.LogDetConeTriangle,
MOI.RootDetConeTriangle,
},
) where {T}
) where {T<:Real}
n = isqrt(2 * length(x))
# The type annotation is needed for JET.
X = zeros(T, n, n)::Matrix{T}
Expand All @@ -208,6 +208,24 @@ function _reshape(
return LinearAlgebra.Symmetric(X)
end

function _reshape(
x::AbstractVector{T},
set::MOI.PositiveSemidefiniteConeTriangle,
) where {T<:Complex}
n = isqrt(2 * length(x))
# The type annotation is needed for JET.
X = zeros(T, n, n)::Matrix{T}
k = 1
for i in 1:n
for j in 1:i
X[i, j] = conj(x[k])
X[j, i] = x[k]
k += 1
end
end
return LinearAlgebra.Hermitian(X)
end

# This is the minimal L2-norm.
function distance_to_set(
::ProjectionUpperBoundDistance,
Expand Down Expand Up @@ -553,7 +571,7 @@ function distance_to_set(
MOI.PositiveSemidefiniteConeSquare,
MOI.PositiveSemidefiniteConeTriangle,
},
) where {T<:Real}
) where {T<:Union{Real,Complex}}
_check_dimension(x, set)
# We should return the norm of `A` defined by:
# ```julia
Expand All @@ -565,8 +583,7 @@ function distance_to_set(
# The norm should correspond to `MOI.Utilities.set_dot` so it's the
# Frobenius norm, which is the Euclidean norm of the vector of eigenvalues.
eigvals = LinearAlgebra.eigvals(_reshape(x, set))
eigvals .= min.(zero(T), eigvals)
return LinearAlgebra.norm(eigvals, 2)
return LinearAlgebra.norm(min.(0, eigvals), 2)
end

"""
Expand Down Expand Up @@ -702,3 +719,44 @@ function distance_to_set(
push!(eigvals_neg, max(x[1] - x[2] * sum(log.(eigvals_pos)), zero(T)))
return LinearAlgebra.norm(eigvals_neg, 2)
end

"""
distance_to_set(
::ProjectionUpperBoundDistance,
x::AbstractVector,
set::MOI.Scaled{S},
)

This is the distance in the un-scaled space.
"""
function distance_to_set(
dist::ProjectionUpperBoundDistance,
x::AbstractVector{T},
set::MOI.Scaled{S},
) where {T,S<:MOI.AbstractVectorSet}
_check_dimension(x, set)
scale = MOI.Utilities.SetDotScalingVector{T}(set.set)
return distance_to_set(dist, x ./ scale, set.set)
end

function distance_to_set(
dist::ProjectionUpperBoundDistance,
x::AbstractVector{T},
set::MOI.HermitianPositiveSemidefiniteConeTriangle,
) where {T<:Real}
_check_dimension(x, set)
output_set = MOI.PositiveSemidefiniteConeTriangle(set.side_dimension)
y = zeros(Complex{T}, MOI.dimension(output_set))
real_offset, imag_offset = 0, length(y)
for col in 1:set.side_dimension
for row in 1:col
real_offset += 1
y[real_offset] = x[real_offset]
if row != col
imag_offset += 1
y[real_offset] += x[imag_offset] * im
end
end
end
return distance_to_set(dist, y, output_set)
end
41 changes: 40 additions & 1 deletion test/Utilities/distance_to_set.jl
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,8 @@ function test_positivesemidefiniteconesquare()
[1.0, 0.0, 0.0, 1.0] => 0.0,
[1.0, -1.0, -1.0, 1.0] => 0.0,
[1.0, -2.0, -2.0, 1.0] => 1.0,
[1.0, 1.1, 1.1, -2.3] => 2.633053201505194;
[1.0, 1.1, 1.1, -2.3] => 2.633053201505194,
[1.0, -2.0, -2.0, 1.0] => 1.0;
mismatch = [1.0],
)
return
Expand Down Expand Up @@ -476,6 +477,44 @@ function test_LogDetConeSquare()
return
end

function test_Scaled()
_test_set(
MOI.Scaled(MOI.PositiveSemidefiniteConeTriangle(2)),
[1.0, 0.0, 1.0] => 0.0,
[1.0, -1.0, 1.0] => 0.0,
[1.0, -2.0 * sqrt(2), 1.0] => 1.0,
[1.0, 1.1 * sqrt(2), -2.3] => 2.633053201505194;
mismatch = [1.0],
)
return
end

function test_PositiveSemidefiniteConeTriangle_Complex()
_test_set(
MOI.PositiveSemidefiniteConeTriangle(2),
ComplexF64[1.0, 0.0, 1.0] => 0.0,
ComplexF64[1.0, -1.0, 1.0] => 0.0,
ComplexF64[1.0, -2.0, 1.0] => 1.0,
ComplexF64[1.0, 1.1, -2.3] => 2.633053201505194,
ComplexF64[1.0, 1-im, 1.0] => 0.41421356237309537;
mismatch = [1.0],
)
return
end

function test_HermitianPositiveSemidefiniteConeTriangle()
_test_set(
MOI.HermitianPositiveSemidefiniteConeTriangle(2),
[1.0, 0.0, 1.0, 0.0] => 0.0,
[1.0, -1.0, 1.0, 0.0] => 0.0,
[1.0, -2.0, 1.0, 0.0] => 1.0,
[1.0, 1.1, -2.3, 0.0] => 2.633053201505194,
[1.0, 1.0, 1.0, -1.0] => 0.41421356237309537;
mismatch = [1.0],
)
return
end

end

TestFeasibilityChecker.runtests()
Loading