diff --git a/src/ToQUBO.jl b/src/ToQUBO.jl index 5d0cb56..ba87638 100644 --- a/src/ToQUBO.jl +++ b/src/ToQUBO.jl @@ -27,9 +27,6 @@ const GT{T} = MOI.GreaterThan{T} const VI = MOI.VariableIndex const CI{F,S} = MOI.ConstraintIndex{F,S} -# Library -include("error.jl") - # Encoding Module include("encoding/encoding.jl") diff --git a/src/attributes/compiler.jl b/src/attributes/compiler.jl index 6ccc02f..e080571 100644 --- a/src/attributes/compiler.jl +++ b/src/attributes/compiler.jl @@ -20,6 +20,60 @@ abstract type CompilerAttribute <: MOI.AbstractOptimizerAttribute end MOI.supports(::Optimizer, ::A) where {A<:CompilerAttribute} = true +@doc raw""" + CompilationTime() +""" +struct CompilationTime <: CompilerAttribute end + +MOI.is_set_by_optimize(::CompilationTime) = true + +function MOI.get(model::Optimizer, ::CompilationTime)::Union{Float64,Nothing} + return get(model.compiler_settings, :compilation_time, nothing) +end + +function MOI.set(model::Optimizer, ::CompilationTime, t::Any) + model.compiler_settings[:compilation_time] = convert(Float64, t) + + return nothing +end + +function MOI.set(model::Optimizer, ::CompilationTime, ::Nothing) + delete!(model.compiler_settings, :compilation_time) + + return nothing +end + +function compilation_time(model::Optimizer)::Union{Float64,Nothing} + return MOI.get(model, CompilationTime()) +end + +@doc raw""" + CompilationStatus() +""" +struct CompilationStatus <: CompilerAttribute end + +MOI.is_set_by_optimize(::CompilationStatus) = true + +function MOI.get(model::Optimizer, ::CompilationStatus) + return get(model.compiler_settings, :compilation_status, MOI.OPTIMIZE_NOT_CALLED) +end + +function MOI.set(model::Optimizer, ::CompilationStatus, status::MOI.TerminationStatusCode) + model.compiler_settings[:compilation_status] = status + + return nothing +end + +function MOI.set(model::Optimizer, ::CompilationStatus, ::Nothing) + delete!(model.compiler_settings, :compilation_status) + + return nothing +end + +function compilation_status(model::Optimizer)::MOI.TerminationStatusCode + return MOI.get(model, CompilationStatus()) +end + @doc raw""" Warnings() """ diff --git a/src/attributes/solver.jl b/src/attributes/solver.jl index cf247b8..0b459dd 100644 --- a/src/attributes/solver.jl +++ b/src/attributes/solver.jl @@ -55,10 +55,7 @@ end function MOI.get( model::Virtual.Model, - attr::Union{ - MOI.SolveTimeSec, - MOI.RawStatusString, - }, + attr::MOI.SolveTimeSec, ) if !isnothing(model.optimizer) return MOI.get(model.optimizer, attr) @@ -69,10 +66,7 @@ end function MOI.supports( model::Virtual.Model, - attr::Union{ - MOI.SolveTimeSec, - MOI.RawStatusString, - }, + attr::MOI.SolveTimeSec, ) if !isnothing(model.optimizer) return MOI.supports(model.optimizer, attr) @@ -81,22 +75,43 @@ function MOI.supports( end end -function MOI.get(model::Virtual.Model, attr::MOI.TerminationStatus) - if !isnothing(model.optimizer) +function MOI.get( + model::Virtual.Model, + attr::MOI.RawStatusString, +) + if !isnothing(model.optimizer) && MOI.supports(model.optimizer, attr) return MOI.get(model.optimizer, attr) else - return get(model.compiler_settings, :compilation_status, MOI.OTHER_LIMIT) + return get(model.moi_settings, :raw_status_string, "") end end -function MOI.supports(model::Virtual.Model, attr::MOI.TerminationStatus) +function MOI.set( + model::Virtual.Model, + ::MOI.RawStatusString, + value::AbstractString, +) + model.moi_settings[:raw_status_string] = String(value) + + return nothing +end + +function MOI.supports(::Virtual.Model, ::MOI.RawStatusString) + return true +end + +function MOI.get(model::Virtual.Model, attr::MOI.TerminationStatus) if !isnothing(model.optimizer) - return MOI.supports(model.optimizer, attr) + return MOI.get(model.optimizer, attr) else - return true + return MOI.get(model, Attributes.CompilationStatus()) end end +function MOI.supports(::Virtual.Model, ::MOI.TerminationStatus) + return true +end + function MOI.get(model::Virtual.Model, attr::Union{MOI.PrimalStatus, MOI.DualStatus}) if !isnothing(model.optimizer) return MOI.get(model.optimizer, attr) diff --git a/src/compiler/build.jl b/src/compiler/build.jl index dbcdc2a..0bd1ef8 100644 --- a/src/compiler/build.jl +++ b/src/compiler/build.jl @@ -12,7 +12,7 @@ function build!(model::Virtual.Model{T}, arch::AbstractArchitecture) where {T} end function objective_function(model::Virtual.Model{T}, ::AbstractArchitecture) where {T} - empty!(model.H) + Base.empty!(model.H) # Calculate an upper bound on the number of terms num_terms = @@ -115,8 +115,13 @@ function output!(model::Virtual.Model{T}, ::AbstractArchitecture) where {T} # have this condition here. # HINT: When debugging this, a good place to start is to check if the 'Quadratize' # flag is set or not. If missing, it should mean that some constraint might induce - # PBFs of higher degree without calling 'MOI.set(model, Quadratize(), true)'. - compilation_error("Quadratization failed") + # PBFs of higher degree without calling + # MOI.set(model, AttributesQuadratize(), true) + compilation_error!( + model, + "Fatal: Quadratization failed"; + status="Failure in quadratization", + ) end end diff --git a/src/compiler/compiler.jl b/src/compiler/compiler.jl index a1bfaa4..8876305 100644 --- a/src/compiler/compiler.jl +++ b/src/compiler/compiler.jl @@ -1,18 +1,15 @@ module Compiler # Imports -using MathOptInterface -const MOI = MathOptInterface +import MathOptInterface as MOI +import MathOptInterface: empty! +import PseudoBooleanOptimization as PBO -import QUBOTools: PBO import QUBOTools: AbstractArchitecture, GenericArchitecture -import ..Encoding: - Encoding, VariableEncodingMethod, Mirror, Unary, Binary, Arithmetic, OneHot, DomainWall - -import ..Virtual: Virtual, encoding, expansion, penaltyfn - import ..Attributes +import ..Encoding +import ..Virtual # Constants const VI = MOI.VariableIndex @@ -25,6 +22,7 @@ const EQ{T} = MOI.EqualTo{T} const LT{T} = MOI.LessThan{T} const GT{T} = MOI.GreaterThan{T} +include("error.jl") include("analysis.jl") include("interface.jl") include("parse.jl") @@ -82,16 +80,16 @@ function reset!(model::Virtual.Model, ::AbstractArchitecture = GenericArchitectu MOI.empty!(model.target_model) # Virtual Variables - empty!(model.variables) - empty!(model.source) - empty!(model.target) + Base.empty!(model.variables) + Base.empty!(model.source) + Base.empty!(model.target) # PBF/IR - empty!(model.f) - empty!(model.g) - empty!(model.h) - empty!(model.ρ) - empty!(model.θ) + Base.empty!(model.f) + Base.empty!(model.g) + Base.empty!(model.h) + Base.empty!(model.ρ) + Base.empty!(model.θ) return nothing end diff --git a/src/error.jl b/src/compiler/error.jl similarity index 62% rename from src/error.jl rename to src/compiler/error.jl index f72319a..499337f 100644 --- a/src/error.jl +++ b/src/compiler/error.jl @@ -21,4 +21,17 @@ end function compilation_error(msg::Union{Nothing,String} = nothing) throw(QUBOCompilationError(msg)) -end \ No newline at end of file + + return nothing +end + +function compilation_error!(model::Virtual.Model, msg::Union{Nothing,String} = nothing; status::AbstractString = "") + # Update model status + MOI.set(model, Attributes.CompilationStatus(), MOI.OTHER_ERROR) + MOI.set(model, MOI.RawStatusString(), status) + + # Throw error + compilation_error(msg) + + return nothing +end diff --git a/src/compiler/parse.jl b/src/compiler/parse.jl index 5769935..201226f 100644 --- a/src/compiler/parse.jl +++ b/src/compiler/parse.jl @@ -17,7 +17,7 @@ function parse!( vi::VI, ::AbstractArchitecture, ) where {T} - empty!(g) + Base.empty!(g) for (ω, c) in expansion(model.source[vi]) g[ω] += c @@ -32,7 +32,7 @@ function parse!( f::SAF{T}, ::AbstractArchitecture, ) where {T} - empty!(g) + Base.empty!(g) sizehint!(g, length(f.terms) + 1) @@ -41,7 +41,7 @@ function parse!( x = a.variable v = model.source[x] - for (ω, d) in expansion(v) + for (ω, d) in Virtual.expansion(v) g[ω] += c * d end end @@ -100,7 +100,7 @@ function parse!( f::SQF{T}, ::AbstractArchitecture, ) where {T} - empty!(g) + Base.empty!(g) sizehint!(g, length(f.quadratic_terms) + length(f.affine_terms) + 1) @@ -118,8 +118,8 @@ function parse!( c /= 2 end - for (ωi, di) in expansion(vi) - for (ωj, dj) in expansion(vj) + for (ωi, di) in Virtual.expansion(vi) + for (ωj, dj) in Virtual.expansion(vj) g[union(ωi, ωj)] += c * di * dj end end @@ -130,7 +130,7 @@ function parse!( x = a.variable v = model.source[x] - for (ω, d) in expansion(v) + for (ω, d) in Virtual.expansion(v) g[ω] += c * d end end diff --git a/src/compiler/variables.jl b/src/compiler/variables.jl index 06235b3..62dd80d 100644 --- a/src/compiler/variables.jl +++ b/src/compiler/variables.jl @@ -90,7 +90,7 @@ function variables!(model::Virtual.Model{T}, ::AbstractArchitecture) where {T} end function variable_𝔹!(model::Virtual.Model{T}, x::VI) where {T} - Encoding.encode!(model, x, Mirror{T}()) + Encoding.encode!(model, x, Encoding.Mirror{T}()) return nothing end diff --git a/src/virtual/model.jl b/src/virtual/model.jl index 1217a05..1748004 100644 --- a/src/virtual/model.jl +++ b/src/virtual/model.jl @@ -32,6 +32,7 @@ mutable struct Model{T,O} <: MOI.AbstractOptimizer compiler_settings::Dict{Symbol,Any} variable_settings::Dict{Symbol,Dict{VI,Any}} constraint_settings::Dict{Symbol,Dict{CI,Any}} + moi_settings::Dict{Symbol,Any} function Model{T}(constructor::Any; kws...) where {T} optimizer = constructor()::MOI.AbstractOptimizer @@ -80,6 +81,7 @@ mutable struct Model{T,O} <: MOI.AbstractOptimizer Dict{Symbol,Any}(), Dict{Symbol,Dict{VI,Any}}(), Dict{Symbol,Dict{CI,Any}}(), + Dict{Symbol,Any}(), ) end end diff --git a/src/wrapper.jl b/src/wrapper.jl index b26b14d..dd50e2e 100644 --- a/src/wrapper.jl +++ b/src/wrapper.jl @@ -28,10 +28,16 @@ function MOI.optimize!(model::Optimizer) index_map = MOIU.identity_index_map(model.source_model) # De facto JuMP to QUBO Compilation - ToQUBO.Compiler.compile!(model) + let t = @elapsed ToQUBO.Compiler.compile!(model) + MOI.set(model, Attributes.CompilationTime(), t) + end if !isnothing(model.optimizer) MOI.optimize!(model.optimizer, model.target_model) + MOI.set(model, MOI.RawStatusString(), MOI.get(model.optimizer, MOI.RawStatusString())) + else + MOI.set(model, Attributes.CompilationStatus(), MOI.LOCALLY_SOLVED) + MOI.set(model, MOI.RawStatusString(), "Compilation complete without an internal solver") end return (index_map, false)