diff --git a/src/CDDLib.jl b/src/CDDLib.jl index ffecd74..ae3e735 100644 --- a/src/CDDLib.jl +++ b/src/CDDLib.jl @@ -6,35 +6,35 @@ using BinDeps using Polyhedra if isfile(joinpath(dirname(@__FILE__),"..","deps","deps.jl")) - include("../deps/deps.jl") + include("../deps/deps.jl") else - error("CDDLib not properly installed. Please run Pkg.build(\"CDDLib\")") + error("CDDLib not properly installed. Please run Pkg.build(\"CDDLib\")") end macro dd_ccall(f, args...) - quote - ret = ccall(($"dd_$f", libcdd), $(map(esc,args)...)) - ret - end + quote + ret = ccall(($"dd_$f", libcdd), $(map(esc,args)...)) + ret + end end macro ddf_ccall(f, args...) - quote - ret = ccall(($"ddf_$f", libcdd), $(map(esc,args)...)) - ret - end + quote + ret = ccall(($"ddf_$f", libcdd), $(map(esc,args)...)) + ret + end end macro cdd_ccall(f, args...) - quote - ret = ccall(($"$f", libcdd), $(map(esc,args)...)) - ret - end + quote + ret = ccall(($"$f", libcdd), $(map(esc,args)...)) + ret + end end function __init__() - @dd_ccall set_global_constants Void () + @dd_ccall set_global_constants Void () end import Base.convert, Base.push!, Base.eltype, Base.copy diff --git a/src/error.jl b/src/error.jl index 41b39ec..0b7e91e 100644 --- a/src/error.jl +++ b/src/error.jl @@ -17,9 +17,9 @@ error_message = [ "LP cycling", "Numerically inconsistent"] function myerror(err::Cdd_ErrorType) - if err < 0 || err > 17 - error("This should not happen, please report this bug") - elseif err < 17 # 17 means no error - error(error_message[err+1]) - end + if err < 0 || err > 17 + error("This should not happen, please report this bug") + elseif err < 17 # 17 means no error + error(error_message[err+1]) + end end diff --git a/src/lp.jl b/src/lp.jl index 6910ede..018e0de 100644 --- a/src/lp.jl +++ b/src/lp.jl @@ -2,264 +2,264 @@ import MathProgBase importall MathProgBase.SolverInterface mutable struct Cdd_LPSolutionData{T<:MyType} - filename::Cdd_DataFileType - objective::Cdd_LPObjectiveType - solver::Cdd_LPSolverType - m::Cdd_rowrange - d::Cdd_colrange - numbtype::Cdd_NumberType + filename::Cdd_DataFileType + objective::Cdd_LPObjectiveType + solver::Cdd_LPSolverType + m::Cdd_rowrange + d::Cdd_colrange + numbtype::Cdd_NumberType - LPS::Cdd_LPStatusType - # the current solution status - optvalue::T - # optimal value - sol::Cdd_Arow{T} - # primal solution - dsol::Cdd_Arow{T} - # dual solution - nbindex::Cdd_colindex - # current basis represented by nonbasic indices - re::Cdd_rowrange - # row index as a certificate in the case of inconsistency - se::Cdd_colrange - # col index as a certificate in the case of dual inconsistency - pivots0::Clong - pivots1::Clong - pivots2::Clong - pivots3::Clong - pivots4::Clong - # pivots[0]=setup (to find a basis), pivots[1]=PhaseI or Criss-Cross, - # pivots[2]=Phase II, pivots[3]=Anticycling, pivots[4]=GMP postopt. - total_pivots::Clong + LPS::Cdd_LPStatusType + # the current solution status + optvalue::T + # optimal value + sol::Cdd_Arow{T} + # primal solution + dsol::Cdd_Arow{T} + # dual solution + nbindex::Cdd_colindex + # current basis represented by nonbasic indices + re::Cdd_rowrange + # row index as a certificate in the case of inconsistency + se::Cdd_colrange + # col index as a certificate in the case of dual inconsistency + pivots0::Clong + pivots1::Clong + pivots2::Clong + pivots3::Clong + pivots4::Clong + # pivots[0]=setup (to find a basis), pivots[1]=PhaseI or Criss-Cross, + # pivots[2]=Phase II, pivots[3]=Anticycling, pivots[4]=GMP postopt. + total_pivots::Clong end function dd_freelpsolution(lp::Ptr{Cdd_LPSolutionData{Cdouble}}) - @ddf_ccall FreeLPSolution Void (Ptr{Cdd_LPSolutionData{Cdouble}},) lp + @ddf_ccall FreeLPSolution Void (Ptr{Cdd_LPSolutionData{Cdouble}},) lp end function dd_freelpsolution(lp::Ptr{Cdd_LPSolutionData{GMPRational}}) - @dd_ccall FreeLPSolution Void (Ptr{Cdd_LPSolutionData{GMPRational}},) lp + @dd_ccall FreeLPSolution Void (Ptr{Cdd_LPSolutionData{GMPRational}},) lp end mutable struct CDDLPSolution{T<:MyType} - sol::Ptr{Cdd_LPSolutionData{T}} + sol::Ptr{Cdd_LPSolutionData{T}} - function CDDLPSolution{T}(sol::Ptr{Cdd_LPSolutionData{T}}) where {T <: MyType} - s = new{T}(sol) - finalizer(s, myfree) - s - end + function CDDLPSolution{T}(sol::Ptr{Cdd_LPSolutionData{T}}) where {T <: MyType} + s = new{T}(sol) + finalizer(s, myfree) + s + end end CDDLPSolution(sol::Ptr{Cdd_LPSolutionData{T}}) where {T<:MyType} = CDDLPSolution{T}(sol) function myfree(sol::CDDLPSolution) - dd_freelpsolution(sol.sol) + dd_freelpsolution(sol.sol) end function status(sol::CDDLPSolution) - [:Undecided, :Optimal, :Inconsistent, - :DualInconsistent, :StructInconsistent, :StructDualInconsistent, - :Unbounded, :DualUnbounded][unsafe_load(sol.sol).LPS+1] + [:Undecided, :Optimal, :Inconsistent, + :DualInconsistent, :StructInconsistent, :StructDualInconsistent, + :Unbounded, :DualUnbounded][unsafe_load(sol.sol).LPS+1] end function simplestatus(sol::CDDLPSolution) - [:Undecided, :Optimal, :Infeasible, - :Unbounded, :Infeasible, :Unbounded, - :Unbounded, :Infeasible][unsafe_load(sol.sol).LPS+1] + [:Undecided, :Optimal, :Infeasible, + :Unbounded, :Infeasible, :Unbounded, + :Unbounded, :Infeasible][unsafe_load(sol.sol).LPS+1] end function getobjval(sol::CDDLPSolution{GMPRational}) - Rational{Int}(unsafe_load(sol.sol).optvalue) + Rational{Int}(unsafe_load(sol.sol).optvalue) end function getobjval(sol::CDDLPSolution{Cdouble}) - unsafe_load(sol.sol).optvalue + unsafe_load(sol.sol).optvalue end function getsolution(sol::CDDLPSolution{GMPRational}) - soldata = unsafe_load(sol.sol) - solutiontmp = myconvert(Array, soldata.sol, soldata.d) - solution = Array{Rational{BigInt}}(solutiontmp)[2:end] - myfree(solutiontmp) - solution + soldata = unsafe_load(sol.sol) + solutiontmp = myconvert(Array, soldata.sol, soldata.d) + solution = Array{Rational{BigInt}}(solutiontmp)[2:end] + myfree(solutiontmp) + solution end function getsolution(sol::CDDLPSolution{Cdouble}) - soldata = unsafe_load(sol.sol) - solutiontmp = myconvert(Array, soldata.sol, soldata.d) - solutiontmp[2:end] + soldata = unsafe_load(sol.sol) + solutiontmp = myconvert(Array, soldata.sol, soldata.d) + solutiontmp[2:end] end function getconstrduals(sol::CDDLPSolution{GMPRational}) - soldata = unsafe_load(sol.sol) - # -1 because there is the objective - nbindex = myconvert(Array, soldata.nbindex, soldata.d+1) - dsol = myconvert(Array, soldata.dsol, soldata.d+1) - dual = zeros(Rational{BigInt}, soldata.m-1) - for j in 2:soldata.d - if nbindex[j+1] > 0 - dual[nbindex[j+1]] = dsol[j] - end - end - myfree(dsol) - dual + soldata = unsafe_load(sol.sol) + # -1 because there is the objective + nbindex = myconvert(Array, soldata.nbindex, soldata.d+1) + dsol = myconvert(Array, soldata.dsol, soldata.d+1) + dual = zeros(Rational{BigInt}, soldata.m-1) + for j in 2:soldata.d + if nbindex[j+1] > 0 + dual[nbindex[j+1]] = dsol[j] + end + end + myfree(dsol) + dual end function getconstrduals(sol::CDDLPSolution{Cdouble}) - soldata = unsafe_load(sol.sol) - # -1 because there is the objective - nbindex = myconvert(Array, soldata.nbindex, soldata.d+1) - dsol = myconvert(Array, soldata.dsol, soldata.d+1) - dual = zeros(Cdouble, soldata.m-1) - for j in 2:soldata.d - if nbindex[j+1] > 0 - dual[nbindex[j+1]] = dsol[j] - end - end - dual + soldata = unsafe_load(sol.sol) + # -1 because there is the objective + nbindex = myconvert(Array, soldata.nbindex, soldata.d+1) + dsol = myconvert(Array, soldata.dsol, soldata.d+1) + dual = zeros(Cdouble, soldata.m-1) + for j in 2:soldata.d + if nbindex[j+1] > 0 + dual[nbindex[j+1]] = dsol[j] + end + end + dual end mutable struct Cdd_LPData{T<:MyType} - filename::Cdd_DataFileType - objective::Cdd_LPObjectiveType - solver::Cdd_LPSolverType - Homogeneous::Cdd_boolean - # The first column except for the obj row is all zeros. - m::Cdd_rowrange - d::Cdd_colrange - A::Cdd_Amatrix{T} - B::Cdd_Bmatrix{T} - objrow::Cdd_rowrange - rhscol::Cdd_colrange - numbtype::Cdd_NumberType - eqnumber::Cdd_rowrange - # the number of equalities - equalityset::Cdd_rowset + filename::Cdd_DataFileType + objective::Cdd_LPObjectiveType + solver::Cdd_LPSolverType + Homogeneous::Cdd_boolean + # The first column except for the obj row is all zeros. + m::Cdd_rowrange + d::Cdd_colrange + A::Cdd_Amatrix{T} + B::Cdd_Bmatrix{T} + objrow::Cdd_rowrange + rhscol::Cdd_colrange + numbtype::Cdd_NumberType + eqnumber::Cdd_rowrange + # the number of equalities + equalityset::Cdd_rowset - redcheck_extensive::Cdd_boolean - # Apply the extensive redundancy check. - ired::Cdd_rowrange - # the row index for the redundancy checking - redset_extra::Cdd_rowset - # a set of rows that are newly recognized redundan by the extensive search. - redset_accum::Cdd_rowset - # the accumulated set of rows that are recognized redundant - posset_extra::Cdd_rowset - # a set of rows that are recognized non-linearity + redcheck_extensive::Cdd_boolean + # Apply the extensive redundancy check. + ired::Cdd_rowrange + # the row index for the redundancy checking + redset_extra::Cdd_rowset + # a set of rows that are newly recognized redundan by the extensive search. + redset_accum::Cdd_rowset + # the accumulated set of rows that are recognized redundant + posset_extra::Cdd_rowset + # a set of rows that are recognized non-linearity - lexicopivot::Cdd_boolean - # flag to use the lexicogrphic pivot rule (symbolic perturbation). + lexicopivot::Cdd_boolean + # flag to use the lexicogrphic pivot rule (symbolic perturbation). - LPS::Cdd_LPStatusType - # the current solution status - m_alloc::Cdd_rowrange - # the allocated row size of matrix A - d_alloc::Cdd_colrange - # the allocated col size of matrix A - optvalue::T - # optimal value - sol::Cdd_Arow{T} - # primal solution - dsol::Cdd_Arow{T} - # dual solution - nbindex::Cdd_colindex - # current basis represented by nonbasic indices - re::Cdd_rowrange - # row index as a certificate in the case of inconsistency - se::Cdd_colrange - #col index as a certificate in the case of dual inconsistency - pivots0::Clong - pivots1::Clong - pivots2::Clong - pivots3::Clong - pivots4::Clong - # pivots[0]=setup (to find a basis), pivots[1]=PhaseI or Criss-Cross, - # pivots[2]=Phase II, pivots[3]=Anticycling, pivots[4]=GMP postopt. - total_pivots::Clong - use_given_basis::Cint - # switch to indicate the use of the given basis - given_nbindex::Cdd_colindex - # given basis represented by nonbasic indices - starttime::Ctime_t - endtime::Ctime_t + LPS::Cdd_LPStatusType + # the current solution status + m_alloc::Cdd_rowrange + # the allocated row size of matrix A + d_alloc::Cdd_colrange + # the allocated col size of matrix A + optvalue::T + # optimal value + sol::Cdd_Arow{T} + # primal solution + dsol::Cdd_Arow{T} + # dual solution + nbindex::Cdd_colindex + # current basis represented by nonbasic indices + re::Cdd_rowrange + # row index as a certificate in the case of inconsistency + se::Cdd_colrange + #col index as a certificate in the case of dual inconsistency + pivots0::Clong + pivots1::Clong + pivots2::Clong + pivots3::Clong + pivots4::Clong + # pivots[0]=setup (to find a basis), pivots[1]=PhaseI or Criss-Cross, + # pivots[2]=Phase II, pivots[3]=Anticycling, pivots[4]=GMP postopt. + total_pivots::Clong + use_given_basis::Cint + # switch to indicate the use of the given basis + given_nbindex::Cdd_colindex + # given basis represented by nonbasic indices + starttime::Ctime_t + endtime::Ctime_t end function dd_freelpdata(lp::Ptr{Cdd_LPData{Cdouble}}) - @ddf_ccall FreeLPData Void (Ptr{Cdd_LPData{Cdouble}},) lp + @ddf_ccall FreeLPData Void (Ptr{Cdd_LPData{Cdouble}},) lp end function dd_freelpdata(lp::Ptr{Cdd_LPData{GMPRational}}) - @dd_ccall FreeLPData Void (Ptr{Cdd_LPData{GMPRational}},) lp + @dd_ccall FreeLPData Void (Ptr{Cdd_LPData{GMPRational}},) lp end mutable struct CDDLP{T<:MyType} - lp::Ptr{Cdd_LPData{T}} + lp::Ptr{Cdd_LPData{T}} - function CDDLP{T}(lp::Ptr{Cdd_LPData{T}}) where {T <: MyType} - l = new{T}(lp) - finalizer(l, myfree) - l - end + function CDDLP{T}(lp::Ptr{Cdd_LPData{T}}) where {T <: MyType} + l = new{T}(lp) + finalizer(l, myfree) + l + end end CDDLP(lp::Ptr{Cdd_LPData{T}}) where {T<:MyType} = CDDLP{T}(lp) function myfree(lp::CDDLP) - dd_freelpdata(lp.lp) + dd_freelpdata(lp.lp) end function dd_matrix2feasibility(matrix::Ptr{Cdd_MatrixData{Cdouble}}) - err = Ref{Cdd_ErrorType}(0) - lp = (@ddf_ccall Matrix2Feasibility Ptr{Cdd_LPData{Cdouble}} (Ptr{Cdd_MatrixData{Cdouble}}, Ref{Cdd_ErrorType}) matrix err) - myerror(err[]) - lp + err = Ref{Cdd_ErrorType}(0) + lp = (@ddf_ccall Matrix2Feasibility Ptr{Cdd_LPData{Cdouble}} (Ptr{Cdd_MatrixData{Cdouble}}, Ref{Cdd_ErrorType}) matrix err) + myerror(err[]) + lp end function dd_matrix2feasibility(matrix::Ptr{Cdd_MatrixData{GMPRational}}) - err = Ref{Cdd_ErrorType}(0) - lp = (@dd_ccall Matrix2Feasibility Ptr{Cdd_LPData{GMPRational}} (Ptr{Cdd_MatrixData{GMPRational}}, Ref{Cdd_ErrorType}) matrix err) - myerror(err[]) - lp + err = Ref{Cdd_ErrorType}(0) + lp = (@dd_ccall Matrix2Feasibility Ptr{Cdd_LPData{GMPRational}} (Ptr{Cdd_MatrixData{GMPRational}}, Ref{Cdd_ErrorType}) matrix err) + myerror(err[]) + lp end function matrix2feasibility(matrix::CDDInequalityMatrix) - CDDLP(dd_matrix2feasibility(matrix.matrix)) + CDDLP(dd_matrix2feasibility(matrix.matrix)) end function dd_matrix2lp(matrix::Ptr{Cdd_MatrixData{Cdouble}}) - err = Ref{Cdd_ErrorType}(0) - lp = (@ddf_ccall Matrix2LP Ptr{Cdd_LPData{Cdouble}} (Ptr{Cdd_MatrixData{Cdouble}}, Ref{Cdd_ErrorType}) matrix err) - myerror(err[]) - lp + err = Ref{Cdd_ErrorType}(0) + lp = (@ddf_ccall Matrix2LP Ptr{Cdd_LPData{Cdouble}} (Ptr{Cdd_MatrixData{Cdouble}}, Ref{Cdd_ErrorType}) matrix err) + myerror(err[]) + lp end function dd_matrix2lp(matrix::Ptr{Cdd_MatrixData{GMPRational}}) - err = Ref{Cdd_ErrorType}(0) - lp = (@dd_ccall Matrix2LP Ptr{Cdd_LPData{GMPRational}} (Ptr{Cdd_MatrixData{GMPRational}}, Ref{Cdd_ErrorType}) matrix err) - myerror(err[]) - lp + err = Ref{Cdd_ErrorType}(0) + lp = (@dd_ccall Matrix2LP Ptr{Cdd_LPData{GMPRational}} (Ptr{Cdd_MatrixData{GMPRational}}, Ref{Cdd_ErrorType}) matrix err) + myerror(err[]) + lp end function matrix2lp(matrix::CDDInequalityMatrix) - CDDLP(dd_matrix2lp(matrix.matrix)) + CDDLP(dd_matrix2lp(matrix.matrix)) end function dd_lpsolve(lp::Ptr{Cdd_LPData{Cdouble}}, solver::Cdd_LPSolverType) - err = Ref{Cdd_ErrorType}(0) - found = (@ddf_ccall LPSolve Cdd_ErrorType (Ptr{Cdd_LPData{Cdouble}}, Cdd_LPSolverType, Ref{Cdd_ErrorType}) lp solver err) - myerror(err[]) - found + err = Ref{Cdd_ErrorType}(0) + found = (@ddf_ccall LPSolve Cdd_ErrorType (Ptr{Cdd_LPData{Cdouble}}, Cdd_LPSolverType, Ref{Cdd_ErrorType}) lp solver err) + myerror(err[]) + found end function dd_lpsolve(lp::Ptr{Cdd_LPData{GMPRational}}, solver::Cdd_LPSolverType) - err = Ref{Cdd_ErrorType}(0) - found = (@dd_ccall LPSolve Cdd_ErrorType (Ptr{Cdd_LPData{GMPRational}}, Cdd_LPSolverType, Ref{Cdd_ErrorType}) lp solver err) - myerror(err[]) - found + err = Ref{Cdd_ErrorType}(0) + found = (@dd_ccall LPSolve Cdd_ErrorType (Ptr{Cdd_LPData{GMPRational}}, Cdd_LPSolverType, Ref{Cdd_ErrorType}) lp solver err) + myerror(err[]) + found end function lpsolve(lp::CDDLP, solver::Symbol=:DualSimplex) - found = dd_lpsolve(lp.lp, solver == :DualSimplex ? dd_DualSimplex : dd_CrissCross) - if !Bool(found) - error("LP could not be solved") - end + found = dd_lpsolve(lp.lp, solver == :DualSimplex ? dd_DualSimplex : dd_CrissCross) + if !Bool(found) + error("LP could not be solved") + end end function dd_copylpsolution(lp::Ptr{Cdd_LPData{Cdouble}}) - @ddf_ccall CopyLPSolution Ptr{Cdd_LPSolutionData{Cdouble}} (Ptr{Cdd_LPData{Cdouble}},) lp + @ddf_ccall CopyLPSolution Ptr{Cdd_LPSolutionData{Cdouble}} (Ptr{Cdd_LPData{Cdouble}},) lp end function dd_copylpsolution(lp::Ptr{Cdd_LPData{GMPRational}}) - @dd_ccall CopyLPSolution Ptr{Cdd_LPSolutionData{GMPRational}} (Ptr{Cdd_LPData{GMPRational}},) lp + @dd_ccall CopyLPSolution Ptr{Cdd_LPSolutionData{GMPRational}} (Ptr{Cdd_LPData{GMPRational}},) lp end function copylpsolution(lp::CDDLP) - CDDLPSolution(dd_copylpsolution(lp.lp)) + CDDLPSolution(dd_copylpsolution(lp.lp)) end diff --git a/src/mathprogbase.jl b/src/mathprogbase.jl index 0bf0879..ee7044e 100644 --- a/src/mathprogbase.jl +++ b/src/mathprogbase.jl @@ -1,116 +1,116 @@ export CDDPolyhedraModel, CDDSolver mutable struct CDDPolyhedraModel <: AbstractPolyhedraModel - solver_type::Symbol - exact::Bool + solver_type::Symbol + exact::Bool - prob::Nullable{CDDInequalityMatrix} + prob::Nullable{CDDInequalityMatrix} - status - objval - solution - constrsolution - constrduals - infeasibilityray + status + objval + solution + constrsolution + constrduals + infeasibilityray end mutable struct CDDSolver <: AbstractMathProgSolver - solver_type::Symbol - exact::Bool - - function CDDSolver(;solver_type::Symbol=:DualSimplex, exact::Bool=false) - if !(solver_type in [:CrissCross, :DualSimplex]) - error("Invalid solver type, it should be :CrissCross or :DualSimplex") + solver_type::Symbol + exact::Bool + + function CDDSolver(;solver_type::Symbol=:DualSimplex, exact::Bool=false) + if !(solver_type in [:CrissCross, :DualSimplex]) + error("Invalid solver type, it should be :CrissCross or :DualSimplex") + end + new(solver_type, exact) end - new(solver_type, exact) - end end function PolyhedraModel(s::CDDSolver) - CDDPolyhedraModel(s.solver_type, s.exact, nothing, :Undefined, 0, [], [], [], []) + CDDPolyhedraModel(s.solver_type, s.exact, nothing, :Undefined, 0, [], [], [], []) end LinearQuadraticModel(s::CDDSolver) = PolyhedraToLPQPBridge(PolyhedraModel(s)) function loadproblem!(lpm::CDDPolyhedraModel, rep::HRep{N}, obj, sense) where N - T = lpm.exact ? Rational{BigInt} : Float64 - prob = CDDInequalityMatrix{N, T, mytype(T)}(rep) - setobjective(prob, obj, sense) - lpm.prob = prob + T = lpm.exact ? Rational{BigInt} : Float64 + prob = CDDInequalityMatrix{N, T, mytype(T)}(rep) + setobjective(prob, obj, sense) + lpm.prob = prob end nonnull(x) = (x != nothing && !isempty(x)) function optimize!(lpm::CDDPolyhedraModel) - if isnull(lpm.prob) - error("Problem not loaded") - end - prob = get(lpm.prob) - lp = matrix2lp(prob) - lpsolve(lp, lpm.solver_type) - sol = copylpsolution(lp) - lpm.status = simplestatus(sol) - # We have just called lpsolve so it shouldn't be Undecided - # if no error occured - lpm.status == :Undecided && (lpm.status = :Error) - lpm.objval = getobjval(sol) - lpm.solution = getsolution(sol) - - lpm.constrduals = getconstrduals(sol) - # if A has equalities, cddlib splits them as 2 inequalities - m = nhreps(prob) - if length(lpm.constrduals) > m - secondeqduals = lpm.constrduals[m+1:end] - lpm.constrduals = lpm.constrduals[1:m] - lpm.constrduals[collect(linset(prob))] -= secondeqduals - end - # FIXME if A is GMPRational, check that no creation/leak - - T = Polyhedra.coefficienttype(prob) - - lpm.constrsolution = Vector{T}(nhreps(prob)) - lpm.infeasibilityray = zeros(T, nhreps(prob)) - - eps = 1e-7 - for i in 1:nhreps(prob) - a, β = extractrow(prob, i) - lpm.constrsolution[i] = dot(a, lpm.solution) - if Polyhedra._gt(lpm.constrsolution[i], β) - lpm.infeasibilityray[i] = -1 - end - end - - # A and b free'd by ine + if isnull(lpm.prob) + error("Problem not loaded") + end + prob = get(lpm.prob) + lp = matrix2lp(prob) + lpsolve(lp, lpm.solver_type) + sol = copylpsolution(lp) + lpm.status = simplestatus(sol) + # We have just called lpsolve so it shouldn't be Undecided + # if no error occured + lpm.status == :Undecided && (lpm.status = :Error) + lpm.objval = getobjval(sol) + lpm.solution = getsolution(sol) + + lpm.constrduals = getconstrduals(sol) + # if A has equalities, cddlib splits them as 2 inequalities + m = nhreps(prob) + if length(lpm.constrduals) > m + secondeqduals = lpm.constrduals[m+1:end] + lpm.constrduals = lpm.constrduals[1:m] + lpm.constrduals[collect(linset(prob))] -= secondeqduals + end + # FIXME if A is GMPRational, check that no creation/leak + + T = Polyhedra.coefficienttype(prob) + + lpm.constrsolution = Vector{T}(nhreps(prob)) + lpm.infeasibilityray = zeros(T, nhreps(prob)) + + eps = 1e-7 + for i in 1:nhreps(prob) + a, β = extractrow(prob, i) + lpm.constrsolution[i] = dot(a, lpm.solution) + if Polyhedra._gt(lpm.constrsolution[i], β) + lpm.infeasibilityray[i] = -1 + end + end + + # A and b free'd by ine end function status(lpm::CDDPolyhedraModel) - lpm.status + lpm.status end function getobjval(lpm::CDDPolyhedraModel) - lpm.objval + lpm.objval end function getsolution(lpm::CDDPolyhedraModel) - copy(lpm.solution) + copy(lpm.solution) end function getconstrsolution(lpm::CDDPolyhedraModel) - copy(lpm.constrsolution) + copy(lpm.constrsolution) end function getreducedcosts(lpm::CDDPolyhedraModel) - prob = get(lpm.prob) - spzeros(Polyhedra.coefficienttype(prob), fulldim(prob)) + prob = get(lpm.prob) + spzeros(Polyhedra.coefficienttype(prob), fulldim(prob)) end function getconstrduals(lpm::CDDPolyhedraModel) - copy(lpm.constrduals) + copy(lpm.constrduals) end function getinfeasibilityray(lpm::CDDPolyhedraModel) - copy(lpm.infeasibilityray) + copy(lpm.infeasibilityray) end function getunboundedray(lpm::CDDPolyhedraModel) - copy(lpm.solution) + copy(lpm.solution) end diff --git a/src/mytype.jl b/src/mytype.jl index 85c720a..062d3d8 100644 --- a/src/mytype.jl +++ b/src/mytype.jl @@ -3,46 +3,46 @@ import Base.+, Base.-, Base.*, Base.promote_rule, Base.==, Base.zero, Base.zeros # It is immutable so that it is stored by value in the structures # GMPRational and GMPRationalMut and not by reference struct GMPInteger - alloc::Cint - size::Cint - data::Ptr{UInt32} + alloc::Cint + size::Cint + data::Ptr{UInt32} end mutable struct GMPRationalMut - num::GMPInteger - den::GMPInteger - - function GMPRationalMut() - m = new() - ccall((:__gmpq_init, :libgmp), Void, (Ptr{GMPRationalMut},), &m) - # No need to clear anything since the num and den are used by - # the GMPRational that is created - #finalizer(m, _mpq_clear_fn) - m - end + num::GMPInteger + den::GMPInteger + + function GMPRationalMut() + m = new() + ccall((:__gmpq_init, :libgmp), Void, (Ptr{GMPRationalMut},), &m) + # No need to clear anything since the num and den are used by + # the GMPRational that is created + #finalizer(m, _mpq_clear_fn) + m + end end function Base.convert(::Type{GMPRationalMut}, a::Rational{BigInt}) - m = GMPRationalMut() - ccall((:__gmpq_set_num, :libgmp), Void, - (Ptr{GMPRationalMut}, Ptr{BigInt}), &m, &a.num) - ccall((:__gmpq_set_den, :libgmp), Void, - (Ptr{GMPRationalMut}, Ptr{BigInt}), &m, &a.den) - m + m = GMPRationalMut() + ccall((:__gmpq_set_num, :libgmp), Void, + (Ptr{GMPRationalMut}, Ptr{BigInt}), &m, &a.num) + ccall((:__gmpq_set_den, :libgmp), Void, + (Ptr{GMPRationalMut}, Ptr{BigInt}), &m, &a.den) + m end Base.convert(::Type{GMPRationalMut}, a::Rational) = GMPRationalMut(Rational{BigInt}(a)) Base.convert(::Type{GMPRationalMut}, a::AbstractFloat) = GMPRationalMut(Rational(a)) # Can do it faster for Int function GMPRationalMut(a::Int, b::Int) - if b < 0 - a = -a - b = -b - end - m = GMPRationalMut() - ccall((:__gmpq_set_si, :libgmp), Void, - (Ptr{GMPRationalMut}, Clong, Culong), &m, a, b) - m + if b < 0 + a = -a + b = -b + end + m = GMPRationalMut() + ccall((:__gmpq_set_si, :libgmp), Void, + (Ptr{GMPRationalMut}, Clong, Culong), &m, a, b) + m end Base.convert(::Type{GMPRationalMut}, a::Int) = GMPRationalMut(a, 1) Base.convert(::Type{GMPRationalMut}, a::Rational{Int}) = GMPRationalMut(a.num, a.den) @@ -52,21 +52,21 @@ Base.zero(::Type{GMPRationalMut}) = GMPRationalMut(0) # I cannot have a finalizer for an immutable so you are responsibe to free it # if you use it using e.g. myfree define below struct GMPRational <: Real - num::GMPInteger - den::GMPInteger - function GMPRational(m::GMPRationalMut) - r = new(m.num, m.den) - r - end + num::GMPInteger + den::GMPInteger + function GMPRational(m::GMPRationalMut) + r = new(m.num, m.den) + r + end end function myfree(a::Array{Cdouble}) - # nothing to free + # nothing to free end function myfree(a::Array{GMPRational}) - for el in a - ccall((:__gmpq_clear, :libgmp), Void, (Ptr{GMPRational},), &el) - end + for el in a + ccall((:__gmpq_clear, :libgmp), Void, (Ptr{GMPRational},), &el) + end end Base.convert(::Type{GMPRational}, x::GMPRationalMut) = GMPRational(x) @@ -83,49 +83,49 @@ Base.zero(::Type{GMPRational}) = GMPRational(0) # so each element has the same data1 and data2 pointers... # This is why I need to redefine it function Base.zeros(::Type{GMPRational}, dims...) - ret = Array(GMPRational, dims...) - for i in eachindex(ret) - ret[i] = Base.zero(GMPRational) - end - ret + ret = Array(GMPRational, dims...) + for i in eachindex(ret) + ret[i] = Base.zero(GMPRational) + end + ret end function -(a::GMPRational) - m = GMPRationalMut() - ccall((:__gmpq_neg, :libgmp), Void, - (Ptr{GMPRationalMut}, Ptr{GMPRational}), &m, &a) - GMPRational(m) + m = GMPRationalMut() + ccall((:__gmpq_neg, :libgmp), Void, + (Ptr{GMPRationalMut}, Ptr{GMPRational}), &m, &a) + GMPRational(m) end function *(a::GMPRational, b::GMPRational) - m = GMPRationalMut() - ccall((:__gmpq_mul, :libgmp), Void, - (Ptr{GMPRationalMut}, Ptr{GMPRational}, Ptr{GMPRational}), &m, &a, &b) - GMPRational(m) + m = GMPRationalMut() + ccall((:__gmpq_mul, :libgmp), Void, + (Ptr{GMPRationalMut}, Ptr{GMPRational}, Ptr{GMPRational}), &m, &a, &b) + GMPRational(m) end function +(a::GMPRational, b::GMPRational) - m = GMPRationalMut() - ccall((:__gmpq_add, :libgmp), Void, - (Ptr{GMPRationalMut}, Ptr{GMPRational}, Ptr{GMPRational}), &m, &a, &b) - GMPRational(m) + m = GMPRationalMut() + ccall((:__gmpq_add, :libgmp), Void, + (Ptr{GMPRationalMut}, Ptr{GMPRational}, Ptr{GMPRational}), &m, &a, &b) + GMPRational(m) end # Debug function Base.show(io::IO, x::GMPInteger) - show(io, (x.alloc, x.size, unsafe_load(x.data))) + show(io, (x.alloc, x.size, unsafe_load(x.data))) end function Base.show(io::IO, x::GMPRational) - show(io, Rational(x)) + show(io, Rational(x)) end function Base.convert(::Type{Rational{BigInt}}, r::GMPRational) - a = BigInt() - ccall((:__gmpq_get_num, :libgmp), Void, - (Ptr{BigInt}, Ptr{GMPRational}), &a, &r) - b = BigInt() - ccall((:__gmpq_get_den, :libgmp), Void, - (Ptr{BigInt}, Ptr{GMPRational}), &b, &r) - a // b + a = BigInt() + ccall((:__gmpq_get_num, :libgmp), Void, + (Ptr{BigInt}, Ptr{GMPRational}), &a, &r) + b = BigInt() + ccall((:__gmpq_get_den, :libgmp), Void, + (Ptr{BigInt}, Ptr{GMPRational}), &b, &r) + a // b end Base.convert(::Type{Rational}, r::GMPRational) = Base.convert(Rational{BigInt}, r) # I need to define the following conversion because of ambuity with Real -> Bool @@ -154,15 +154,15 @@ polytypefor(::Type{T}) where {T <: PolyType} = T # Used by mathprogbase.jl function myconvert(::Type{Array}, x::Ptr{T}, n) where T<:Union{Cdouble, Clong} - copy(unsafe_wrap(Array, x, n)) + copy(unsafe_wrap(Array, x, n)) end function myconvert(::Type{Array}, x::Ptr{GMPRational}, n) - y = Array{GMPRationalMut, 1}(n) - for i = 1:n - y[i] = GMPRationalMut() - ccall((:__gmpq_set, :libgmp), Void, (Ptr{GMPRationalMut}, Ptr{GMPRational}), pointer_from_objref(y[i]), x+((i-1)*sizeof(GMPRational))) - end - Array{GMPRational}(y) + y = Array{GMPRationalMut, 1}(n) + for i = 1:n + y[i] = GMPRationalMut() + ccall((:__gmpq_set, :libgmp), Void, (Ptr{GMPRationalMut}, Ptr{GMPRational}), pointer_from_objref(y[i]), x+((i-1)*sizeof(GMPRational))) + end + Array{GMPRational}(y) end export MyType, GMPRational diff --git a/src/operations.jl b/src/operations.jl index 8d1ce7b..922f503 100644 --- a/src/operations.jl +++ b/src/operations.jl @@ -1,265 +1,265 @@ function dd_inputappend(poly::Ptr{Cdd_PolyhedraData{Cdouble}}, matrix::Ptr{Cdd_MatrixData{Cdouble}}) - err = Ref{Cdd_ErrorType}(0) - polyptr = Ref{Ptr{Cdd_PolyhedraData{Cdouble}}}(poly) - found = (@ddf_ccall DDInputAppend Cdd_boolean (Ref{Ptr{Cdd_PolyhedraData{Cdouble}}}, Ptr{Cdd_MatrixData{Cdouble}}, Ref{Cdd_ErrorType}) polyptr matrix err) - myerror(err[]) - if !Bool(found) - println("Double description not found") - end - polyptr[] + err = Ref{Cdd_ErrorType}(0) + polyptr = Ref{Ptr{Cdd_PolyhedraData{Cdouble}}}(poly) + found = (@ddf_ccall DDInputAppend Cdd_boolean (Ref{Ptr{Cdd_PolyhedraData{Cdouble}}}, Ptr{Cdd_MatrixData{Cdouble}}, Ref{Cdd_ErrorType}) polyptr matrix err) + myerror(err[]) + if !Bool(found) + println("Double description not found") + end + polyptr[] end function dd_inputappend(poly::Ptr{Cdd_PolyhedraData{GMPRational}}, matrix::Ptr{Cdd_MatrixData{GMPRational}}) - err = Ref{Cdd_ErrorType}(0) - polyptr = Ref{Ptr{Cdd_PolyhedraData{GMPRational}}}(poly) - found = (@dd_ccall DDInputAppend Cdd_boolean (Ref{Ptr{Cdd_PolyhedraData{GMPRational}}}, Ptr{Cdd_MatrixData{GMPRational}}, Ref{Cdd_ErrorType}) polyptr matrix err) - myerror(err[]) - if !Bool(found) - println("Double description not found") # FIXME - end - polyptr[] + err = Ref{Cdd_ErrorType}(0) + polyptr = Ref{Ptr{Cdd_PolyhedraData{GMPRational}}}(poly) + found = (@dd_ccall DDInputAppend Cdd_boolean (Ref{Ptr{Cdd_PolyhedraData{GMPRational}}}, Ptr{Cdd_MatrixData{GMPRational}}, Ref{Cdd_ErrorType}) polyptr matrix err) + myerror(err[]) + if !Bool(found) + println("Double description not found") # FIXME + end + polyptr[] end function Base.push!(poly::CDDPolyhedra{N, T}, ine::CDDInequalityMatrix{N, T}) where {N, T<:PolyType} - if !poly.inequality - switchinputtype!(poly) - end - poly.poly = dd_inputappend(poly.poly, ine.matrix) + if !poly.inequality + switchinputtype!(poly) + end + poly.poly = dd_inputappend(poly.poly, ine.matrix) end function Base.push!(poly::CDDPolyhedra{N, T}, ext::CDDGeneratorMatrix{N, T}) where {N, T<:PolyType} - if poly.inequality - switchinputtype!(poly) - end - poly.poly = dd_inputappend(poly.poly, ext.matrix) + if poly.inequality + switchinputtype!(poly) + end + poly.poly = dd_inputappend(poly.poly, ext.matrix) end function Base.push!(poly::CDDPolyhedra{N,T}, rep::Representation{N,S}) where {N,T,S} - Base.push!(poly, cddmatrix(T, rep)) + Base.push!(poly, cddmatrix(T, rep)) end function dd_matrixappend(matrix1::Ptr{Cdd_MatrixData{Cdouble}}, matrix2::Ptr{Cdd_MatrixData{Cdouble}}) - @ddf_ccall MatrixAppend Ptr{Cdd_MatrixData{Cdouble}} (Ptr{Cdd_MatrixData{Cdouble}}, Ptr{Cdd_MatrixData{Cdouble}}) matrix1 matrix2 + @ddf_ccall MatrixAppend Ptr{Cdd_MatrixData{Cdouble}} (Ptr{Cdd_MatrixData{Cdouble}}, Ptr{Cdd_MatrixData{Cdouble}}) matrix1 matrix2 end function dd_matrixappend(matrix1::Ptr{Cdd_MatrixData{GMPRational}}, matrix2::Ptr{Cdd_MatrixData{GMPRational}}) - @dd_ccall MatrixAppend Ptr{Cdd_MatrixData{GMPRational}} (Ptr{Cdd_MatrixData{GMPRational}}, Ptr{Cdd_MatrixData{GMPRational}}) matrix1 matrix2 + @dd_ccall MatrixAppend Ptr{Cdd_MatrixData{GMPRational}} (Ptr{Cdd_MatrixData{GMPRational}}, Ptr{Cdd_MatrixData{GMPRational}}) matrix1 matrix2 end function matrixappend(matrix1::CDDInequalityMatrix{N, T, S}, matrix2::CDDInequalityMatrix{N, T, S}) where {N, T, S} - CDDInequalityMatrix{N, T, S}(dd_matrixappend(matrix1.matrix, matrix2.matrix)) + CDDInequalityMatrix{N, T, S}(dd_matrixappend(matrix1.matrix, matrix2.matrix)) end function matrixappend(matrix1::CDDGeneratorMatrix{N, T, S}, matrix2::CDDGeneratorMatrix{N, T, S}) where {N, T, S} - CDDGeneratorMatrix{N, T, S}(dd_matrixappend(matrix1.matrix, matrix2.matrix)) + CDDGeneratorMatrix{N, T, S}(dd_matrixappend(matrix1.matrix, matrix2.matrix)) end function matrixappend(matrix::CDDMatrix{N, T}, repr::Representation{N, S}) where {N, S, T} - matrixappend(matrix, cddmatrix(T, repr)) + matrixappend(matrix, cddmatrix(T, repr)) end # Redundant function dd_redundant(matrix::Ptr{Cdd_MatrixData{Cdouble}}, i::Cdd_rowrange, len::Int) - err = Ref{Cdd_ErrorType}(0) - certificate = Array{Cdouble, 1}(len) - found = (@ddf_ccall Redundant Cdd_boolean (Ptr{Cdd_MatrixData{Cdouble}}, Cdd_rowrange, Ptr{Cdouble}, Ref{Cdd_ErrorType}) matrix i certificate err) - myerror(err[]) - (found, certificate) + err = Ref{Cdd_ErrorType}(0) + certificate = Array{Cdouble, 1}(len) + found = (@ddf_ccall Redundant Cdd_boolean (Ptr{Cdd_MatrixData{Cdouble}}, Cdd_rowrange, Ptr{Cdouble}, Ref{Cdd_ErrorType}) matrix i certificate err) + myerror(err[]) + (found, certificate) end function dd_redundant(matrix::Ptr{Cdd_MatrixData{GMPRational}}, i::Cdd_rowrange, len::Int) - err = Ref{Cdd_ErrorType}(0) - certificateGMPRat = zeros(GMPRational, len) - found = (@dd_ccall Redundant Cdd_boolean (Ptr{Cdd_MatrixData{GMPRational}}, Cdd_rowrange, Ptr{GMPRational}, Ref{Cdd_ErrorType}) matrix i certificateGMPRat err) - myerror(err[]) - certificate = Array{Rational{BigInt}}(certificateGMPRat) - # myfree(certificateGMPRat) # disabled due to https://github.com/JuliaPolyhedra/CDDLib.jl/issues/13 - (found, certificate) + err = Ref{Cdd_ErrorType}(0) + certificateGMPRat = zeros(GMPRational, len) + found = (@dd_ccall Redundant Cdd_boolean (Ptr{Cdd_MatrixData{GMPRational}}, Cdd_rowrange, Ptr{GMPRational}, Ref{Cdd_ErrorType}) matrix i certificateGMPRat err) + myerror(err[]) + certificate = Array{Rational{BigInt}}(certificateGMPRat) + # myfree(certificateGMPRat) # disabled due to https://github.com/JuliaPolyhedra/CDDLib.jl/issues/13 + (found, certificate) end function redundant(matrix::CDDMatrix, i::Integer) - if dd_set_member(unsafe_load(matrix.matrix).linset, i) - error("Redundancy check for equality not supported") - end - (found, certificate) = dd_redundant(matrix.matrix, Cdd_rowrange(i), fulldim(matrix)+1) - # FIXME what is the meaning of the first element of the certificate ? - (Bool(found), certificate[2:end]) + if dd_set_member(unsafe_load(matrix.matrix).linset, i) + error("Redundancy check for equality not supported") + end + (found, certificate) = dd_redundant(matrix.matrix, Cdd_rowrange(i), fulldim(matrix)+1) + # FIXME what is the meaning of the first element of the certificate ? + (Bool(found), certificate[2:end]) end function redundant(repr::Representation, i::Integer) - redundant(CDDMatrix(repr), i) + redundant(CDDMatrix(repr), i) end # Redundant rows function dd_redundantrows(matrix::Ptr{Cdd_MatrixData{Cdouble}}) - err = Ref{Cdd_ErrorType}(0) - redundant_list = (@ddf_ccall RedundantRows Ptr{Culong} (Ptr{Cdd_MatrixData{Cdouble}}, Ref{Cdd_ErrorType}) matrix err) - myerror(err[]) - redundant_list + err = Ref{Cdd_ErrorType}(0) + redundant_list = (@ddf_ccall RedundantRows Ptr{Culong} (Ptr{Cdd_MatrixData{Cdouble}}, Ref{Cdd_ErrorType}) matrix err) + myerror(err[]) + redundant_list end function dd_redundantrows(matrix::Ptr{Cdd_MatrixData{GMPRational}}) - err = Ref{Cdd_ErrorType}(0) - redundant_list = (@dd_ccall RedundantRows Ptr{Culong} (Ptr{Cdd_MatrixData{GMPRational}}, Ref{Cdd_ErrorType}) matrix err) - myerror(err[]) - redundant_list + err = Ref{Cdd_ErrorType}(0) + redundant_list = (@dd_ccall RedundantRows Ptr{Culong} (Ptr{Cdd_MatrixData{GMPRational}}, Ref{Cdd_ErrorType}) matrix err) + myerror(err[]) + redundant_list end function redundantrows(matrix::CDDMatrix) - Base.convert(IntSet, CDDSet(dd_redundantrows(matrix.matrix), length(matrix))) + Base.convert(IntSet, CDDSet(dd_redundantrows(matrix.matrix), length(matrix))) end function redundantrows(repr::Representation) - redundantrows(CDDMatrix(repr)) + redundantrows(CDDMatrix(repr)) end # Strictly redundant function dd_sredundant(matrix::Ptr{Cdd_MatrixData{Cdouble}}, i::Cdd_rowrange, len::Int) - err = Ref{Cdd_ErrorType}(0) - certificate = Array{Cdouble, 1}(len) - found = (@ddf_ccall SRedundant Cdd_boolean (Ptr{Cdd_MatrixData{Cdouble}}, Cdd_rowrange, Ptr{Cdouble}, Ref{Cdd_ErrorType}) matrix i certificate err) - myerror(err[]) - (found, certificate) + err = Ref{Cdd_ErrorType}(0) + certificate = Array{Cdouble, 1}(len) + found = (@ddf_ccall SRedundant Cdd_boolean (Ptr{Cdd_MatrixData{Cdouble}}, Cdd_rowrange, Ptr{Cdouble}, Ref{Cdd_ErrorType}) matrix i certificate err) + myerror(err[]) + (found, certificate) end function dd_sredundant(matrix::Ptr{Cdd_MatrixData{GMPRational}}, i::Cdd_rowrange, len::Int) - err = Ref{Cdd_ErrorType}(0) - certificateGMPRat = zeros(GMPRational, len) - found = (@dd_ccall SRedundant Cdd_boolean (Ptr{Cdd_MatrixData{GMPRational}}, Cdd_rowrange, Ptr{GMPRational}, Ref{Cdd_ErrorType}) matrix i certificateGMPRat err) - myerror(err[]) - certificate = Array{Rational{BigInt}}(certificateGMPRat) - # myfree(certificateGMPRat) # disabled due to https://github.com/JuliaPolyhedra/CDDLib.jl/issues/13 - (found, certificate) + err = Ref{Cdd_ErrorType}(0) + certificateGMPRat = zeros(GMPRational, len) + found = (@dd_ccall SRedundant Cdd_boolean (Ptr{Cdd_MatrixData{GMPRational}}, Cdd_rowrange, Ptr{GMPRational}, Ref{Cdd_ErrorType}) matrix i certificateGMPRat err) + myerror(err[]) + certificate = Array{Rational{BigInt}}(certificateGMPRat) + # myfree(certificateGMPRat) # disabled due to https://github.com/JuliaPolyhedra/CDDLib.jl/issues/13 + (found, certificate) end function sredundant(matrix::CDDMatrix, i::Integer) - if dd_set_member(unsafe_load(matrix.matrix).linset, i) - error("Redundancy check for equality not supported") - end - (found, certificate) = dd_sredundant(matrix.matrix, Cdd_rowrange(i), fulldim(matrix)+1) - # FIXME what is the meaning of the first element of the certificate ? 1 for point, 0 for ray ? - (Bool(found), certificate[2:end]) + if dd_set_member(unsafe_load(matrix.matrix).linset, i) + error("Redundancy check for equality not supported") + end + (found, certificate) = dd_sredundant(matrix.matrix, Cdd_rowrange(i), fulldim(matrix)+1) + # FIXME what is the meaning of the first element of the certificate ? 1 for point, 0 for ray ? + (Bool(found), certificate[2:end]) end function sredundant(repr::Representation, i::Integer) - sredundant(CDDMatrix(repr), i) + sredundant(CDDMatrix(repr), i) end function dd_matrixcanonicalize(matrix::Ptr{Cdd_MatrixData{Cdouble}}) - matptr = Ref{Ptr{Cdd_MatrixData{Cdouble}}}(matrix) - impl_linset = Ref{Cdd_rowset}(0) - redset = Ref{Cdd_rowset}(0) - newpos = Ref{Cdd_rowindex}(0) - err = Ref{Cdd_ErrorType}(0) - found = (@ddf_ccall MatrixCanonicalize Cdd_boolean (Ref{Ptr{Cdd_MatrixData{Cdouble}}}, Ref{Cdd_rowset}, Ref{Cdd_rowset}, Ref{Cdd_rowindex}, Ref{Cdd_ErrorType}) matptr impl_linset redset newpos err) - myerror(err[]) - (found, matptr[], impl_linset[], redset[], newpos[]) + matptr = Ref{Ptr{Cdd_MatrixData{Cdouble}}}(matrix) + impl_linset = Ref{Cdd_rowset}(0) + redset = Ref{Cdd_rowset}(0) + newpos = Ref{Cdd_rowindex}(0) + err = Ref{Cdd_ErrorType}(0) + found = (@ddf_ccall MatrixCanonicalize Cdd_boolean (Ref{Ptr{Cdd_MatrixData{Cdouble}}}, Ref{Cdd_rowset}, Ref{Cdd_rowset}, Ref{Cdd_rowindex}, Ref{Cdd_ErrorType}) matptr impl_linset redset newpos err) + myerror(err[]) + (found, matptr[], impl_linset[], redset[], newpos[]) end function dd_matrixcanonicalize(matrix::Ptr{Cdd_MatrixData{GMPRational}}) - matptr = Ref{Ptr{Cdd_MatrixData{GMPRational}}}(matrix) - impl_linset = Ref{Cdd_rowset}(0) - redset = Ref{Cdd_rowset}(0) - newpos = Ref{Cdd_rowindex}(0) - err = Ref{Cdd_ErrorType}(0) - found = (@dd_ccall MatrixCanonicalize Cdd_boolean (Ref{Ptr{Cdd_MatrixData{GMPRational}}}, Ref{Cdd_rowset}, Ref{Cdd_rowset}, Ref{Cdd_rowindex}, Ref{Cdd_ErrorType}) matptr impl_linset redset newpos err) - myerror(err[]) - (found, matptr[], impl_linset[], redset[], newpos[]) + matptr = Ref{Ptr{Cdd_MatrixData{GMPRational}}}(matrix) + impl_linset = Ref{Cdd_rowset}(0) + redset = Ref{Cdd_rowset}(0) + newpos = Ref{Cdd_rowindex}(0) + err = Ref{Cdd_ErrorType}(0) + found = (@dd_ccall MatrixCanonicalize Cdd_boolean (Ref{Ptr{Cdd_MatrixData{GMPRational}}}, Ref{Cdd_rowset}, Ref{Cdd_rowset}, Ref{Cdd_rowindex}, Ref{Cdd_ErrorType}) matptr impl_linset redset newpos err) + myerror(err[]) + (found, matptr[], impl_linset[], redset[], newpos[]) end function canonicalize!(matrix::CDDMatrix) - iszero(length(matrix)) && return # See https://github.com/JuliaPolyhedra/CDDLib.jl/issues/24 - (found, matrix.matrix, impl_linset, redset, newpos) = dd_matrixcanonicalize(matrix.matrix) - if !Bool(found) - error("Canonicalization not found") - end - (impl_linset, redset, newpos) # TODO transform and free + iszero(length(matrix)) && return # See https://github.com/JuliaPolyhedra/CDDLib.jl/issues/24 + (found, matrix.matrix, impl_linset, redset, newpos) = dd_matrixcanonicalize(matrix.matrix) + if !Bool(found) + error("Canonicalization not found") + end + (impl_linset, redset, newpos) # TODO transform and free end function dd_matrixcanonicalizelinearity(matrix::Ptr{Cdd_MatrixData{Cdouble}}) - matptr = Ref{Ptr{Cdd_MatrixData{Cdouble}}}(matrix) - impl_linset = Ref{Cdd_rowset}(0) - redset = Ref{Cdd_rowset}(0) - newpos = Ref{Cdd_rowindex}(0) - err = Ref{Cdd_ErrorType}(0) - found = (@ddf_ccall MatrixCanonicalizeLinearity Cdd_boolean (Ref{Ptr{Cdd_MatrixData{Cdouble}}}, Ref{Cdd_rowset}, Ref{Cdd_rowindex}, Ref{Cdd_ErrorType}) matptr impl_linset newpos err) - myerror(err[]) - (found, matptr[], impl_linset[], newpos[]) + matptr = Ref{Ptr{Cdd_MatrixData{Cdouble}}}(matrix) + impl_linset = Ref{Cdd_rowset}(0) + redset = Ref{Cdd_rowset}(0) + newpos = Ref{Cdd_rowindex}(0) + err = Ref{Cdd_ErrorType}(0) + found = (@ddf_ccall MatrixCanonicalizeLinearity Cdd_boolean (Ref{Ptr{Cdd_MatrixData{Cdouble}}}, Ref{Cdd_rowset}, Ref{Cdd_rowindex}, Ref{Cdd_ErrorType}) matptr impl_linset newpos err) + myerror(err[]) + (found, matptr[], impl_linset[], newpos[]) end function dd_matrixcanonicalizelinearity(matrix::Ptr{Cdd_MatrixData{GMPRational}}) - matptr = Ref{Ptr{Cdd_MatrixData{GMPRational}}}(matrix) - impl_linset = Ref{Cdd_rowset}(0) - redset = Ref{Cdd_rowset}(0) - newpos = Ref{Cdd_rowindex}(0) - err = Ref{Cdd_ErrorType}(0) - found = (@dd_ccall MatrixCanonicalizeLinearity Cdd_boolean (Ref{Ptr{Cdd_MatrixData{GMPRational}}}, Ref{Cdd_rowset}, Ref{Cdd_rowindex}, Ref{Cdd_ErrorType}) matptr impl_linset newpos err) - myerror(err[]) - (found, matptr[], impl_linset[], newpos[]) + matptr = Ref{Ptr{Cdd_MatrixData{GMPRational}}}(matrix) + impl_linset = Ref{Cdd_rowset}(0) + redset = Ref{Cdd_rowset}(0) + newpos = Ref{Cdd_rowindex}(0) + err = Ref{Cdd_ErrorType}(0) + found = (@dd_ccall MatrixCanonicalizeLinearity Cdd_boolean (Ref{Ptr{Cdd_MatrixData{GMPRational}}}, Ref{Cdd_rowset}, Ref{Cdd_rowindex}, Ref{Cdd_ErrorType}) matptr impl_linset newpos err) + myerror(err[]) + (found, matptr[], impl_linset[], newpos[]) end function canonicalizelinearity!(matrix::CDDMatrix) - (found, matrix.matrix, impl_linset, newpos) = dd_matrixcanonicalizelinearity(matrix.matrix) - if !Bool(found) - error("Linearity canonicalization not found") - end - (impl_linset, newpos) # TODO transform and free + (found, matrix.matrix, impl_linset, newpos) = dd_matrixcanonicalizelinearity(matrix.matrix) + if !Bool(found) + error("Linearity canonicalization not found") + end + (impl_linset, newpos) # TODO transform and free end function dd_matrixredundancyremove(matrix::Ptr{Cdd_MatrixData{Cdouble}}) - matptr = Ref{Ptr{Cdd_MatrixData{Cdouble}}}(matrix) - redset = Ref{Cdd_rowset}(0) - newpos = Ref{Cdd_rowindex}(0) - err = Ref{Cdd_ErrorType}(0) - found = (@ddf_ccall MatrixRedundancyRemove Cdd_boolean (Ref{Ptr{Cdd_MatrixData{Cdouble}}}, Ref{Cdd_rowset}, Ref{Cdd_rowindex}, Ref{Cdd_ErrorType}) matptr redset newpos err) - myerror(err[]) - (found, matptr[], redset[], newpos[]) + matptr = Ref{Ptr{Cdd_MatrixData{Cdouble}}}(matrix) + redset = Ref{Cdd_rowset}(0) + newpos = Ref{Cdd_rowindex}(0) + err = Ref{Cdd_ErrorType}(0) + found = (@ddf_ccall MatrixRedundancyRemove Cdd_boolean (Ref{Ptr{Cdd_MatrixData{Cdouble}}}, Ref{Cdd_rowset}, Ref{Cdd_rowindex}, Ref{Cdd_ErrorType}) matptr redset newpos err) + myerror(err[]) + (found, matptr[], redset[], newpos[]) end function dd_matrixredundancyremove(matrix::Ptr{Cdd_MatrixData{GMPRational}}) - matptr = Ref{Ptr{Cdd_MatrixData{GMPRational}}}(matrix) - redset = Ref{Cdd_rowset}(0) - newpos = Ref{Cdd_rowindex}(0) - err = Ref{Cdd_ErrorType}(0) - found = (@dd_ccall MatrixRedundancyRemove Cdd_boolean (Ref{Ptr{Cdd_MatrixData{GMPRational}}}, Ref{Cdd_rowset}, Ref{Cdd_rowindex}, Ref{Cdd_ErrorType}) matptr redset newpos err) - myerror(err[]) - (found, matptr[], redset[], newpos[]) + matptr = Ref{Ptr{Cdd_MatrixData{GMPRational}}}(matrix) + redset = Ref{Cdd_rowset}(0) + newpos = Ref{Cdd_rowindex}(0) + err = Ref{Cdd_ErrorType}(0) + found = (@dd_ccall MatrixRedundancyRemove Cdd_boolean (Ref{Ptr{Cdd_MatrixData{GMPRational}}}, Ref{Cdd_rowset}, Ref{Cdd_rowindex}, Ref{Cdd_ErrorType}) matptr redset newpos err) + myerror(err[]) + (found, matptr[], redset[], newpos[]) end function redundancyremove!(matrix::CDDMatrix) - (found, matrix.matrix, redset, newpos) = dd_matrixredundancyremove(matrix.matrix) - if !Bool(found) - error("Redundancy removal not found") - end - (redset, newpos) # TODO transform and free + (found, matrix.matrix, redset, newpos) = dd_matrixredundancyremove(matrix.matrix) + if !Bool(found) + error("Redundancy removal not found") + end + (redset, newpos) # TODO transform and free end # Fourier Elimination function dd_fourierelimination(matrix::Ptr{Cdd_MatrixData{Cdouble}}) - err = Ref{Cdd_ErrorType}(0) - newmatrix = (@ddf_ccall FourierElimination Ptr{Cdd_MatrixData{Cdouble}} (Ptr{Cdd_MatrixData{Cdouble}}, Ref{Cdd_ErrorType}) matrix err) - myerror(err[]) - newmatrix + err = Ref{Cdd_ErrorType}(0) + newmatrix = (@ddf_ccall FourierElimination Ptr{Cdd_MatrixData{Cdouble}} (Ptr{Cdd_MatrixData{Cdouble}}, Ref{Cdd_ErrorType}) matrix err) + myerror(err[]) + newmatrix end function dd_fourierelimination(matrix::Ptr{Cdd_MatrixData{GMPRational}}) - err = Ref{Cdd_ErrorType}(0) - newmatrix = (@dd_ccall FourierElimination Ptr{Cdd_MatrixData{GMPRational}} (Ptr{Cdd_MatrixData{GMPRational}}, Ref{Cdd_ErrorType}) matrix err) - myerror(err[]) - newmatrix + err = Ref{Cdd_ErrorType}(0) + newmatrix = (@dd_ccall FourierElimination Ptr{Cdd_MatrixData{GMPRational}} (Ptr{Cdd_MatrixData{GMPRational}}, Ref{Cdd_ErrorType}) matrix err) + myerror(err[]) + newmatrix end function fourierelimination(matrix::CDDInequalityMatrix{N, T, S}) where {N, T, S} - CDDInequalityMatrix{N-1, T, S}(dd_fourierelimination(matrix.matrix)) + CDDInequalityMatrix{N-1, T, S}(dd_fourierelimination(matrix.matrix)) end function fourierelimination(ine::HRepresentation) - fourierelimination(CDDInequalityMatrix(ine)) + fourierelimination(CDDInequalityMatrix(ine)) end # Block Elimination function dd_blockelimination(matrix::Ptr{Cdd_MatrixData{Cdouble}}, delset::Cdd_colset) - err = Ref{Cdd_ErrorType}(0) - newmatrix = (@ddf_ccall BlockElimination Ptr{Cdd_MatrixData{Cdouble}} (Ptr{Cdd_MatrixData{Cdouble}}, Cdd_colset, Ref{Cdd_ErrorType}) matrix delset err) - myerror(err[]) - newmatrix + err = Ref{Cdd_ErrorType}(0) + newmatrix = (@ddf_ccall BlockElimination Ptr{Cdd_MatrixData{Cdouble}} (Ptr{Cdd_MatrixData{Cdouble}}, Cdd_colset, Ref{Cdd_ErrorType}) matrix delset err) + myerror(err[]) + newmatrix end function dd_blockelimination(matrix::Ptr{Cdd_MatrixData{GMPRational}}, delset::Cdd_colset) - err = Ref{Cdd_ErrorType}(0) - newmatrix = (@dd_ccall BlockElimination Ptr{Cdd_MatrixData{GMPRational}} (Ptr{Cdd_MatrixData{GMPRational}}, Cdd_colset, Ref{Cdd_ErrorType}) matrix delset err) - myerror(err[]) - newmatrix + err = Ref{Cdd_ErrorType}(0) + newmatrix = (@dd_ccall BlockElimination Ptr{Cdd_MatrixData{GMPRational}} (Ptr{Cdd_MatrixData{GMPRational}}, Cdd_colset, Ref{Cdd_ErrorType}) matrix delset err) + myerror(err[]) + newmatrix end function blockelimination(matrix::CDDInequalityMatrix{N, T, S}, delset=IntSet([N])) where {N, T, S} - if last(delset) > N - error("Invalid variable to eliminate") - end - # offset of 1 because 1 is for the first column of the matrix - # (indicating the linearity) so 2 is the first dimension - CDDInequalityMatrix{N-length(delset), T, S}(dd_blockelimination(matrix.matrix, CDDSet(delset, N+1, 1).s)) + if last(delset) > N + error("Invalid variable to eliminate") + end + # offset of 1 because 1 is for the first column of the matrix + # (indicating the linearity) so 2 is the first dimension + CDDInequalityMatrix{N-length(delset), T, S}(dd_blockelimination(matrix.matrix, CDDSet(delset, N+1, 1).s)) end function blockelimination(ine::HRepresentation, delset=IntSet([fulldim(ine)])) - blockelimination(Base.convert(CDDInequalityMatrix, ine), delset) + blockelimination(Base.convert(CDDInequalityMatrix, ine), delset) end export redundant, redundantrows, sredundant, fourierelimination, blockelimination, canonicalize!, redundancyremove! diff --git a/src/polyhedra.jl b/src/polyhedra.jl index 83a30a7..2fd7c52 100644 --- a/src/polyhedra.jl +++ b/src/polyhedra.jl @@ -1,125 +1,125 @@ mutable struct Cdd_PolyhedraData{T<:MyType} - representation::Cdd_RepresentationType - # given representation - homogeneous::Cdd_boolean - d::Cdd_colrange - m::Cdd_rowrange - A::Cdd_Amatrix{T} - # Inequality System: m times d matrix - numbtype::Cdd_NumberType - child::Ptr{Void} # dd_ConePtr - # pointing to the homogenized cone data - m_alloc::Cdd_rowrange - # allocated row size of matrix A - d_alloc::Cdd_colrange - # allocated col size of matrix A - c::Cdd_Arow{T} - # cost vector - - EqualityIndex::Cdd_rowflag - # ith component is 1 if it is equality, -1 if it is strict inequality, 0 otherwise. - - IsEmpty::Cdd_boolean - # This is to tell whether the set is empty or not - - NondegAssumed::Cdd_boolean - InitBasisAtBottom::Cdd_boolean - RestrictedEnumeration::Cdd_boolean - RelaxedEnumeration::Cdd_boolean - - m1::Cdd_rowrange - # = m or m+1 (when representation=Inequality && !homogeneous) - # This data is written after dd_ConeDataLoad is called. This - # determines the size of Ainc. - AincGenerated::Cdd_boolean - # Indicates whether Ainc, Ared, Adom are all computed. - # All the variables below are valid only when this is TRUE - ldim::Cdd_colrange - # linearity dimension - n::Cdd_bigrange - # the size of output = total number of rays - # in the computed cone + linearity dimension - Ainc::Cdd_Aincidence - # incidence of input and output - Ared::Cdd_rowset - # redundant set of rows whose removal results in a minimal system - Adom::Cdd_rowset - # dominant set of rows (those containing all rays). + representation::Cdd_RepresentationType + # given representation + homogeneous::Cdd_boolean + d::Cdd_colrange + m::Cdd_rowrange + A::Cdd_Amatrix{T} + # Inequality System: m times d matrix + numbtype::Cdd_NumberType + child::Ptr{Void} # dd_ConePtr + # pointing to the homogenized cone data + m_alloc::Cdd_rowrange + # allocated row size of matrix A + d_alloc::Cdd_colrange + # allocated col size of matrix A + c::Cdd_Arow{T} + # cost vector + + EqualityIndex::Cdd_rowflag + # ith component is 1 if it is equality, -1 if it is strict inequality, 0 otherwise. + + IsEmpty::Cdd_boolean + # This is to tell whether the set is empty or not + + NondegAssumed::Cdd_boolean + InitBasisAtBottom::Cdd_boolean + RestrictedEnumeration::Cdd_boolean + RelaxedEnumeration::Cdd_boolean + + m1::Cdd_rowrange + # = m or m+1 (when representation=Inequality && !homogeneous) + # This data is written after dd_ConeDataLoad is called. This + # determines the size of Ainc. + AincGenerated::Cdd_boolean + # Indicates whether Ainc, Ared, Adom are all computed. + # All the variables below are valid only when this is TRUE + ldim::Cdd_colrange + # linearity dimension + n::Cdd_bigrange + # the size of output = total number of rays + # in the computed cone + linearity dimension + Ainc::Cdd_Aincidence + # incidence of input and output + Ared::Cdd_rowset + # redundant set of rows whose removal results in a minimal system + Adom::Cdd_rowset + # dominant set of rows (those containing all rays). end function dd_matrix2poly(matrix::Ptr{Cdd_MatrixData{Cdouble}}) - err = Ref{Cdd_ErrorType}(0) - poly = @ddf_ccall DDMatrix2Poly Ptr{Cdd_PolyhedraData{Cdouble}} (Ptr{Cdd_MatrixData{Cdouble}}, Ref{Cdd_ErrorType}) matrix err - myerror(err[]) - poly + err = Ref{Cdd_ErrorType}(0) + poly = @ddf_ccall DDMatrix2Poly Ptr{Cdd_PolyhedraData{Cdouble}} (Ptr{Cdd_MatrixData{Cdouble}}, Ref{Cdd_ErrorType}) matrix err + myerror(err[]) + poly end function dd_matrix2poly(matrix::Ptr{Cdd_MatrixData{GMPRational}}) - err = Ref{Cdd_ErrorType}(0) - poly = @dd_ccall DDMatrix2Poly Ptr{Cdd_PolyhedraData{GMPRational}} (Ptr{Cdd_MatrixData{GMPRational}}, Ref{Cdd_ErrorType}) matrix err - myerror(err[]) - poly + err = Ref{Cdd_ErrorType}(0) + poly = @dd_ccall DDMatrix2Poly Ptr{Cdd_PolyhedraData{GMPRational}} (Ptr{Cdd_MatrixData{GMPRational}}, Ref{Cdd_ErrorType}) matrix err + myerror(err[]) + poly end mutable struct CDDPolyhedra{N, T<:PolyType, S} - poly::Ptr{Cdd_PolyhedraData{S}} - inequality::Bool # The input type is inequality + poly::Ptr{Cdd_PolyhedraData{S}} + inequality::Bool # The input type is inequality - function CDDPolyhedra{N, T, S}(matrix::CDDMatrix{N, T}) where {N, T <: PolyType, S} - polyptr = dd_matrix2poly(matrix.matrix) - poly = new{N, T, S}(polyptr, isaninequalityrepresentation(matrix)) - finalizer(poly, myfree) - poly - end + function CDDPolyhedra{N, T, S}(matrix::CDDMatrix{N, T}) where {N, T <: PolyType, S} + polyptr = dd_matrix2poly(matrix.matrix) + poly = new{N, T, S}(polyptr, isaninequalityrepresentation(matrix)) + finalizer(poly, myfree) + poly + end end function myfree(poly::CDDPolyhedra{N, Cdouble}) where N - @ddf_ccall FreePolyhedra Void (Ptr{Cdd_PolyhedraData{Cdouble}},) poly.poly + @ddf_ccall FreePolyhedra Void (Ptr{Cdd_PolyhedraData{Cdouble}},) poly.poly end function myfree(poly::CDDPolyhedra{N, Rational{BigInt}}) where N - @dd_ccall FreePolyhedra Void (Ptr{Cdd_PolyhedraData{GMPRational}},) poly.poly + @dd_ccall FreePolyhedra Void (Ptr{Cdd_PolyhedraData{GMPRational}},) poly.poly end CDDPolyhedra(matrix::CDDMatrix{N, T, S}) where {N, T, S} = CDDPolyhedra{N, T, S}(matrix) CDDPolyhedra(rep::Representation) = CDDPolyhedra(CDDMatrix(rep)) function Base.convert(::Type{CDDPolyhedra{N, T, S}}, matrix::CDDMatrix{N, T, S}) where {N, T, S} - CDDPolyhedra{N, T, S}(matrix) + CDDPolyhedra{N, T, S}(matrix) end Base.convert(::Type{CDDPolyhedra{N, T, S}}, repr::Representation{N, T}) where {N, T, S} = CDDPolyhedra(CDDMatrix(repr)) function dd_copyinequalities(poly::Ptr{Cdd_PolyhedraData{Cdouble}}) - @ddf_ccall CopyInequalities Ptr{Cdd_MatrixData{Cdouble}} (Ptr{Cdd_PolyhedraData{Cdouble}},) poly + @ddf_ccall CopyInequalities Ptr{Cdd_MatrixData{Cdouble}} (Ptr{Cdd_PolyhedraData{Cdouble}},) poly end function dd_copyinequalities(poly::Ptr{Cdd_PolyhedraData{GMPRational}}) - @dd_ccall CopyInequalities Ptr{Cdd_MatrixData{GMPRational}} (Ptr{Cdd_PolyhedraData{GMPRational}},) poly + @dd_ccall CopyInequalities Ptr{Cdd_MatrixData{GMPRational}} (Ptr{Cdd_PolyhedraData{GMPRational}},) poly end function copyinequalities(poly::CDDPolyhedra) - CDDInequalityMatrix(dd_copyinequalities(poly.poly)) + CDDInequalityMatrix(dd_copyinequalities(poly.poly)) end function dd_copygenerators(poly::Ptr{Cdd_PolyhedraData{Cdouble}}) - @ddf_ccall CopyGenerators Ptr{Cdd_MatrixData{Cdouble}} (Ptr{Cdd_PolyhedraData{Cdouble}},) poly + @ddf_ccall CopyGenerators Ptr{Cdd_MatrixData{Cdouble}} (Ptr{Cdd_PolyhedraData{Cdouble}},) poly end function dd_copygenerators(poly::Ptr{Cdd_PolyhedraData{GMPRational}}) - @dd_ccall CopyGenerators Ptr{Cdd_MatrixData{GMPRational}} (Ptr{Cdd_PolyhedraData{GMPRational}},) poly + @dd_ccall CopyGenerators Ptr{Cdd_MatrixData{GMPRational}} (Ptr{Cdd_PolyhedraData{GMPRational}},) poly end function copygenerators(poly::CDDPolyhedra) - CDDGeneratorMatrix(dd_copygenerators(poly.poly)) + CDDGeneratorMatrix(dd_copygenerators(poly.poly)) end function switchinputtype!(poly::CDDPolyhedra) - if poly.inequality - ext = copygenerators(poly) - myfree(poly) - poly.poly = dd_matrix2poly(ext.matrix) - else - ine = copyinequalities(poly) - myfree(poly) - poly.poly = dd_matrix2poly(ine.matrix) - end - poly.inequality = ~poly.inequality + if poly.inequality + ext = copygenerators(poly) + myfree(poly) + poly.poly = dd_matrix2poly(ext.matrix) + else + ine = copyinequalities(poly) + myfree(poly) + poly.poly = dd_matrix2poly(ine.matrix) + end + poly.inequality = ~poly.inequality end export CDDPolyhedra, copyinequalities, copygenerators, switchinputtype! diff --git a/src/polyhedron.jl b/src/polyhedron.jl index e97a593..b8c9d3c 100644 --- a/src/polyhedron.jl +++ b/src/polyhedron.jl @@ -1,36 +1,36 @@ export CDDLibrary, CDDPolyhedron struct CDDLibrary <: PolyhedraLibrary - precision::Symbol + precision::Symbol - function CDDLibrary(precision::Symbol=:float) - if !(precision in [:float, :exact]) - error("Invalid precision, it should be :float or :exact") + function CDDLibrary(precision::Symbol=:float) + if !(precision in [:float, :exact]) + error("Invalid precision, it should be :float or :exact") + end + new(precision) end - new(precision) - end end Polyhedra.similar_library(::CDDLibrary, ::FullDim, ::Type{T}) where T<:Union{Integer,Rational} = CDDLibrary(:exact) Polyhedra.similar_library(::CDDLibrary, ::FullDim, ::Type{T}) where T<:AbstractFloat = CDDLibrary(:float) mutable struct CDDPolyhedron{N, T<:PolyType} <: Polyhedron{N, T} - ine::Nullable{CDDInequalityMatrix{N,T}} - ext::Nullable{CDDGeneratorMatrix{N,T}} - poly::Nullable{CDDPolyhedra{N,T}} - hlinearitydetected::Bool - vlinearitydetected::Bool - noredundantinequality::Bool - noredundantgenerator::Bool + ine::Nullable{CDDInequalityMatrix{N,T}} + ext::Nullable{CDDGeneratorMatrix{N,T}} + poly::Nullable{CDDPolyhedra{N,T}} + hlinearitydetected::Bool + vlinearitydetected::Bool + noredundantinequality::Bool + noredundantgenerator::Bool - function CDDPolyhedron{N, T}(ine::CDDInequalityMatrix) where {N, T <: PolyType} - new{N, T}(ine, nothing, nothing, false, false, false, false) - end - function CDDPolyhedron{N, T}(ext::CDDGeneratorMatrix) where {N, T <: PolyType} - new{N, T}(nothing, ext, nothing, false, false, false, false) - end -# function CDDPolyhedron(poly::CDDPolyhedra{T}) -# new(nothing, nothing, poly) -# end + function CDDPolyhedron{N, T}(ine::CDDInequalityMatrix) where {N, T <: PolyType} + new{N, T}(ine, nothing, nothing, false, false, false, false) + end + function CDDPolyhedron{N, T}(ext::CDDGeneratorMatrix) where {N, T <: PolyType} + new{N, T}(nothing, ext, nothing, false, false, false, false) + end + # function CDDPolyhedron(poly::CDDPolyhedra{T}) + # new(nothing, nothing, poly) + # end end Polyhedra.library(::CDDPolyhedron{N, T}) where {N, T} = Polyhedra.similar_library(CDDLibrary(), FullDim{N}(), T) Polyhedra.hvectortype(::Union{CDDPolyhedron{N, T}, Type{<:CDDPolyhedron{N, T}}}) where {N, T} = Polyhedra.hvectortype(CDDInequalityMatrix{N, T}) @@ -42,98 +42,98 @@ Base.convert(::Type{CDDPolyhedron{N, T}}, rep::Representation{N, T}) where {N, T # Helpers function getine(p::CDDPolyhedron) - if isnull(p.ine) - p.ine = copyinequalities(getpoly(p)) - end - get(p.ine) + if isnull(p.ine) + p.ine = copyinequalities(getpoly(p)) + end + get(p.ine) end function getext(p::CDDPolyhedron) - if isnull(p.ext) - p.ext = copygenerators(getpoly(p)) - end - get(p.ext) + if isnull(p.ext) + p.ext = copygenerators(getpoly(p)) + end + get(p.ext) end function getpoly(p::CDDPolyhedron, inepriority=true) - if isnull(p.poly) - if !inepriority && !isnull(p.ext) - p.poly = CDDPolyhedra(get(p.ext)) - elseif !isnull(p.ine) - p.poly = CDDPolyhedra(get(p.ine)) - elseif !isnull(p.ext) - p.poly = CDDPolyhedra(get(p.ext)) - else - error("Please report this bug") + if isnull(p.poly) + if !inepriority && !isnull(p.ext) + p.poly = CDDPolyhedra(get(p.ext)) + elseif !isnull(p.ine) + p.poly = CDDPolyhedra(get(p.ine)) + elseif !isnull(p.ext) + p.poly = CDDPolyhedra(get(p.ext)) + else + error("Please report this bug") + end end - end - get(p.poly) + get(p.poly) end function clearfield!(p::CDDPolyhedron) - p.ine = nothing - p.ext = nothing - p.poly = nothing - p.hlinearitydetected = false - p.vlinearitydetected = false - p.noredundantinequality = false - p.noredundantgenerator = false + p.ine = nothing + p.ext = nothing + p.poly = nothing + p.hlinearitydetected = false + p.vlinearitydetected = false + p.noredundantinequality = false + p.noredundantgenerator = false end function updateine!(p::CDDPolyhedron{N}, ine::CDDInequalityMatrix{N}) where N - clearfield!(p) - p.ine = ine + clearfield!(p) + p.ine = ine end function updateext!(p::CDDPolyhedron{N}, ext::CDDGeneratorMatrix{N}) where N - clearfield!(p) - p.ext = ext + clearfield!(p) + p.ext = ext end function updatepoly!(p::CDDPolyhedron{N}, poly::CDDPolyhedra{N}) where N - clearfield!(p) - p.poly = poly + clearfield!(p) + p.poly = poly end function Base.copy(p::CDDPolyhedron{N, T}) where {N, T} - pcopy = nothing - if !isnull(p.ine) - pcopy = CDDPolyhedron{N, T}(copy(get(p.ine))) - end - if !isnull(p.ext) + pcopy = nothing + if !isnull(p.ine) + pcopy = CDDPolyhedron{N, T}(copy(get(p.ine))) + end + if !isnull(p.ext) + if pcopy == nothing + pcopy = CDDPolyhedron{N, T}(copy(get(p.ext))) + else + pcopy.ext = copy(get(p.ext)) + end + end if pcopy == nothing - pcopy = CDDPolyhedron{N, T}(copy(get(p.ext))) - else - pcopy.ext = copy(get(p.ext)) + # copy of ine and ext may be not necessary here + # but I do it to be sure + pcopy = CDDPolyhedron{N, T}(copy(getine(p))) + pcopy.ext = copy(getext(p)) end - end - if pcopy == nothing - # copy of ine and ext may be not necessary here - # but I do it to be sure - pcopy = CDDPolyhedron{N, T}(copy(getine(p))) - pcopy.ext = copy(getext(p)) - end - pcopy.hlinearitydetected = p.hlinearitydetected - pcopy.vlinearitydetected = p.vlinearitydetected - pcopy.noredundantinequality = p.noredundantinequality - pcopy.noredundantgenerator = p.noredundantgenerator - pcopy + pcopy.hlinearitydetected = p.hlinearitydetected + pcopy.vlinearitydetected = p.vlinearitydetected + pcopy.noredundantinequality = p.noredundantinequality + pcopy.noredundantgenerator = p.noredundantgenerator + pcopy end # Implementation of Polyhedron's mandatory interface function polytypeforprecision(precision::Symbol) - if !(precision in (:float, :exact)) - error("precision should be :float or :exact, you gave $precision") - end - precision == :float ? Cdouble : Rational{BigInt} + if !(precision in (:float, :exact)) + error("precision should be :float or :exact, you gave $precision") + end + precision == :float ? Cdouble : Rational{BigInt} end function Polyhedra.polyhedron(rep::Representation{N}, lib::CDDLibrary) where N - T = polytypeforprecision(lib.precision) - CDDPolyhedron{N, T}(rep) + T = polytypeforprecision(lib.precision) + CDDPolyhedron{N, T}(rep) end function Polyhedra.polyhedron(hyperplanes::Polyhedra.HyperPlaneIt{N}, halfspaces::Polyhedra.HalfSpaceIt{N}, lib::CDDLibrary) where N - T = polytypeforprecision(lib.precision) - CDDPolyhedron{N, T}(hyperplanes, halfspaces) + T = polytypeforprecision(lib.precision) + CDDPolyhedron{N, T}(hyperplanes, halfspaces) end function Polyhedra.polyhedron(points::Polyhedra.PointIt{N}, lines::Polyhedra.LineIt{N}, rays::Polyhedra.RayIt{N}, lib::CDDLibrary) where N - T = polytypeforprecision(lib.precision) - CDDPolyhedron{N, T}(points, lines, rays) + T = polytypeforprecision(lib.precision) + CDDPolyhedron{N, T}(points, lines, rays) end # need to specify to avoid ambiguïty @@ -144,17 +144,17 @@ CDDPolyhedron{N, T}(hits::Polyhedra.HIt{N, T}...) where {N, T} = CDDPolyhedron{N CDDPolyhedron{N, T}(vits::Polyhedra.VIt{N, T}...) where {N, T} = CDDPolyhedron{N, T}(CDDGeneratorMatrix{N, T, mytype(T)}(vits...)) function Polyhedra.hrepiscomputed(p::CDDPolyhedron) - !isnull(p.ine) + !isnull(p.ine) end function Polyhedra.hrep(p::CDDPolyhedron{N, T}) where {N, T} - getine(p) + getine(p) end function Polyhedra.vrepiscomputed(p::CDDPolyhedron) - !isnull(p.ext) + !isnull(p.ext) end function Polyhedra.vrep(p::CDDPolyhedron{N, T}) where {N, T} - getext(p) + getext(p) end @@ -250,15 +250,15 @@ end Base.intersect!(p::CDDPolyhedron{N}, h::HRepElement{N}) where N = intersect!(p, intersect(h)) function Base.intersect!(p::CDDPolyhedron{N}, ine::HRepresentation{N}) where N - updateine!(p, matrixappend(getine(p), ine)) - #push!(getpoly(p, true), ine) # too slow because it computes double description - #updatepoly!(p, getpoly(p)) # invalidate others + updateine!(p, matrixappend(getine(p), ine)) + #push!(getpoly(p, true), ine) # too slow because it computes double description + #updatepoly!(p, getpoly(p)) # invalidate others end Polyhedra.convexhull!(p::CDDPolyhedron{N}, v::VRepElement{N}) where N = convexhull!(p, convexhull(v)) function Polyhedra.convexhull!(p::CDDPolyhedron{N}, ext::VRepresentation{N}) where N - updateext!(p, matrixappend(getext(p), ext)) - #push!(getpoly(p, false), ext) # too slow because it computes double description - #updatepoly!(p, getpoly(p)) # invalidate others + updateext!(p, matrixappend(getext(p), ext)) + #push!(getpoly(p, false), ext) # too slow because it computes double description + #updatepoly!(p, getpoly(p)) # invalidate others end function Polyhedra.default_solver(p::CDDPolyhedron{N, T}) where {N, T} @@ -278,18 +278,18 @@ end # Implementation of Polyhedron's optional interface function Base.isempty(p::CDDPolyhedron, solver::CDDSolver) - lp = matrix2feasibility(getine(p)) - lpsolve(lp) - # It is impossible to be unbounded since there is no objective - # Note that `status` would also work - simplestatus(copylpsolution(lp)) != :Optimal + lp = matrix2feasibility(getine(p)) + lpsolve(lp) + # It is impossible to be unbounded since there is no objective + # Note that `status` would also work + simplestatus(copylpsolution(lp)) != :Optimal end function gethredundantindices(p::CDDPolyhedron) - redundantrows(getine(p)) + redundantrows(getine(p)) end function getvredundantindices(p::CDDPolyhedron) - redundantrows(getext(p)) + redundantrows(getext(p)) end # type CDDLPPolyhedron{N, T} <: LPPolyhedron{N, T} diff --git a/src/settype.jl b/src/settype.jl index 14058f0..9c576aa 100644 --- a/src/settype.jl +++ b/src/settype.jl @@ -1,62 +1,62 @@ function dd_set_initialize(maxel::Clong) - x = Ref{Cset_type}(0) - @cdd_ccall set_initialize Void (Ref{Ptr{Culong}}, Clong) x maxel - x[] + x = Ref{Cset_type}(0) + @cdd_ccall set_initialize Void (Ref{Ptr{Culong}}, Clong) x maxel + x[] end function dd_set_addelem(st::Cset_type, el::Clong) - @cdd_ccall set_addelem Void (Cset_type, Clong) st convert(Clong, el) + @cdd_ccall set_addelem Void (Cset_type, Clong) st convert(Clong, el) end function dd_set_member(st::Cset_type, el::Clong) - 1 == (@cdd_ccall set_member Cint (Clong, Cset_type) el st) + 1 == (@cdd_ccall set_member Cint (Clong, Cset_type) el st) end dd_set_member(st::Cset_type, el) = dd_set_member(st, Clong(el)) function dd_set_card(st::Cset_type) - @cdd_ccall set_card Clong (Cset_type,) st + @cdd_ccall set_card Clong (Cset_type,) st end function dd_settype(st::Cset_type, s, offset::Integer=0) - for el in s - dd_set_addelem(st, Clong(offset+el)) - end + for el in s + dd_set_addelem(st, Clong(offset+el)) + end end # CDDSet mutable struct CDDSet - s::Cset_type - maxel::Clong + s::Cset_type + maxel::Clong end function CDDSet(s, maxel::Clong, offset::Integer) - st = dd_set_initialize(maxel) - dd_settype(st, s, offset) - CDDSet(st, maxel) + st = dd_set_initialize(maxel) + dd_settype(st, s, offset) + CDDSet(st, maxel) end CDDSet(s, maxel, offset::Integer) = CDDSet(s, Clong(maxel), offset) function Base.convert(::Type{IntSet}, st::CDDSet) - s = IntSet() - for i = 1:st.maxel - if dd_set_member(st.s, convert(Clong, i)) - push!(s, i) + s = IntSet() + for i = 1:st.maxel + if dd_set_member(st.s, convert(Clong, i)) + push!(s, i) + end end - end - s + s end # I don't want it to overwrite Base.convert behaviour function myconvert(::Type{IntSet}, a::Matrix) - b = Array{Bool}(a) - s = IntSet() - for i = 1:length(a) - if b[i] - push!(s, i) + b = Array{Bool}(a) + s = IntSet() + for i = 1:length(a) + if b[i] + push!(s, i) + end end - end - s + s end export CDDSet