From 001ed9f4a2e7551d06326c32b5434221aceeb898 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Xavier Date: Thu, 3 Nov 2022 09:01:13 -0300 Subject: [PATCH] Add `QUBOTools` support --- .JuliaFormatter.toml | 2 +- src/analysis/analysis.jl | 2 +- src/compiler/objective.jl | 7 ++++++- src/compiler/penalties.jl | 2 +- src/model/models.jl | 4 ++-- src/model/virtual.jl | 6 ++++-- src/model/wrapper.jl | 44 +++++++++++++++++++++++++-------------- src/virtual/encoding.jl | 8 ++++++- 8 files changed, 50 insertions(+), 25 deletions(-) diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml index 490c5eeb..b3132b16 100644 --- a/.JuliaFormatter.toml +++ b/.JuliaFormatter.toml @@ -1,3 +1,3 @@ align_assignment = true align_pair_arrow = true -align_matrix = true \ No newline at end of file +align_matrix = true \ No newline at end of file diff --git a/src/analysis/analysis.jl b/src/analysis/analysis.jl index 605d7e3f..b5df90e6 100644 --- a/src/analysis/analysis.jl +++ b/src/analysis/analysis.jl @@ -22,7 +22,7 @@ function QUBOTools.backend(model::VirtualQUBOModel{T}) where {T} c = a.coefficient x = a.variable - L[x] = get(L, x, zero(T)) + c + L[x] = get(L, x, zero(T)) + c end offset = f.constant diff --git a/src/compiler/objective.jl b/src/compiler/objective.jl index a3489ce7..db395fee 100644 --- a/src/compiler/objective.jl +++ b/src/compiler/objective.jl @@ -1,5 +1,10 @@ function toqubo_sense!(model::VirtualQUBOModel, ::AbstractArchitecture) - MOI.set(model.target_model, MOI.ObjectiveSense(), MOI.get(model, MOI.ObjectiveSense())) + if MOI.get(model, MOI.ObjectiveSense()) === MOI.MAX_SENSE + MOI.set(model.target_model, MOI.ObjectiveSense(), MOI.MAX_SENSE) + else + # Feasibility is interpreted as minimization + MOI.set(model.target_model, MOI.ObjectiveSense(), MOI.MIN_SENSE) + end return nothing end diff --git a/src/compiler/penalties.jl b/src/compiler/penalties.jl index 6b6044df..c985014f 100644 --- a/src/compiler/penalties.jl +++ b/src/compiler/penalties.jl @@ -1,5 +1,5 @@ function toqubo_penalties!(model::VirtualQUBOModel{T}, ::AbstractArchitecture) where {T} - # -*- :: Invert Sign:: -*- # + # -*- :: Invert Sign :: -*- # s = MOI.get(model, MOI.ObjectiveSense()) === MOI.MAX_SENSE ? -1 : 1 β = one(T) # TODO: This should be made a parameter too? Yes! diff --git a/src/model/models.jl b/src/model/models.jl index 09106e5d..c2883a26 100644 --- a/src/model/models.jl +++ b/src/model/models.jl @@ -14,8 +14,8 @@ MOIU.@model(PreQUBOModel, # Name of model # :: Drop Automatic Constraint Support :: # MOI.supports_constraint( ::PreQUBOModel{T}, - ::Type{<:Union{SAF, SQF}}, - ::Type{<:Union{MOI.Integer, MOI.ZeroOne, GT}}, + ::Type{<:Union{SAF{T}, SQF{T}}}, + ::Type{<:Union{GT{T}}}, ) where {T} = false # -*- Model: QUBOModel -*- diff --git a/src/model/virtual.jl b/src/model/virtual.jl index 4e16aa7e..2ff4e56e 100644 --- a/src/model/virtual.jl +++ b/src/model/virtual.jl @@ -30,7 +30,7 @@ struct VirtualQUBOModel{T} <: VM.AbstractVirtualModel{T} f::PBO.PBF{VI, T} # Objective Function g::Dict{CI, PBO.PBF{VI, T}} # Problem Constraints h::Dict{VI, PBO.PBF{VI, T}} # Variable Encoding Constraints - ρ::Dict{Union{CI, VI}, T} # Penalties + ρ::Dict{Union{CI, VI}, T} # Penalties # -*- Attributes -*- attrs::VirtualQUBOModelAttributes{T} @@ -67,9 +67,11 @@ end MOI.get(model::VirtualQUBOModel, ::VM.Source) = model.source MOI.get(model::VirtualQUBOModel, ::VM.Source, x::VI) = model.source[x] MOI.set(model::VirtualQUBOModel{T}, ::VM.Source, x::VI, v::VM.VV{<:Any, T}) where T = (model.source[x] = v) + MOI.get(model::VirtualQUBOModel, ::VM.Target) = model.target MOI.get(model::VirtualQUBOModel, ::VM.Target, y::VI) = model.target[y] MOI.set(model::VirtualQUBOModel{T}, ::VM.Target, y::VI, v::VM.VV{<:Any, T}) where T = (model.target[y] = v) -MOI.get(model::VirtualQUBOModel, ::VM.Variables) = model.variables + +MOI.get(model::VirtualQUBOModel, ::VM.Variables) = model.variables MOI.get(model::VirtualQUBOModel, ::VM.SourceModel) = model.source_model MOI.get(model::VirtualQUBOModel, ::VM.TargetModel) = model.target_model \ No newline at end of file diff --git a/src/model/wrapper.jl b/src/model/wrapper.jl index cbdf8a1d..d5f82875 100644 --- a/src/model/wrapper.jl +++ b/src/model/wrapper.jl @@ -29,11 +29,10 @@ function MOI.optimize!(model::VirtualQUBOModel) source_model = MOI.get(model, VM.SourceModel()) target_model = MOI.get(model, VM.TargetModel()) + index_map = MOIU.identity_index_map(source_model) MOI.optimize!(model.optimizer, target_model) - index_map = MOIU.identity_index_map(source_model) - return (index_map, false) end @@ -42,14 +41,14 @@ function MOI.copy_to(model::VirtualQUBOModel{T}, source::MOI.ModelLike) where {T error("QUBO Model is not empty") end - # -*- Copy to PreQUBOModel + Trigger Bridges -*- + # -*- Copy to PreQUBOModel + Add Bridges -*- # source_model = MOI.get(model, VM.SourceModel()) + bridge_model = MOIB.full_bridge_optimizer(source_model, T) - index_map = MOI.copy_to( - MOIB.full_bridge_optimizer(source_model, T), - source, - ) + # -*- Copy to source using bridges - *- # + index_map = MOI.copy_to(bridge_model, source) + # -*- JuMP to QUBO Compilation -*- # ToQUBO.toqubo!(model) return index_map @@ -64,13 +63,19 @@ MOI.supports( # -*- :: Constraint Support :: -*- # MOI.supports_constraint( ::VirtualQUBOModel{T}, - ::Type{<:VI}, - ::Type{<:Union{MOI.ZeroOne,MOI.Integer,MOI.Interval{T}}}, + ::Type{VI}, + ::Type{<:Union{ + MOI.ZeroOne, + MOI.Integer, + MOI.Interval{T}, + MOI.LessThan{T}, + MOI.GreaterThan{T}, + }}, ) where {T} = true MOI.supports_constraint( ::VirtualQUBOModel{T}, - ::Type{<:Union{VI,SAF{T},SQF{T}}}, + ::Type{<:Union{SAF{T},SQF{T}}}, ::Type{<:Union{MOI.EqualTo{T},MOI.LessThan{T}}}, ) where {T} = true @@ -82,7 +87,13 @@ MOI.supports_constraint( MOI.supports_add_constrained_variable( ::VirtualQUBOModel{T}, - ::Type{<:Union{MOI.ZeroOne,MOI.Integer,MOI.Interval{T}}}, + ::Type{<:Union{ + MOI.ZeroOne, + MOI.Integer, + MOI.Interval{T}, + MOI.LessThan{T}, + MOI.GreaterThan{T}, + }}, ) where {T} = true function MOI.get( @@ -140,9 +151,10 @@ function MOI.get(model::VirtualQUBOModel{T}, vp::MOI.VariablePrimal, x::VI) wher if isnothing(model.optimizer) return zero(T) else + v = MOI.get(model, VM.Source(), x) s = zero(T) - - for (ω, c) in VM.expansion(MOI.get(model, VM.Source(), x)) + + for (ω, c) in VM.expansion(v) for y in ω c *= MOI.get(model.optimizer, vp, y) end @@ -154,11 +166,11 @@ function MOI.get(model::VirtualQUBOModel{T}, vp::MOI.VariablePrimal, x::VI) wher end end -MOI.get(::VirtualQUBOModel, ::MOI.SolverName) = "Virtual QUBO Model" -MOI.get(::VirtualQUBOModel, ::MOI.SolverVersion) = PROJECT_VERSION +MOI.get(::VirtualQUBOModel, ::MOI.SolverName) = "Virtual QUBO Model" +MOI.get(::VirtualQUBOModel, ::MOI.SolverVersion) = PROJECT_VERSION MOI.get(model::VirtualQUBOModel, rs::MOI.RawSolver) = MOI.get(model.optimizer, rs) -PBO.showvar(x::VI) = PBO.showvar(x.value) +PBO.showvar(x::VI) = PBO.showvar(x.value) PBO.varcmp(x::VI, y::VI) = PBO.varcmp(x.value, y.value) const Optimizer{T} = VirtualQUBOModel{T} diff --git a/src/virtual/encoding.jl b/src/virtual/encoding.jl index 4f84b3e8..4f2818f3 100644 --- a/src/virtual/encoding.jl +++ b/src/virtual/encoding.jl @@ -163,7 +163,13 @@ function encode!(E::Type{<:Binary}, model::AbstractVirtualModel{T}, x::Union{VI, M = trunc(Int, β - α) N = ceil(Int, log2(M + 1)) - encode!(E, model, x, T[[2^i for i = 0:N-2];[M - 2^(N-1) + 1]], α) + γ = if N == 0 + T[M + 1/2] + else + T[[2^i for i = 0:N-2];[M - 2^(N-1) + 1]] + end + + encode!(E, model, x, γ, α) end function encode!(E::Type{<:Binary}, model::AbstractVirtualModel{T}, x::Union{VI, Nothing}, a::T, b::T, n::Integer) where T