Skip to content

Commit 9a9188a

Browse files
authored
[Test] add tests for NormNuclearCone, NormSpectralCone and HermitianPSDCone (#2174)
1 parent 197424d commit 9a9188a

File tree

1 file changed

+315
-0
lines changed

1 file changed

+315
-0
lines changed

src/Test/test_solve.jl

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,3 +1564,318 @@ function setup_test(
15641564
)
15651565
return
15661566
end
1567+
1568+
function _test_matrix_norm_cone(
1569+
model::MOI.ModelLike,
1570+
config::Config{T},
1571+
set::Union{MOI.NormSpectralCone,MOI.NormNuclearCone},
1572+
b::Union{Nothing,Vector{T}},
1573+
) where {T}
1574+
@requires _supports(config, MOI.optimize!)
1575+
F = b == nothing ? MOI.VectorOfVariables : MOI.VectorAffineFunction{T}
1576+
@requires MOI.supports_constraint(model, F, typeof(set))
1577+
t = MOI.add_variable(model)
1578+
X = MOI.add_variables(model, 6)
1579+
f = if b === nothing
1580+
MOI.VectorOfVariables([t; X])
1581+
else
1582+
fx = MOI.Utilities.operate.(+, T, X, b)
1583+
MOI.Utilities.operate(vcat, T, t, fx...)
1584+
end
1585+
MOI.add_constraint(model, f, set)
1586+
for i in 1:6
1587+
MOI.add_constraint(model, X[i], MOI.EqualTo{T}(i))
1588+
end
1589+
MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)
1590+
MOI.set(model, MOI.ObjectiveFunction{MOI.VariableIndex}(), t)
1591+
MOI.optimize!(model)
1592+
x_result = MOI.get(model, MOI.VariablePrimal(), X)
1593+
@test (x_result, 1:6, config)
1594+
Y = reshape(x_result .+ something(b, T(0)), set.row_dim, set.column_dim)
1595+
# svdvals doesn't work for BigFloat etc. So don't use `T` as the element
1596+
# type when computing the singular values.
1597+
σ = LinearAlgebra.svdvals(convert(Matrix{Float64}, Y))
1598+
result = set isa MOI.NormSpectralCone ? maximum(σ) : sum(σ)
1599+
@test (MOI.get(model, MOI.VariablePrimal(), t), result, config)
1600+
return
1601+
end
1602+
1603+
function test_NormSpectralCone_VectorOfVariables_without_transform(
1604+
model::MOI.ModelLike,
1605+
config::Config,
1606+
)
1607+
_test_matrix_norm_cone(model, config, MOI.NormSpectralCone(3, 2), nothing)
1608+
return
1609+
end
1610+
1611+
function setup_test(
1612+
::typeof(test_NormSpectralCone_VectorOfVariables_without_transform),
1613+
model::MOIU.MockOptimizer,
1614+
::Config{T},
1615+
) where {T}
1616+
# svdvals doesn't work for BigFloat etc. So don't use `T` as the element
1617+
# type when computing the result.
1618+
result = [1, 2, 3, 4, 5, 6]
1619+
t = LinearAlgebra.opnorm(reshape(result, 3, 2))
1620+
MOIU.set_mock_optimize!(
1621+
model,
1622+
(mock::MOIU.MockOptimizer) ->
1623+
MOIU.mock_optimize!(mock, MOI.OPTIMAL, T[t; result]),
1624+
)
1625+
return
1626+
end
1627+
1628+
function test_NormSpectralCone_VectorOfVariables_with_transform(
1629+
model::MOI.ModelLike,
1630+
config::Config,
1631+
)
1632+
_test_matrix_norm_cone(model, config, MOI.NormSpectralCone(2, 3), nothing)
1633+
return
1634+
end
1635+
1636+
function setup_test(
1637+
::typeof(test_NormSpectralCone_VectorOfVariables_with_transform),
1638+
model::MOIU.MockOptimizer,
1639+
::Config{T},
1640+
) where {T}
1641+
# svdvals doesn't work for BigFloat etc. So don't use `T` as the element
1642+
# type when computing the result.
1643+
result = [1, 2, 3, 4, 5, 6]
1644+
t = LinearAlgebra.opnorm(reshape(result, 2, 3))
1645+
MOIU.set_mock_optimize!(
1646+
model,
1647+
(mock::MOIU.MockOptimizer) ->
1648+
MOIU.mock_optimize!(mock, MOI.OPTIMAL, T[t; result]),
1649+
)
1650+
return
1651+
end
1652+
1653+
function test_NormSpectralCone_VectorAffineFunction_without_transform(
1654+
model::MOI.ModelLike,
1655+
config::Config{T},
1656+
) where {T}
1657+
b = convert(Vector{T}, 7:12)
1658+
_test_matrix_norm_cone(model, config, MOI.NormSpectralCone(3, 2), b)
1659+
return
1660+
end
1661+
1662+
function setup_test(
1663+
::typeof(test_NormSpectralCone_VectorAffineFunction_without_transform),
1664+
model::MOIU.MockOptimizer,
1665+
::Config{T},
1666+
) where {T}
1667+
# svdvals doesn't work for BigFloat etc. So don't use `T` as the element
1668+
# type when computing the result.
1669+
result = [1, 2, 3, 4, 5, 6]
1670+
t = LinearAlgebra.opnorm(reshape(result + collect(7:12), 3, 2))
1671+
MOIU.set_mock_optimize!(
1672+
model,
1673+
(mock::MOIU.MockOptimizer) ->
1674+
MOIU.mock_optimize!(mock, MOI.OPTIMAL, T[t; result]),
1675+
)
1676+
return
1677+
end
1678+
1679+
function test_NormSpectralCone_VectorAffineFunction_with_transform(
1680+
model::MOI.ModelLike,
1681+
config::Config{T},
1682+
) where {T}
1683+
b = convert(Vector{T}, 7:12)
1684+
_test_matrix_norm_cone(model, config, MOI.NormSpectralCone(2, 3), b)
1685+
return
1686+
end
1687+
1688+
function setup_test(
1689+
::typeof(test_NormSpectralCone_VectorAffineFunction_with_transform),
1690+
model::MOIU.MockOptimizer,
1691+
::Config{T},
1692+
) where {T}
1693+
# svdvals doesn't work for BigFloat etc. So don't use `T` as the element
1694+
# type when computing the result.
1695+
result = [1, 2, 3, 4, 5, 6]
1696+
t = LinearAlgebra.opnorm(reshape(result + collect(7:12), 2, 3))
1697+
MOIU.set_mock_optimize!(
1698+
model,
1699+
(mock::MOIU.MockOptimizer) ->
1700+
MOIU.mock_optimize!(mock, MOI.OPTIMAL, T[t; result]),
1701+
)
1702+
return
1703+
end
1704+
1705+
function test_NormNuclearCone_VectorOfVariables_without_transform(
1706+
model::MOI.ModelLike,
1707+
config::Config,
1708+
)
1709+
_test_matrix_norm_cone(model, config, MOI.NormNuclearCone(3, 2), nothing)
1710+
return
1711+
end
1712+
1713+
function setup_test(
1714+
::typeof(test_NormNuclearCone_VectorOfVariables_without_transform),
1715+
model::MOIU.MockOptimizer,
1716+
::Config{T},
1717+
) where {T}
1718+
# svdvals doesn't work for BigFloat etc. So don't use `T` as the element
1719+
# type when computing the result.
1720+
result = [1, 2, 3, 4, 5, 6]
1721+
t = sum(LinearAlgebra.svdvals(reshape(result, 3, 2)))
1722+
MOIU.set_mock_optimize!(
1723+
model,
1724+
(mock::MOIU.MockOptimizer) ->
1725+
MOIU.mock_optimize!(mock, MOI.OPTIMAL, T[t; result]),
1726+
)
1727+
return
1728+
end
1729+
1730+
function test_NormNuclearCone_VectorOfVariables_with_transform(
1731+
model::MOI.ModelLike,
1732+
config::Config,
1733+
)
1734+
_test_matrix_norm_cone(model, config, MOI.NormNuclearCone(2, 3), nothing)
1735+
return
1736+
end
1737+
1738+
function setup_test(
1739+
::typeof(test_NormNuclearCone_VectorOfVariables_with_transform),
1740+
model::MOIU.MockOptimizer,
1741+
::Config{T},
1742+
) where {T}
1743+
# svdvals doesn't work for BigFloat etc. So don't use `T` as the element
1744+
# type when computing the result.
1745+
result = [1, 2, 3, 4, 5, 6]
1746+
t = sum(LinearAlgebra.svdvals(reshape(result, 2, 3)))
1747+
MOIU.set_mock_optimize!(
1748+
model,
1749+
(mock::MOIU.MockOptimizer) ->
1750+
MOIU.mock_optimize!(mock, MOI.OPTIMAL, T[t; result]),
1751+
)
1752+
return
1753+
end
1754+
1755+
function test_NormNuclearCone_VectorAffineFunction_without_transform(
1756+
model::MOI.ModelLike,
1757+
config::Config{T},
1758+
) where {T}
1759+
b = convert(Vector{T}, 7:12)
1760+
_test_matrix_norm_cone(model, config, MOI.NormNuclearCone(3, 2), b)
1761+
return
1762+
end
1763+
1764+
function setup_test(
1765+
::typeof(test_NormNuclearCone_VectorAffineFunction_without_transform),
1766+
model::MOIU.MockOptimizer,
1767+
::Config{T},
1768+
) where {T}
1769+
# svdvals doesn't work for BigFloat etc. So don't use `T` as the element
1770+
# type when computing the result.
1771+
result = [1, 2, 3, 4, 5, 6]
1772+
t = sum(LinearAlgebra.svdvals(reshape(result + collect(7:12), 3, 2)))
1773+
MOIU.set_mock_optimize!(
1774+
model,
1775+
(mock::MOIU.MockOptimizer) ->
1776+
MOIU.mock_optimize!(mock, MOI.OPTIMAL, T[t; result]),
1777+
)
1778+
return
1779+
end
1780+
1781+
function test_NormNuclearCone_VectorAffineFunction_with_transform(
1782+
model::MOI.ModelLike,
1783+
config::Config{T},
1784+
) where {T}
1785+
b = convert(Vector{T}, 7:12)
1786+
_test_matrix_norm_cone(model, config, MOI.NormNuclearCone(2, 3), b)
1787+
return
1788+
end
1789+
1790+
function setup_test(
1791+
::typeof(test_NormNuclearCone_VectorAffineFunction_with_transform),
1792+
model::MOIU.MockOptimizer,
1793+
::Config{T},
1794+
) where {T}
1795+
# svdvals doesn't work for BigFloat etc. So don't use `T` as the element
1796+
# type when computing the result.
1797+
result = [1, 2, 3, 4, 5, 6]
1798+
t = sum(LinearAlgebra.svdvals(reshape(result + collect(7:12), 2, 3)))
1799+
MOIU.set_mock_optimize!(
1800+
model,
1801+
(mock::MOIU.MockOptimizer) ->
1802+
MOIU.mock_optimize!(mock, MOI.OPTIMAL, T[t; result]),
1803+
)
1804+
return
1805+
end
1806+
1807+
function test_HermitianPSDCone_basic(
1808+
model::MOI.ModelLike,
1809+
config::Config{T},
1810+
) where {T}
1811+
@requires _supports(config, MOI.optimize!)
1812+
S = MOI.HermitianPositiveSemidefiniteConeTriangle
1813+
@requires MOI.supports_constraint(model, MOI.VectorAffineFunction{T}, S)
1814+
x = MOI.add_variables(model, 9)
1815+
for i in eachindex(x)
1816+
MOI.add_constraint(model, x[i], MOI.EqualTo{T}(i))
1817+
end
1818+
b = T[12, 0, 12, 0, 0, 12, 0, 0, 0]
1819+
f = MOI.Utilities.operate(vcat, T, MOI.Utilities.operate.(+, T, x, b)...)
1820+
set = MOI.HermitianPositiveSemidefiniteConeTriangle(3)
1821+
MOI.add_constraint(model, f, set)
1822+
MOI.optimize!(model)
1823+
MOI.get(model, MOI.TerminationStatus()) == config.optimal_status
1824+
@test (MOI.get(model, MOI.VariablePrimal(), x), 1:9, config)
1825+
return
1826+
end
1827+
1828+
function setup_test(
1829+
::typeof(test_HermitianPSDCone_basic),
1830+
model::MOIU.MockOptimizer,
1831+
::Config{T},
1832+
) where {T}
1833+
MOIU.set_mock_optimize!(
1834+
model,
1835+
(mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(
1836+
mock,
1837+
MOI.OPTIMAL,
1838+
T[1, 2, 3, 4, 5, 6, 7, 8, 9],
1839+
),
1840+
)
1841+
return
1842+
end
1843+
1844+
function test_HermitianPSDCone_min_t(
1845+
model::MOI.ModelLike,
1846+
config::Config{T},
1847+
) where {T}
1848+
@requires _supports(config, MOI.optimize!)
1849+
S = MOI.HermitianPositiveSemidefiniteConeTriangle
1850+
@requires MOI.supports_constraint(model, MOI.VectorAffineFunction{T}, S)
1851+
t = MOI.add_variable(model)
1852+
x = MOI.add_variables(model, 9)
1853+
for (i, xi) in enumerate(x)
1854+
MOI.add_constraint(model, xi, MOI.EqualTo{T}(i))
1855+
end
1856+
bt = Union{MOI.VariableIndex,T}[t, T(0), t, T(0), T(0), t, T(0), T(0), T(0)]
1857+
f = MOI.Utilities.operate(vcat, T, MOI.Utilities.operate.(+, T, x, bt)...)
1858+
set = MOI.HermitianPositiveSemidefiniteConeTriangle(3)
1859+
MOI.add_constraint(model, f, set)
1860+
MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)
1861+
MOI.set(model, MOI.ObjectiveFunction{MOI.VariableIndex}(), t)
1862+
MOI.optimize!(model)
1863+
MOI.get(model, MOI.TerminationStatus()) == config.optimal_status
1864+
x_result = MOI.get(model, MOI.VariablePrimal(), x)
1865+
@test (x_result, 1:9, config)
1866+
@test (MOI.get(model, MOI.VariablePrimal(), t), 11.034899152582094, config)
1867+
return
1868+
end
1869+
1870+
function setup_test(
1871+
::typeof(test_HermitianPSDCone_min_t),
1872+
model::MOIU.MockOptimizer,
1873+
::Config{T},
1874+
) where {T}
1875+
x = T[11.034899152582094, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1876+
MOIU.set_mock_optimize!(
1877+
model,
1878+
(mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.OPTIMAL, x),
1879+
)
1880+
return
1881+
end

0 commit comments

Comments
 (0)