From cf0569501c804f6dc2143ba2c02e780b58ed92ba Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Fri, 10 Oct 2025 13:53:40 +1300 Subject: [PATCH 1/9] Refactor into src/libdsdp.jl --- .github/workflows/format_check.yml | 2 +- Project.toml | 4 +- gen/Project.toml | 6 + gen/gen.jl | 33 ++ gen/generate.toml | 13 + gen/prologue.jl | 7 + src/DSDP.jl | 83 +--- src/MOI_wrapper.jl | 208 ++++++--- src/bcone.jl | 54 --- src/blockdiag.jl | 37 -- src/dsdp5_API.jl | 424 ----------------- src/dsdp5_enums.jl | 42 -- src/libdsdp.jl | 703 +++++++++++++++++++++++++++++ src/lpcone.jl | 126 ------ src/sdpcone.jl | 495 -------------------- test/MOI_wrapper.jl | 38 +- test/build.jl | 17 - test/c_api.jl | 252 +++++++++++ test/maxcut.jl | 155 ------- test/options.jl | 23 - test/runtests.jl | 8 +- test/sdp.jl | 81 ---- 22 files changed, 1213 insertions(+), 1598 deletions(-) create mode 100644 gen/Project.toml create mode 100644 gen/gen.jl create mode 100644 gen/generate.toml create mode 100644 gen/prologue.jl delete mode 100644 src/bcone.jl delete mode 100644 src/blockdiag.jl delete mode 100644 src/dsdp5_API.jl delete mode 100644 src/dsdp5_enums.jl create mode 100644 src/libdsdp.jl delete mode 100644 src/lpcone.jl delete mode 100644 src/sdpcone.jl delete mode 100644 test/build.jl create mode 100644 test/c_api.jl delete mode 100644 test/maxcut.jl delete mode 100644 test/options.jl delete mode 100644 test/sdp.jl diff --git a/.github/workflows/format_check.yml b/.github/workflows/format_check.yml index c4482c2..c0435ca 100644 --- a/.github/workflows/format_check.yml +++ b/.github/workflows/format_check.yml @@ -18,7 +18,7 @@ jobs: shell: julia --color=yes {0} run: | using Pkg - Pkg.add(PackageSpec(name="JuliaFormatter", version="1")) + Pkg.add(PackageSpec(name="JuliaFormatter", version="2")) using JuliaFormatter format(".", verbose=true) out = String(read(Cmd(`git diff`))) diff --git a/Project.toml b/Project.toml index 8bc5e08..0a4e80b 100644 --- a/Project.toml +++ b/Project.toml @@ -1,14 +1,16 @@ name = "DSDP" uuid = "2714ae6b-e930-5b4e-9c21-d0bacf577842" -repo = "https://github.com/jump-dev/DSDP.jl.git" version = "0.2.1" +repo = "https://github.com/jump-dev/DSDP.jl.git" [deps] +CEnum = "fa961155-64e5-5f13-b03f-caf6b980ea82" DSDP_jll = "1065e140-e56c-5613-be8b-7480bf7138df" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" [compat] +CEnum = "0.5.0" DSDP_jll = "0.0.1" MathOptInterface = "1" julia = "1.10" diff --git a/gen/Project.toml b/gen/Project.toml new file mode 100644 index 0000000..87e6020 --- /dev/null +++ b/gen/Project.toml @@ -0,0 +1,6 @@ +[deps] +Clang = "40e3b903-d033-50b4-a0cc-940c62c95e31" +DSDP_jll = "1065e140-e56c-5613-be8b-7480bf7138df" + +[compat] +Clang = "0.17" diff --git a/gen/gen.jl b/gen/gen.jl new file mode 100644 index 0000000..dafeddd --- /dev/null +++ b/gen/gen.jl @@ -0,0 +1,33 @@ +# Copyright (c) 2019 Mathieu Besançon, Oscar Dowson, and contributors +# +# Use of this source code is governed by an MIT-style license that can be found +# in the LICENSE.md file or at https://opensource.org/licenses/MIT. + +import Clang +import DSDP_jll + +dir = joinpath(DSDP_jll.artifact_dir, "include") +Clang.Generators.create_context( + joinpath.(dir, ["dsdp5.h"]), + [Clang.Generators.get_default_args(); "-I$dir"], + Clang.Generators.load_options(joinpath(@__DIR__, "generate.toml")), +) |> Clang.Generators.build! + +filename = joinpath(@__DIR__, "..", "src", "libdsdp.jl") +contents = read(filename, String) +for cone in ["DSDP", "SDPCone", "LPCone", "BCone"] + global contents = replace( + contents, + "const $(cone)_C = Cvoid\n\n" => "", + "const $(cone) = Ptr{$(cone)_C}\n\n" => "", + "::$(cone)," => "::Ptr{Cvoid},", + "::$(cone))" => "::Ptr{Cvoid})", + "{$(cone)}" => "{Ptr{Cvoid}}", + ) +end +contents = replace(contents, r"const .+?\n\n" => "") +contents = replace(contents, r"# Skipping.+" => "") +for _ in 1:10 + global contents = replace(contents, "\n\n\n" => "\n\n") +end +write(filename, contents) diff --git a/gen/generate.toml b/gen/generate.toml new file mode 100644 index 0000000..db46d2e --- /dev/null +++ b/gen/generate.toml @@ -0,0 +1,13 @@ +[general] +library_name = "libdsdp" +output_file_path = "src/libdsdp.jl" +print_using_CEnum = false +prologue_file_path = "gen/prologue.jl" +use_deterministic_symbol = true + +[codegen] +opaque_as_mutable_struct = false +use_ccall_macro = true + +[codegen.macro] +macro_mode = "basic" diff --git a/gen/prologue.jl b/gen/prologue.jl new file mode 100644 index 0000000..3123837 --- /dev/null +++ b/gen/prologue.jl @@ -0,0 +1,7 @@ +# Copyright (c) 2022: Joey Huchette, Benoît Legat, and contributors +# +# Use of this source code is governed by an MIT-style license that can be found +# in the LICENSE.md file or at https://opensource.org/licenses/MIT. + +# Disable JuliaFormatter for this file. +#!format:off diff --git a/src/DSDP.jl b/src/DSDP.jl index 41399b9..2bda23f 100644 --- a/src/DSDP.jl +++ b/src/DSDP.jl @@ -5,84 +5,15 @@ module DSDP -import DSDP_jll +using CEnum: @cenum +using DSDP_jll: libdsdp +import LinearAlgebra +import MathOptInterface as MOI -using LinearAlgebra +include("libdsdp.jl") -macro dsdp_ccall(f, args...) - quote - # QuoteNode prevents the interpretion of the symbol - # and leave it as a symbol - info = - ccall(($(QuoteNode(f)), DSDP_jll.libdsdp), Cint, $(esc.(args)...)) - if !iszero(info) - error("DSDP call $($(QuoteNode(f))) returned nonzero status $info.") - end - end -end - -const DSDPT = Ptr{Nothing} - -include("dsdp5_enums.jl") -include("dsdp5_API.jl") - -include("lpcone.jl") -function CreateLPCone(dsdp::DSDPT) - lpcone = Ref{LPCone.LPConeT}() - @dsdp_ccall DSDPCreateLPCone (DSDPT, Ref{LPCone.LPConeT}) dsdp lpcone - return lpcone[] -end - -include("sdpcone.jl") -function CreateSDPCone(dsdp::DSDPT, n::Integer) - sdpcone = Ref{SDPCone.SDPConeT}() - @dsdp_ccall DSDPCreateSDPCone (DSDPT, Cint, Ref{SDPCone.SDPConeT}) dsdp n sdpcone - return sdpcone[] -end - -include("bcone.jl") -function CreateBCone(dsdp::DSDPT) - bcone = Ref{BCone.BConeT}() - @dsdp_ccall DSDPCreateBCone (DSDPT, Ref{BCone.BConeT}) dsdp bcone - return bcone[] -end - -# Writes to `input.sdpa` -function PrintData( - dsdp::DSDPT, - sdpcone::SDPCone.SDPConeT, - lpcone::LPCone.LPConeT, -) - @dsdp_ccall DSDPPrintData (DSDPT, SDPCone.SDPConeT, LPCone.LPConeT) dsdp sdpcone lpcone -end - -function PrintSolution( - fp::Libc.FILE, - dsdp::DSDPT, - sdpcone::SDPCone.SDPConeT, - lpcone::LPCone.LPConeT, -) - @dsdp_ccall DSDPPrintSolution ( - Ptr{Cvoid}, - DSDPT, - SDPCone.SDPConeT, - LPCone.LPConeT, - ) fp dsdp sdpcone lpcone -end - -function PrintSolution( - dsdp::DSDPT, - sdpcone::SDPCone.SDPConeT, - lpcone::LPCone.LPConeT, -) - # See https://discourse.julialang.org/t/access-c-stdout-in-julia/24187/2 - stdout = Libc.FILE(Libc.RawFD(1), "w") - return PrintSolution(stdout, dsdp, sdpcone, lpcone) -end - -#function PrintSolution(arg1, arg2::DSDPT, arg3::SDPCone.SDPConeT, arg4::LPCone.LPConeT) -# @dsdp_ccall DSDPPrintSolution (Ptr{FILE}, DSDP, SDPCone.SDPConeT, LPCone.LPConeT) arg1 arg2 arg3 arg4 -#end +# This one is named poorly in the upstream C API +const DSDPSetReuseMatrix = DSDPReuseMatrix include("MOI_wrapper.jl") diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index c895e8e..53ed5f0 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -3,11 +3,19 @@ # Use of this source code is governed by an MIT-style license that can be found # in the LICENSE.md file or at https://opensource.org/licenses/MIT. -import MathOptInterface as MOI +macro check(expr) + @assert expr.head == :call + msg = "Error calling $(expr.args[1])" + return quote + if (ret = $(esc(expr))) != 0 + error($msg) + end + end +end mutable struct Optimizer <: MOI.AbstractOptimizer - dsdp::DSDPT - lpcone::LPCone.LPConeT + dsdp::Ptr{Cvoid} + lpcone::Ptr{Cvoid} objective_constant::Cdouble objective_sign::Int b::Vector{Cdouble} @@ -21,7 +29,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer # Otherwise, `blk[i]` is the **number** of SDP blocks before + 1 # and hence the index in `sdpdrows`, `sdpdcols` and `sdpdcoefs`. blk::Vector{Int} - sdpcone::SDPCone.SDPConeT + sdpcone::Ptr{Nothing} # Sum of length of diagonal blocks nlpdrows::Int lpdvars::Vector{Int} @@ -63,6 +71,8 @@ end varmap(optimizer::Optimizer, vi::MOI.VariableIndex) = optimizer.varmap[vi.value] +# MOI.Silent + MOI.supports(::Optimizer, ::MOI.Silent) = true function MOI.set(optimizer::Optimizer, ::MOI.Silent, value::Bool) @@ -72,6 +82,8 @@ end MOI.get(optimizer::Optimizer, ::MOI.Silent) = optimizer.silent +# MOI.SolverName + MOI.get(::Optimizer, ::MOI.SolverName) = "DSDP" function MOI.empty!(optimizer::Optimizer) @@ -118,9 +130,9 @@ function _free(m::Optimizer) end # Taken from src/solver/dsdpsetup.c -const gettable_options = Dict( +const gettable_options = Dict{Symbol,Union{Cint,Cdouble}}( # Stopping parameters - :MaxIts => 500, + :MaxIts => Cint(500), :GapTolerance => 1.0e-7, # 100<=nconstrs<=3000 => 1e-6, nconstrs>3000 => 5e-6 :PNormTolerance => 1.0e30, :DualBound => 1.0e20, @@ -132,8 +144,9 @@ const gettable_options = Dict( :BarrierParameter => -1.0, :PotentialParameter => 5.0, # nconstrs>100 => 3.0 :PenaltyParameter => 1.0e8, - :ReuseMatrix => 4, # 100 7, nconstrs>1000 => 10 - :YBounds => (-1e7, 1e7), + :ReuseMatrix => Cint(4), # 100 7, nconstrs>1000 => 10 + # Handled separately + # :YBounds => (-1e7, 1e7), ) # TODO # UsePenalty(dsdp,0) @@ -142,7 +155,7 @@ const gettable_options = Dict( # DSDPSetFixedVariable[s] # DSDPSetDualLowerBound -const options = Dict( +const options = Dict{Symbol,Union{Cint,Cdouble}}( # Solver options :R0 => -1.0, :ZBar => 1e10, @@ -174,35 +187,32 @@ function MOI.get(m::Optimizer, o::GettableOption) end for (param, default) in gettable_options - getter = Symbol("Get" * string(param)) + getter, setter = Symbol("DSDPGet$param"), Symbol("DSDPSet$param") + T = typeof(default) + sym = QuoteNode(param) @eval begin struct $param <: GettableOption end function _call_get(dsdp, ::$param) - return $getter(dsdp) + ret = Ref{$T}() + @check $getter(dsdp, ret) + return ret[] end + options_setters[$sym] = $setter + _dict_set!(options, ::$param, val) = options[$sym] = val + _dict_get(options, ::$param) = get(options, $sym, $default) + _call_set!(dsdp, ::$param, val) = @check $setter(dsdp, val) end end -for option in keys(options) - @eval begin - struct $option <: Option end - end -end - -for (param, default) in Iterators.flatten((options, gettable_options)) - setter = Symbol("Set" * string(param)) +for (param, default) in options + setter = Symbol("DSDPSet$param") sym = QuoteNode(param) @eval begin + struct $param <: Option end options_setters[$sym] = $setter - function _dict_set!(options, ::$param, val) - return options[$sym] = val - end - function _dict_get(options, ::$param) - return get(options, $sym, $default) - end - function _call_set!(dsdp, ::$param, val) - return $setter(dsdp, val) - end + _dict_set!(options, ::$param, val) = options[$sym] = val + _dict_get(options, ::$param) = get(options, $sym, $default) + _call_set!(dsdp, ::$param, val) = @check $setter(dsdp, val) end end @@ -346,7 +356,7 @@ end function _set_A_matrices(m::Optimizer, i) for (blk, blkdim) in zip(m.blk, m.blockdims) if blkdim > 0 - SDPCone.SetASparseVecMat( + SDPConeSetASparseVecMat( m.sdpcone, blk - 1, i, @@ -422,27 +432,31 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) dest.lpdvars = Int[] dest.lpdrows = Int[] dest.lpcoefs = Cdouble[] - dest.dsdp = Create(length(dest.b)) + p = Ref{Ptr{Cvoid}}() + @check DSDPCreate(length(dest.b), p) + dest.dsdp = p[] for (option, value) in dest.options options_setters[option](dest.dsdp, value) end if !iszero(num_sdp) - dest.sdpcone = CreateSDPCone(dest.dsdp, num_sdp) + sdpcone = Ref{Ptr{Cvoid}}() + @check DSDPCreateSDPCone(dest.dsdp, num_sdp, sdpcone) + dest.sdpcone = sdpcone[] for i in eachindex(dest.blockdims) if dest.blockdims[i] < 0 continue end blk = dest.blk[i] - SDPCone.SetBlockSize(dest.sdpcone, blk - 1, dest.blockdims[i]) + SDPConeSetBlockSize(dest.sdpcone, blk - 1, dest.blockdims[i]) # TODO what does this `0` mean ? - SDPCone.SetSparsity(dest.sdpcone, blk - 1, 0) - SDPCone.SetStorageFormat(dest.sdpcone, blk - 1, UInt8('U')) + SDPConeSetSparsity(dest.sdpcone, blk - 1, 0) + SDPConeSetStorageFormat(dest.sdpcone, blk - 1, UInt8('U')) end end for constr in eachindex(dest.b) # TODO in examples/readsdpa.c line 162, # -0.0 is used instead of 0.0 if the dual obj is <= 0., check if it has impact - SetY0(dest.dsdp, constr, 0.0) + @check DSDPSetY0(dest.dsdp, constr, 0.0) end # TODO ComputeY0 as in examples/readsdpa.c empty!(dest.y) @@ -460,7 +474,7 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) ), ) end - SetDualObjective(dest.dsdp, k, MOI.constant(set)) + @check DSDPSetDualObjective(dest.dsdp, k, MOI.constant(set)) _new_A_matrix(dest) for t in func.terms if !iszero(t.coefficient) @@ -518,27 +532,52 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) end # Pass info to `dest.dsdp` if !isempty(dest.lpdvars) - dest.lpcone = CreateLPCone(dest.dsdp) - LPCone.SetDataSparse( - dest.lpcone, - dest.nlpdrows, + lpcone = Ref{Ptr{Cvoid}}() + @check DSDPCreateLPCone(dest.dsdp, lpcone) + dest.lpcone = lpcone[] + nnzin, row, aval = _buildlp( length(dest.b) + 1, dest.lpdvars, dest.lpdrows, dest.lpcoefs, ) + LPConeSetData(dest.lpcone, dest.nlpdrows, nnzin, row, aval) end - Setup(dest.dsdp) + @check DSDPSetup(dest.dsdp) return index_map end +function _buildlp(nvars, lpdvars, lpdrows, lpcoefs) + @assert length(lpdvars) == length(lpdrows) == length(lpcoefs) + nzin = zeros(Cint, nvars) + n = length(lpdvars) + for var in lpdvars + nzin[var] += 1 + end + nnzin = Cint[zero(Cint); cumsum(nzin)] + @assert nnzin[end] == n + idx = map(var -> Int[], 1:nvars) + for (i, var) in enumerate(lpdvars) + push!(idx[var], i) + end + row = Vector{Cint}(undef, n) + aval = Vector{Cdouble}(undef, n) + for var in 1:nvars + sort!(idx[var]; by = i -> lpdrows[i]) + row[(nnzin[var]+1):(nnzin[var+1])] = lpdrows[idx[var]] + aval[(nnzin[var]+1):(nnzin[var+1])] = lpcoefs[idx[var]] + end + return nnzin, row, aval +end + function MOI.optimize!(m::Optimizer) - Solve(m.dsdp) + @check DSDPSetStandardMonitor(m.dsdp, !m.silent ? 1 : 0) + @check DSDPSolve(m.dsdp) # Calling `ComputeX` not right after `Solve` seems to sometime cause segfaults or weird Heisenbug's # let's call it directly what `DSDP/examples/readsdpa.c` does - ComputeX(m.dsdp) + @check DSDPComputeX(m.dsdp) m.y = zeros(Cdouble, length(m.b)) - GetY(m.dsdp, m.y) + @check DSDPGetY(m.dsdp, m.y, length(m.y)) map!(-, m.y, m.y) # The primal objective is Max in SDOI but Min in DSDP return end @@ -547,7 +586,9 @@ function MOI.get(m::Optimizer, ::MOI.RawStatusString) if m.dsdp == C_NULL return "`optimize!` not called" end - status = StopReason(m.dsdp) + stop = Ref{DSDPTerminationReason}() + @check DSDPStopReason(m.dsdp, stop) + status = stop[] if status == DSDP_CONVERGED return "Converged" elseif status == DSDP_INFEASIBLE_START @@ -574,9 +615,13 @@ function MOI.get(m::Optimizer, ::MOI.TerminationStatus) if m.dsdp == C_NULL return MOI.OPTIMIZE_NOT_CALLED end - status = StopReason(m.dsdp) + stop = Ref{DSDPTerminationReason}() + @check DSDPStopReason(m.dsdp, stop) + status = stop[] if status == DSDP_CONVERGED - sol_status = GetSolutionType(m.dsdp) + sol = Ref{DSDPSolutionType}() + @check DSDPGetSolutionType(m.dsdp, sol) + sol_status = sol[] if sol_status == DSDP_PDFEASIBLE return MOI.OPTIMAL elseif sol_status == DSDP_UNBOUNDED @@ -612,7 +657,9 @@ function MOI.get(m::Optimizer, attr::MOI.PrimalStatus) if attr.result_index > MOI.get(m, MOI.ResultCount()) return MOI.NO_SOLUTION end - status = GetSolutionType(m.dsdp) + sol = Ref{DSDPSolutionType}() + @check DSDPGetSolutionType(m.dsdp, sol) + status = sol[] if status == DSDP_PDUNKNOWN return MOI.UNKNOWN_RESULT_STATUS elseif status == DSDP_PDFEASIBLE @@ -629,7 +676,9 @@ function MOI.get(m::Optimizer, attr::MOI.DualStatus) if attr.result_index > MOI.get(m, MOI.ResultCount()) return MOI.NO_SOLUTION end - status = GetSolutionType(m.dsdp) + sol = Ref{DSDPSolutionType}() + @check DSDPGetSolutionType(m.dsdp, sol) + status = sol[] if status == DSDP_PDUNKNOWN return MOI.UNKNOWN_RESULT_STATUS elseif status == DSDP_PDFEASIBLE @@ -647,12 +696,16 @@ MOI.get(m::Optimizer, ::MOI.ResultCount) = m.dsdp == C_NULL ? 0 : 1 function MOI.get(m::Optimizer, attr::MOI.ObjectiveValue) MOI.check_result_index_bounds(m, attr) - return m.objective_sign * GetPPObjective(m.dsdp) + m.objective_constant + ret = Ref{Cdouble}() + @check DSDPGetPPObjective(m.dsdp, ret) + return m.objective_sign * ret[] + m.objective_constant end function MOI.get(m::Optimizer, attr::MOI.DualObjectiveValue) MOI.check_result_index_bounds(m, attr) - return m.objective_sign * GetDDObjective(m.dsdp) + m.objective_constant + ret = Ref{Cdouble}() + @check DSDPGetDDObjective(m.dsdp, ret) + return m.objective_sign * ret[] + m.objective_constant end abstract type LPBlock <: AbstractMatrix{Cdouble} end @@ -677,31 +730,70 @@ function Base.getindex(x::SDPBlock, i, j) end end -include("blockdiag.jl") +abstract type AbstractBlockMatrix{T} <: AbstractMatrix{T} end + +function nblocks end + +function block end + +function Base.size(bm::AbstractBlockMatrix) + n = mapreduce( + blk -> LinearAlgebra.checksquare(block(bm, blk)), + +, + 1:nblocks(bm); + init = 0, + ) + return (n, n) +end + +function Base.getindex(bm::AbstractBlockMatrix, i::Integer, j::Integer) + (i < 0 || j < 0) && throw(BoundsError(i, j)) + for k in 1:nblocks(bm) + blk = block(bm, k) + n = size(blk, 1) + if i <= n && j <= n + return blk[i, j] + elseif i <= n || j <= n + return 0 + else + i -= n + j -= n + end + end + i, j = (i, j) .+ size(bm) + throw(BoundsError(i, j)) +end + +Base.getindex(A::AbstractBlockMatrix, I::Tuple) = getindex(A, I...) abstract type BlockMat <: AbstractBlockMatrix{Cdouble} end nblocks(x::BlockMat) = length(x.optimizer.blk) struct LPXBlock <: LPBlock - lpcone::LPCone.LPConeT + lpcone::Ptr{Cvoid} dim::Int offset::Int end function get_array(x::LPXBlock) - return LPCone.GetXArray(x.lpcone) + xout = Ref{Ptr{Cdouble}}() + n = Ref{Cint}() + LPConeGetXArray(x.lpcone, xout, n) + return unsafe_wrap(Array, xout[], n[]) end struct SDPXBlock <: SDPBlock - sdpcone::SDPCone.SDPConeT + sdpcone::Ptr{Nothing} dim::Int blockj::Int end -#get_array(x::SDPXBlock) = SDPCone.GetXArray(x.sdpcone, x.blockj - 1) function get_array(x::SDPXBlock) - v = SDPCone.GetXArray(x.sdpcone, x.blockj - 1) + xmat = Ref{Ptr{Cdouble}}() + nn = Ref{Cint}() + SDPConeGetXArray(x.sdpcone, x.blockj - 1, xmat, nn) + v = unsafe_wrap(Array, xmat[], nn[]) return [v[i+(j-1)*x.dim] for j in 1:x.dim for i in 1:j] end @@ -747,7 +839,7 @@ function block( end function vectorize_block(M, blk::Integer, ::Type{MOI.Nonnegatives}) - return diag(block(M, blk)) + return LinearAlgebra.diag(block(M, blk)) end function vectorize_block( diff --git a/src/bcone.jl b/src/bcone.jl deleted file mode 100644 index ac01804..0000000 --- a/src/bcone.jl +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (c) 2022: Joey Huchette, Benoît Legat, and contributors -# -# Use of this source code is governed by an MIT-style license that can be found -# in the LICENSE.md file or at https://opensource.org/licenses/MIT. - -export BCone - -module BCone - -import ..@dsdp_ccall -const BConeT = Ptr{Nothing} - -function AllocateBounds(bcone::BConeT, arg2::Integer) - @dsdp_ccall BConeAllocateBounds (BConeT, Cint) bcone arg2 -end - -function SetLowerBound(bcone::BConeT, arg2::Integer, arg3::Cdouble) - @dsdp_ccall BConeSetLowerBound (BConeT, Cint, Cdouble) bcone arg2 arg3 -end - -function SetUpperBound(bcone::BConeT, arg2::Integer, arg3::Cdouble) - @dsdp_ccall BConeSetUpperBound (BConeT, Cint, Cdouble) bcone arg2 arg3 -end - -function SetPSlackVariable(bcone::BConeT, arg2::Integer) - @dsdp_ccall BConeSetPSlackVariable (BConeT, Cint) bcone arg2 -end - -function SetPSurplusVariable(bcone::BConeT, arg2::Integer) - @dsdp_ccall BConeSetPSurplusVariable (BConeT, Cint) bcone arg2 -end - -function ScaleBarrier(bcone::BConeT, arg2::Cdouble) - @dsdp_ccall BConeScaleBarrier (BConeT, Cdouble) bcone arg2 -end - -function View(bcone::BConeT) - @dsdp_ccall BConeView (BConeT,) bcone -end - -function SetXArray(bcone::BConeT, arg2::Vector{Cdouble}, arg3::Integer) - @dsdp_ccall BConeSetXArray (BConeT, Ptr{Cdouble}, Cint) bcone arg2 arg3 -end - -function CopyX( - bcone::BConeT, - arg2::Vector{Cdouble}, - arg3::Vector{Cdouble}, - arg4::Integer, -) - @dsdp_ccall BConeCopyX (BConeT, Ptr{Cdouble}, Ptr{Cdouble}, Cint) bcone arg2 arg3 arg4 -end - -end diff --git a/src/blockdiag.jl b/src/blockdiag.jl deleted file mode 100644 index 83ad513..0000000 --- a/src/blockdiag.jl +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) 2022: Joey Huchette, Benoît Legat, and contributors -# -# Use of this source code is governed by an MIT-style license that can be found -# in the LICENSE.md file or at https://opensource.org/licenses/MIT. - -abstract type AbstractBlockMatrix{T} <: AbstractMatrix{T} end - -function nblocks end -function block end - -function Base.size(bm::AbstractBlockMatrix) - n = mapreduce( - blk -> LinearAlgebra.checksquare(block(bm, blk)), - +, - 1:nblocks(bm); - init = 0, - ) - return (n, n) -end -function Base.getindex(bm::AbstractBlockMatrix, i::Integer, j::Integer) - (i < 0 || j < 0) && throw(BoundsError(i, j)) - for k in 1:nblocks(bm) - blk = block(bm, k) - n = size(blk, 1) - if i <= n && j <= n - return blk[i, j] - elseif i <= n || j <= n - return 0 - else - i -= n - j -= n - end - end - i, j = (i, j) .+ size(bm) - throw(BoundsError(i, j)) -end -Base.getindex(A::AbstractBlockMatrix, I::Tuple) = getindex(A, I...) diff --git a/src/dsdp5_API.jl b/src/dsdp5_API.jl deleted file mode 100644 index 99f94a0..0000000 --- a/src/dsdp5_API.jl +++ /dev/null @@ -1,424 +0,0 @@ -# Copyright (c) 2022: Joey Huchette, Benoît Legat, and contributors -# -# Use of this source code is governed by an MIT-style license that can be found -# in the LICENSE.md file or at https://opensource.org/licenses/MIT. - -# Julia wrapper for header: include/dsdp5.h -# Automatically generated using Clang.jl wrap_c, version 0.0.0 - -function LogInfoAllow(i::Integer) - @dsdp_ccall DSDPLogInfoAllow (Cint, Ptr{Cchar}) i C_NULL -end - -function SetConvergenceFlag(dsdp::DSDPT, arg2::DSDPTerminationReason) - @dsdp_ccall DSDPSetConvergenceFlag (DSDPT, DSDPTerminationReason) dsdp arg2 -end - -function Create(m::Integer) - dsdp = Ref{DSDPT}() - @dsdp_ccall DSDPCreate (Cint, Ref{DSDPT}) m dsdp - return dsdp[] -end - -function Setup(dsdp::DSDPT) - @dsdp_ccall DSDPSetup (DSDPT,) dsdp -end - -function Solve(dsdp::DSDPT) - @dsdp_ccall DSDPSolve (DSDPT,) dsdp -end - -function ComputeX(dsdp::DSDPT) - @dsdp_ccall DSDPComputeX (DSDPT,) dsdp -end - -function ComputeAndFactorS(dsdp::DSDPT) - psdefinite = Ref{DSDPTruth}() - GC.@preserve psdefinite dsdp begin - @dsdp_ccall DSDPComputeAndFactorS (DSDPT, Ref{DSDPTruth}) dsdp psdefinite - return psdefinite[] - end -end - -function Destroy(dsdp::DSDPT) - @dsdp_ccall DSDPDestroy (DSDPT,) dsdp -end - -function SetDualObjective(dsdp::DSDPT, arg2::Integer, arg3::Cdouble) - @dsdp_ccall DSDPSetDualObjective (DSDPT, Cint, Cdouble) dsdp arg2 arg3 -end - -function AddObjectiveConstant(dsdp::DSDPT, arg2::Cdouble) - @dsdp_ccall DSDPAddObjectiveConstant (DSDPT, Cdouble) dsdp arg2 -end - -function GetDObjective(dsdp::DSDPT) - dobj = Ref{Cdouble}() - @dsdp_ccall DSDPGetDObjective (DSDPT, Ref{Cdouble}) dsdp dobj - return dobj[] -end - -function GetDDObjective(dsdp::DSDPT) - ddobj = Ref{Cdouble}() - @dsdp_ccall DSDPGetDDObjective (DSDPT, Ref{Cdouble}) dsdp ddobj - return ddobj[] -end - -function GetPObjective(dsdp::DSDPT) - pobj = Ref{Cdouble}() - @dsdp_ccall DSDPGetPObjective (DSDPT, Ptr{Cdouble}) dsdp pobj - return pobj[] -end - -function GetPPObjective(dsdp::DSDPT) - ppobj = Ref{Cdouble}() - @dsdp_ccall DSDPGetPPObjective (DSDPT, Ptr{Cdouble}) dsdp ppobj - return ppobj[] -end - -function GetDualityGap(dsdp::DSDPT) - dgap = Ref{Cdouble}() - @dsdp_ccall DSDPGetDualityGap (DSDPT, Ptr{Cdouble}) dsdp dgap - return dgap[] -end - -function GetScale(dsdp::DSDPT) - scale = Ref{Cdouble}() - @dsdp_ccall DSDPGetScale (DSDPT, Ref{Cdouble}) dsdp scale - return scale[] -end - -function SetScale(dsdp::DSDPT, scale::Cdouble) - @dsdp_ccall DSDPSetScale (DSDPT, Cdouble) dsdp scale -end - -function GetPenaltyParameter(dsdp::DSDPT) - pp = Ref{Cdouble}() - @dsdp_ccall DSDPGetPenaltyParameter (DSDPT, Ref{Cdouble}) dsdp pp - return pp[] -end - -function GetPenalty(dsdp::DSDPT, arg2::Vector{Cdouble}) - @dsdp_ccall DSDPGetPenalty (DSDPT, Ptr{Cdouble}) dsdp arg2 -end - -function CopyB(dsdp::DSDPT, arg2::Vector{Cdouble}, arg3::Integer) - @dsdp_ccall DSDPCopyB (DSDPT, Ptr{Cdouble}, Cint) dsdp arg2 arg3 -end - -function SetR0(dsdp::DSDPT, arg2::Cdouble) - @dsdp_ccall DSDPSetR0 (DSDPT, Cdouble) dsdp arg2 -end - -function GetR(dsdp::DSDPT, arg2::Vector{Cdouble}) - @dsdp_ccall DSDPGetR (DSDPT, Ptr{Cdouble}) dsdp arg2 -end - -function SetRTolerance(dsdp::DSDPT, arg2::Cdouble) - @dsdp_ccall DSDPSetRTolerance (DSDPT, Cdouble) dsdp arg2 -end - -function GetRTolerance(dsdp::DSDPT) - rtol = Ref{Cdouble}() - @dsdp_ccall DSDPGetRTolerance (DSDPT, Ref{Cdouble}) dsdp rtol - return rtol[] -end - -function SetY0(dsdp::DSDPT, arg2::Integer, arg3::Cdouble) - @dsdp_ccall DSDPSetY0 (DSDPT, Cint, Cdouble) dsdp arg2 arg3 -end - -function GetY(dsdp::DSDPT, y::Vector{Cdouble}) - @dsdp_ccall DSDPGetY (DSDPT, Ptr{Cdouble}, Cint) dsdp pointer(y) length(y) -end - -function GetYMakeX(dsdp::DSDPT, arg2, arg3::Integer) - @dsdp_ccall DSDPGetYMakeX (DSDPT, Ptr{Cdouble}, Cint) dsdp arg2 arg3 -end - -function GetDYMakeX(dsdp::DSDPT, arg2, arg3::Integer) - @dsdp_ccall DSDPGetDYMakeX (DSDPT, Ptr{Cdouble}, Cint) dsdp arg2 arg3 -end - -function GetMuMakeX(dsdp::DSDPT, arg2::Vector{Cdouble}) - @dsdp_ccall DSDPGetMuMakeX (DSDPT, Ptr{Cdouble}) dsdp arg2 -end - -function GetBarrierParameter(dsdp::DSDPT) - bp = Ref{Cdouble}() - @dsdp_ccall DSDPGetBarrierParameter (DSDPT, Ptr{Cdouble}) dsdp bp - return bp[] -end - -function SetBarrierParameter(dsdp::DSDPT, arg2::Cdouble) - @dsdp_ccall DSDPSetBarrierParameter (DSDPT, Cdouble) dsdp arg2 -end - -function SetReuseMatrix(dsdp::DSDPT, arg2::Integer) - @dsdp_ccall DSDPReuseMatrix (DSDPT, Cint) dsdp arg2 -end - -function GetReuseMatrix(dsdp::DSDPT) - reuse = Ref{Cint}() - @dsdp_ccall DSDPGetReuseMatrix (DSDPT, Ref{Cint}) dsdp reuse - return reuse[] -end - -function GetDimension(dsdp::DSDPT, arg2::Vector{Cdouble}) - @dsdp_ccall DSDPGetDimension (DSDPT, Ptr{Cdouble}) dsdp arg2 -end - -function SetMaxIts(dsdp::DSDPT, arg2::Integer) - @dsdp_ccall DSDPSetMaxIts (DSDPT, Cint) dsdp arg2 -end - -function GetMaxIts(dsdp::DSDPT) - maxits = Ref{Cint}() - @dsdp_ccall DSDPGetMaxIts (DSDPT, Ref{Cint}) dsdp maxits - return maxits[] -end - -function SetStepTolerance(dsdp::DSDPT, steptol::Cdouble) - @assert steptol > 0 - @dsdp_ccall DSDPSetStepTolerance (DSDPT, Cdouble) dsdp arg2 -end - -function GetStepTolerance(dsdp::DSDPT) - steptol = Ref{Cdouble}() - @dsdp_ccall DSDPGetStepTolerance (DSDPT, Ref{Cdouble}) dsdp steptol - return steptol[] -end - -function SetGapTolerance(dsdp::DSDPT, arg2::Cdouble) - @dsdp_ccall DSDPSetGapTolerance (DSDPT, Cdouble) dsdp arg2 -end - -function GetGapTolerance(dsdp::DSDPT) - gaptol = Ref{Cdouble}() - @dsdp_ccall DSDPGetGapTolerance (DSDPT, Ref{Cdouble}) dsdp gaptol - return gaptol[] -end - -function SetPNormTolerance(dsdp::DSDPT, pnormtol::Real) - @assert pnormtol > 0 - @dsdp_ccall DSDPSetPNormTolerance (DSDPT, Cdouble) dsdp pnormtol -end - -function GetPNormTolerance(dsdp::DSDPT) - pnormtol = Ref{Cdouble}() - @dsdp_ccall DSDPGetPNormTolerance (DSDPT, Ref{Cdouble}) dsdp pnormtol - return pnormtol[] -end - -function SetDualBound(dsdp::DSDPT, arg2::Cdouble) - @dsdp_ccall DSDPSetDualBound (DSDPT, Cdouble) dsdp arg2 -end - -function GetDualBound(dsdp::DSDPT) - dualb = Ref{Cdouble}() - @dsdp_ccall DSDPGetDualBound (DSDPT, Ref{Cdouble}) dsdp dualb - return dualb[] -end - -function SetPTolerance(dsdp::DSDPT, arg2::Cdouble) - @dsdp_ccall DSDPSetPTolerance (DSDPT, Cdouble) dsdp arg2 -end - -function GetPTolerance(dsdp::DSDPT) - ptol = Ref{Cdouble}() - @dsdp_ccall DSDPGetPTolerance (DSDPT, Ref{Cdouble}) dsdp ptol - return ptol[] -end - -function GetPInfeasibility(dsdp::DSDPT, arg2::Vector{Cdouble}) - @dsdp_ccall DSDPGetPInfeasibility (DSDPT, Ptr{Cdouble}) dsdp arg2 -end - -function SetMaxTrustRadius(dsdp::DSDPT, maxtrust::Cdouble) - @dsdp_ccall DSDPSetMaxTrustRadius (DSDPT, Cdouble) dsdp maxtrust -end - -function GetMaxTrustRadius(dsdp::DSDPT) - maxtrust = Ref{Cdouble}() - @dsdp_ccall DSDPGetMaxTrustRadius (DSDPT, Ptr{Cdouble}) dsdp maxtrust - return maxtrust[] -end - -function StopReason(dsdp::DSDPT) - stop = Ref{DSDPTerminationReason}() - @dsdp_ccall DSDPStopReason (DSDPT, Ref{DSDPTerminationReason}) dsdp stop - return stop[] -end - -function GetSolutionType(dsdp::DSDPT) - sol = Ref{DSDPSolutionType}() - @dsdp_ccall DSDPGetSolutionType (DSDPT, Ref{DSDPSolutionType}) dsdp sol - return sol[] -end - -function SetPotentialParameter(dsdp::DSDPT, pp::Real) - @dsdp_ccall DSDPSetPotentialParameter (DSDPT, Cdouble) dsdp pp -end - -function GetPotentialParameter(dsdp::DSDPT) - pp = Ref{Cdouble}() - @dsdp_ccall DSDPGetPotentialParameter (DSDPT, Ref{Cdouble}) dsdp pp - return pp[] -end - -function UseDynamicRho(dsdp::DSDPT, arg2::Integer) - @dsdp_ccall DSDPUseDynamicRho (DSDPT, Cint) dsdp arg2 -end - -function GetPotential(dsdp::DSDPT, arg2::Vector{Cdouble}) - @dsdp_ccall DSDPGetPotential (DSDPT, Ptr{Cdouble}) dsdp arg2 -end - -function UseLAPACKForSchur(dsdp::DSDPT, arg2::Integer) - @dsdp_ccall DSDPUseLAPACKForSchur (DSDPT, Cint) dsdp arg2 -end - -function GetNumberOfVariables(dsdp::DSDPT) - n = Ref{Cint}(0) - @dsdp_ccall DSDPGetNumberOfVariables (DSDPT, Ref{Cint}) dsdp n - return n[] -end - -function GetFinalErrors(dsdp::DSDPT) - err = zeros(Cdouble, 6) - @dsdp_ccall DSDPGetFinalErrors (DSDPT, Ptr{Cdouble}) dsdp err - return err -end - -function GetGapHistory(dsdp::DSDPT, arg2::Vector{Cdouble}, arg3::Integer) - @dsdp_ccall DSDPGetGapHistory (DSDPT, Ptr{Cdouble}, Cint) dsdp arg2 arg3 -end - -function GetRHistory(dsdp::DSDPT, arg2::Vector{Cdouble}, arg3::Integer) - @dsdp_ccall DSDPGetRHistory (DSDPT, Ptr{Cdouble}, Cint) dsdp arg2 arg3 -end - -function GetIts(dsdp::DSDPT) - its = Ref{Cint}() - @dsdp_ccall DSDPGetIts (DSDPT, Ptr{Cint}) dsdp its - return its[] -end - -function GetPnorm(dsdp::DSDPT, arg2::Vector{Cdouble}) - @dsdp_ccall DSDPGetPnorm (DSDPT, Ptr{Cdouble}) dsdp arg2 -end - -function GetStepLengths( - dsdp::DSDPT, - arg2::Vector{Cdouble}, - arg3::Vector{Cdouble}, -) - @dsdp_ccall DSDPGetStepLengths (DSDPT, Ptr{Cdouble}, Ptr{Cdouble}) dsdp arg2 arg3 -end - -function SetMonitor(dsdp::DSDPT, arg2, arg3) - @dsdp_ccall DSDPSetMonitor (DSDPT, DSDPT, DSDPT) dsdp arg2 arg3 -end - -function SetStandardMonitor(dsdp::DSDPT, arg2::Integer) - @dsdp_ccall DSDPSetStandardMonitor (DSDPT, Cint) dsdp arg2 -end - -function SetFileMonitor(dsdp::DSDPT, arg2::Integer) - @dsdp_ccall DSDPSetFileMonitor (DSDPT, Cint) dsdp arg2 -end - -function SetPenaltyParameter(dsdp::DSDPT, arg2::Cdouble) - @dsdp_ccall DSDPSetPenaltyParameter (DSDPT, Cdouble) dsdp arg2 -end - -function UsePenalty(dsdp::DSDPT, arg2::Integer) - @dsdp_ccall DSDPUsePenalty (DSDPT, Cint) dsdp arg2 -end - -function PrintLogInfo(arg1::Integer) - @dsdp_ccall DSDPPrintLogInfo (Cint,) arg1 -end - -function ComputeMinimumXEigenvalue(dsdp::DSDPT, arg2::Vector{Cdouble}) - @dsdp_ccall DSDPComputeMinimumXEigenvalue (DSDPT, Ptr{Cdouble}) dsdp arg2 -end - -function GetTraceX(dsdp::DSDPT, sdpcone::Vector{Cdouble}) - @dsdp_ccall DSDPGetTraceX (DSDPT, Ptr{Cdouble}) dsdp sdpcone -end - -function SetZBar(dsdp::DSDPT, arg2::Cdouble) - @dsdp_ccall DSDPSetZBar (DSDPT, Cdouble) dsdp arg2 -end - -function SetDualLowerBound(dsdp::DSDPT, arg2::Cdouble) - @dsdp_ccall DSDPSetDualLowerBound (DSDPT, Cdouble) dsdp arg2 -end - -function GetDataNorms(dsdp::DSDPT, arg2::NTuple{3,Cdouble}) - @dsdp_ccall DSDPGetDataNorms (DSDPT, NTuple{3,Cdouble}) dsdp arg2 -end - -function GetYMaxNorm(dsdp::DSDPT, arg2::Vector{Cdouble}) - @dsdp_ccall DSDPGetYMaxNorm (DSDPT, Ptr{Cdouble}) dsdp arg2 -end - -function BoundDualVariables(dsdp::DSDPT, arg2::Cdouble, arg3::Cdouble) - @dsdp_ccall DSDPBoundDualVariables (DSDPT, Cdouble, Cdouble) dsdp arg2 arg3 -end - -function SetYBounds(dsdp::DSDPT, ylow::Cdouble, yhigh::Cdouble) - @dsdp_ccall DSDPSetYBounds (DSDPT, Cdouble, Cdouble) dsdp ylow yhigh -end - -function GetYBounds(dsdp::DSDPT) - ylow = Ref{Cdouble}() - yhigh = Ref{Cdouble}() - @dsdp_ccall DSDPGetYBounds (DSDPT, Ref{Cdouble}, Ref{Cdouble}) dsdp ylow yhigh - return ylow[], yhigh[] -end - -function SetFixedVariable(dsdp::DSDPT, arg2::Integer, arg3::Cdouble) - @dsdp_ccall DSDPSetFixedVariable (DSDPT, Cint, Cdouble) dsdp arg2 arg3 -end - -function SetFixedVariables( - dsdp::DSDPT, - arg2::Vector{Cdouble}, - arg3::Vector{Cdouble}, - arg4::Vector{Cdouble}, - arg5::Integer, -) - @dsdp_ccall DSDPSetFixedVariables ( - DSDPT, - Ptr{Cdouble}, - Ptr{Cdouble}, - Ptr{Cdouble}, - Cint, - ) dsdp arg2 arg3 arg4 arg5 -end - -function GetFixedYX(dsdp::DSDPT, arg2::Integer, arg3::Vector{Cdouble}) - @dsdp_ccall DSDPGetFixedYX (DSDPT, Cint, Ptr{Cdouble}) dsdp arg2 arg3 -end - -function View(dsdp::DSDPT) - @dsdp_ccall DSDPView (DSDPT,) dsdp -end - -function PrintOptions() - return ccall((:DSDPPrintOptions, libdsdp), Cint, ()) -end - -function SetOptions(dsdp::DSDPT, arg2::Vector{Cstring}, arg3::Integer) - @dsdp_ccall DSDPSetOptions (DSDPT, Ptr{Cstring}, Cint) dsdp arg2 arg3 -end - -function ReadOptions(dsdp::DSDPT, arg2::Vector{UInt8}) - @dsdp_ccall DSDPReadOptions (DSDPT, Ptr{UInt8}) dsdp arg2 -end - -function SetDestroyRoutine(dsdp::DSDPT, arg2, arg3) - @dsdp_ccall DSDPSetDestroyRoutine (DSDPT, DSDPT, DSDPT) dsdp arg2 arg3 -end diff --git a/src/dsdp5_enums.jl b/src/dsdp5_enums.jl deleted file mode 100644 index c0ae8c2..0000000 --- a/src/dsdp5_enums.jl +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2022: Joey Huchette, Benoît Legat, and contributors -# -# Use of this source code is governed by an MIT-style license that can be found -# in the LICENSE.md file or at https://opensource.org/licenses/MIT. - -# Automatically generated using Clang.jl wrap_c, version 0.0.0 - -const DSDPTruth = Cuint - -# begin enum DSDPTerminationReason -const DSDPTerminationReason = Cint -const DSDP_CONVERGED = DSDPTerminationReason(1) # Good news: Solution found -const DSDP_INFEASIBLE_START = DSDPTerminationReason(-6) # The initial points y and r imply that S is not positive -const DSDP_SMALL_STEPS = DSDPTerminationReason(-2) # Short step lengths created by numerical difficulties prevent progress -const DSDP_INDEFINITE_SCHUR_MATRIX = DSDPTerminationReason(-8) # Theoretically this matrix is positive definite -const DSDP_MAX_IT = DSDPTerminationReason(-3) # Reached maximum number of iterations -const DSDP_NUMERICAL_ERROR = DSDPTerminationReason(-9) # Another numerical error occurred. Check solution -const DSDP_UPPERBOUND = DSDPTerminationReason(5) # Objective (DD) big enough to stop -const DSDP_USER_TERMINATION = DSDPTerminationReason(7) # DSDP didn't stop it, did you? -const CONTINUE_ITERATING = DSDPTerminationReason(0) # Don't Stop -# end enum DSDPTerminationReason - -# begin enum DSDPSolutionType -const DSDPSolutionType = Cuint # converged -const DSDP_PDUNKNOWN = DSDPSolutionType(0) # Not sure whether (D) or (P) is feasible, check y bounds -const DSDP_PDFEASIBLE = DSDPSolutionType(1) # Both (D) and (P) are feasible and bounded -const DSDP_UNBOUNDED = DSDPSolutionType(3) # (D) is unbounded and (P) is infeasible -const DSDP_INFEASIBLE = DSDPSolutionType(4) # (D) in infeasible and (P) is unbounded -# end enum DSDPSolutionType - -# begin enum DSDPDualFactorMatrix -const DSDPDualFactorMatrix = Cuint -const DUAL_FACTOR = DSDPDualFactorMatrix(1) # First instance for dual variable S -const PRIMAL_FACTOR = DSDPDualFactorMatrix(2) # Second instance used to compute X -# end enum DSDPDualFactorMatrix - -# begin enum DSDPPenalty -const DSDPPenalty = Cuint -const DSDPAlways = DSDPPenalty(1) -const DSDPNever = DSDPPenalty(2) -const DSDPInfeasible = DSDPPenalty(0) -# end enum DSDPPenalty diff --git a/src/libdsdp.jl b/src/libdsdp.jl new file mode 100644 index 0000000..595e4bc --- /dev/null +++ b/src/libdsdp.jl @@ -0,0 +1,703 @@ +# Copyright (c) 2022: Joey Huchette, Benoît Legat, and contributors +# +# Use of this source code is governed by an MIT-style license that can be found +# in the LICENSE.md file or at https://opensource.org/licenses/MIT. + +# Disable JuliaFormatter for this file. +#!format:off + +function DSDPError(arg1, arg2, arg3) + @ccall libdsdp.DSDPError(arg1::Ptr{Cchar}, arg2::Cint, arg3::Ptr{Cchar})::Cvoid +end + +function DSDPSetBarrierParameter(arg1, arg2) + @ccall libdsdp.DSDPSetBarrierParameter(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function DSDPGetBarrierParameter(arg1, arg2) + @ccall libdsdp.DSDPGetBarrierParameter(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +@cenum DSDPTruth::UInt32 begin + DSDP_FALSE = 0 + DSDP_TRUE = 1 +end + +@cenum DSDPDualFactorMatrix::UInt32 begin + DUAL_FACTOR = 1 + PRIMAL_FACTOR = 2 +end + +@cenum DSDPPenalty::UInt32 begin + DSDPAlways = 1 + DSDPNever = 2 + DSDPInfeasible = 0 +end + +@cenum DSDPSolutionType::UInt32 begin + DSDP_PDUNKNOWN = 0 + DSDP_PDFEASIBLE = 1 + DSDP_UNBOUNDED = 3 + DSDP_INFEASIBLE = 4 +end + +@cenum DSDPTerminationReason::Int32 begin + DSDP_CONVERGED = 1 + DSDP_INFEASIBLE_START = -6 + DSDP_SMALL_STEPS = -2 + DSDP_INDEFINITE_SCHUR_MATRIX = -8 + DSDP_MAX_IT = -3 + DSDP_NUMERICAL_ERROR = -9 + DSDP_UPPERBOUND = 5 + DSDP_USER_TERMINATION = 7 + CONTINUE_ITERATING = 0 +end + +function DSDPSetConvergenceFlag(arg1, arg2) + @ccall libdsdp.DSDPSetConvergenceFlag(arg1::Ptr{Cvoid}, arg2::DSDPTerminationReason)::Cint +end + +function DSDPTime(arg1) + @ccall libdsdp.DSDPTime(arg1::Ptr{Cdouble})::Cvoid +end + +function DSDPLogInfoAllow(arg1, arg2) + @ccall libdsdp.DSDPLogInfoAllow(arg1::Cint, arg2::Ptr{Cchar})::Cint +end + +function DSDPMemoryLog() + @ccall libdsdp.DSDPMemoryLog()::Cvoid +end + +function DSDPEventLogBegin(arg1) + @ccall libdsdp.DSDPEventLogBegin(arg1::Cint)::Cint +end + +function DSDPEventLogEnd(arg1) + @ccall libdsdp.DSDPEventLogEnd(arg1::Cint)::Cint +end + +function DSDPEventLogRegister(arg1, arg2) + @ccall libdsdp.DSDPEventLogRegister(arg1::Ptr{Cchar}, arg2::Ptr{Cint})::Cint +end + +function DSDPEventLogInitialize() + @ccall libdsdp.DSDPEventLogInitialize()::Cint +end + +function DSDPEventLogSummary() + @ccall libdsdp.DSDPEventLogSummary()::Cint +end + +function DSDPMMalloc(arg1, arg2, arg3) + @ccall libdsdp.DSDPMMalloc(arg1::Ptr{Cchar}, arg2::Csize_t, arg3::Ptr{Ptr{Cvoid}})::Cint +end + +function DSDPFFree(arg1) + @ccall libdsdp.DSDPFFree(arg1::Ptr{Ptr{Cvoid}})::Cint +end + +function DSDPCreate(arg1, arg2) + @ccall libdsdp.DSDPCreate(arg1::Cint, arg2::Ptr{Ptr{Cvoid}})::Cint +end + +function DSDPSetup(arg1) + @ccall libdsdp.DSDPSetup(arg1::Ptr{Cvoid})::Cint +end + +function DSDPSolve(arg1) + @ccall libdsdp.DSDPSolve(arg1::Ptr{Cvoid})::Cint +end + +function DSDPComputeX(arg1) + @ccall libdsdp.DSDPComputeX(arg1::Ptr{Cvoid})::Cint +end + +function DSDPComputeAndFactorS(arg1, arg2) + @ccall libdsdp.DSDPComputeAndFactorS(arg1::Ptr{Cvoid}, arg2::Ptr{DSDPTruth})::Cint +end + +function DSDPDestroy(arg1) + @ccall libdsdp.DSDPDestroy(arg1::Ptr{Cvoid})::Cint +end + +function DSDPCreateBCone(arg1, arg2) + @ccall libdsdp.DSDPCreateBCone(arg1::Ptr{Cvoid}, arg2::Ptr{Ptr{Cvoid}})::Cint +end + +function BConeAllocateBounds(arg1, arg2) + @ccall libdsdp.BConeAllocateBounds(arg1::Ptr{Cvoid}, arg2::Cint)::Cint +end + +function BConeSetLowerBound(arg1, arg2, arg3) + @ccall libdsdp.BConeSetLowerBound(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cdouble)::Cint +end + +function BConeSetUpperBound(arg1, arg2, arg3) + @ccall libdsdp.BConeSetUpperBound(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cdouble)::Cint +end + +function BConeSetPSlackVariable(arg1, arg2) + @ccall libdsdp.BConeSetPSlackVariable(arg1::Ptr{Cvoid}, arg2::Cint)::Cint +end + +function BConeSetPSurplusVariable(arg1, arg2) + @ccall libdsdp.BConeSetPSurplusVariable(arg1::Ptr{Cvoid}, arg2::Cint)::Cint +end + +function BConeScaleBarrier(arg1, arg2) + @ccall libdsdp.BConeScaleBarrier(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function BConeView(arg1) + @ccall libdsdp.BConeView(arg1::Ptr{Cvoid})::Cint +end + +function BConeSetXArray(arg1, arg2, arg3) + @ccall libdsdp.BConeSetXArray(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble}, arg3::Cint)::Cint +end + +function BConeCopyX(arg1, arg2, arg3, arg4) + @ccall libdsdp.BConeCopyX(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble}, arg3::Ptr{Cdouble}, arg4::Cint)::Cint +end + +function DSDPBoundDualVariables(arg1, arg2, arg3) + @ccall libdsdp.DSDPBoundDualVariables(arg1::Ptr{Cvoid}, arg2::Cdouble, arg3::Cdouble)::Cint +end + +function DSDPSetYBounds(arg1, arg2, arg3) + @ccall libdsdp.DSDPSetYBounds(arg1::Ptr{Cvoid}, arg2::Cdouble, arg3::Cdouble)::Cint +end + +function DSDPGetYBounds(arg1, arg2, arg3) + @ccall libdsdp.DSDPGetYBounds(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble}, arg3::Ptr{Cdouble})::Cint +end + +function DSDPCreateLPCone(arg1, arg2) + @ccall libdsdp.DSDPCreateLPCone(arg1::Ptr{Cvoid}, arg2::Ptr{Ptr{Cvoid}})::Cint +end + +function LPConeSetData(arg1, arg2, arg3, arg4, arg5) + @ccall libdsdp.LPConeSetData(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Ptr{Cint}, arg4::Ptr{Cint}, arg5::Ptr{Cdouble})::Cint +end + +function LPConeSetData2(arg1, arg2, arg3, arg4, arg5) + @ccall libdsdp.LPConeSetData2(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Ptr{Cint}, arg4::Ptr{Cint}, arg5::Ptr{Cdouble})::Cint +end + +function LPConeGetData(arg1, arg2, arg3, arg4) + @ccall libdsdp.LPConeGetData(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Ptr{Cdouble}, arg4::Cint)::Cint +end + +function LPConeScaleBarrier(arg1, arg2) + @ccall libdsdp.LPConeScaleBarrier(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function LPConeGetXArray(arg1, arg2, arg3) + @ccall libdsdp.LPConeGetXArray(arg1::Ptr{Cvoid}, arg2::Ptr{Ptr{Cdouble}}, arg3::Ptr{Cint})::Cint +end + +function LPConeGetSArray(arg1, arg2, arg3) + @ccall libdsdp.LPConeGetSArray(arg1::Ptr{Cvoid}, arg2::Ptr{Ptr{Cdouble}}, arg3::Ptr{Cint})::Cint +end + +function LPConeGetDimension(arg1, arg2) + @ccall libdsdp.LPConeGetDimension(arg1::Ptr{Cvoid}, arg2::Ptr{Cint})::Cint +end + +function LPConeView(lpcone) + @ccall libdsdp.LPConeView(lpcone::Ptr{Cvoid})::Cint +end + +function LPConeView2(lpcone) + @ccall libdsdp.LPConeView2(lpcone::Ptr{Cvoid})::Cint +end + +function LPConeCopyS(arg1, arg2, arg3) + @ccall libdsdp.LPConeCopyS(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble}, arg3::Cint)::Cint +end + +function DSDPCreateSDPCone(arg1, arg2, arg3) + @ccall libdsdp.DSDPCreateSDPCone(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Ptr{Ptr{Cvoid}})::Cint +end + +function SDPConeSetBlockSize(arg1, arg2, arg3) + @ccall libdsdp.SDPConeSetBlockSize(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint)::Cint +end + +function SDPConeGetBlockSize(arg1, arg2, arg3) + @ccall libdsdp.SDPConeGetBlockSize(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Ptr{Cint})::Cint +end + +function SDPConeSetStorageFormat(arg1, arg2, arg3) + @ccall libdsdp.SDPConeSetStorageFormat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cchar)::Cint +end + +function SDPConeGetStorageFormat(arg1, arg2, arg3) + @ccall libdsdp.SDPConeGetStorageFormat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Ptr{Cchar})::Cint +end + +function SDPConeCheckStorageFormat(arg1, arg2, arg3) + @ccall libdsdp.SDPConeCheckStorageFormat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cchar)::Cint +end + +function SDPConeSetSparsity(arg1, arg2, arg3) + @ccall libdsdp.SDPConeSetSparsity(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint)::Cint +end + +function SDPConeView(arg1) + @ccall libdsdp.SDPConeView(arg1::Ptr{Cvoid})::Cint +end + +function SDPConeView2(arg1) + @ccall libdsdp.SDPConeView2(arg1::Ptr{Cvoid})::Cint +end + +function SDPConeView3(arg1) + @ccall libdsdp.SDPConeView3(arg1::Ptr{Cvoid})::Cint +end + +function SDPConeSetASparseVecMat(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) + @ccall libdsdp.SDPConeSetASparseVecMat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Cint, arg5::Cdouble, arg6::Cint, arg7::Ptr{Cint}, arg8::Ptr{Cdouble}, arg9::Cint)::Cint +end + +function SDPConeSetADenseVecMat(arg1, arg2, arg3, arg4, arg5, arg6, arg7) + @ccall libdsdp.SDPConeSetADenseVecMat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Cint, arg5::Cdouble, arg6::Ptr{Cdouble}, arg7::Cint)::Cint +end + +function SDPConeSetARankOneMat(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) + @ccall libdsdp.SDPConeSetARankOneMat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Cint, arg5::Cdouble, arg6::Cint, arg7::Ptr{Cint}, arg8::Ptr{Cdouble}, arg9::Cint)::Cint +end + +function SDPConeSetConstantMat(arg1, arg2, arg3, arg4, arg5) + @ccall libdsdp.SDPConeSetConstantMat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Cint, arg5::Cdouble)::Cint +end + +function SDPConeSetZeroMat(arg1, arg2, arg3, arg4) + @ccall libdsdp.SDPConeSetZeroMat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Cint)::Cint +end + +function SDPConeSetIdentity(arg1, arg2, arg3, arg4, arg5) + @ccall libdsdp.SDPConeSetIdentity(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Cint, arg5::Cdouble)::Cint +end + +function SDPConeViewDataMatrix(arg1, arg2, arg3) + @ccall libdsdp.SDPConeViewDataMatrix(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint)::Cint +end + +function SDPConeMatrixView(arg1, arg2) + @ccall libdsdp.SDPConeMatrixView(arg1::Ptr{Cvoid}, arg2::Cint)::Cint +end + +function SDPConeAddASparseVecMat(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) + @ccall libdsdp.SDPConeAddASparseVecMat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Cint, arg5::Cdouble, arg6::Cint, arg7::Ptr{Cint}, arg8::Ptr{Cdouble}, arg9::Cint)::Cint +end + +function SDPConeAddADenseVecMat(arg1, arg2, arg3, arg4, arg5, arg6, arg7) + @ccall libdsdp.SDPConeAddADenseVecMat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Cint, arg5::Cdouble, arg6::Ptr{Cdouble}, arg7::Cint)::Cint +end + +function SDPConeAddConstantMat(arg1, arg2, arg3, arg4, arg5) + @ccall libdsdp.SDPConeAddConstantMat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Cint, arg5::Cdouble)::Cint +end + +function SDPConeAddIdentity(arg1, arg2, arg3, arg4, arg5) + @ccall libdsdp.SDPConeAddIdentity(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Cint, arg5::Cdouble)::Cint +end + +function SDPConeAddARankOneMat(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) + @ccall libdsdp.SDPConeAddARankOneMat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Cint, arg5::Cdouble, arg6::Cint, arg7::Ptr{Cint}, arg8::Ptr{Cdouble}, arg9::Cint)::Cint +end + +function SDPConeAddSparseVecMat(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) + @ccall libdsdp.SDPConeAddSparseVecMat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Cint, arg5::Cint, arg6::Ptr{Cint}, arg7::Ptr{Cdouble}, arg8::Cint)::Cint +end + +function SDPConeAddDenseVecMat(arg1, arg2, arg3, arg4, arg5, arg6) + @ccall libdsdp.SDPConeAddDenseVecMat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Cint, arg5::Ptr{Cdouble}, arg6::Cint)::Cint +end + +function SDPConeSetSparseVecMat(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) + @ccall libdsdp.SDPConeSetSparseVecMat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Cint, arg5::Cint, arg6::Ptr{Cint}, arg7::Ptr{Cdouble}, arg8::Cint)::Cint +end + +function SDPConeSetDenseVecMat(arg1, arg2, arg3, arg4, arg5, arg6) + @ccall libdsdp.SDPConeSetDenseVecMat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Cint, arg5::Ptr{Cdouble}, arg6::Cint)::Cint +end + +function SDPConeSetXMat(arg1, arg2, arg3) + @ccall libdsdp.SDPConeSetXMat(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint)::Cint +end + +function SDPConeSetXArray(arg1, arg2, arg3, arg4, arg5) + @ccall libdsdp.SDPConeSetXArray(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Ptr{Cdouble}, arg5::Cint)::Cint +end + +function SDPConeGetXArray(arg1, arg2, arg3, arg4) + @ccall libdsdp.SDPConeGetXArray(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Ptr{Ptr{Cdouble}}, arg4::Ptr{Cint})::Cint +end + +function SDPConeRestoreXArray(arg1, arg2, arg3, arg4) + @ccall libdsdp.SDPConeRestoreXArray(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Ptr{Ptr{Cdouble}}, arg4::Ptr{Cint})::Cint +end + +function SDPConeCheckData(arg1) + @ccall libdsdp.SDPConeCheckData(arg1::Ptr{Cvoid})::Cint +end + +function SDPConeRemoveDataMatrix(arg1, arg2, arg3) + @ccall libdsdp.SDPConeRemoveDataMatrix(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint)::Cint +end + +function SDPConeGetNumberOfBlocks(arg1, arg2) + @ccall libdsdp.SDPConeGetNumberOfBlocks(arg1::Ptr{Cvoid}, arg2::Ptr{Cint})::Cint +end + +function SDPConeComputeS(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) + @ccall libdsdp.SDPConeComputeS(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cdouble, arg4::Ptr{Cdouble}, arg5::Cint, arg6::Cdouble, arg7::Cint, arg8::Ptr{Cdouble}, arg9::Cint)::Cint +end + +function SDPConeComputeX(arg1, arg2, arg3, arg4, arg5) + @ccall libdsdp.SDPConeComputeX(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Ptr{Cdouble}, arg5::Cint)::Cint +end + +function SDPConeAddADotX(arg1, arg2, arg3, arg4, arg5, arg6, arg7) + @ccall libdsdp.SDPConeAddADotX(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cdouble, arg4::Ptr{Cdouble}, arg5::Cint, arg6::Ptr{Cdouble}, arg7::Cint)::Cint +end + +function SDPConeViewX(arg1, arg2, arg3, arg4, arg5) + @ccall libdsdp.SDPConeViewX(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cint, arg4::Ptr{Cdouble}, arg5::Cint)::Cint +end + +function SDPConeSetLanczosIterations(arg1, arg2) + @ccall libdsdp.SDPConeSetLanczosIterations(arg1::Ptr{Cvoid}, arg2::Cint)::Cint +end + +function SDPConeScaleBarrier(arg1, arg2, arg3) + @ccall libdsdp.SDPConeScaleBarrier(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cdouble)::Cint +end + +function SDPConeXVMultiply(arg1, arg2, arg3, arg4, arg5) + @ccall libdsdp.SDPConeXVMultiply(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Ptr{Cdouble}, arg4::Ptr{Cdouble}, arg5::Cint)::Cint +end + +function SDPConeComputeXV(arg1, arg2, arg3) + @ccall libdsdp.SDPConeComputeXV(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Ptr{Cint})::Cint +end + +function SDPConeAddXVAV(arg1, arg2, arg3, arg4, arg5, arg6) + @ccall libdsdp.SDPConeAddXVAV(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Ptr{Cdouble}, arg4::Cint, arg5::Ptr{Cdouble}, arg6::Cint)::Cint +end + +function SDPConeUseLAPACKForDualMatrix(arg1, arg2) + @ccall libdsdp.SDPConeUseLAPACKForDualMatrix(arg1::Ptr{Cvoid}, arg2::Cint)::Cint +end + +function DSDPSetDualObjective(arg1, arg2, arg3) + @ccall libdsdp.DSDPSetDualObjective(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cdouble)::Cint +end + +function DSDPAddObjectiveConstant(arg1, arg2) + @ccall libdsdp.DSDPAddObjectiveConstant(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function DSDPGetDObjective(arg1, arg2) + @ccall libdsdp.DSDPGetDObjective(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPGetDDObjective(arg1, arg2) + @ccall libdsdp.DSDPGetDDObjective(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPGetPObjective(arg1, arg2) + @ccall libdsdp.DSDPGetPObjective(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPGetPPObjective(arg1, arg2) + @ccall libdsdp.DSDPGetPPObjective(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPGetDualityGap(arg1, arg2) + @ccall libdsdp.DSDPGetDualityGap(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPGetScale(arg1, arg2) + @ccall libdsdp.DSDPGetScale(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPSetScale(arg1, arg2) + @ccall libdsdp.DSDPSetScale(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function DSDPGetPenaltyParameter(arg1, arg2) + @ccall libdsdp.DSDPGetPenaltyParameter(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPGetPenalty(arg1, arg2) + @ccall libdsdp.DSDPGetPenalty(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPCopyB(arg1, arg2, arg3) + @ccall libdsdp.DSDPCopyB(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble}, arg3::Cint)::Cint +end + +function DSDPSetR0(arg1, arg2) + @ccall libdsdp.DSDPSetR0(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function DSDPGetR(arg1, arg2) + @ccall libdsdp.DSDPGetR(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPSetRTolerance(arg1, arg2) + @ccall libdsdp.DSDPSetRTolerance(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function DSDPGetRTolerance(arg1, arg2) + @ccall libdsdp.DSDPGetRTolerance(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPSetY0(arg1, arg2, arg3) + @ccall libdsdp.DSDPSetY0(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cdouble)::Cint +end + +function DSDPGetY(arg1, arg2, arg3) + @ccall libdsdp.DSDPGetY(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble}, arg3::Cint)::Cint +end + +function DSDPGetYMakeX(arg1, arg2, arg3) + @ccall libdsdp.DSDPGetYMakeX(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble}, arg3::Cint)::Cint +end + +function DSDPGetDYMakeX(arg1, arg2, arg3) + @ccall libdsdp.DSDPGetDYMakeX(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble}, arg3::Cint)::Cint +end + +function DSDPGetMuMakeX(arg1, arg2) + @ccall libdsdp.DSDPGetMuMakeX(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPReuseMatrix(arg1, arg2) + @ccall libdsdp.DSDPReuseMatrix(arg1::Ptr{Cvoid}, arg2::Cint)::Cint +end + +function DSDPGetReuseMatrix(arg1, arg2) + @ccall libdsdp.DSDPGetReuseMatrix(arg1::Ptr{Cvoid}, arg2::Ptr{Cint})::Cint +end + +function DSDPGetDimension(arg1, arg2) + @ccall libdsdp.DSDPGetDimension(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPSetMaxIts(arg1, arg2) + @ccall libdsdp.DSDPSetMaxIts(arg1::Ptr{Cvoid}, arg2::Cint)::Cint +end + +function DSDPGetMaxIts(arg1, arg2) + @ccall libdsdp.DSDPGetMaxIts(arg1::Ptr{Cvoid}, arg2::Ptr{Cint})::Cint +end + +function DSDPSetStepTolerance(arg1, arg2) + @ccall libdsdp.DSDPSetStepTolerance(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function DSDPGetStepTolerance(arg1, arg2) + @ccall libdsdp.DSDPGetStepTolerance(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPSetGapTolerance(arg1, arg2) + @ccall libdsdp.DSDPSetGapTolerance(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function DSDPGetGapTolerance(arg1, arg2) + @ccall libdsdp.DSDPGetGapTolerance(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPSetPNormTolerance(arg1, arg2) + @ccall libdsdp.DSDPSetPNormTolerance(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function DSDPGetPNormTolerance(arg1, arg2) + @ccall libdsdp.DSDPGetPNormTolerance(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPSetDualBound(arg1, arg2) + @ccall libdsdp.DSDPSetDualBound(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function DSDPGetDualBound(arg1, arg2) + @ccall libdsdp.DSDPGetDualBound(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPSetPTolerance(arg1, arg2) + @ccall libdsdp.DSDPSetPTolerance(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function DSDPGetPTolerance(arg1, arg2) + @ccall libdsdp.DSDPGetPTolerance(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPGetPInfeasibility(arg1, arg2) + @ccall libdsdp.DSDPGetPInfeasibility(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPSetMaxTrustRadius(arg1, arg2) + @ccall libdsdp.DSDPSetMaxTrustRadius(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function DSDPGetMaxTrustRadius(arg1, arg2) + @ccall libdsdp.DSDPGetMaxTrustRadius(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPStopReason(arg1, arg2) + @ccall libdsdp.DSDPStopReason(arg1::Ptr{Cvoid}, arg2::Ptr{DSDPTerminationReason})::Cint +end + +function DSDPGetSolutionType(arg1, arg2) + @ccall libdsdp.DSDPGetSolutionType(arg1::Ptr{Cvoid}, arg2::Ptr{DSDPSolutionType})::Cint +end + +function DSDPSetPotentialParameter(arg1, arg2) + @ccall libdsdp.DSDPSetPotentialParameter(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function DSDPGetPotentialParameter(arg1, arg2) + @ccall libdsdp.DSDPGetPotentialParameter(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPUseDynamicRho(arg1, arg2) + @ccall libdsdp.DSDPUseDynamicRho(arg1::Ptr{Cvoid}, arg2::Cint)::Cint +end + +function DSDPGetPotential(arg1, arg2) + @ccall libdsdp.DSDPGetPotential(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPUseLAPACKForSchur(arg1, arg2) + @ccall libdsdp.DSDPUseLAPACKForSchur(arg1::Ptr{Cvoid}, arg2::Cint)::Cint +end + +function DSDPGetNumberOfVariables(arg1, arg2) + @ccall libdsdp.DSDPGetNumberOfVariables(arg1::Ptr{Cvoid}, arg2::Ptr{Cint})::Cint +end + +function DSDPGetFinalErrors(arg1, arg2) + @ccall libdsdp.DSDPGetFinalErrors(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPGetGapHistory(arg1, arg2, arg3) + @ccall libdsdp.DSDPGetGapHistory(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble}, arg3::Cint)::Cint +end + +function DSDPGetRHistory(arg1, arg2, arg3) + @ccall libdsdp.DSDPGetRHistory(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble}, arg3::Cint)::Cint +end + +function DSDPGetIts(arg1, arg2) + @ccall libdsdp.DSDPGetIts(arg1::Ptr{Cvoid}, arg2::Ptr{Cint})::Cint +end + +function DSDPGetPnorm(arg1, arg2) + @ccall libdsdp.DSDPGetPnorm(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPGetStepLengths(arg1, arg2, arg3) + @ccall libdsdp.DSDPGetStepLengths(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble}, arg3::Ptr{Cdouble})::Cint +end + +function DSDPSetMonitor(arg1, arg2, arg3) + @ccall libdsdp.DSDPSetMonitor(arg1::Ptr{Cvoid}, arg2::Ptr{Cvoid}, arg3::Ptr{Cvoid})::Cint +end + +function DSDPSetStandardMonitor(arg1, arg2) + @ccall libdsdp.DSDPSetStandardMonitor(arg1::Ptr{Cvoid}, arg2::Cint)::Cint +end + +function DSDPSetFileMonitor(arg1, arg2) + @ccall libdsdp.DSDPSetFileMonitor(arg1::Ptr{Cvoid}, arg2::Cint)::Cint +end + +function DSDPSetPenaltyParameter(arg1, arg2) + @ccall libdsdp.DSDPSetPenaltyParameter(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function DSDPUsePenalty(arg1, arg2) + @ccall libdsdp.DSDPUsePenalty(arg1::Ptr{Cvoid}, arg2::Cint)::Cint +end + +function DSDPPrintLogInfo(arg1) + @ccall libdsdp.DSDPPrintLogInfo(arg1::Cint)::Cint +end + +function DSDPComputeMinimumXEigenvalue(arg1, arg2) + @ccall libdsdp.DSDPComputeMinimumXEigenvalue(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPGetTraceX(dsdp, arg2) + @ccall libdsdp.DSDPGetTraceX(dsdp::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPSetZBar(arg1, arg2) + @ccall libdsdp.DSDPSetZBar(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function DSDPSetDualLowerBound(arg1, arg2) + @ccall libdsdp.DSDPSetDualLowerBound(arg1::Ptr{Cvoid}, arg2::Cdouble)::Cint +end + +function DSDPGetDataNorms(arg1, arg2) + @ccall libdsdp.DSDPGetDataNorms(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function DSDPGetYMaxNorm(arg1, arg2) + @ccall libdsdp.DSDPGetYMaxNorm(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble})::Cint +end + +function SDPConeUseFullSymmetricFormat(arg1, arg2) + @ccall libdsdp.SDPConeUseFullSymmetricFormat(arg1::Ptr{Cvoid}, arg2::Cint)::Cint +end + +function SDPConeUsePackedFormat(arg1, arg2) + @ccall libdsdp.SDPConeUsePackedFormat(arg1::Ptr{Cvoid}, arg2::Cint)::Cint +end + +function DSDPSetFixedVariable(arg1, arg2, arg3) + @ccall libdsdp.DSDPSetFixedVariable(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Cdouble)::Cint +end + +function DSDPSetFixedVariables(arg1, arg2, arg3, arg4, arg5) + @ccall libdsdp.DSDPSetFixedVariables(arg1::Ptr{Cvoid}, arg2::Ptr{Cdouble}, arg3::Ptr{Cdouble}, arg4::Ptr{Cdouble}, arg5::Cint)::Cint +end + +function DSDPGetFixedYX(arg1, arg2, arg3) + @ccall libdsdp.DSDPGetFixedYX(arg1::Ptr{Cvoid}, arg2::Cint, arg3::Ptr{Cdouble})::Cint +end + +function DSDPView(arg1) + @ccall libdsdp.DSDPView(arg1::Ptr{Cvoid})::Cint +end + +# no prototype is found for this function at dsdp5.h:206:12, please use with caution +function DSDPPrintOptions() + @ccall libdsdp.DSDPPrintOptions()::Cint +end + +function DSDPPrintData(arg1, arg2, arg3) + @ccall libdsdp.DSDPPrintData(arg1::Ptr{Cvoid}, arg2::Ptr{Cvoid}, arg3::Ptr{Cvoid})::Cint +end + +function DSDPPrintSolution(arg1, arg2, arg3, arg4) + @ccall libdsdp.DSDPPrintSolution(arg1::Ptr{Libc.FILE}, arg2::Ptr{Cvoid}, arg3::Ptr{Cvoid}, arg4::Ptr{Cvoid})::Cint +end + +function DSDPSetOptions(arg1, arg2, arg3) + @ccall libdsdp.DSDPSetOptions(arg1::Ptr{Cvoid}, arg2::Ptr{Ptr{Cchar}}, arg3::Cint)::Cint +end + +function DSDPReadOptions(arg1, arg2) + @ccall libdsdp.DSDPReadOptions(arg1::Ptr{Cvoid}, arg2::Ptr{Cchar})::Cint +end + +function DSDPSetDestroyRoutine(arg1, arg2, arg3) + @ccall libdsdp.DSDPSetDestroyRoutine(arg1::Ptr{Cvoid}, arg2::Ptr{Cvoid}, arg3::Ptr{Cvoid})::Cint +end diff --git a/src/lpcone.jl b/src/lpcone.jl deleted file mode 100644 index 4e58b20..0000000 --- a/src/lpcone.jl +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright (c) 2022: Joey Huchette, Benoît Legat, and contributors -# -# Use of this source code is governed by an MIT-style license that can be found -# in the LICENSE.md file or at https://opensource.org/licenses/MIT. - -export LPCone - -module LPCone - -import ..@dsdp_ccall -const LPConeT = Ptr{Nothing} - -function buildlp(nvars, lpdvars, lpdrows, lpcoefs) - @assert length(lpdvars) == length(lpdrows) == length(lpcoefs) - nzin = zeros(Cint, nvars) - n = length(lpdvars) - for var in lpdvars - nzin[var] += 1 - end - nnzin = Cint[zero(Cint); cumsum(nzin)] - @assert nnzin[end] == n - idx = map(var -> Int[], 1:nvars) - for (i, var) in enumerate(lpdvars) - push!(idx[var], i) - end - row = Vector{Cint}(undef, n) - aval = Vector{Cdouble}(undef, n) - for var in 1:nvars - sort!(idx[var]; by = i -> lpdrows[i]) - row[(nnzin[var]+1):(nnzin[var+1])] = lpdrows[idx[var]] - aval[(nnzin[var]+1):(nnzin[var+1])] = lpcoefs[idx[var]] - end - return nnzin, row, aval -end - -# This function is not part of DSDP API -function SetDataSparse( - lpcone::LPConeT, - n::Integer, - nvars, - lpdvars, - lpdrows, - lpcoefs, -) - return SetData(lpcone, n, buildlp(nvars, lpdvars, lpdrows, lpcoefs)...) -end - -function SetData( - lpcone::LPConeT, - n::Integer, - nnzin::Vector{Cint}, - row::Vector{Cint}, - aval::Vector{Cdouble}, -) - @assert length(row) == length(aval) - @dsdp_ccall LPConeSetData ( - LPConeT, - Cint, - Ptr{Cint}, - Ptr{Cint}, - Ptr{Cdouble}, - ) lpcone n nnzin row aval -end - -function SetData2( - arg1::LPConeT, - arg2::Integer, - arg3::Vector{Cint}, - arg4::Vector{Cint}, - arg5::Vector{Cdouble}, -) - @dsdp_ccall LPConeSetData2 ( - LPConeT, - Cint, - Ptr{Cint}, - Ptr{Cint}, - Ptr{Cdouble}, - ) arg1 arg2 arg3 arg4 arg5 -end - -function GetData( - arg1::LPConeT, - arg2::Integer, - arg3::Vector{Cdouble}, - arg4::Integer, -) - @dsdp_ccall LPConeGetData (LPConeT, Cint, Ptr{Cdouble}, Cint) arg1 arg2 arg3 arg4 -end - -function ScaleBarrier(arg1::LPConeT, arg2::Cdouble) - @dsdp_ccall LPConeScaleBarrier (LPConeT, Cdouble) arg1 arg2 -end - -function GetXArray(lpcone::LPConeT) - xout = Ref{Ptr{Cdouble}}() - n = Ref{Cint}() - @dsdp_ccall LPConeGetXArray (LPConeT, Ptr{Ptr{Cdouble}}, Ptr{Cint}) lpcone xout n - return unsafe_wrap(Array, xout[], n[]) -end - -function GetSArray(lpcone::LPConeT) - sout = Ref{Ptr{Cdouble}}() - n = Ref{Cint}() - @dsdp_ccall LPConeGetSArray (LPConeT, Ref{Ptr{Cdouble}}, Ref{Cint}) lpcone sout n - return unsafe_wrap(Array, sout[], n[]) -end - -function GetDimension(arg1::LPConeT) - dim = Ref{Cint}() - @dsdp_ccall LPConeGetDimension (LPConeT, Ref{Cint}) arg1 dim - return dim[] -end - -function View(lpcone::LPConeT) - @dsdp_ccall LPConeView (LPConeT,) lpcone -end - -function View2(lpcone::LPConeT) - @dsdp_ccall LPConeView2 (LPConeT,) lpcone -end - -function CopyS(arg1::LPConeT, arg2::Vector{Cdouble}, arg3::Integer) - @dsdp_ccall LPConeCopyS (LPConeT, Ptr{Cdouble}, Cint) arg1 arg2 arg3 -end - -end diff --git a/src/sdpcone.jl b/src/sdpcone.jl deleted file mode 100644 index 8500452..0000000 --- a/src/sdpcone.jl +++ /dev/null @@ -1,495 +0,0 @@ -# Copyright (c) 2022: Joey Huchette, Benoît Legat, and contributors -# -# Use of this source code is governed by an MIT-style license that can be found -# in the LICENSE.md file or at https://opensource.org/licenses/MIT. - -export SDPCone - -module SDPCone - -import ..@dsdp_ccall - -const SDPConeT = Ptr{Nothing} - -function SetBlockSize(sdpcone::SDPConeT, i::Integer, j::Integer) - @dsdp_ccall SDPConeSetBlockSize (SDPConeT, Cint, Cint) sdpcone i j -end - -function GetBlockSize(sdpcone::SDPConeT, arg2::Integer) - n = Ref{Cint}() - @dsdp_ccall SDPConeGetBlockSize (SDPConeT, Cint, Ref{Cint}) sdpcone arg2 n - return n[] -end - -function SetStorageFormat(sdpcone::SDPConeT, arg2::Integer, arg3::UInt8) - @dsdp_ccall SDPConeSetStorageFormat (SDPConeT, Cint, UInt8) sdpcone arg2 arg3 -end - -function GetStorageFormat(sdpcone::SDPConeT, arg2::Integer) - format = Ref{Cchar}() - @dsdp_ccall SDPConeGetStorageFormat (SDPConeT, Cint, Ref{Cchar}) sdpcone arg2 format - return format[] -end - -function CheckStorageFormat(sdpcone::SDPConeT, arg2::Integer, arg3::UInt8) - @dsdp_ccall SDPConeCheckStorageFormat (SDPConeT, Cint, UInt8) sdpcone arg2 arg3 -end - -function SetSparsity(sdpcone::SDPConeT, arg2::Integer, arg3::Integer) - @dsdp_ccall SDPConeSetSparsity (SDPConeT, Cint, Cint) sdpcone arg2 arg3 -end - -function View(sdpcone::SDPConeT) - @dsdp_ccall SDPConeView (SDPConeT,) sdpcone -end - -function View2(sdpcone::SDPConeT) - @dsdp_ccall SDPConeView2 (SDPConeT,) sdpcone -end - -function View3(sdpcone::SDPConeT) - @dsdp_ccall SDPConeView3 (SDPConeT,) sdpcone -end - -function SetASparseVecMat( - sdpcone::SDPConeT, - blockj::Integer, - vari::Integer, - n::Integer, - alpha::Cdouble, - ishift::Integer, - ind::Union{Ptr{Cint},Vector{Cint}}, - val::Union{Ptr{Cdouble},Vector{Cdouble}}, - nnz::Integer, -) - @dsdp_ccall SDPConeSetASparseVecMat ( - SDPConeT, - Cint, - Cint, - Cint, - Cdouble, - Cint, - Ptr{Cint}, - Ptr{Cdouble}, - Cint, - ) sdpcone blockj vari n alpha ishift ind val nnz -end - -function SetADenseVecMat( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Integer, - arg4::Integer, - arg5::Cdouble, - arg6::Vector{Cdouble}, - arg7::Integer, -) - @dsdp_ccall SDPConeSetADenseVecMat ( - SDPConeT, - Cint, - Cint, - Cint, - Cdouble, - Ptr{Cdouble}, - Cint, - ) sdpcone arg2 arg3 arg4 arg5 arg6 arg7 -end - -function SetARankOneMat( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Integer, - arg4::Integer, - arg5::Cdouble, - arg6::Integer, - arg7::Vector{Cint}, - arg8::Vector{Cdouble}, - arg9::Integer, -) - @dsdp_ccall SDPConeSetARankOneMat ( - SDPConeT, - Cint, - Cint, - Cint, - Cdouble, - Cint, - Ptr{Cint}, - Ptr{Cdouble}, - Cint, - ) sdpcone arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9 -end - -function SetConstantMat( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Integer, - arg4::Integer, - arg5::Cdouble, -) - @dsdp_ccall SDPConeSetConstantMat (SDPConeT, Cint, Cint, Cint, Cdouble) sdpcone arg2 arg3 arg4 arg5 -end - -function SetZeroMat( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Integer, - arg4::Integer, -) - @dsdp_ccall SDPConeSetZeroMat (SDPConeT, Cint, Cint, Cint) sdpcone arg2 arg3 arg4 -end - -function SetIdentity( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Integer, - arg4::Integer, - arg5::Cdouble, -) - @dsdp_ccall SDPConeSetIdentity (SDPConeT, Cint, Cint, Cint, Cdouble) sdpcone arg2 arg3 arg4 arg5 -end - -function ViewDataMatrix(sdpcone::SDPConeT, arg2::Integer, arg3::Integer) - @dsdp_ccall SDPConeViewDataMatrix (SDPConeT, Cint, Cint) sdpcone arg2 arg3 -end - -function MatrixView(sdpcone::SDPConeT, arg2::Integer) - @dsdp_ccall SDPConeMatrixView (SDPConeT, Cint) sdpcone arg2 -end - -function AddASparseVecMat( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Integer, - arg4::Integer, - arg5::Cdouble, - arg6::Integer, - arg7::Union{Ptr{Cint},Vector{Cint}}, - arg8::Union{Ptr{Cdouble},Vector{Cdouble}}, - arg9::Integer, -) - @dsdp_ccall SDPConeAddASparseVecMat ( - SDPConeT, - Cint, - Cint, - Cint, - Cdouble, - Cint, - Ptr{Cint}, - Ptr{Cdouble}, - Cint, - ) sdpcone arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9 -end - -function AddADenseVecMat( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Integer, - arg4::Integer, - arg5::Cdouble, - arg6::Vector{Cdouble}, - arg7::Integer, -) - @dsdp_ccall SDPConeAddADenseVecMat ( - SDPConeT, - Cint, - Cint, - Cint, - Cdouble, - Ptr{Cdouble}, - Cint, - ) sdpcone arg2 arg3 arg4 arg5 arg6 arg7 -end - -function AddConstantMat( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Integer, - arg4::Integer, - arg5::Cdouble, -) - @dsdp_ccall SDPConeAddConstantMat (SDPConeT, Cint, Cint, Cint, Cdouble) sdpcone arg2 arg3 arg4 arg5 -end - -function AddIdentity( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Integer, - arg4::Integer, - arg5::Cdouble, -) - @dsdp_ccall SDPConeAddIdentity (SDPConeT, Cint, Cint, Cint, Cdouble) sdpcone arg2 arg3 arg4 arg5 -end - -function AddARankOneMat( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Integer, - arg4::Integer, - arg5::Cdouble, - arg6::Integer, - arg7::Vector{Cint}, - arg8::Vector{Cdouble}, - arg9::Integer, -) - @dsdp_ccall SDPConeAddARankOneMat ( - SDPConeT, - Cint, - Cint, - Cint, - Cdouble, - Cint, - Ptr{Cint}, - Ptr{Cdouble}, - Cint, - ) sdpcone arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9 -end - -function AddSparseVecMat( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Integer, - arg4::Integer, - arg5::Integer, - arg6::Vector{Cint}, - arg7::Vector{Cdouble}, - arg8::Integer, -) - @dsdp_ccall SDPConeAddSparseVecMat ( - SDPConeT, - Cint, - Cint, - Cint, - Cint, - Ptr{Cint}, - Ptr{Cdouble}, - Cint, - ) sdpcone arg2 arg3 arg4 arg5 arg6 arg7 arg8 -end - -function AddDenseVecMat( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Integer, - arg4::Integer, - arg5::Vector{Cdouble}, - arg6::Integer, -) - @dsdp_ccall SDPConeAddDenseVecMat ( - SDPConeT, - Cint, - Cint, - Cint, - Ptr{Cdouble}, - Cint, - ) sdpcone arg2 arg3 arg4 arg5 arg6 -end - -function SetSparseVecMat( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Integer, - arg4::Integer, - arg5::Integer, - arg6::Vector{Cint}, - arg7::Vector{Cdouble}, - arg8::Integer, -) - @dsdp_ccall SDPConeSetSparseVecMat ( - SDPConeT, - Cint, - Cint, - Cint, - Cint, - Ptr{Cint}, - Ptr{Cdouble}, - Cint, - ) sdpcone arg2 arg3 arg4 arg5 arg6 arg7 arg8 -end - -function SetDenseVecMat( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Integer, - arg4::Integer, - arg5::Vector{Cdouble}, - arg6::Integer, -) - @dsdp_ccall SDPConeSetDenseVecMat ( - SDPConeT, - Cint, - Cint, - Cint, - Ptr{Cdouble}, - Cint, - ) sdpcone arg2 arg3 arg4 arg5 arg6 -end - -function SetXMat(sdpcone::SDPConeT, arg2::Integer, arg3::Integer) - @dsdp_ccall SDPConeSetXMat (SDPConeT, Cint, Cint) sdpcone arg2 arg3 -end - -function SetXArray( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Integer, - arg4::Vector{Cdouble}, - arg5::Integer, -) - @dsdp_ccall SDPConeSetXArray (SDPConeT, Cint, Cint, Ptr{Cdouble}, Cint) sdpcone arg2 arg3 arg4 arg5 -end - -function GetXArray(sdpcone::SDPConeT, blockj::Integer) - xmat = Ref{Ptr{Cdouble}}() - nn = Ref{Cint}() - @dsdp_ccall SDPConeGetXArray (SDPConeT, Cint, Ref{Ptr{Cdouble}}, Ref{Cint}) sdpcone blockj xmat nn - return unsafe_wrap(Array, xmat[], nn[]) -end - -function RestoreXArray( - sdpcone::SDPConeT, - arg2::Integer, - arg3, - arg4::Vector{Cint}, -) - @dsdp_ccall SDPConeRestoreXArray ( - SDPConeT, - Cint, - Ptr{Ptr{Cdouble}}, - Ptr{Cint}, - ) sdpcone arg2 arg3 arg4 -end - -function CheckData(sdpcone::SDPConeT) - @dsdp_ccall SDPConeCheckData (SDPConeT,) sdpcone -end - -function RemoveDataMatrix(sdpcone::SDPConeT, arg2::Integer, arg3::Integer) - @dsdp_ccall SDPConeRemoveDataMatrix (SDPConeT, Cint, Cint) sdpcone arg2 arg3 -end - -function GetNumberOfBlocks(sdpcone::SDPConeT) - num = Ref{Cint}() - @dsdp_ccall SDPConeGetNumberOfBlocks (SDPConeT, Ref{Cint}) sdpcone num - return num[] -end - -function ComputeS( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Cdouble, - arg4, - arg5::Integer, - arg6::Cdouble, - arg7::Integer, - arg8::Vector{Cdouble}, - arg9::Integer, -) - @dsdp_ccall SDPConeComputeS ( - SDPConeT, - Cint, - Cdouble, - Ptr{Cdouble}, - Cint, - Cdouble, - Cint, - Ptr{Cdouble}, - Cint, - ) sdpcone arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9 -end - -function ComputeX(sdpcone::SDPConeT, blockj::Integer, n::Integer, nn::Integer) - xmat = zeros(Cdouble, nn) - @dsdp_ccall SDPConeComputeX (SDPConeT, Cint, Cint, Ptr{Cdouble}, Cint) sdpcone blockj n xmat nn - return xmat -end - -function AddADotX( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Cdouble, - arg4::Vector{Cdouble}, - arg5::Integer, - arg6::Vector{Cdouble}, - arg7::Integer, -) - @dsdp_ccall SDPConeAddADotX ( - SDPConeT, - Cint, - Cdouble, - Ptr{Cdouble}, - Cint, - Ptr{Cdouble}, - Cint, - ) sdpcone arg2 arg3 arg4 arg5 arg6 arg7 -end - -function ViewX( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Integer, - arg4::Vector{Cdouble}, - arg5::Integer, -) - @dsdp_ccall SDPConeViewX (SDPConeT, Cint, Cint, Ptr{Cdouble}, Cint) sdpcone arg2 arg3 arg4 arg5 -end - -function SetLanczosIterations(sdpcone::SDPConeT, arg2::Integer) - @dsdp_ccall SDPConeSetLanczosIterations (SDPConeT, Cint) sdpcone arg2 -end - -function ScaleBarrier(sdpcone::SDPConeT, arg2::Integer, arg3::Cdouble) - @dsdp_ccall SDPConeScaleBarrier (SDPConeT, Cint, Cdouble) sdpcone arg2 arg3 -end - -function XVMultiply( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Vector{Cdouble}, - arg4::Vector{Cdouble}, -) - n = length(arg3) - @assert n == length(arg4) - @dsdp_ccall SDPConeXVMultiply ( - SDPConeT, - Cint, - Ptr{Cdouble}, - Ptr{Cdouble}, - Cint, - ) sdpcone arg2 pointer(arg3) pointer(arg4) n -end - -function ComputeXV(sdpcone::SDPConeT, arg2::Integer) - derror = Ref{Cint}() - @dsdp_ccall SDPConeComputeXV (SDPConeT, Cint, Ref{Cint}) sdpcone arg2 derror - return derror[] -end - -function AddXVAV( - sdpcone::SDPConeT, - arg2::Integer, - arg3::Vector{Cdouble}, - arg5::Vector{Cdouble}, -) - @dsdp_ccall SDPConeAddXVAV ( - SDPConeT, - Cint, - Ptr{Cdouble}, - Cint, - Ptr{Cdouble}, - Cint, - ) sdpcone arg2 pointer(arg3) length(arg3) pointer(arg5) length(arg5) -end - -function UseLAPACKForDualMatrix(sdpcone::SDPConeT, arg2::Integer) - @dsdp_ccall SDPConeUseLAPACKForDualMatrix (SDPConeT, Cint) sdpcone arg2 -end - -function UseFullSymmetricFormat(sdpcone::SDPConeT, arg2::Integer) - @dsdp_ccall SDPConeUseFullSymmetricFormat (SDPConeT, Cint) sdpcone arg2 -end - -function UsePackedFormat(sdpcone::SDPConeT, arg2::Integer) - @dsdp_ccall SDPConeUsePackedFormat (SDPConeT, Cint) sdpcone arg2 -end - -end diff --git a/test/MOI_wrapper.jl b/test/MOI_wrapper.jl index 5006afd..0fd8a00 100644 --- a/test/MOI_wrapper.jl +++ b/test/MOI_wrapper.jl @@ -24,7 +24,7 @@ function test_solver_name() @test MOI.get(DSDP.Optimizer(), MOI.SolverName()) == "DSDP" end -function test_options() +function test_bad_options() param = MOI.RawOptimizerAttribute("bad_option") err = MOI.UnsupportedAttribute(param) @test_throws err MOI.set( @@ -170,6 +170,42 @@ function test_runtests() return end +function test_options() + optimizer = MOI.Utilities.CachingOptimizer( + MOI.Utilities.Model{Float64}(), + DSDP.Optimizer(), + ) + x, cx = MOI.add_constrained_variables(optimizer, MOI.Nonnegatives(1)) + MOI.add_constraint(optimizer, 1.0x[1], MOI.EqualTo(1.0)) + MOI.Utilities.attach_optimizer(optimizer) + for (option, default) in + Iterators.flatten((DSDP.options, DSDP.gettable_options)) + opt = getfield(DSDP, option) + @test MOI.get(optimizer, opt()) == default + end + return +end + +function test_moi(tol = 1e-6) + model = MOI.Utilities.Model{Float64}() + X, _ = MOI.add_constrained_variables( + model, + MOI.PositiveSemidefiniteConeTriangle(2), + ) + c = MOI.add_constraint(model, 1.0 * X[2], MOI.EqualTo(1.0)) + obj = 1.0 * X[1] + 1.0 * X[3] + MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) + MOI.set(model, MOI.ObjectiveFunction{typeof(obj)}(), obj) + dsdp = DSDP.Optimizer() + MOI.copy_to(dsdp, model) + MOI.optimize!(dsdp) + @test MOI.get(dsdp, MOI.ObjectiveValue()) ≈ 2 rtol = tol + @test MOI.get(dsdp, MOI.DualObjectiveValue()) ≈ 2 rtol = tol + @test MOI.get.(dsdp, MOI.VariablePrimal(), X) ≈ [1, 1, 1] rtol = tol + @test MOI.get(dsdp, MOI.ConstraintDual(), c) ≈ 2 rtol = tol + return +end + end # module TestDSDP.runtests() diff --git a/test/build.jl b/test/build.jl deleted file mode 100644 index a6b0f54..0000000 --- a/test/build.jl +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2022: Joey Huchette, Benoît Legat, and contributors -# -# Use of this source code is governed by an MIT-style license that can be found -# in the LICENSE.md file or at https://opensource.org/licenses/MIT. - -@testset "LPConeSetData doc example" begin - lpdvars = Cint[3, 3, 2, 2, 1, 3, 1, 1] - lpdrows = Cint[2, 0, 1, 0, 0, 1, 1, 2] - lpcoefs = Cdouble[-1, 2, 3, 4, 6, 7, 10, 12] - nnzin, row, aval = LPCone.buildlp(3, lpdvars, lpdrows, lpcoefs) - @test nnzin isa Vector{Cint} - @test nnzin == [0, 3, 5, 8] - @test row isa Vector{Cint} - @test row == [0, 1, 2, 0, 1, 0, 1, 2] - @test aval isa Vector{Cdouble} - @test aval == [6, 10, 12, 4, 3, 2, 7, -1] -end diff --git a/test/c_api.jl b/test/c_api.jl new file mode 100644 index 0000000..ee5fe9a --- /dev/null +++ b/test/c_api.jl @@ -0,0 +1,252 @@ +# Copyright (c) 2022: Joey Huchette, Benoît Legat, and contributors +# +# Use of this source code is governed by an MIT-style license that can be found +# in the LICENSE.md file or at https://opensource.org/licenses/MIT. + +module Test_c_api + +using DSDP +using Test + +function di(u, v) + u, v = max(u, v), min(u, v) + return div((u - Cint(1)) * u, Cint(2)) + (v - Cint(1)) +end +di(u) = di(u, u) + +signz(t) = t < 0 ? -1 : 1 + +# Apply the Goemens and Williamson randomized cut algorithm to the SDP relaxation of the max-cut problem +function MaxCutRandomized(sdpcone, nnodes::Integer) + ymin = Cdouble(0) + + vv = Vector{Cdouble}(undef, nnodes) + tt = Vector{Cdouble}(undef, nnodes) + cc = Vector{Cdouble}(undef, nnodes + 2) + derror = Ref{Cint}() + DSDP.SDPConeComputeXV(sdpcone, 0, derror) + @assert derror[] == 0 + for i in 1:nnodes + for j in eachindex(vv) + dd = rand() - 0.5 + vv[j] = tan(π * dd) + end + DSDP.SDPConeXVMultiply(sdpcone, 0, vv, tt, nnodes) + map!(signz, tt, tt) + map!(zero, cc, cc) + DSDP.SDPConeAddXVAV(sdpcone, 0, tt, nnodes, cc, nnodes + 2) + if cc[1] < ymin + ymin = cc[1] + end + end + return ymin +end + +function maxcut(nnodes, edges) + nedges = length(edges) + p = Ref{Ptr{Cvoid}}() + DSDP.DSDPCreate(nnodes, p) + dsdp = p[] + DSDP.DSDPCreateSDPCone(dsdp, 1, p) + sdpcone = p[] + + DSDP.SDPConeSetBlockSize(sdpcone, 0, nnodes) + + # Formulate the problem from the data + # Diagonal elements equal 1.0 + # Create Constraint matrix A_i for i=1, ..., nnodes. + # that has a single nonzero element. + diag = ones(Cdouble, nnodes) + N = Cint(1):Cint(nnodes) + iptr = di.(N) + + for i in 1:nnodes + DSDP.DSDPSetDualObjective(dsdp, i, 1.0) + DSDP.SDPConeSetASparseVecMat( + sdpcone, + 0, + i, + nnodes, + 1.0, + 0, + pointer(iptr, i), + pointer(diag, i), + 1, + ) + end + + # C matrix is the Laplacian of the adjacency matrix + # Also compute a feasible initial point y such that S >= 0 + yy = zeros(nnodes) + indd = zeros(Cint, nnodes + nedges) + val = zeros(nnodes + nedges) + indd[nedges .+ (1:nnodes)] = iptr + tval = 0.0 + for (i, (u, v, w)) in enumerate(edges) + indd[i] = di(u, v) + tval += abs(w) + val[i] = w / 4 + val[nedges+u] -= w / 4 + val[nedges+v] -= w / 4 + yy[u] -= abs(w / 2) + yy[v] -= abs(w / 2) + end + + DSDP.SDPConeSetASparseVecMat( + sdpcone, + 0, + 0, + nnodes, + 1.0, + 0, + pointer(indd), + pointer(val), + nedges, + ) + DSDP.SDPConeAddASparseVecMat( + sdpcone, + 0, + 0, + nnodes, + 1.0, + 0, + pointer(indd, nedges + 1), + pointer(val, nedges + 1), + nnodes, + ) + + # Initial Point + DSDP.DSDPSetR0(dsdp, 0.0) + DSDP.DSDPSetZBar(dsdp, 10 * tval + 1.0) + for i in 1:nnodes + DSDP.DSDPSetY0(dsdp, i, 10 * yy[i]) + end + + # Get read to go + DSDP.DSDPSetGapTolerance(dsdp, 0.001) + DSDP.DSDPSetPotentialParameter(dsdp, 5) + DSDP.DSDPSetReuseMatrix(dsdp, 0) + DSDP.DSDPSetPNormTolerance(dsdp, 1.0) + #info = TCheckArgs(dsdp,argc,argv) + DSDP.DSDPSetStandardMonitor(dsdp, 0) + DSDP.DSDPSetup(dsdp) + DSDP.DSDPSolve(dsdp) + stop = Ref{DSDP.DSDPTerminationReason}() + DSDP.DSDPStopReason(dsdp, stop) + reason = stop[] + @test reason != DSDP.DSDP_INFEASIBLE_START + ret = Ref{Cdouble}() + DSDP.DSDPGetDObjective(dsdp, ret) + @test ret[] ≈ -9.250079 rtol = 1e-7 + DSDP.DSDPGetDDObjective(dsdp, ret) + @test ret[] ≈ -9.250079 rtol = 1e-7 + DSDP.DSDPGetPObjective(dsdp, ret) + @test ret[] ≈ 1e10 + DSDP.DSDPGetPPObjective(dsdp, ret) + @test ret[] ≈ -9.240522 rtol = 1e-7 + DSDP.DSDPGetDualityGap(dsdp, ret) + @test ret[] ≈ 0.009557113 rtol = 1e-7 + # Randomized solution strategy + @test MaxCutRandomized(sdpcone, nnodes) ≈ -9.25 + return DSDP.DSDPDestroy(dsdp) +end + +function test_sdp(tol = 1e-6) + p = Ref{Ptr{Cvoid}}() + DSDP.DSDPCreate(1, p) + dsdp = p[] + DSDP.DSDPCreateSDPCone(dsdp, 1, p) + sdpcone = p[] + DSDP.SDPConeSetBlockSize(sdpcone, 0, 2) + DSDP.SDPConeSetSparsity(sdpcone, 0, 0) + DSDP.SDPConeSetStorageFormat(sdpcone, 0, UInt8('U')) + DSDP.DSDPSetY0(dsdp, 1, 0.0) + DSDP.DSDPSetDualObjective(dsdp, 1, 1.0) + DSDP.SDPConeSetASparseVecMat(sdpcone, 0, 1, 2, 1.0, 0, Int32[2], [0.5], 1) + DSDP.SDPConeSetASparseVecMat( + sdpcone, + 0, + 0, + 2, + 1.0, + 0, + Int32[0, 3], + [1.0, 1.0], + 2, + ) + DSDP.DSDPSetup(dsdp) + DSDP.DSDPSolve(dsdp) + DSDP.DSDPComputeX(dsdp) + ret = Ref{Cint}() + DSDP.DSDPGetIts(dsdp, ret) + @test ret[] == 10 + derr = zeros(Cdouble, 6) + DSDP.DSDPGetFinalErrors(dsdp, derr) + @test derr != zeros(Cdouble, 6) # To check that it's not just the allocated vector and we actually got the errors + @test derr ≈ zeros(Cdouble, 6) atol = tol + + # P Infeasible: derr[1] + # D Infeasible: derr[3] + # Minimal P Eigenvalue: derr[2] + # Minimal D Eigenvalue: 0.00, see `DSDP` source in `examples/readsdpa.c` + # Relative P - D Objective values: derr[5] + # Relative X Dot S: %4.2e: derr[6] + stop = Ref{DSDP.DSDPTerminationReason}() + DSDP.DSDPStopReason(dsdp, stop) + @test stop[] == 1 + sol = Ref{DSDP.DSDPSolutionType}() + DSDP.DSDPGetSolutionType(dsdp, sol) + @test sol[] == 1 + ret = Ref{Cdouble}() + DSDP.DSDPGetDObjective(dsdp, ret) + @test ret[] ≈ 2 rtol = tol + DSDP.DSDPGetPObjective(dsdp, ret) + @test ret[] ≈ 2 rtol = tol + xmat = Ref{Ptr{Cdouble}}() + nn = Ref{Cint}() + DSDP.SDPConeGetXArray(sdpcone, 0, xmat, nn) + @test unsafe_wrap(Array, xmat[], nn[]) ≈ [1, 0, 1, 1] rtol = tol + num = Ref{Cint}() + DSDP.DSDPGetNumberOfVariables(dsdp, num) + @test num[] == 1 + DSDP.SDPConeGetNumberOfBlocks(sdpcone, num) + @test num[] == 1 + y = zeros(Cdouble, 1) + DSDP.DSDPGetY(dsdp, y, 1) + @test y[1] ≈ 2 rtol = tol + return +end + +@testset "SDP example" begin + test_sdp() +end + +@testset "DSDP MaxCut example" begin + nnodes = 6 + edges = [ + (1, 2, 0.3) + (1, 4, 2.7) + (1, 6, 1.5) + (2, 3, -1.0) + (2, 5, 1.45) + (3, 4, -0.2) + (4, 5, 1.2) + (5, 6, 2.1) + ] + maxcut(nnodes, edges) +end + +@testset "LPConeSetData doc example" begin + lpdvars = Cint[3, 3, 2, 2, 1, 3, 1, 1] + lpdrows = Cint[2, 0, 1, 0, 0, 1, 1, 2] + lpcoefs = Cdouble[-1, 2, 3, 4, 6, 7, 10, 12] + nnzin, row, aval = DSDP._buildlp(3, lpdvars, lpdrows, lpcoefs) + @test nnzin isa Vector{Cint} + @test nnzin == [0, 3, 5, 8] + @test row isa Vector{Cint} + @test row == [0, 1, 2, 0, 1, 0, 1, 2] + @test aval isa Vector{Cdouble} + @test aval == [6, 10, 12, 4, 3, 2, 7, -1] +end + +end # module diff --git a/test/maxcut.jl b/test/maxcut.jl deleted file mode 100644 index cd496a2..0000000 --- a/test/maxcut.jl +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright (c) 2022: Joey Huchette, Benoît Legat, and contributors -# -# Use of this source code is governed by an MIT-style license that can be found -# in the LICENSE.md file or at https://opensource.org/licenses/MIT. - -function di(u, v) - u, v = max(u, v), min(u, v) - return div((u - Cint(1)) * u, Cint(2)) + (v - Cint(1)) -end -di(u) = di(u, u) - -signz(t) = t < 0 ? -1 : 1 - -# Apply the Goemens and Williamson randomized cut algorithm to the SDP relaxation of the max-cut problem -function MaxCutRandomized(sdpcone::SDPCone.SDPConeT, nnodes::Integer) - ymin = Cdouble(0) - - vv = Vector{Cdouble}(undef, nnodes) - tt = Vector{Cdouble}(undef, nnodes) - cc = Vector{Cdouble}(undef, nnodes + 2) - SDPCone.ComputeXV(sdpcone, 0) - for i in 1:nnodes - for j in eachindex(vv) - dd = rand() - 0.5 - vv[j] = tan(π * dd) - end - SDPCone.XVMultiply(sdpcone, 0, vv, tt) - map!(signz, tt, tt) - map!(zero, cc, cc) - SDPCone.AddXVAV(sdpcone, 0, tt, cc) - if cc[1] < ymin - ymin = cc[1] - end - end - return ymin -end - -function maxcut(nnodes, edges) - nedges = length(edges) - dsdp = DSDP.Create(nnodes) - sdpcone = DSDP.CreateSDPCone(dsdp, 1) - - SDPCone.SetBlockSize(sdpcone, 0, nnodes) - - # Formulate the problem from the data - # Diagonal elements equal 1.0 - # Create Constraint matrix A_i for i=1, ..., nnodes. - # that has a single nonzero element. - diag = ones(Cdouble, nnodes) - N = Cint(1):Cint(nnodes) - iptr = di.(N) - - for i in 1:nnodes - DSDP.SetDualObjective(dsdp, i, 1.0) - SDPCone.SetASparseVecMat( - sdpcone, - 0, - i, - nnodes, - 1.0, - 0, - pointer(iptr, i), - pointer(diag, i), - 1, - ) - end - - # C matrix is the Laplacian of the adjacency matrix - # Also compute a feasible initial point y such that S >= 0 - yy = zeros(nnodes) - indd = zeros(Cint, nnodes + nedges) - val = zeros(nnodes + nedges) - indd[nedges.+(1:nnodes)] = iptr - tval = 0.0 - for (i, (u, v, w)) in enumerate(edges) - indd[i] = di(u, v) - tval += abs(w) - val[i] = w / 4 - val[nedges+u] -= w / 4 - val[nedges+v] -= w / 4 - yy[u] -= abs(w / 2) - yy[v] -= abs(w / 2) - end - - SDPCone.SetASparseVecMat( - sdpcone, - 0, - 0, - nnodes, - 1.0, - 0, - pointer(indd), - pointer(val), - nedges, - ) - SDPCone.AddASparseVecMat( - sdpcone, - 0, - 0, - nnodes, - 1.0, - 0, - pointer(indd, nedges + 1), - pointer(val, nedges + 1), - nnodes, - ) - - # Initial Point - DSDP.SetR0(dsdp, 0.0) - DSDP.SetZBar(dsdp, 10 * tval + 1.0) - for i in 1:nnodes - DSDP.SetY0(dsdp, i, 10 * yy[i]) - end - - # Get read to go - DSDP.SetGapTolerance(dsdp, 0.001) - DSDP.SetPotentialParameter(dsdp, 5) - DSDP.SetReuseMatrix(dsdp, 0) - DSDP.SetPNormTolerance(dsdp, 1.0) - #info = TCheckArgs(dsdp,argc,argv) - - DSDP.SetStandardMonitor(dsdp, 0) - - DSDP.Setup(dsdp) - - DSDP.Solve(dsdp) - reason = DSDP.StopReason(dsdp) - - @test reason != DSDP.DSDP_INFEASIBLE_START - @test DSDP.GetDObjective(dsdp) ≈ -9.250079 rtol = 1e-7 - @test DSDP.GetDDObjective(dsdp) ≈ -9.250079 rtol = 1e-7 - @test DSDP.GetPObjective(dsdp) ≈ 1e10 - @test DSDP.GetPPObjective(dsdp) ≈ -9.240522 rtol = 1e-7 - @test DSDP.GetDualityGap(dsdp) ≈ 0.009557113 rtol = 1e-7 - - # Randomized solution strategy - @test MaxCutRandomized(sdpcone, nnodes) ≈ -9.25 - - return DSDP.Destroy(dsdp) -end - -@testset "DSDP MaxCut example" begin - nnodes = 6 - edges = [ - (1, 2, 0.3) - (1, 4, 2.7) - (1, 6, 1.5) - (2, 3, -1.0) - (2, 5, 1.45) - (3, 4, -0.2) - (4, 5, 1.2) - (5, 6, 2.1) - ] - maxcut(nnodes, edges) -end diff --git a/test/options.jl b/test/options.jl deleted file mode 100644 index 53c29f6..0000000 --- a/test/options.jl +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2022: Joey Huchette, Benoît Legat, and contributors -# -# Use of this source code is governed by an MIT-style license that can be found -# in the LICENSE.md file or at https://opensource.org/licenses/MIT. - -using MathOptInterface -const MOI = MathOptInterface - -@testset "Options" begin - optimizer = MOI.Utilities.CachingOptimizer( - MOI.Utilities.Model{Float64}(), - DSDP.Optimizer(), - ) - x, cx = MOI.add_constrained_variables(optimizer, MOI.Nonnegatives(1)) - MOI.add_constraint(optimizer, 1.0x[1], MOI.EqualTo(1.0)) - MOI.Utilities.attach_optimizer(optimizer) - for (option, default) in - Iterators.flatten((DSDP.options, DSDP.gettable_options)) - @eval begin - @test MOI.get($optimizer, DSDP.$option()) == $default - end - end -end diff --git a/test/runtests.jl b/test/runtests.jl index 6b67cf2..49f9e16 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,11 +3,5 @@ # Use of this source code is governed by an MIT-style license that can be found # in the LICENSE.md file or at https://opensource.org/licenses/MIT. -using DSDP -using Test - -include("maxcut.jl") -include("sdp.jl") -include("build.jl") -include("options.jl") +include("c_api.jl") include("MOI_wrapper.jl") diff --git a/test/sdp.jl b/test/sdp.jl deleted file mode 100644 index 717459a..0000000 --- a/test/sdp.jl +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (c) 2022: Joey Huchette, Benoît Legat, and contributors -# -# Use of this source code is governed by an MIT-style license that can be found -# in the LICENSE.md file or at https://opensource.org/licenses/MIT. - -using Test, DSDP - -function test_sdp(tol = 1e-6) - dsdp = DSDP.Create(1) - sdpcone = DSDP.CreateSDPCone(dsdp, 1) - DSDP.SDPCone.SetBlockSize(sdpcone, 0, 2) - DSDP.SDPCone.SetSparsity(sdpcone, 0, 0) - DSDP.SDPCone.SetStorageFormat(sdpcone, 0, UInt8('U')) - DSDP.SetY0(dsdp, 1, 0.0) - DSDP.SetDualObjective(dsdp, 1, 1.0) - DSDP.SDPCone.SetASparseVecMat(sdpcone, 0, 1, 2, 1.0, 0, Int32[2], [0.5], 1) - DSDP.SDPCone.SetASparseVecMat( - sdpcone, - 0, - 0, - 2, - 1.0, - 0, - Int32[0, 3], - [1.0, 1.0], - 2, - ) - DSDP.Setup(dsdp) - DSDP.Solve(dsdp) - DSDP.ComputeX(dsdp) - @test DSDP.GetIts(dsdp) == 10 - derr = DSDP.GetFinalErrors(dsdp) - @test derr != zeros(Cdouble, 6) # To check that it's not just the allocated vector and we actually got the errors - @test derr ≈ zeros(Cdouble, 6) atol = tol - - # P Infeasible: derr[1] - # D Infeasible: derr[3] - # Minimal P Eigenvalue: derr[2] - # Minimal D Eigenvalue: 0.00, see `DSDP` source in `examples/readsdpa.c` - # Relative P - D Objective values: derr[5] - # Relative X Dot S: %4.2e: derr[6] - - @test DSDP.StopReason(dsdp) == 1 - @test DSDP.GetSolutionType(dsdp) == 1 - @test DSDP.GetDObjective(dsdp) ≈ 2 rtol = tol - @test DSDP.GetPObjective(dsdp) ≈ 2 rtol = tol - @test DSDP.SDPCone.GetXArray(sdpcone, 0) ≈ [1, 0, 1, 1] rtol = tol - @test DSDP.GetNumberOfVariables(dsdp) == 1 - @test DSDP.SDPCone.GetNumberOfBlocks(sdpcone) == 1 - y = zeros(Cdouble, 1) - DSDP.GetY(dsdp, y) - @test y[1] ≈ 2 rtol = tol - return -end - -import MathOptInterface as MOI - -function test_moi(tol = 1e-6) - model = MOI.Utilities.Model{Float64}() - X, _ = MOI.add_constrained_variables( - model, - MOI.PositiveSemidefiniteConeTriangle(2), - ) - c = MOI.add_constraint(model, 1.0 * X[2], MOI.EqualTo(1.0)) - obj = 1.0 * X[1] + 1.0 * X[3] - MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) - MOI.set(model, MOI.ObjectiveFunction{typeof(obj)}(), obj) - dsdp = DSDP.Optimizer() - MOI.copy_to(dsdp, model) - MOI.optimize!(dsdp) - @test MOI.get(dsdp, MOI.ObjectiveValue()) ≈ 2 rtol = tol - @test MOI.get(dsdp, MOI.DualObjectiveValue()) ≈ 2 rtol = tol - @test MOI.get.(dsdp, MOI.VariablePrimal(), X) ≈ [1, 1, 1] rtol = tol - @test MOI.get(dsdp, MOI.ConstraintDual(), c) ≈ 2 rtol = tol - return -end - -@testset "SDP example" begin - test_sdp() - test_moi() -end From f117c6cbed892ca23af2f7d920717f2697723ac2 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Fri, 10 Oct 2025 15:50:03 +1300 Subject: [PATCH 2/9] Simplify and refactor the MOI wrapper --- src/MOI_wrapper.jl | 203 ++++++++++++++------------------------------ test/MOI_wrapper.jl | 2 +- 2 files changed, 63 insertions(+), 142 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 53ed5f0..222b064 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -69,8 +69,6 @@ mutable struct Optimizer <: MOI.AbstractOptimizer end end -varmap(optimizer::Optimizer, vi::MOI.VariableIndex) = optimizer.varmap[vi.value] - # MOI.Silent MOI.supports(::Optimizer, ::MOI.Silent) = true @@ -86,6 +84,8 @@ MOI.get(optimizer::Optimizer, ::MOI.Silent) = optimizer.silent MOI.get(::Optimizer, ::MOI.SolverName) = "DSDP" +# Empty + function MOI.empty!(optimizer::Optimizer) _free(optimizer) optimizer.objective_constant = 0 @@ -121,7 +121,7 @@ end function _free(m::Optimizer) if m.dsdp != C_NULL - #Destroy(m.dsdp) + @check DSDPDestroy(m.dsdp) m.dsdp = C_NULL m.lpcone = C_NULL m.sdpcone = C_NULL @@ -216,6 +216,8 @@ for (param, default) in options end end +# MOI.supports + function MOI.supports( ::Optimizer, ::Union{ @@ -228,12 +230,9 @@ end MOI.supports_add_constrained_variables(::Optimizer, ::Type{MOI.Reals}) = false -const SupportedSets = - Union{MOI.Nonnegatives,MOI.PositiveSemidefiniteConeTriangle} - function MOI.supports_add_constrained_variables( ::Optimizer, - ::Type{<:SupportedSets}, + ::Type{<:Union{MOI.Nonnegatives,MOI.PositiveSemidefiniteConeTriangle}}, ) return true end @@ -269,13 +268,6 @@ function new_block( return end -function _add_constrained_variables(optimizer::Optimizer, set::SupportedSets) - offset = length(optimizer.varmap) - new_block(optimizer, set) - ci = MOI.ConstraintIndex{MOI.VectorOfVariables,typeof(set)}(offset + 1) - return [MOI.VariableIndex(i) for i in offset .+ (1:MOI.dimension(set))], ci -end - function _error(start, stop) return error( start, @@ -284,13 +276,12 @@ function _error(start, stop) ) end -# Copied from CSDP.jl function constrain_variables_on_creation( - dest::MOI.ModelLike, + dest::Optimizer, src::MOI.ModelLike, index_map::MOI.Utilities.IndexMap, ::Type{S}, -) where {S<:SupportedSets} +) where {S<:Union{MOI.Nonnegatives,MOI.PositiveSemidefiniteConeTriangle}} for ci_src in MOI.get(src, MOI.ListOfConstraintIndices{MOI.VectorOfVariables,S}()) f_src = MOI.get(src, MOI.ConstraintFunction(), ci_src) @@ -304,13 +295,14 @@ function constrain_variables_on_creation( "Cannot copy constraint `$(ci_src)` as variables constrained on creation because some variables of the function `$(f_src)` are in another constraint as well.", "to bridge constraints having the same variables by creating slack variables.", ) - else - set = MOI.get(src, MOI.ConstraintSet(), ci_src)::S - vis_dest, ci_dest = _add_constrained_variables(dest, set) - index_map[ci_src] = ci_dest - for (vi_src, vi_dest) in zip(f_src.variables, vis_dest) - index_map[vi_src] = vi_dest - end + end + set = MOI.get(src, MOI.ConstraintSet(), ci_src)::S + offset = length(dest.varmap) + new_block(dest, set) + index_map[ci_src] = + MOI.ConstraintIndex{MOI.VectorOfVariables,S}(offset + 1) + for (i, vi_src) in enumerate(f_src.variables) + index_map[vi_src] = MOI.VariableIndex(offset + i) end end return @@ -340,23 +332,10 @@ function _setcoefficient!( return end -# Loads objective coefficient α * vi -function load_objective_term!( - optimizer::Optimizer, - index_map, - α, - vi::MOI.VariableIndex, -) - blk, i, j = varmap(optimizer, vi) - coef = optimizer.objective_sign * α - _setcoefficient!(optimizer, coef, 0, blk, i, j) - return -end - function _set_A_matrices(m::Optimizer, i) for (blk, blkdim) in zip(m.blk, m.blockdims) if blkdim > 0 - SDPConeSetASparseVecMat( + @check SDPConeSetASparseVecMat( m.sdpcone, blk - 1, i, @@ -386,7 +365,7 @@ end # Largely inspired from CSDP.jl function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) - MOI.empty!(dest) + @assert MOI.is_empty(dest) index_map = MOI.Utilities.IndexMap() # Step 1) Compute the dimensions of what needs to be allocated constrain_variables_on_creation(dest, src, index_map, MOI.Nonnegatives) @@ -403,21 +382,14 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) "to bridge free variables into `x - y` where `x` and `y` are nonnegative.", ) end - cis_src = MOI.get( - src, - MOI.ListOfConstraintIndices{ - MOI.ScalarAffineFunction{Cdouble}, - MOI.EqualTo{Cdouble}, - }(), - ) + F = MOI.ScalarAffineFunction{Cdouble} + cis_src = + MOI.get(src, MOI.ListOfConstraintIndices{F,MOI.EqualTo{Cdouble}}()) if isempty(cis_src) - throw( - ArgumentError("DSDP does not support problems with no constraint."), - ) + msg = "DSDP does not support problems with no constraint." + throw(ArgumentError(msg)) end - dest.b = Vector{Cdouble}(undef, length(cis_src)) - _free(dest) - dest.nlpdrows = 0 + resize!(dest.b, length(cis_src)) dest.blk = zero(dest.blockdims) num_sdp = 0 for i in 1:length(dest.blockdims) @@ -429,35 +401,27 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) dest.blk[i] = num_sdp end end - dest.lpdvars = Int[] - dest.lpdrows = Int[] - dest.lpcoefs = Cdouble[] + # Create a new solver object with the correct number of constraints. p = Ref{Ptr{Cvoid}}() @check DSDPCreate(length(dest.b), p) dest.dsdp = p[] + # Set options for (option, value) in dest.options options_setters[option](dest.dsdp, value) end - if !iszero(num_sdp) + if num_sdp > 0 sdpcone = Ref{Ptr{Cvoid}}() @check DSDPCreateSDPCone(dest.dsdp, num_sdp, sdpcone) dest.sdpcone = sdpcone[] - for i in eachindex(dest.blockdims) - if dest.blockdims[i] < 0 - continue + for (i, blk_dim) in enumerate(dest.blockdims) + if blk_dim < 0 + continue # It's an LP block end blk = dest.blk[i] - SDPConeSetBlockSize(dest.sdpcone, blk - 1, dest.blockdims[i]) - # TODO what does this `0` mean ? - SDPConeSetSparsity(dest.sdpcone, blk - 1, 0) - SDPConeSetStorageFormat(dest.sdpcone, blk - 1, UInt8('U')) + @check SDPConeSetBlockSize(dest.sdpcone, blk - 1, blk_dim) + @check SDPConeSetStorageFormat(dest.sdpcone, blk - 1, UInt8('U')) end end - for constr in eachindex(dest.b) - # TODO in examples/readsdpa.c line 162, - # -0.0 is used instead of 0.0 if the dual obj is <= 0., check if it has impact - @check DSDPSetY0(dest.dsdp, constr, 0.0) - end # TODO ComputeY0 as in examples/readsdpa.c empty!(dest.y) for (k, ci_src) in enumerate(cis_src) @@ -467,7 +431,7 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) throw( MOI.ScalarFunctionConstantNotZero{ Cdouble, - MOI.ScalarAffineFunction{Cdouble}, + F, MOI.EqualTo{Cdouble}, }( MOI.constant(func), @@ -478,18 +442,13 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) _new_A_matrix(dest) for t in func.terms if !iszero(t.coefficient) - blk, i, j = varmap(dest, index_map[t.variable]) + blk, i, j = dest.varmap[index_map[t.variable].value] _setcoefficient!(dest, t.coefficient, k, blk, i, j) end end _set_A_matrices(dest, k) dest.b[k] = MOI.constant(set) - index_map[ci_src] = MOI.ConstraintIndex{ - MOI.ScalarAffineFunction{Cdouble}, - MOI.EqualTo{Cdouble}, - }( - k, - ) + index_map[ci_src] = MOI.ConstraintIndex{F,MOI.EqualTo{Cdouble}}(k) end # Throw error for variable attributes MOI.Utilities.pass_attributes(dest, src, index_map, vis_src) @@ -497,35 +456,26 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) MOI.Utilities.pass_attributes(dest, src, index_map, cis_src) # Pass objective attributes and throw error for other ones model_attributes = MOI.get(src, MOI.ListOfModelAttributesSet()) + obj_attr = MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Cdouble}}() for attr in model_attributes - if attr != MOI.ObjectiveSense() && - attr != MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Cdouble}}() + if attr != MOI.ObjectiveSense() && attr != obj_attr throw(MOI.UnsupportedAttribute(attr)) end end - # We make sure to set `objective_sign` first before setting the objective if MOI.ObjectiveSense() in model_attributes - # DSDP convention is MIN so we reverse the sign of coef if it is MAX sense = MOI.get(src, MOI.ObjectiveSense()) dest.objective_sign = sense == MOI.MIN_SENSE ? 1 : -1 end - if MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Cdouble}}() in - model_attributes - func = MOI.get( - src, - MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Cdouble}}(), - ) - obj = MOI.Utilities.canonical(func) + if obj_attr in model_attributes + obj = MOI.Utilities.canonical(MOI.get(src, obj_attr)) dest.objective_constant = obj.constant _new_A_matrix(dest) for term in obj.terms - if !iszero(term.coefficient) - load_objective_term!( - dest, - index_map, - term.coefficient, - index_map[term.variable], - ) + if iszero(term.coefficient) + vi = index_map[term.variable] + blk, i, j = optimizer.varmap[vi.value] + coef = optimizer.objective_sign * term.coefficient + _setcoefficient!(dest, coef, 0, blk, i, j) end end _set_A_matrices(dest, 0) @@ -541,7 +491,7 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) dest.lpdrows, dest.lpcoefs, ) - LPConeSetData(dest.lpcone, dest.nlpdrows, nnzin, row, aval) + @check LPConeSetData(dest.lpcone, dest.nlpdrows, nnzin, row, aval) end @check DSDPSetup(dest.dsdp) return index_map @@ -605,10 +555,10 @@ function MOI.get(m::Optimizer, ::MOI.RawStatusString) return "Upperbound" elseif status == DSDP_USER_TERMINATION return "User termination" - elseif status == CONTINUE_ITERATING + else + @assert status == CONTINUE_ITERATING return "Continue iterating" end - return error("Internal library error: status=$status") end function MOI.get(m::Optimizer, ::MOI.TerminationStatus) @@ -628,10 +578,9 @@ function MOI.get(m::Optimizer, ::MOI.TerminationStatus) return MOI.INFEASIBLE elseif sol_status == DSDP_INFEASIBLE return MOI.DUAL_INFEASIBLE - elseif sol_status == DSDP_PDUNKNOWN - return MOI.OTHER_ERROR else - error("Internal library error: status=$sol_status") + @assert sol_status == DSDP_PDUNKNOWN + return MOI.OTHER_ERROR end elseif status == DSDP_INFEASIBLE_START return MOI.OTHER_ERROR @@ -647,10 +596,10 @@ function MOI.get(m::Optimizer, ::MOI.TerminationStatus) return MOI.OBJECTIVE_LIMIT elseif status == DSDP_USER_TERMINATION return MOI.INTERRUPTED - elseif status == CONTINUE_ITERATING + else + @assert status == CONTINUE_ITERATING return MOI.OTHER_ERROR end - return error("Internal library error: status=$status") end function MOI.get(m::Optimizer, attr::MOI.PrimalStatus) @@ -666,10 +615,10 @@ function MOI.get(m::Optimizer, attr::MOI.PrimalStatus) return MOI.FEASIBLE_POINT elseif status == DSDP_UNBOUNDED return MOI.INFEASIBLE_POINT - elseif status == DSDP_INFEASIBLE + else + @assert status == DSDP_INFEASIBLE return MOI.INFEASIBILITY_CERTIFICATE end - return error("Internal library error: status=$status") end function MOI.get(m::Optimizer, attr::MOI.DualStatus) @@ -685,10 +634,9 @@ function MOI.get(m::Optimizer, attr::MOI.DualStatus) return MOI.FEASIBLE_POINT elseif status == DSDP_UNBOUNDED return MOI.INFEASIBILITY_CERTIFICATE - elseif status == DSDP_INFEASIBLE - return MOI.INFEASIBLE_POINT else - error("Internal library error: status=$status") + @assert status == DSDP_INFEASIBLE + return MOI.INFEASIBLE_POINT end end @@ -732,10 +680,6 @@ end abstract type AbstractBlockMatrix{T} <: AbstractMatrix{T} end -function nblocks end - -function block end - function Base.size(bm::AbstractBlockMatrix) n = mapreduce( blk -> LinearAlgebra.checksquare(block(bm, blk)), @@ -779,7 +723,7 @@ end function get_array(x::LPXBlock) xout = Ref{Ptr{Cdouble}}() n = Ref{Cint}() - LPConeGetXArray(x.lpcone, xout, n) + @check LPConeGetXArray(x.lpcone, xout, n) return unsafe_wrap(Array, xout[], n[]) end @@ -792,7 +736,7 @@ end function get_array(x::SDPXBlock) xmat = Ref{Ptr{Cdouble}}() nn = Ref{Cint}() - SDPConeGetXArray(x.sdpcone, x.blockj - 1, xmat, nn) + @check SDPConeGetXArray(x.sdpcone, x.blockj - 1, xmat, nn) v = unsafe_wrap(Array, xmat[], nn[]) return [v[i+(j-1)*x.dim] for j in 1:x.dim for i in 1:j] end @@ -817,20 +761,6 @@ function block(x::XBlockMat, i) end end -struct PrimalSolutionMatrix <: MOI.AbstractModelAttribute end - -MOI.is_set_by_optimize(::PrimalSolutionMatrix) = true - -MOI.get(optimizer::Optimizer, ::PrimalSolutionMatrix) = XBlockMat(optimizer) - -struct DualSolutionVector <: MOI.AbstractModelAttribute end - -MOI.is_set_by_optimize(::DualSolutionVector) = true - -function MOI.get(optimizer::Optimizer, ::DualSolutionVector) - return optimizer.y -end - function block( optimizer::Optimizer, ci::MOI.ConstraintIndex{MOI.VectorOfVariables}, @@ -868,28 +798,19 @@ function MOI.get( vi::MOI.VariableIndex, ) MOI.check_result_index_bounds(optimizer, attr) - blk, i, j = varmap(optimizer, vi) - return block(MOI.get(optimizer, PrimalSolutionMatrix()), blk)[i, j] + blk, i, j = optimizer.varmap[vi.value] + return block(XBlockMat(optimizer), blk)[i, j] end function MOI.get( optimizer::Optimizer, attr::MOI.ConstraintPrimal, ci::MOI.ConstraintIndex{MOI.VectorOfVariables,S}, -) where {S<:SupportedSets} +) where {S<:Union{MOI.Nonnegatives,MOI.PositiveSemidefiniteConeTriangle}} MOI.check_result_index_bounds(optimizer, attr) - return vectorize_block( - MOI.get(optimizer, PrimalSolutionMatrix()), - block(optimizer, ci), - S, - ) + return vectorize_block(XBlockMat(optimizer), block(optimizer, ci), S) end -#function MOI.get(optimizer::Optimizer, attr::MOI.ConstraintDual, -# ci::MOI.ConstraintIndex{MOI.VectorOfVariables, S}) where S<:SupportedSets -# MOI.check_result_index_bounds(optimizer, attr) -# return vectorize_block(MOI.get(optimizer, DualSlackMatrix()), block(optimizer, ci), S) -#end function MOI.get( optimizer::Optimizer, attr::MOI.ConstraintDual, @@ -899,5 +820,5 @@ function MOI.get( }, ) MOI.check_result_index_bounds(optimizer, attr) - return -MOI.get(optimizer, DualSolutionVector())[ci.value] + return -optimizer.y[ci.value] end diff --git a/test/MOI_wrapper.jl b/test/MOI_wrapper.jl index 0fd8a00..d6f4e54 100644 --- a/test/MOI_wrapper.jl +++ b/test/MOI_wrapper.jl @@ -44,7 +44,7 @@ function test_runtests() model.optimizer, MOI.Bridges.Variable.ZerosBridge{Float64}, ) - MOI.set(model, MOI.Silent(), true) + # MOI.set(model, MOI.Silent(), true) MOI.Test.runtests( model, MOI.Test.Config(; From 0ecdc8e3ad9cc7cc420aeb12c3fe81958410291a Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Fri, 10 Oct 2025 16:08:30 +1300 Subject: [PATCH 3/9] Update --- src/MOI_wrapper.jl | 203 +++++++++++++++++++------------------------- test/MOI_wrapper.jl | 16 ---- 2 files changed, 88 insertions(+), 131 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 222b064..1d5bc7d 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -41,7 +41,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer sdpdcoefs::Vector{Vector{Vector{Cdouble}}} y::Vector{Cdouble} silent::Bool - options::Dict{Symbol,Any} + options::Dict{String,Any} function Optimizer() optimizer = new( @@ -62,13 +62,16 @@ mutable struct Optimizer <: MOI.AbstractOptimizer Vector{Cdouble}[], Cdouble[], false, - Dict{Symbol,Any}(), + Dict{String,Any}(), ) - finalizer(_free, optimizer) + finalizer(MOI.empty!, optimizer) return optimizer end end +Base.cconvert(::Type{Ptr{Cvoid}}, x::Optimizer) = x +Base.unsafe_convert(::Type{Ptr{Cvoid}}, x::Optimizer) = x.dsdp + # MOI.Silent MOI.supports(::Optimizer, ::MOI.Silent) = true @@ -87,7 +90,12 @@ MOI.get(::Optimizer, ::MOI.SolverName) = "DSDP" # Empty function MOI.empty!(optimizer::Optimizer) - _free(optimizer) + if optimizer.dsdp != C_NULL + @check DSDPDestroy(optimizer) + optimizer.dsdp = C_NULL + optimizer.lpcone = C_NULL + optimizer.sdpcone = C_NULL + end optimizer.objective_constant = 0 optimizer.objective_sign = 1 empty!(optimizer.b) @@ -119,101 +127,66 @@ function MOI.is_empty(optimizer::Optimizer) isempty(optimizer.sdpdcoefs) end -function _free(m::Optimizer) - if m.dsdp != C_NULL - @check DSDPDestroy(m.dsdp) - m.dsdp = C_NULL - m.lpcone = C_NULL - m.sdpcone = C_NULL - end - return -end - -# Taken from src/solver/dsdpsetup.c -const gettable_options = Dict{Symbol,Union{Cint,Cdouble}}( - # Stopping parameters - :MaxIts => Cint(500), - :GapTolerance => 1.0e-7, # 100<=nconstrs<=3000 => 1e-6, nconstrs>3000 => 5e-6 - :PNormTolerance => 1.0e30, - :DualBound => 1.0e20, - :StepTolerance => 5.0e-2, - :RTolerance => 1.0e-6, - :PTolerance => 1.0e-4, - # Solver options - :MaxTrustRadius => 1.0e10, - :BarrierParameter => -1.0, - :PotentialParameter => 5.0, # nconstrs>100 => 3.0 - :PenaltyParameter => 1.0e8, - :ReuseMatrix => Cint(4), # 100 7, nconstrs>1000 => 10 - # Handled separately - # :YBounds => (-1e7, 1e7), -) -# TODO -# UsePenalty(dsdp,0) -# UseDynamicRho(dsdp,1) -# DSDPLogInfoAllow(iloginfo,0) -# DSDPSetFixedVariable[s] -# DSDPSetDualLowerBound - -const options = Dict{Symbol,Union{Cint,Cdouble}}( - # Solver options - :R0 => -1.0, - :ZBar => 1e10, -) - -const options_setters = Dict{Symbol,Function}() - -abstract type Option <: MOI.AbstractOptimizerAttribute end - -abstract type GettableOption <: Option end - -MOI.supports(solver::Optimizer, ::Option) = true - -function MOI.set(m::Optimizer, o::Option, val) - # Need to set it in the dictionary so that it is also used when init! is called again - _dict_set!(m.options, o, val) - _call_set!(m.dsdp, o, val)r - return -end - -MOI.get(m::Optimizer, o::Option) = _dict_get(m.options, o) - -function MOI.get(m::Optimizer, o::GettableOption) - if m.dsdp == C_NULL - return _dict_get(m.options, o) - end - # May be different from _dict_get for ReuseMatrix, GapTolerance and PotentialParameter since it depends on nconstrs - return _call_get(m.dsdp, o) -end - -for (param, default) in gettable_options - getter, setter = Symbol("DSDPGet$param"), Symbol("DSDPSet$param") - T = typeof(default) - sym = QuoteNode(param) - @eval begin - struct $param <: GettableOption end - function _call_get(dsdp, ::$param) - ret = Ref{$T}() - @check $getter(dsdp, ret) - return ret[] - end - options_setters[$sym] = $setter - _dict_set!(options, ::$param, val) = options[$sym] = val - _dict_get(options, ::$param) = get(options, $sym, $default) - _call_set!(dsdp, ::$param, val) = @check $setter(dsdp, val) - end +function MOI.supports(model::Optimizer, attr::MOI.RawOptimizerAttribute) + return attr.name in ( + "MaxIts", + "GapTolerance", + "PNormTolerance", + "DualBound", + "StepTolerance", + "RTolerance", + "PTolerance", + "MaxTrustRadius", + "BarrierParameter", + "PotentialParameter", + "PenaltyParameter", + "ReuseMatrix", + "R0", + "ZBar", + ) end -for (param, default) in options - setter = Symbol("DSDPSet$param") - sym = QuoteNode(param) - @eval begin - struct $param <: Option end - options_setters[$sym] = $setter - _dict_set!(options, ::$param, val) = options[$sym] = val - _dict_get(options, ::$param) = get(options, $sym, $default) - _call_set!(dsdp, ::$param, val) = @check $setter(dsdp, val) +function MOI.get(model::Optimizer, attr::MOI.RawOptimizerAttribute) + if !MOI.supports(model, attr) + throw(MOI.UnsupportedAttribute(attr)) + end + return get(model, attr.name, nothing) +end + +function MOI.set(model::Optimizer, attr::MOI.RawOptimizerAttribute, value) + if attr.name == "MaxIts" + @check DSDPSetMaxIts(model, value) + elseif attr.name == "GapTolerance" + @check DSDPSetGapTolerance(model, value) + elseif attr.name == "PNormTolerance" + @check DSDPSetPNormTolerance(model, value) + elseif attr.name == "DualBound" + @check DSDPSetDualBound(model, value) + elseif attr.name == "StepTolerance" + @check DSDPSetStepTolerance(model, value) + elseif attr.name == "RTolerance" + @check DSDPSetRTolerance(model, value) + elseif attr.name == "PTolerance" + @check DSDPSetPTolerance(model, value) + elseif attr.name == "MaxTrustRadius" + @check DSDPSetMaxTrustRadius(model, value) + elseif attr.name == "BarrierParameter" + @check DSDPSetBarrierParameter(model, value) + elseif attr.name == "PotentialParameter" + @check DSDPSetPotentialParameter(model, value) + elseif attr.name == "PenaltyParameter" + @check DSDPSetPenaltyParameter(model, value) + elseif attr.name == "ReuseMatrix" + @check DSDPSetReuseMatrix(model, value) + elseif attr.name == "R0" + @check DSDPSetR0(model, value) + elseif attr.name == "ZBar" + @check DSDPSetZBar(model, value) + else + throw(MOI.UnsupportedAttribute(attr)) end + model.options[attr.name] = value + return end # MOI.supports @@ -407,11 +380,11 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) dest.dsdp = p[] # Set options for (option, value) in dest.options - options_setters[option](dest.dsdp, value) + MOI.set(dest, MOI.RawOptimizerAttribute(option), value) end if num_sdp > 0 sdpcone = Ref{Ptr{Cvoid}}() - @check DSDPCreateSDPCone(dest.dsdp, num_sdp, sdpcone) + @check DSDPCreateSDPCone(dest, num_sdp, sdpcone) dest.sdpcone = sdpcone[] for (i, blk_dim) in enumerate(dest.blockdims) if blk_dim < 0 @@ -438,7 +411,7 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) ), ) end - @check DSDPSetDualObjective(dest.dsdp, k, MOI.constant(set)) + @check DSDPSetDualObjective(dest, k, MOI.constant(set)) _new_A_matrix(dest) for t in func.terms if !iszero(t.coefficient) @@ -471,10 +444,10 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) dest.objective_constant = obj.constant _new_A_matrix(dest) for term in obj.terms - if iszero(term.coefficient) + if !iszero(term.coefficient) vi = index_map[term.variable] - blk, i, j = optimizer.varmap[vi.value] - coef = optimizer.objective_sign * term.coefficient + blk, i, j = dest.varmap[vi.value] + coef = dest.objective_sign * term.coefficient _setcoefficient!(dest, coef, 0, blk, i, j) end end @@ -483,7 +456,7 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) # Pass info to `dest.dsdp` if !isempty(dest.lpdvars) lpcone = Ref{Ptr{Cvoid}}() - @check DSDPCreateLPCone(dest.dsdp, lpcone) + @check DSDPCreateLPCone(dest, lpcone) dest.lpcone = lpcone[] nnzin, row, aval = _buildlp( length(dest.b) + 1, @@ -493,7 +466,7 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) ) @check LPConeSetData(dest.lpcone, dest.nlpdrows, nnzin, row, aval) end - @check DSDPSetup(dest.dsdp) + @check DSDPSetup(dest) return index_map end @@ -521,13 +494,13 @@ function _buildlp(nvars, lpdvars, lpdrows, lpcoefs) end function MOI.optimize!(m::Optimizer) - @check DSDPSetStandardMonitor(m.dsdp, !m.silent ? 1 : 0) - @check DSDPSolve(m.dsdp) + @check DSDPSetStandardMonitor(m, !m.silent ? 1 : 0) + @check DSDPSolve(m) # Calling `ComputeX` not right after `Solve` seems to sometime cause segfaults or weird Heisenbug's # let's call it directly what `DSDP/examples/readsdpa.c` does - @check DSDPComputeX(m.dsdp) + @check DSDPComputeX(m) m.y = zeros(Cdouble, length(m.b)) - @check DSDPGetY(m.dsdp, m.y, length(m.y)) + @check DSDPGetY(m, m.y, length(m.y)) map!(-, m.y, m.y) # The primal objective is Max in SDOI but Min in DSDP return end @@ -537,7 +510,7 @@ function MOI.get(m::Optimizer, ::MOI.RawStatusString) return "`optimize!` not called" end stop = Ref{DSDPTerminationReason}() - @check DSDPStopReason(m.dsdp, stop) + @check DSDPStopReason(m, stop) status = stop[] if status == DSDP_CONVERGED return "Converged" @@ -566,11 +539,11 @@ function MOI.get(m::Optimizer, ::MOI.TerminationStatus) return MOI.OPTIMIZE_NOT_CALLED end stop = Ref{DSDPTerminationReason}() - @check DSDPStopReason(m.dsdp, stop) + @check DSDPStopReason(m, stop) status = stop[] if status == DSDP_CONVERGED sol = Ref{DSDPSolutionType}() - @check DSDPGetSolutionType(m.dsdp, sol) + @check DSDPGetSolutionType(m, sol) sol_status = sol[] if sol_status == DSDP_PDFEASIBLE return MOI.OPTIMAL @@ -607,7 +580,7 @@ function MOI.get(m::Optimizer, attr::MOI.PrimalStatus) return MOI.NO_SOLUTION end sol = Ref{DSDPSolutionType}() - @check DSDPGetSolutionType(m.dsdp, sol) + @check DSDPGetSolutionType(m, sol) status = sol[] if status == DSDP_PDUNKNOWN return MOI.UNKNOWN_RESULT_STATUS @@ -626,7 +599,7 @@ function MOI.get(m::Optimizer, attr::MOI.DualStatus) return MOI.NO_SOLUTION end sol = Ref{DSDPSolutionType}() - @check DSDPGetSolutionType(m.dsdp, sol) + @check DSDPGetSolutionType(m, sol) status = sol[] if status == DSDP_PDUNKNOWN return MOI.UNKNOWN_RESULT_STATUS @@ -645,14 +618,14 @@ MOI.get(m::Optimizer, ::MOI.ResultCount) = m.dsdp == C_NULL ? 0 : 1 function MOI.get(m::Optimizer, attr::MOI.ObjectiveValue) MOI.check_result_index_bounds(m, attr) ret = Ref{Cdouble}() - @check DSDPGetPPObjective(m.dsdp, ret) + @check DSDPGetPPObjective(m, ret) return m.objective_sign * ret[] + m.objective_constant end function MOI.get(m::Optimizer, attr::MOI.DualObjectiveValue) MOI.check_result_index_bounds(m, attr) ret = Ref{Cdouble}() - @check DSDPGetDDObjective(m.dsdp, ret) + @check DSDPGetDDObjective(m, ret) return m.objective_sign * ret[] + m.objective_constant end diff --git a/test/MOI_wrapper.jl b/test/MOI_wrapper.jl index d6f4e54..ed4a437 100644 --- a/test/MOI_wrapper.jl +++ b/test/MOI_wrapper.jl @@ -170,22 +170,6 @@ function test_runtests() return end -function test_options() - optimizer = MOI.Utilities.CachingOptimizer( - MOI.Utilities.Model{Float64}(), - DSDP.Optimizer(), - ) - x, cx = MOI.add_constrained_variables(optimizer, MOI.Nonnegatives(1)) - MOI.add_constraint(optimizer, 1.0x[1], MOI.EqualTo(1.0)) - MOI.Utilities.attach_optimizer(optimizer) - for (option, default) in - Iterators.flatten((DSDP.options, DSDP.gettable_options)) - opt = getfield(DSDP, option) - @test MOI.get(optimizer, opt()) == default - end - return -end - function test_moi(tol = 1e-6) model = MOI.Utilities.Model{Float64}() X, _ = MOI.add_constrained_variables( From d7e8d4cbad992b44200cdcf5efca5406b0eebbab Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Fri, 10 Oct 2025 16:36:19 +1300 Subject: [PATCH 4/9] Rename --- src/MOI_wrapper.jl | 360 +++++++++++++++++++++------------------------ 1 file changed, 170 insertions(+), 190 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 1d5bc7d..5ca1188 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -3,7 +3,7 @@ # Use of this source code is governed by an MIT-style license that can be found # in the LICENSE.md file or at https://opensource.org/licenses/MIT. -macro check(expr) +macro _check(expr) @assert expr.head == :call msg = "Error calling $(expr.args[1])" return quote @@ -44,7 +44,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer options::Dict{String,Any} function Optimizer() - optimizer = new( + model = new( C_NULL, C_NULL, 0.0, @@ -59,29 +59,30 @@ mutable struct Optimizer <: MOI.AbstractOptimizer Int[], Cdouble[], Vector{Int}[], - Vector{Cdouble}[], + Vector{Vector{Cdouble}}[], Cdouble[], false, Dict{String,Any}(), ) - finalizer(MOI.empty!, optimizer) - return optimizer + finalizer(MOI.empty!, model) + return model end end Base.cconvert(::Type{Ptr{Cvoid}}, x::Optimizer) = x + Base.unsafe_convert(::Type{Ptr{Cvoid}}, x::Optimizer) = x.dsdp # MOI.Silent MOI.supports(::Optimizer, ::MOI.Silent) = true -function MOI.set(optimizer::Optimizer, ::MOI.Silent, value::Bool) - optimizer.silent = value +function MOI.set(model::Optimizer, ::MOI.Silent, value::Bool) + model.silent = value return end -MOI.get(optimizer::Optimizer, ::MOI.Silent) = optimizer.silent +MOI.get(model::Optimizer, ::MOI.Silent) = model.silent # MOI.SolverName @@ -89,44 +90,46 @@ MOI.get(::Optimizer, ::MOI.SolverName) = "DSDP" # Empty -function MOI.empty!(optimizer::Optimizer) - if optimizer.dsdp != C_NULL - @check DSDPDestroy(optimizer) - optimizer.dsdp = C_NULL - optimizer.lpcone = C_NULL - optimizer.sdpcone = C_NULL - end - optimizer.objective_constant = 0 - optimizer.objective_sign = 1 - empty!(optimizer.b) - empty!(optimizer.blockdims) - empty!(optimizer.varmap) - empty!(optimizer.blk) - optimizer.nlpdrows = 0 - empty!(optimizer.lpdvars) - empty!(optimizer.lpdrows) - empty!(optimizer.lpcoefs) - empty!(optimizer.sdpdinds) - empty!(optimizer.sdpdcoefs) - empty!(optimizer.y) +function MOI.empty!(model::Optimizer) + if model.dsdp != C_NULL + @_check DSDPDestroy(model) + model.dsdp = C_NULL + model.lpcone = C_NULL + model.sdpcone = C_NULL + end + model.objective_constant = 0 + model.objective_sign = 1 + empty!(model.b) + empty!(model.blockdims) + empty!(model.varmap) + empty!(model.blk) + model.nlpdrows = 0 + empty!(model.lpdvars) + empty!(model.lpdrows) + empty!(model.lpcoefs) + empty!(model.sdpdinds) + empty!(model.sdpdcoefs) + empty!(model.y) return end -function MOI.is_empty(optimizer::Optimizer) - return iszero(optimizer.objective_constant) && - isone(optimizer.objective_sign) && - isempty(optimizer.b) && - isempty(optimizer.blockdims) && - isempty(optimizer.varmap) && - isempty(optimizer.blk) && - iszero(optimizer.nlpdrows) && - isempty(optimizer.lpdvars) && - isempty(optimizer.lpdrows) && - isempty(optimizer.lpcoefs) && - isempty(optimizer.sdpdinds) && - isempty(optimizer.sdpdcoefs) +function MOI.is_empty(model::Optimizer) + return iszero(model.objective_constant) && + isone(model.objective_sign) && + isempty(model.b) && + isempty(model.blockdims) && + isempty(model.varmap) && + isempty(model.blk) && + iszero(model.nlpdrows) && + isempty(model.lpdvars) && + isempty(model.lpdrows) && + isempty(model.lpcoefs) && + isempty(model.sdpdinds) && + isempty(model.sdpdcoefs) end +# MOI.RawOptimizerAttribute + function MOI.supports(model::Optimizer, attr::MOI.RawOptimizerAttribute) return attr.name in ( "MaxIts", @@ -155,33 +158,33 @@ end function MOI.set(model::Optimizer, attr::MOI.RawOptimizerAttribute, value) if attr.name == "MaxIts" - @check DSDPSetMaxIts(model, value) + @_check DSDPSetMaxIts(model, value) elseif attr.name == "GapTolerance" - @check DSDPSetGapTolerance(model, value) + @_check DSDPSetGapTolerance(model, value) elseif attr.name == "PNormTolerance" - @check DSDPSetPNormTolerance(model, value) + @_check DSDPSetPNormTolerance(model, value) elseif attr.name == "DualBound" - @check DSDPSetDualBound(model, value) + @_check DSDPSetDualBound(model, value) elseif attr.name == "StepTolerance" - @check DSDPSetStepTolerance(model, value) + @_check DSDPSetStepTolerance(model, value) elseif attr.name == "RTolerance" - @check DSDPSetRTolerance(model, value) + @_check DSDPSetRTolerance(model, value) elseif attr.name == "PTolerance" - @check DSDPSetPTolerance(model, value) + @_check DSDPSetPTolerance(model, value) elseif attr.name == "MaxTrustRadius" - @check DSDPSetMaxTrustRadius(model, value) + @_check DSDPSetMaxTrustRadius(model, value) elseif attr.name == "BarrierParameter" - @check DSDPSetBarrierParameter(model, value) + @_check DSDPSetBarrierParameter(model, value) elseif attr.name == "PotentialParameter" - @check DSDPSetPotentialParameter(model, value) + @_check DSDPSetPotentialParameter(model, value) elseif attr.name == "PenaltyParameter" - @check DSDPSetPenaltyParameter(model, value) + @_check DSDPSetPenaltyParameter(model, value) elseif attr.name == "ReuseMatrix" - @check DSDPSetReuseMatrix(model, value) + @_check DSDPSetReuseMatrix(model, value) elseif attr.name == "R0" - @check DSDPSetR0(model, value) + @_check DSDPSetR0(model, value) elseif attr.name == "ZBar" - @check DSDPSetZBar(model, value) + @_check DSDPSetZBar(model, value) else throw(MOI.UnsupportedAttribute(attr)) end @@ -191,12 +194,11 @@ end # MOI.supports +MOI.supports(::Optimizer, ::MOI.ObjectiveSense) = true + function MOI.supports( ::Optimizer, - ::Union{ - MOI.ObjectiveSense, - MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Cdouble}}, - }, + ::MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Cdouble}}, ) return true end @@ -218,24 +220,21 @@ function MOI.supports_constraint( return true end -function new_block(optimizer::Optimizer, set::MOI.Nonnegatives) - push!(optimizer.blockdims, -MOI.dimension(set)) - blk = length(optimizer.blockdims) +function _new_block(model::Optimizer, set::MOI.Nonnegatives) + push!(model.blockdims, -MOI.dimension(set)) + blk = length(model.blockdims) for i in 1:MOI.dimension(set) - push!(optimizer.varmap, (blk, i, i)) + push!(model.varmap, (blk, i, i)) end return end -function new_block( - optimizer::Optimizer, - set::MOI.PositiveSemidefiniteConeTriangle, -) - push!(optimizer.blockdims, set.side_dimension) - blk = length(optimizer.blockdims) +function _new_block(model::Optimizer, set::MOI.PositiveSemidefiniteConeTriangle) + push!(model.blockdims, set.side_dimension) + blk = length(model.blockdims) for j in 1:set.side_dimension for i in 1:j - push!(optimizer.varmap, (blk, i, j)) + push!(model.varmap, (blk, i, j)) end end return @@ -249,7 +248,7 @@ function _error(start, stop) ) end -function constrain_variables_on_creation( +function _constrain_variables_on_creation( dest::Optimizer, src::MOI.ModelLike, index_map::MOI.Utilities.IndexMap, @@ -271,7 +270,7 @@ function constrain_variables_on_creation( end set = MOI.get(src, MOI.ConstraintSet(), ci_src)::S offset = length(dest.varmap) - new_block(dest, set) + _new_block(dest, set) index_map[ci_src] = MOI.ConstraintIndex{MOI.VectorOfVariables,S}(offset + 1) for (i, vi_src) in enumerate(f_src.variables) @@ -281,56 +280,56 @@ function constrain_variables_on_creation( return end -function _setcoefficient!( - m::Optimizer, +function _set_coefficient( + model::Optimizer, coef, constr::Integer, blk::Integer, i::Integer, j::Integer, ) - if m.blockdims[blk] < 0 + if model.blockdims[blk] < 0 @assert i == j - push!(m.lpdvars, constr + 1) - push!(m.lpdrows, m.blk[blk] + i - 1) # -1 because indexing starts at 0 in DSDP - push!(m.lpcoefs, coef) + push!(model.lpdvars, constr + 1) + push!(model.lpdrows, model.blk[blk] + i - 1) # -1 because indexing starts at 0 in DSDP + push!(model.lpcoefs, coef) else - sdp = m.blk[blk] - push!(m.sdpdinds[end][sdp], i + (j - 1) * m.blockdims[blk] - 1) + sdp = model.blk[blk] + push!(model.sdpdinds[end][sdp], i + (j - 1) * model.blockdims[blk] - 1) if i != j coef /= 2 end - push!(m.sdpdcoefs[end][sdp], coef) + push!(model.sdpdcoefs[end][sdp], coef) end return end -function _set_A_matrices(m::Optimizer, i) - for (blk, blkdim) in zip(m.blk, m.blockdims) +function _set_A_matrices(model::Optimizer, i) + for (blk, blkdim) in zip(model.blk, model.blockdims) if blkdim > 0 - @check SDPConeSetASparseVecMat( - m.sdpcone, + @_check SDPConeSetASparseVecMat( + model.sdpcone, blk - 1, i, blkdim, 1.0, 0, - m.sdpdinds[end][blk], - m.sdpdcoefs[end][blk], - length(m.sdpdcoefs[end][blk]), + model.sdpdinds[end][blk], + model.sdpdcoefs[end][blk], + length(model.sdpdcoefs[end][blk]), ) end end return end -function _new_A_matrix(m::Optimizer) - push!(m.sdpdinds, Vector{Cint}[]) - push!(m.sdpdcoefs, Vector{Cdouble}[]) - for i in eachindex(m.blockdims) - if m.blockdims[i] >= 0 - push!(m.sdpdinds[end], Cint[]) - push!(m.sdpdcoefs[end], Cdouble[]) +function _new_A_matrix(model::Optimizer) + push!(model.sdpdinds, Vector{Cint}[]) + push!(model.sdpdcoefs, Vector{Cdouble}[]) + for i in eachindex(model.blockdims) + if model.blockdims[i] >= 0 + push!(model.sdpdinds[end], Cint[]) + push!(model.sdpdcoefs[end], Cdouble[]) end end return @@ -341,8 +340,8 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) @assert MOI.is_empty(dest) index_map = MOI.Utilities.IndexMap() # Step 1) Compute the dimensions of what needs to be allocated - constrain_variables_on_creation(dest, src, index_map, MOI.Nonnegatives) - constrain_variables_on_creation( + _constrain_variables_on_creation(dest, src, index_map, MOI.Nonnegatives) + _constrain_variables_on_creation( dest, src, index_map, @@ -355,9 +354,8 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) "to bridge free variables into `x - y` where `x` and `y` are nonnegative.", ) end - F = MOI.ScalarAffineFunction{Cdouble} - cis_src = - MOI.get(src, MOI.ListOfConstraintIndices{F,MOI.EqualTo{Cdouble}}()) + F, S = MOI.ScalarAffineFunction{Cdouble}, MOI.EqualTo{Float64} + cis_src = MOI.get(src, MOI.ListOfConstraintIndices{F,S}()) if isempty(cis_src) msg = "DSDP does not support problems with no constraint." throw(ArgumentError(msg)) @@ -376,7 +374,7 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) end # Create a new solver object with the correct number of constraints. p = Ref{Ptr{Cvoid}}() - @check DSDPCreate(length(dest.b), p) + @_check DSDPCreate(length(dest.b), p) dest.dsdp = p[] # Set options for (option, value) in dest.options @@ -384,15 +382,15 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) end if num_sdp > 0 sdpcone = Ref{Ptr{Cvoid}}() - @check DSDPCreateSDPCone(dest, num_sdp, sdpcone) + @_check DSDPCreateSDPCone(dest, num_sdp, sdpcone) dest.sdpcone = sdpcone[] for (i, blk_dim) in enumerate(dest.blockdims) if blk_dim < 0 continue # It's an LP block end blk = dest.blk[i] - @check SDPConeSetBlockSize(dest.sdpcone, blk - 1, blk_dim) - @check SDPConeSetStorageFormat(dest.sdpcone, blk - 1, UInt8('U')) + @_check SDPConeSetBlockSize(dest.sdpcone, blk - 1, blk_dim) + @_check SDPConeSetStorageFormat(dest.sdpcone, blk - 1, UInt8('U')) end end # TODO ComputeY0 as in examples/readsdpa.c @@ -400,28 +398,21 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) for (k, ci_src) in enumerate(cis_src) func = MOI.get(src, MOI.CanonicalConstraintFunction(), ci_src) set = MOI.get(src, MOI.ConstraintSet(), ci_src) - if !iszero(MOI.constant(func)) - throw( - MOI.ScalarFunctionConstantNotZero{ - Cdouble, - F, - MOI.EqualTo{Cdouble}, - }( - MOI.constant(func), - ), - ) + f_k = MOI.constant(func) + if !iszero(f_k) + throw(MOI.ScalarFunctionConstantNotZero{Cdouble,F,S}(f_k)) end - @check DSDPSetDualObjective(dest, k, MOI.constant(set)) + @_check DSDPSetDualObjective(dest, k, MOI.constant(set)) _new_A_matrix(dest) for t in func.terms if !iszero(t.coefficient) blk, i, j = dest.varmap[index_map[t.variable].value] - _setcoefficient!(dest, t.coefficient, k, blk, i, j) + _set_coefficient(dest, t.coefficient, k, blk, i, j) end end _set_A_matrices(dest, k) dest.b[k] = MOI.constant(set) - index_map[ci_src] = MOI.ConstraintIndex{F,MOI.EqualTo{Cdouble}}(k) + index_map[ci_src] = MOI.ConstraintIndex{F,S}(k) end # Throw error for variable attributes MOI.Utilities.pass_attributes(dest, src, index_map, vis_src) @@ -448,7 +439,7 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) vi = index_map[term.variable] blk, i, j = dest.varmap[vi.value] coef = dest.objective_sign * term.coefficient - _setcoefficient!(dest, coef, 0, blk, i, j) + _set_coefficient(dest, coef, 0, blk, i, j) end end _set_A_matrices(dest, 0) @@ -456,21 +447,21 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) # Pass info to `dest.dsdp` if !isempty(dest.lpdvars) lpcone = Ref{Ptr{Cvoid}}() - @check DSDPCreateLPCone(dest, lpcone) + @_check DSDPCreateLPCone(dest, lpcone) dest.lpcone = lpcone[] - nnzin, row, aval = _buildlp( + nnzin, row, aval = _build_lp( length(dest.b) + 1, dest.lpdvars, dest.lpdrows, dest.lpcoefs, ) - @check LPConeSetData(dest.lpcone, dest.nlpdrows, nnzin, row, aval) + @_check LPConeSetData(dest.lpcone, dest.nlpdrows, nnzin, row, aval) end - @check DSDPSetup(dest) + @_check DSDPSetup(dest) return index_map end -function _buildlp(nvars, lpdvars, lpdrows, lpcoefs) +function _build_lp(nvars, lpdvars, lpdrows, lpcoefs) @assert length(lpdvars) == length(lpdrows) == length(lpcoefs) nzin = zeros(Cint, nvars) n = length(lpdvars) @@ -493,24 +484,24 @@ function _buildlp(nvars, lpdvars, lpdrows, lpcoefs) return nnzin, row, aval end -function MOI.optimize!(m::Optimizer) - @check DSDPSetStandardMonitor(m, !m.silent ? 1 : 0) - @check DSDPSolve(m) - # Calling `ComputeX` not right after `Solve` seems to sometime cause segfaults or weird Heisenbug's - # let's call it directly what `DSDP/examples/readsdpa.c` does - @check DSDPComputeX(m) - m.y = zeros(Cdouble, length(m.b)) - @check DSDPGetY(m, m.y, length(m.y)) - map!(-, m.y, m.y) # The primal objective is Max in SDOI but Min in DSDP +function MOI.optimize!(model::Optimizer) + @_check DSDPSetStandardMonitor(model, !model.silent ? 1 : 0) + @_check DSDPSolve(model) + # Calling `DSDPComputeX` not right after `DSDPSolve` seems to sometime cause + # segfaults or weird Heisenbug's. Let's call it directly after, like + # `DSDP/examples/readsdpa.c` does + @_check DSDPComputeX(model) + resize!(model.y, length(model.b)) + @_check DSDPGetY(model, model.y, length(model.y)) return end -function MOI.get(m::Optimizer, ::MOI.RawStatusString) - if m.dsdp == C_NULL +function MOI.get(model::Optimizer, ::MOI.RawStatusString) + if model.dsdp == C_NULL return "`optimize!` not called" end stop = Ref{DSDPTerminationReason}() - @check DSDPStopReason(m, stop) + @_check DSDPStopReason(model, stop) status = stop[] if status == DSDP_CONVERGED return "Converged" @@ -534,16 +525,16 @@ function MOI.get(m::Optimizer, ::MOI.RawStatusString) end end -function MOI.get(m::Optimizer, ::MOI.TerminationStatus) - if m.dsdp == C_NULL +function MOI.get(model::Optimizer, ::MOI.TerminationStatus) + if model.dsdp == C_NULL return MOI.OPTIMIZE_NOT_CALLED end stop = Ref{DSDPTerminationReason}() - @check DSDPStopReason(m, stop) + @_check DSDPStopReason(model, stop) status = stop[] if status == DSDP_CONVERGED sol = Ref{DSDPSolutionType}() - @check DSDPGetSolutionType(m, sol) + @_check DSDPGetSolutionType(model, sol) sol_status = sol[] if sol_status == DSDP_PDFEASIBLE return MOI.OPTIMAL @@ -575,12 +566,12 @@ function MOI.get(m::Optimizer, ::MOI.TerminationStatus) end end -function MOI.get(m::Optimizer, attr::MOI.PrimalStatus) - if attr.result_index > MOI.get(m, MOI.ResultCount()) +function MOI.get(model::Optimizer, attr::MOI.PrimalStatus) + if attr.result_index > MOI.get(model, MOI.ResultCount()) return MOI.NO_SOLUTION end sol = Ref{DSDPSolutionType}() - @check DSDPGetSolutionType(m, sol) + @_check DSDPGetSolutionType(model, sol) status = sol[] if status == DSDP_PDUNKNOWN return MOI.UNKNOWN_RESULT_STATUS @@ -594,12 +585,12 @@ function MOI.get(m::Optimizer, attr::MOI.PrimalStatus) end end -function MOI.get(m::Optimizer, attr::MOI.DualStatus) - if attr.result_index > MOI.get(m, MOI.ResultCount()) +function MOI.get(model::Optimizer, attr::MOI.DualStatus) + if attr.result_index > MOI.get(model, MOI.ResultCount()) return MOI.NO_SOLUTION end sol = Ref{DSDPSolutionType}() - @check DSDPGetSolutionType(m, sol) + @_check DSDPGetSolutionType(model, sol) status = sol[] if status == DSDP_PDUNKNOWN return MOI.UNKNOWN_RESULT_STATUS @@ -613,20 +604,20 @@ function MOI.get(m::Optimizer, attr::MOI.DualStatus) end end -MOI.get(m::Optimizer, ::MOI.ResultCount) = m.dsdp == C_NULL ? 0 : 1 +MOI.get(model::Optimizer, ::MOI.ResultCount) = model.dsdp == C_NULL ? 0 : 1 -function MOI.get(m::Optimizer, attr::MOI.ObjectiveValue) - MOI.check_result_index_bounds(m, attr) +function MOI.get(model::Optimizer, attr::MOI.ObjectiveValue) + MOI.check_result_index_bounds(model, attr) ret = Ref{Cdouble}() - @check DSDPGetPPObjective(m, ret) - return m.objective_sign * ret[] + m.objective_constant + @_check DSDPGetPPObjective(model, ret) + return model.objective_sign * ret[] + model.objective_constant end -function MOI.get(m::Optimizer, attr::MOI.DualObjectiveValue) - MOI.check_result_index_bounds(m, attr) +function MOI.get(model::Optimizer, attr::MOI.DualObjectiveValue) + MOI.check_result_index_bounds(model, attr) ret = Ref{Cdouble}() - @check DSDPGetDDObjective(m, ret) - return m.objective_sign * ret[] + m.objective_constant + @_check DSDPGetDDObjective(model, ret) + return model.objective_sign * ret[] + model.objective_constant end abstract type LPBlock <: AbstractMatrix{Cdouble} end @@ -637,7 +628,7 @@ Base.size(x::Union{LPBlock,SDPBlock}) = (x.dim, x.dim) function Base.getindex(x::LPBlock, i, j) if i == j - return get_array(x)[x.offset+i] + return _get_array(x)[x.offset+i] else return zero(Cdouble) end @@ -647,7 +638,7 @@ function Base.getindex(x::SDPBlock, i, j) if i > j return getindex(x, j, i) else - return get_array(x)[MOI.Utilities.trimap(i, j)] + return _get_array(x)[MOI.Utilities.trimap(i, j)] end end @@ -685,7 +676,7 @@ Base.getindex(A::AbstractBlockMatrix, I::Tuple) = getindex(A, I...) abstract type BlockMat <: AbstractBlockMatrix{Cdouble} end -nblocks(x::BlockMat) = length(x.optimizer.blk) +nblocks(x::BlockMat) = length(x.model.blk) struct LPXBlock <: LPBlock lpcone::Ptr{Cvoid} @@ -693,10 +684,10 @@ struct LPXBlock <: LPBlock offset::Int end -function get_array(x::LPXBlock) +function _get_array(x::LPXBlock) xout = Ref{Ptr{Cdouble}}() n = Ref{Cint}() - @check LPConeGetXArray(x.lpcone, xout, n) + @_check LPConeGetXArray(x.lpcone, xout, n) return unsafe_wrap(Array, xout[], n[]) end @@ -706,46 +697,35 @@ struct SDPXBlock <: SDPBlock blockj::Int end -function get_array(x::SDPXBlock) +function _get_array(x::SDPXBlock) xmat = Ref{Ptr{Cdouble}}() nn = Ref{Cint}() - @check SDPConeGetXArray(x.sdpcone, x.blockj - 1, xmat, nn) + @_check SDPConeGetXArray(x.sdpcone, x.blockj - 1, xmat, nn) v = unsafe_wrap(Array, xmat[], nn[]) return [v[i+(j-1)*x.dim] for j in 1:x.dim for i in 1:j] end struct XBlockMat <: BlockMat - optimizer::Optimizer + model::Optimizer end function block(x::XBlockMat, i) - if x.optimizer.blockdims[i] < 0 - LPXBlock( - x.optimizer.lpcone, - abs(x.optimizer.blockdims[i]), - x.optimizer.blk[i], - ) + if x.model.blockdims[i] < 0 + LPXBlock(x.model.lpcone, abs(x.model.blockdims[i]), x.model.blk[i]) else - SDPXBlock( - x.optimizer.sdpcone, - x.optimizer.blockdims[i], - x.optimizer.blk[i], - ) + SDPXBlock(x.model.sdpcone, x.model.blockdims[i], x.model.blk[i]) end end -function block( - optimizer::Optimizer, - ci::MOI.ConstraintIndex{MOI.VectorOfVariables}, -) - return optimizer.varmap[ci.value][1] +function block(model::Optimizer, ci::MOI.ConstraintIndex{MOI.VectorOfVariables}) + return model.varmap[ci.value][1] end -function vectorize_block(M, blk::Integer, ::Type{MOI.Nonnegatives}) +function _vectorize_block(M, blk::Integer, ::Type{MOI.Nonnegatives}) return LinearAlgebra.diag(block(M, blk)) end -function vectorize_block( +function _vectorize_block( M::AbstractMatrix{Cdouble}, blk::Integer, ::Type{MOI.PositiveSemidefiniteConeTriangle}, @@ -766,32 +746,32 @@ function vectorize_block( end function MOI.get( - optimizer::Optimizer, + model::Optimizer, attr::MOI.VariablePrimal, vi::MOI.VariableIndex, ) - MOI.check_result_index_bounds(optimizer, attr) - blk, i, j = optimizer.varmap[vi.value] - return block(XBlockMat(optimizer), blk)[i, j] + MOI.check_result_index_bounds(model, attr) + blk, i, j = model.varmap[vi.value] + return block(XBlockMat(model), blk)[i, j] end function MOI.get( - optimizer::Optimizer, + model::Optimizer, attr::MOI.ConstraintPrimal, ci::MOI.ConstraintIndex{MOI.VectorOfVariables,S}, ) where {S<:Union{MOI.Nonnegatives,MOI.PositiveSemidefiniteConeTriangle}} - MOI.check_result_index_bounds(optimizer, attr) - return vectorize_block(XBlockMat(optimizer), block(optimizer, ci), S) + MOI.check_result_index_bounds(model, attr) + return _vectorize_block(XBlockMat(model), block(model, ci), S) end function MOI.get( - optimizer::Optimizer, + model::Optimizer, attr::MOI.ConstraintDual, ci::MOI.ConstraintIndex{ MOI.ScalarAffineFunction{Cdouble}, MOI.EqualTo{Cdouble}, }, ) - MOI.check_result_index_bounds(optimizer, attr) - return -optimizer.y[ci.value] + MOI.check_result_index_bounds(model, attr) + return model.y[ci.value] end From 51071df29ab02932512c66ed633d9fec6b0dae4d Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Fri, 10 Oct 2025 16:38:27 +1300 Subject: [PATCH 5/9] Update --- test/c_api.jl | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/test/c_api.jl b/test/c_api.jl index ee5fe9a..d8d933c 100644 --- a/test/c_api.jl +++ b/test/c_api.jl @@ -19,7 +19,6 @@ signz(t) = t < 0 ? -1 : 1 # Apply the Goemens and Williamson randomized cut algorithm to the SDP relaxation of the max-cut problem function MaxCutRandomized(sdpcone, nnodes::Integer) ymin = Cdouble(0) - vv = Vector{Cdouble}(undef, nnodes) tt = Vector{Cdouble}(undef, nnodes) cc = Vector{Cdouble}(undef, nnodes + 2) @@ -49,9 +48,7 @@ function maxcut(nnodes, edges) dsdp = p[] DSDP.DSDPCreateSDPCone(dsdp, 1, p) sdpcone = p[] - DSDP.SDPConeSetBlockSize(sdpcone, 0, nnodes) - # Formulate the problem from the data # Diagonal elements equal 1.0 # Create Constraint matrix A_i for i=1, ..., nnodes. @@ -59,7 +56,6 @@ function maxcut(nnodes, edges) diag = ones(Cdouble, nnodes) N = Cint(1):Cint(nnodes) iptr = di.(N) - for i in 1:nnodes DSDP.DSDPSetDualObjective(dsdp, i, 1.0) DSDP.SDPConeSetASparseVecMat( @@ -74,7 +70,6 @@ function maxcut(nnodes, edges) 1, ) end - # C matrix is the Laplacian of the adjacency matrix # Also compute a feasible initial point y such that S >= 0 yy = zeros(nnodes) @@ -91,7 +86,6 @@ function maxcut(nnodes, edges) yy[u] -= abs(w / 2) yy[v] -= abs(w / 2) end - DSDP.SDPConeSetASparseVecMat( sdpcone, 0, @@ -114,14 +108,12 @@ function maxcut(nnodes, edges) pointer(val, nedges + 1), nnodes, ) - # Initial Point DSDP.DSDPSetR0(dsdp, 0.0) DSDP.DSDPSetZBar(dsdp, 10 * tval + 1.0) for i in 1:nnodes DSDP.DSDPSetY0(dsdp, i, 10 * yy[i]) end - # Get read to go DSDP.DSDPSetGapTolerance(dsdp, 0.001) DSDP.DSDPSetPotentialParameter(dsdp, 5) @@ -184,7 +176,6 @@ function test_sdp(tol = 1e-6) DSDP.DSDPGetFinalErrors(dsdp, derr) @test derr != zeros(Cdouble, 6) # To check that it's not just the allocated vector and we actually got the errors @test derr ≈ zeros(Cdouble, 6) atol = tol - # P Infeasible: derr[1] # D Infeasible: derr[3] # Minimal P Eigenvalue: derr[2] @@ -240,7 +231,7 @@ end lpdvars = Cint[3, 3, 2, 2, 1, 3, 1, 1] lpdrows = Cint[2, 0, 1, 0, 0, 1, 1, 2] lpcoefs = Cdouble[-1, 2, 3, 4, 6, 7, 10, 12] - nnzin, row, aval = DSDP._buildlp(3, lpdvars, lpdrows, lpcoefs) + nnzin, row, aval = DSDP._build_lp(3, lpdvars, lpdrows, lpcoefs) @test nnzin isa Vector{Cint} @test nnzin == [0, 3, 5, 8] @test row isa Vector{Cint} From 766ff9cbdd9aa3bbc8d44433ff311aaf4cc0a95a Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Sun, 12 Oct 2025 13:20:57 +1300 Subject: [PATCH 6/9] Update --- src/MOI_wrapper.jl | 67 +++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 5ca1188..4965001 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -705,32 +705,44 @@ function _get_array(x::SDPXBlock) return [v[i+(j-1)*x.dim] for j in 1:x.dim for i in 1:j] end -struct XBlockMat <: BlockMat - model::Optimizer -end - -function block(x::XBlockMat, i) - if x.model.blockdims[i] < 0 - LPXBlock(x.model.lpcone, abs(x.model.blockdims[i]), x.model.blk[i]) - else - SDPXBlock(x.model.sdpcone, x.model.blockdims[i], x.model.blk[i]) +function block(model::Optimizer, i) + if model.blockdims[i] < 0 + return LPXBlock(model.lpcone, abs(model.blockdims[i]), model.blk[i]) end + return SDPXBlock(model.sdpcone, model.blockdims[i], model.blk[i]) end -function block(model::Optimizer, ci::MOI.ConstraintIndex{MOI.VectorOfVariables}) - return model.varmap[ci.value][1] +function MOI.get( + model::Optimizer, + attr::MOI.VariablePrimal, + vi::MOI.VariableIndex, +) + MOI.check_result_index_bounds(model, attr) + blk, i, j = model.varmap[vi.value] + return block(model, blk)[i, j] end -function _vectorize_block(M, blk::Integer, ::Type{MOI.Nonnegatives}) - return LinearAlgebra.diag(block(M, blk)) +function MOI.get( + model::Optimizer, + attr::MOI.ConstraintPrimal, + ci::MOI.ConstraintIndex{MOI.VectorOfVariables,MOI.Nonnegatives}, +) + MOI.check_result_index_bounds(model, attr) + blk = model.varmap[ci.value][1] + return LinearAlgebra.diag(block(model, blk)) end -function _vectorize_block( - M::AbstractMatrix{Cdouble}, - blk::Integer, - ::Type{MOI.PositiveSemidefiniteConeTriangle}, +function MOI.get( + model::Optimizer, + attr::MOI.ConstraintPrimal, + ci::MOI.ConstraintIndex{ + MOI.VectorOfVariables, + MOI.PositiveSemidefiniteConeTriangle, + }, ) - B = block(M, blk) + MOI.check_result_index_bounds(model, attr) + blk = model.varmap[ci.value][1] + B = block(model, blk) d = LinearAlgebra.checksquare(B) n = MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(d)) v = Vector{Cdouble}(undef, n) @@ -745,25 +757,6 @@ function _vectorize_block( return v end -function MOI.get( - model::Optimizer, - attr::MOI.VariablePrimal, - vi::MOI.VariableIndex, -) - MOI.check_result_index_bounds(model, attr) - blk, i, j = model.varmap[vi.value] - return block(XBlockMat(model), blk)[i, j] -end - -function MOI.get( - model::Optimizer, - attr::MOI.ConstraintPrimal, - ci::MOI.ConstraintIndex{MOI.VectorOfVariables,S}, -) where {S<:Union{MOI.Nonnegatives,MOI.PositiveSemidefiniteConeTriangle}} - MOI.check_result_index_bounds(model, attr) - return _vectorize_block(XBlockMat(model), block(model, ci), S) -end - function MOI.get( model::Optimizer, attr::MOI.ConstraintDual, From 84c6c97f3dd0326cc0fde0349087547107dc2ce0 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Sun, 12 Oct 2025 13:45:59 +1300 Subject: [PATCH 7/9] Update --- src/MOI_wrapper.jl | 112 +++++++++++++++------------------------------ 1 file changed, 38 insertions(+), 74 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 4965001..700becb 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -502,28 +502,39 @@ function MOI.get(model::Optimizer, ::MOI.RawStatusString) end stop = Ref{DSDPTerminationReason}() @_check DSDPStopReason(model, stop) - status = stop[] - if status == DSDP_CONVERGED - return "Converged" - elseif status == DSDP_INFEASIBLE_START - return "Infeasible start" - elseif status == DSDP_SMALL_STEPS - return "Small steps" - elseif status == DSDP_INDEFINITE_SCHUR_MATRIX - return "Indefinite Schur matrix" - elseif status == DSDP_MAX_IT - return "Max iteration" - elseif status == DSDP_NUMERICAL_ERROR - return "Numerical error" - elseif status == DSDP_UPPERBOUND - return "Upperbound" - elseif status == DSDP_USER_TERMINATION - return "User termination" - else - @assert status == CONTINUE_ITERATING - return "Continue iterating" - end -end + return string(stop[]) +end + +const _TERMINATION_REASON_MAP = Dict( + DSDP_INFEASIBLE_START => MOI.OTHER_ERROR, + DSDP_SMALL_STEPS => MOI.SLOW_PROGRESS, + DSDP_INDEFINITE_SCHUR_MATRIX => MOI.NUMERICAL_ERROR, + DSDP_MAX_IT => MOI.ITERATION_LIMIT, + DSDP_NUMERICAL_ERROR => MOI.NUMERICAL_ERROR, + DSDP_UPPERBOUND => MOI.OBJECTIVE_LIMIT, + DSDP_USER_TERMINATION => MOI.INTERRUPTED, + CONTINUE_ITERATING => MOI.OTHER_ERROR, +) + +const _SOLUTION_TYPE_MAP = Dict( + DSDP_PDUNKNOWN => ( + MOI.OTHER_ERROR, + MOI.UNKNOWN_RESULT_STATUS, + MOI.UNKNOWN_RESULT_STATUS, + ), + DSDP_PDFEASIBLE => + (MOI.OPTIMAL, MOI.FEASIBLE_POINT, MOI.FEASIBLE_POINT), + DSDP_UNBOUNDED => ( + MOI.INFEASIBLE, + MOI.INFEASIBLE_POINT, + MOI.INFEASIBILITY_CERTIFICATE, + ), + DSDP_INFEASIBLE => ( + MOI.DUAL_INFEASIBLE, + MOI.INFEASIBILITY_CERTIFICATE, + MOI.INFEASIBLE_POINT, + ), +) function MOI.get(model::Optimizer, ::MOI.TerminationStatus) if model.dsdp == C_NULL @@ -531,39 +542,12 @@ function MOI.get(model::Optimizer, ::MOI.TerminationStatus) end stop = Ref{DSDPTerminationReason}() @_check DSDPStopReason(model, stop) - status = stop[] - if status == DSDP_CONVERGED + if stop[] == DSDP_CONVERGED sol = Ref{DSDPSolutionType}() @_check DSDPGetSolutionType(model, sol) - sol_status = sol[] - if sol_status == DSDP_PDFEASIBLE - return MOI.OPTIMAL - elseif sol_status == DSDP_UNBOUNDED - return MOI.INFEASIBLE - elseif sol_status == DSDP_INFEASIBLE - return MOI.DUAL_INFEASIBLE - else - @assert sol_status == DSDP_PDUNKNOWN - return MOI.OTHER_ERROR - end - elseif status == DSDP_INFEASIBLE_START - return MOI.OTHER_ERROR - elseif status == DSDP_SMALL_STEPS - return MOI.SLOW_PROGRESS - elseif status == DSDP_INDEFINITE_SCHUR_MATRIX - return MOI.NUMERICAL_ERROR - elseif status == DSDP_MAX_IT - return MOI.ITERATION_LIMIT - elseif status == DSDP_NUMERICAL_ERROR - return MOI.NUMERICAL_ERROR - elseif status == DSDP_UPPERBOUND - return MOI.OBJECTIVE_LIMIT - elseif status == DSDP_USER_TERMINATION - return MOI.INTERRUPTED - else - @assert status == CONTINUE_ITERATING - return MOI.OTHER_ERROR + return _SOLUTION_TYPE_MAP[sol[]][1] end + return _TERMINATION_REASON_MAP[stop[]] end function MOI.get(model::Optimizer, attr::MOI.PrimalStatus) @@ -572,17 +556,7 @@ function MOI.get(model::Optimizer, attr::MOI.PrimalStatus) end sol = Ref{DSDPSolutionType}() @_check DSDPGetSolutionType(model, sol) - status = sol[] - if status == DSDP_PDUNKNOWN - return MOI.UNKNOWN_RESULT_STATUS - elseif status == DSDP_PDFEASIBLE - return MOI.FEASIBLE_POINT - elseif status == DSDP_UNBOUNDED - return MOI.INFEASIBLE_POINT - else - @assert status == DSDP_INFEASIBLE - return MOI.INFEASIBILITY_CERTIFICATE - end + return _SOLUTION_TYPE_MAP[sol[]][2] end function MOI.get(model::Optimizer, attr::MOI.DualStatus) @@ -591,17 +565,7 @@ function MOI.get(model::Optimizer, attr::MOI.DualStatus) end sol = Ref{DSDPSolutionType}() @_check DSDPGetSolutionType(model, sol) - status = sol[] - if status == DSDP_PDUNKNOWN - return MOI.UNKNOWN_RESULT_STATUS - elseif status == DSDP_PDFEASIBLE - return MOI.FEASIBLE_POINT - elseif status == DSDP_UNBOUNDED - return MOI.INFEASIBILITY_CERTIFICATE - else - @assert status == DSDP_INFEASIBLE - return MOI.INFEASIBLE_POINT - end + return _SOLUTION_TYPE_MAP[sol[]][3] end MOI.get(model::Optimizer, ::MOI.ResultCount) = model.dsdp == C_NULL ? 0 : 1 From 92bfa113d7563b3e8933d9a9ab4fb60432847dd7 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Mon, 13 Oct 2025 09:32:42 +1300 Subject: [PATCH 8/9] Update --- src/MOI_wrapper.jl | 69 ++++++++++++++++++++------------------------- test/MOI_wrapper.jl | 38 ++----------------------- 2 files changed, 33 insertions(+), 74 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 700becb..15815cb 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -157,38 +157,42 @@ function MOI.get(model::Optimizer, attr::MOI.RawOptimizerAttribute) end function MOI.set(model::Optimizer, attr::MOI.RawOptimizerAttribute, value) - if attr.name == "MaxIts" + model.options[attr.name] = value + return +end + +function _set_inner_option(model, name, value) + if name == "MaxIts" @_check DSDPSetMaxIts(model, value) - elseif attr.name == "GapTolerance" + elseif name == "GapTolerance" @_check DSDPSetGapTolerance(model, value) - elseif attr.name == "PNormTolerance" + elseif name == "PNormTolerance" @_check DSDPSetPNormTolerance(model, value) - elseif attr.name == "DualBound" + elseif name == "DualBound" @_check DSDPSetDualBound(model, value) - elseif attr.name == "StepTolerance" + elseif name == "StepTolerance" @_check DSDPSetStepTolerance(model, value) - elseif attr.name == "RTolerance" + elseif name == "RTolerance" @_check DSDPSetRTolerance(model, value) - elseif attr.name == "PTolerance" + elseif name == "PTolerance" @_check DSDPSetPTolerance(model, value) - elseif attr.name == "MaxTrustRadius" + elseif name == "MaxTrustRadius" @_check DSDPSetMaxTrustRadius(model, value) - elseif attr.name == "BarrierParameter" + elseif name == "BarrierParameter" @_check DSDPSetBarrierParameter(model, value) - elseif attr.name == "PotentialParameter" + elseif name == "PotentialParameter" @_check DSDPSetPotentialParameter(model, value) - elseif attr.name == "PenaltyParameter" + elseif name == "PenaltyParameter" @_check DSDPSetPenaltyParameter(model, value) - elseif attr.name == "ReuseMatrix" + elseif name == "ReuseMatrix" @_check DSDPSetReuseMatrix(model, value) - elseif attr.name == "R0" + elseif name == "R0" @_check DSDPSetR0(model, value) - elseif attr.name == "ZBar" + elseif name == "ZBar" @_check DSDPSetZBar(model, value) else throw(MOI.UnsupportedAttribute(attr)) end - model.options[attr.name] = value return end @@ -356,10 +360,6 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) end F, S = MOI.ScalarAffineFunction{Cdouble}, MOI.EqualTo{Float64} cis_src = MOI.get(src, MOI.ListOfConstraintIndices{F,S}()) - if isempty(cis_src) - msg = "DSDP does not support problems with no constraint." - throw(ArgumentError(msg)) - end resize!(dest.b, length(cis_src)) dest.blk = zero(dest.blockdims) num_sdp = 0 @@ -376,9 +376,8 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) p = Ref{Ptr{Cvoid}}() @_check DSDPCreate(length(dest.b), p) dest.dsdp = p[] - # Set options for (option, value) in dest.options - MOI.set(dest, MOI.RawOptimizerAttribute(option), value) + _set_inner_option(dest, option, value) end if num_sdp > 0 sdpcone = Ref{Ptr{Cvoid}}() @@ -393,25 +392,23 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) @_check SDPConeSetStorageFormat(dest.sdpcone, blk - 1, UInt8('U')) end end - # TODO ComputeY0 as in examples/readsdpa.c - empty!(dest.y) for (k, ci_src) in enumerate(cis_src) - func = MOI.get(src, MOI.CanonicalConstraintFunction(), ci_src) - set = MOI.get(src, MOI.ConstraintSet(), ci_src) - f_k = MOI.constant(func) + f = MOI.get(src, MOI.CanonicalConstraintFunction(), ci_src) + s = MOI.get(src, MOI.ConstraintSet(), ci_src) + f_k = MOI.constant(f) if !iszero(f_k) throw(MOI.ScalarFunctionConstantNotZero{Cdouble,F,S}(f_k)) end - @_check DSDPSetDualObjective(dest, k, MOI.constant(set)) + @_check DSDPSetDualObjective(dest, k, MOI.constant(s)) _new_A_matrix(dest) - for t in func.terms + for t in f.terms if !iszero(t.coefficient) blk, i, j = dest.varmap[index_map[t.variable].value] _set_coefficient(dest, t.coefficient, k, blk, i, j) end end _set_A_matrices(dest, k) - dest.b[k] = MOI.constant(set) + dest.b[k] = MOI.constant(s) index_map[ci_src] = MOI.ConstraintIndex{F,S}(k) end # Throw error for variable attributes @@ -524,16 +521,10 @@ const _SOLUTION_TYPE_MAP = Dict( ), DSDP_PDFEASIBLE => (MOI.OPTIMAL, MOI.FEASIBLE_POINT, MOI.FEASIBLE_POINT), - DSDP_UNBOUNDED => ( - MOI.INFEASIBLE, - MOI.INFEASIBLE_POINT, - MOI.INFEASIBILITY_CERTIFICATE, - ), - DSDP_INFEASIBLE => ( - MOI.DUAL_INFEASIBLE, - MOI.INFEASIBILITY_CERTIFICATE, - MOI.INFEASIBLE_POINT, - ), + # DSDP_UNBOUNDED means that (D) is unbounded, so (P) is infeasible + DSDP_UNBOUNDED => (MOI.INFEASIBLE, MOI.NO_SOLUTION, MOI.NO_SOLUTION), + # DSDP_INFEASIBLE means that (D) is infeasible + DSDP_INFEASIBLE => (MOI.DUAL_INFEASIBLE, MOI.NO_SOLUTION, MOI.NO_SOLUTION), ) function MOI.get(model::Optimizer, ::MOI.TerminationStatus) diff --git a/test/MOI_wrapper.jl b/test/MOI_wrapper.jl index ed4a437..4203c24 100644 --- a/test/MOI_wrapper.jl +++ b/test/MOI_wrapper.jl @@ -39,6 +39,7 @@ function test_runtests() MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()), MOI.instantiate(DSDP.Optimizer; with_bridge_type = Float64), ) + MOI.set(model, MOI.RawOptimizerAttribute("PTolerance"), 1e-8) # `Variable.ZerosBridge` makes dual needed by some tests fail. MOI.Bridges.remove_bridge( model.optimizer, @@ -49,7 +50,7 @@ function test_runtests() model, MOI.Test.Config(; rtol = 1e-2, - atol = 1e-2, + atol = 1e-1, exclude = Any[ MOI.ConstraintBasisStatus, MOI.VariableBasisStatus, @@ -58,26 +59,11 @@ function test_runtests() ], ); exclude = Regex[ - # ArgumentError: DSDP does not support problems with no constraint. - # See https://github.com/jump-dev/MathOptInterface.jl/issues/1741#issuecomment-1057286739 - r"test_modification_set_singlevariable_lessthan$", - r"test_solve_optimize_twice$", - r"test_solve_result_index$", - r"test_objective_ObjectiveFunction_constant$", - r"test_objective_ObjectiveFunction_VariableIndex$", + # Error solving with empty problem r"test_objective_FEASIBILITY_SENSE_clears_objective$", - r"test_modification_transform_singlevariable_lessthan$", - r"test_modification_delete_variables_in_a_batch$", - r"test_modification_delete_variable_with_single_variable_obj$", - r"test_modification_const_scalar_objective$", - r"test_modification_coef_scalar_objective$", r"test_attribute_RawStatusString$", r"test_attribute_SolveTimeSec$", r"test_objective_ObjectiveFunction_blank$", - r"test_objective_ObjectiveFunction_duplicate_terms$", - r"test_solve_TerminationStatus_DUAL_INFEASIBLE$", - r"test_DualObjectiveValue_Max_VariableIndex_LessThan$", - r"test_DualObjectiveValue_Min_VariableIndex_GreaterThan$", # TODO investigate # Expression: MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status # Evaluated: MathOptInterface.OPTIMAL == MathOptInterface.INFEASIBLE @@ -102,11 +88,8 @@ function test_runtests() r"test_conic_NormOneCone_VectorOfVariables$", r"test_conic_linear_VectorAffineFunction$", r"test_conic_linear_VectorAffineFunction_2$", - r"test_conic_linear_VectorOfVariables_2$", r"test_constraint_ScalarAffineFunction_Interval$", - r"test_conic_HermitianPositiveSemidefiniteConeTriangle_1$", r"test_constraint_PrimalStart_DualStart_SecondOrderCone$", - r"test_HermitianPSDCone_basic$", # Incorrect objective # See https://github.com/jump-dev/MathOptInterface.jl/issues/1759 r"test_linear_integration$", @@ -117,15 +100,6 @@ function test_runtests() # TODO: inaccurate solution r"test_linear_HyperRectangle_VectorAffineFunction$", r"test_linear_HyperRectangle_VectorOfVariables$", - r"test_HermitianPSDCone_min_t$", - r"test_NormNuclearCone_VectorAffineFunction_with_transform$", - r"test_NormNuclearCone_VectorAffineFunction_without_transform$", - r"test_NormNuclearCone_VectorOfVariables_with_transform$", - r"test_NormNuclearCone_VectorOfVariables_without_transform$", - r"test_NormSpectralCone_VectorAffineFunction_with_transform$", - r"test_NormSpectralCone_VectorAffineFunction_without_transform$", - r"test_NormSpectralCone_VectorOfVariables_with_transform$", - r"test_NormSpectralCone_VectorOfVariables_without_transform$", r"test_conic_GeometricMeanCone_VectorAffineFunction$", r"test_conic_GeometricMeanCone_VectorAffineFunction_2$", r"test_conic_GeometricMeanCone_VectorAffineFunction_3$", @@ -156,12 +130,6 @@ function test_runtests() r"test_conic_SecondOrderCone_Nonnegatives$", r"test_conic_SecondOrderCone_Nonpositives$", r"test_conic_SecondOrderCone_VectorAffineFunction$", - r"test_conic_SecondOrderCone_negative_initial_bound$", - r"test_conic_SecondOrderCone_negative_post_bound$", - r"test_conic_SecondOrderCone_negative_post_bound_2$", - r"test_conic_SecondOrderCone_negative_post_bound_3$", - r"test_conic_SecondOrderCone_no_initial_bound$", - r"test_conic_SecondOrderCone_nonnegative_initial_bound$", r"test_quadratic_constraint_integration$", r"test_linear_variable_open_intervals$", r"test_conic_SecondOrderCone_out_of_order$", From 985e94b026253fe6ee2187ed3064bebbfb3d6001 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Mon, 13 Oct 2025 09:38:14 +1300 Subject: [PATCH 9/9] Update --- src/MOI_wrapper.jl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 15815cb..9a607a3 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -157,6 +157,9 @@ function MOI.get(model::Optimizer, attr::MOI.RawOptimizerAttribute) end function MOI.set(model::Optimizer, attr::MOI.RawOptimizerAttribute, value) + if !MOI.supports(model, attr) + throw(MOI.UnsupportedAttribute(attr)) + end model.options[attr.name] = value return end @@ -188,10 +191,9 @@ function _set_inner_option(model, name, value) @_check DSDPSetReuseMatrix(model, value) elseif name == "R0" @_check DSDPSetR0(model, value) - elseif name == "ZBar" - @_check DSDPSetZBar(model, value) else - throw(MOI.UnsupportedAttribute(attr)) + @assert name == "ZBar" + @_check DSDPSetZBar(model, value) end return end