From af533a0f904b6a784d2dcb2d0a9dd2025562c450 Mon Sep 17 00:00:00 2001 From: pedromxavier Date: Thu, 23 Nov 2023 14:20:44 -0500 Subject: [PATCH] Add tests --- src/compiler/build.jl | 6 +-- src/compiler/compiler.jl | 3 -- src/compiler/constraints.jl | 20 ++------- src/compiler/penalties.jl | 6 +-- src/encoding/variables/set/one_hot.jl | 6 ++- src/virtual/encoding.jl | 9 ++++ src/wrapper.jl | 2 +- test/integration/interface.jl | 60 +++++++++++++++++++-------- 8 files changed, 66 insertions(+), 46 deletions(-) diff --git a/src/compiler/build.jl b/src/compiler/build.jl index 37e70db..e860ce8 100644 --- a/src/compiler/build.jl +++ b/src/compiler/build.jl @@ -29,7 +29,7 @@ function objective_function(model::Virtual.Model{T}, ::AbstractArchitecture) whe end for (ci, g) in model.g - ρ = model.ρ[ci] + ρ = MOI.get(model, Attributes.ConstraintEncodingPenalty(), ci) for (ω, c) in g model.H[ω] += ρ * c @@ -37,7 +37,7 @@ function objective_function(model::Virtual.Model{T}, ::AbstractArchitecture) whe end for (vi, h) in model.h - θ = model.θ[vi] + θ = MOI.get(model, Attributes.VariableEncodingPenalty(), vi) for (ω, c) in h model.H[ω] += θ * c @@ -45,7 +45,7 @@ function objective_function(model::Virtual.Model{T}, ::AbstractArchitecture) whe end for (ci, s) in model.s - η = model.η[ci] + η = MOI.get(model, Attributes.SlackVariableEncodingPenalty(), ci) for (ω, c) in s model.H[ω] += η * c diff --git a/src/compiler/compiler.jl b/src/compiler/compiler.jl index 8876305..f51548d 100644 --- a/src/compiler/compiler.jl +++ b/src/compiler/compiler.jl @@ -63,9 +63,6 @@ function compile!(model::Virtual.Model{T}, arch::AbstractArchitecture) where {T} # Add Regular Constraints constraints!(model, arch) - # Add Encoding Constraints - encoding_constraints!(model, arch) - # Compute penalties penalties!(model, arch) diff --git a/src/compiler/constraints.jl b/src/compiler/constraints.jl index 9dc1998..0caf19f 100644 --- a/src/compiler/constraints.jl +++ b/src/compiler/constraints.jl @@ -468,6 +468,9 @@ function constraint( end g[w] = one(T) + + # Tell the compiler that quadratization is necessary + MOI.set(model, Attributes.Quadratize(), true) end end @@ -483,20 +486,3 @@ function constraint( return g^2 + h end - -function encoding_constraints!(model::Virtual.Model{T}, ::AbstractArchitecture) where {T} - for v in model.variables - i = Virtual.source(v) - χ = Virtual.penaltyfn(v) - - if !isnothing(χ) - if i isa VI - model.h[i] = χ - elseif i isa CI - model.s[i] = χ - end - end - end - - return nothing -end diff --git a/src/compiler/penalties.jl b/src/compiler/penalties.jl index acb6431..4ff65c2 100644 --- a/src/compiler/penalties.jl +++ b/src/compiler/penalties.jl @@ -13,7 +13,7 @@ function penalties!(model::Virtual.Model{T}, ::AbstractArchitecture) where {T} ρ = σ * (δ / ϵ + β) end - model.ρ[ci] = ρ + MOI.set(model, Attributes.ConstraintEncodingPenalty(), ci, ρ) end for (vi, h) in model.h @@ -24,7 +24,7 @@ function penalties!(model::Virtual.Model{T}, ::AbstractArchitecture) where {T} θ = σ * (δ / ϵ + β) end - model.θ[vi] = θ + MOI.set(model, Attributes.VariableEncodingPenalty(), vi, θ) end for (ci, s) in model.s @@ -35,7 +35,7 @@ function penalties!(model::Virtual.Model{T}, ::AbstractArchitecture) where {T} η = σ * (δ / ϵ + β) end - model.η[ci] = η + MOI.set(model, Attributes.SlackVariableEncodingPenalty(), ci, η) end return nothing diff --git a/src/encoding/variables/set/one_hot.jl b/src/encoding/variables/set/one_hot.jl index 0a847b9..3bcde3b 100644 --- a/src/encoding/variables/set/one_hot.jl +++ b/src/encoding/variables/set/one_hot.jl @@ -99,7 +99,11 @@ function encode( a, b = S - Γ = collect(range(a, b; length = p)) + Γ = if p == 1 + T[(a + b) / 2] + else + collect(T, range(a, b; length = p)) + end return encode(var, e, Γ) end diff --git a/src/virtual/encoding.jl b/src/virtual/encoding.jl index 89073c4..fb58101 100644 --- a/src/virtual/encoding.jl +++ b/src/virtual/encoding.jl @@ -1,10 +1,19 @@ function Encoding.encode!(model::Model{T}, v::Variable{T}) where {T} x = source(v) + χ = penaltyfn(v) if x isa VI model.source[x] = v + + if !isnothing(χ) + model.h[x] = χ + end elseif x isa CI model.slack[x] = v + + if !isnothing(χ) + model.s[x] = χ + end end for y in target(v) diff --git a/src/wrapper.jl b/src/wrapper.jl index dd50e2e..2109be9 100644 --- a/src/wrapper.jl +++ b/src/wrapper.jl @@ -29,6 +29,7 @@ function MOI.optimize!(model::Optimizer) # De facto JuMP to QUBO Compilation let t = @elapsed ToQUBO.Compiler.compile!(model) + MOI.set(model, Attributes.CompilationStatus(), MOI.LOCALLY_SOLVED) MOI.set(model, Attributes.CompilationTime(), t) end @@ -36,7 +37,6 @@ function MOI.optimize!(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 diff --git a/test/integration/interface.jl b/test/integration/interface.jl index b030811..506815c 100644 --- a/test/integration/interface.jl +++ b/test/integration/interface.jl @@ -89,16 +89,16 @@ function test_interface_moi() # max x1 + x2 + x3 # st x1 + x2 <= 1 (c1) # x2 + x3 <= 1 (c2) - # x1 ∈ {0, 1} - # x2 ∈ {0, 1} - # x3 ∈ {0, 1} + # 0 <= x1 <= 1 + # 0 <= x2 <= 1 + # 0 <= x3 <= 1 model = MOI.instantiate( () -> ToQUBO.Optimizer(RandomSampler.Optimizer); with_bridge_type = Float64, ) - x, _ = MOI.add_constrained_variables(model, fill(MOI.ZeroOne(), 3)) + x, _ = MOI.add_constrained_variables(model, fill(MOI.Interval{Float64}(0.0, 1.0), 3)) MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) @@ -205,10 +205,10 @@ function test_interface_moi() @test MOI.get(model, Attributes.VariableEncodingMethod(), x[1]) === nothing @test MOI.get(model, Attributes.VariableEncodingMethod(), x[2]) === nothing - MOI.set(model, Attributes.VariableEncodingMethod(), x[1], Encoding.Arithmetic()) + MOI.set(model, Attributes.VariableEncodingMethod(), x[1], Encoding.OneHot()) MOI.set(model, Attributes.VariableEncodingMethod(), x[2], Encoding.Arithmetic()) - @test MOI.get(model, Attributes.VariableEncodingMethod(), x[1]) isa Encoding.Arithmetic + @test MOI.get(model, Attributes.VariableEncodingMethod(), x[1]) isa Encoding.OneHot @test MOI.get(model, Attributes.VariableEncodingMethod(), x[2]) isa Encoding.Arithmetic # Variable Encoding ATol @@ -233,11 +233,11 @@ function test_interface_moi() @test MOI.get(model, Attributes.VariableEncodingBits(), x[1]) === nothing @test MOI.get(model, Attributes.VariableEncodingBits(), x[2]) === nothing - MOI.set(model, Attributes.VariableEncodingBits(), x[1], 1) - MOI.set(model, Attributes.VariableEncodingBits(), x[2], 2) + MOI.set(model, Attributes.VariableEncodingBits(), x[1], 10) + MOI.set(model, Attributes.VariableEncodingBits(), x[2], 20) - @test MOI.get(model, Attributes.VariableEncodingBits(), x[1]) == 1 - @test MOI.get(model, Attributes.VariableEncodingBits(), x[2]) == 2 + @test MOI.get(model, Attributes.VariableEncodingBits(), x[1]) == 10 + @test MOI.get(model, Attributes.VariableEncodingBits(), x[2]) == 20 # Variable Encoding Penalty @test MOI.get(model, Attributes.VariableEncodingPenaltyHint(), x[1]) === nothing @@ -297,20 +297,28 @@ function test_interface_moi() MOI.optimize!(model) let virtual_model = model.model.optimizer - @test MOI.get(virtual_model, Attributes.Architecture()) isa SuperArchitecture - @test MOI.get(virtual_model, Attributes.Architecture()).super === true - - @test MOI.get(virtual_model, Attributes.Optimization()) === 3 + @test MOI.get(virtual_model, Attributes.Optimization()) == 3 + @test Attributes.optimization(virtual_model) == 3 @test MOI.get(virtual_model, Attributes.Discretize()) === true + @test Attributes.discretize(virtual_model) === true + @test MOI.get(virtual_model, Attributes.Quadratize()) === true + @test Attributes.quadratize(virtual_model) === true + @test MOI.get(virtual_model, Attributes.Warnings()) === false + @test Attributes.warnings(virtual_model) === false + + @test MOI.get(virtual_model, Attributes.Architecture()) isa SuperArchitecture + @test MOI.get(virtual_model, Attributes.Architecture()).super === true + @test Attributes.architecture(virtual_model) isa SuperArchitecture + @test Attributes.architecture(virtual_model).super === true @test MOI.get(virtual_model, Attributes.QuadratizationMethod()) isa PBO.PTR_BG @test MOI.get(virtual_model, Attributes.StableQuadratization()) === true @test MOI.get(virtual_model, Attributes.DefaultVariableEncodingMethod()) isa Encoding.Unary - @test MOI.get(virtual_model, Attributes.VariableEncodingMethod(), x[1]) isa Encoding.Arithmetic + @test MOI.get(virtual_model, Attributes.VariableEncodingMethod(), x[1]) isa Encoding.OneHot @test MOI.get(virtual_model, Attributes.VariableEncodingMethod(), x[2]) isa Encoding.Arithmetic @test MOI.get(virtual_model, Attributes.VariableEncodingMethod(), x[3]) === nothing @@ -320,21 +328,37 @@ function test_interface_moi() @test MOI.get(virtual_model, Attributes.VariableEncodingATol(), x[3]) === nothing @test MOI.get(virtual_model, Attributes.DefaultVariableEncodingBits()) == 3 - @test MOI.get(virtual_model, Attributes.VariableEncodingBits(), x[1]) == 1 - @test MOI.get(virtual_model, Attributes.VariableEncodingBits(), x[2]) == 2 + @test MOI.get(virtual_model, Attributes.VariableEncodingBits(), x[1]) == 10 + @test MOI.get(virtual_model, Attributes.VariableEncodingBits(), x[2]) == 20 @test MOI.get(virtual_model, Attributes.VariableEncodingBits(), x[3]) === nothing @test MOI.get(virtual_model, Attributes.VariableEncodingPenaltyHint(), x[1]) == -1.0 + @test Attributes.variable_encoding_penalty_hint(virtual_model, x[1]) == -1.0 @test MOI.get(virtual_model, Attributes.VariableEncodingPenaltyHint(), x[2]) === nothing + @test Attributes.variable_encoding_penalty_hint(virtual_model, x[2]) === nothing @test MOI.get(virtual_model, Attributes.VariableEncodingPenaltyHint(), x[3]) === nothing + @test Attributes.variable_encoding_penalty_hint(virtual_model, x[3]) === nothing + + @test MOI.get(virtual_model, Attributes.VariableEncodingPenalty(), x[1]) == -1.0 + @test Attributes.variable_encoding_penalty(virtual_model, x[1]) == -1.0 + @test MOI.get(virtual_model, Attributes.VariableEncodingPenalty(), x[2]) === nothing + @test Attributes.variable_encoding_penalty(virtual_model, x[2]) === nothing + @test MOI.get(virtual_model, Attributes.VariableEncodingPenalty(), x[3]) === nothing + @test Attributes.variable_encoding_penalty(virtual_model, x[3]) === nothing @test MOI.get(virtual_model, Attributes.ConstraintEncodingPenaltyHint(), c[1]) == -10.0 @test MOI.get(virtual_model, Attributes.ConstraintEncodingPenaltyHint(), c[2]) === nothing @test MOI.get(virtual_model, Attributes.ConstraintEncodingPenalty(), c[1]) == -10.0 - @test MOI.get(virtual_model, Attributes.ConstraintEncodingPenalty(), c[2]) == -4.0 + @test MOI.get(virtual_model, Attributes.ConstraintEncodingPenalty(), c[2]) <= 0.0 @test MOI.get(model, Attributes.SlackVariableEncodingPenalty(), c[1]) == -100.0 + + @test MOI.get(virtual_model, Attributes.CompilationStatus()) === MOI.LOCALLY_SOLVED + @test Attributes.compilation_status(virtual_model) === MOI.LOCALLY_SOLVED + + @test MOI.get(virtual_model, Attributes.CompilationTime()) > 0.0 + @test Attributes.compilation_time(virtual_model) > 0.0 end end end