From 954ba5c0e144fbb380ea8109a0d50080533d0b54 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Xavier Date: Thu, 13 Apr 2023 00:04:13 -0300 Subject: [PATCH] Redefine `cast` + add `warm_start` --- Project.toml | 2 +- src/formats/bqpjson/parser.jl | 3 +- src/formats/minizinc/parser.jl | 3 +- src/interface/fallback.jl | 15 ++---- src/interface/generic/cast.jl | 49 +++++++------------ src/interface/interface.jl | 43 ++++++++--------- src/library/sampleset.jl | 43 ++++++++--------- src/model/abstract.jl | 18 ++++--- src/model/model.jl | 48 +++++++++++-------- test/unit/interface/generic.jl | 86 ++++++++++------------------------ test/unit/library/sampleset.jl | 50 ++++++++++---------- 11 files changed, 154 insertions(+), 206 deletions(-) diff --git a/Project.toml b/Project.toml index 75de1383..43e3ea7b 100644 --- a/Project.toml +++ b/Project.toml @@ -7,7 +7,7 @@ authors = [ "joaquimg ", "bernalde " ] -version = "0.6.1" +version = "0.7.0" [deps] InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" diff --git a/src/formats/bqpjson/parser.jl b/src/formats/bqpjson/parser.jl index 772319a6..9bcdebe5 100644 --- a/src/formats/bqpjson/parser.jl +++ b/src/formats/bqpjson/parser.jl @@ -25,8 +25,7 @@ function read_model(io::IO, fmt::BQPJSON) target_domain = something(domain(fmt), data[:domain]) L, Q, α, β = cast( - data[:domain], - target_domain, + data[:domain] => target_domain, data[:linear_terms], data[:quadratic_terms], data[:scale], diff --git a/src/formats/minizinc/parser.jl b/src/formats/minizinc/parser.jl index 67b1560e..7d707fd6 100644 --- a/src/formats/minizinc/parser.jl +++ b/src/formats/minizinc/parser.jl @@ -213,8 +213,7 @@ function read_model(io::IO, fmt::MiniZinc) target_domain = something(domain(fmt), data[:domain]) L, Q, α, β = cast( - data[:domain], - target_domain, + data[:domain] => target_domain, data[:linear_terms], data[:quadratic_terms], data[:scale], diff --git a/src/interface/fallback.jl b/src/interface/fallback.jl index ba792b24..c9bac31f 100644 --- a/src/interface/fallback.jl +++ b/src/interface/fallback.jl @@ -5,19 +5,11 @@ This file contains fallback implementations by calling the model's backend. This allows for external models to define a QUBOTools-based backend and profit from these queries. """ -# ~*~ Frontend & Backend ~*~ # -# The `frontend` implementation defaults to `backend` -# because most of the time people will not be working -# with two equivalent models as in `TwinModel`'s API. -function frontend(model) - return backend(model) -end - -function backend(::M) where {M<:AbstractModel} +function backend(::M) where {M} error( """ - The '$M' QUBO Model Type has an incomplete inferface. - It should either implement `backend(::$M)` or the complete `AbstractModel` API. + '$M' has an incomplete inferface for 'QUBOTools'. + It should either implement 'backend(::$M)' or the complete 'AbstractModel' API. Run `julia> ?QUBOTools.AbstractModel` for more information. """ ) @@ -42,6 +34,7 @@ variables(model) = variables(backend(model)) variable_set(model) = variable_set(backend(model)) variable_map(model, args...) = variable_map(backend(model), args...) variable_inv(model, args...) = variable_inv(backend(model), args...) +warm_start(model, args...) = warm_start(backend(model), args...) # ~*~ Model's Normal Forms ~*~ # qubo(model, args...) = qubo(backend(model), args...) diff --git a/src/interface/generic/cast.jl b/src/interface/generic/cast.jl index 70f7ea48..5f73b28a 100644 --- a/src/interface/generic/cast.jl +++ b/src/interface/generic/cast.jl @@ -1,9 +1,9 @@ # -* Sense *- # -function cast(::S, ::S, L̄::Dict{Int,T}) where {S<:Sense,T} +function cast(::Pair{S,S}, L̄::Dict{Int,T}) where {T,S<:Sense} return copy(L̄) end -function cast(::Sense, ::Sense, L̄::Dict{Int,T}) where {T} +function cast(::Pair{A,B}, L̄::Dict{Int,T}) where {T,A<:Sense,B<:Sense} L = sizehint!(Dict{Int,T}(), length(L̄)) for (i, c) in L̄ @@ -13,11 +13,11 @@ function cast(::Sense, ::Sense, L̄::Dict{Int,T}) where {T} return L end -function cast(::S, ::S, Q̄::Dict{Tuple{Int,Int},T}) where {S<:Sense,T} +function cast(::Pair{S,S}, Q̄::Dict{Tuple{Int,Int},T}) where {T,S<:Sense} return copy(Q̄) end -function cast(::Sense, ::Sense, Q̄::Dict{Tuple{Int,Int},T}) where {T} +function cast(::Pair{A,B}, Q̄::Dict{Tuple{Int,Int},T}) where {T,A<:Sense,B<:Sense} Q = sizehint!(Dict{Tuple{Int,Int},T}(), length(Q̄)) for (ij, c) in Q̄ @@ -28,13 +28,12 @@ function cast(::Sense, ::Sense, Q̄::Dict{Tuple{Int,Int},T}) where {T} end function cast( - ::S, - ::S, + ::Pair{S,S}, L̄::Dict{Int,T}, Q̄::Dict{Tuple{Int,Int},T}, α::T = one(T), β::T = zero(T), -) where {S<:Sense,T} +) where {T,S<:Sense} L = copy(L̄) Q = copy(Q̄) @@ -42,28 +41,26 @@ function cast( end function cast( - source::Sense, - target::Sense, + route::Pair{A,B}, L̄::Dict{Int,T}, Q̄::Dict{Tuple{Int,Int},T}, α::T = one(T), β::T = zero(T), -) where {T} - L = cast(source, target, L̄) - Q = cast(source, target, Q̄) +) where {T,A<:Sense,B<:Sense} + L = cast(route, L̄) + Q = cast(route, Q̄) return (L, Q, α, -β) end # -* Domain *- # function cast( - ::D, - ::D, + ::Pair{D,D}, L̄::Dict{Int,T}, Q̄::Dict{Tuple{Int,Int},T}, α::T = one(T), β::T = zero(T), -) where {D<:Domain,T} +) where {T,D<:Domain} L = copy(L̄) Q = copy(Q̄) @@ -71,8 +68,7 @@ function cast( end function cast( - ::SpinDomain, - ::BoolDomain, + ::Pair{SpinDomain,BoolDomain}, L̄::Dict{Int,T}, Q̄::Dict{Tuple{Int,Int},T}, α::T = one(T), @@ -97,8 +93,7 @@ function cast( end function cast( - ::BoolDomain, - ::SpinDomain, + ::Pair{BoolDomain,SpinDomain}, L̄::Dict{Int,T}, Q̄::Dict{Tuple{Int,Int},T}, α::T = one(T), @@ -122,19 +117,11 @@ function cast( return (L, Q, α, β) end - -# -* Model *- # -function cast(source::AbstractModel, target::AbstractModel, data) - return cast(sense(source), sense(target), domain(source), domain(target), data) -end - # -* Chain *- # function cast( - source_sense::Sense, - target_sense::Sense, - source_domain::Domain, - target_domain::Domain, + sense_route::Pair{A,B}, + domain_route::Pair{X,Y}, data, -) - return cast(source_sense, target_sense, cast(source_domain, target_domain, data)) +) where {A<:Sense,B<:Sense,X<:Domain,Y<:Domain} + return cast(sense_route, cast(domain_route, data)) end diff --git a/src/interface/interface.jl b/src/interface/interface.jl index 9f6a5370..4903a933 100644 --- a/src/interface/interface.jl +++ b/src/interface/interface.jl @@ -46,14 +46,6 @@ Returns a list containing all available QUBO file formats. Given a file path, tries to infer the type associated to a QUBO model format. """ function infer_format end -@doc raw""" - frontend(model)::AbstractModel - frontend(model::AbstractModel)::AbstractModel - -Retrieves the model's backend. -Implementing this function allows one to profit from fallback implementations of the other methods. -""" function frontend end - @doc raw""" backend(model)::AbstractModel backend(model::AbstractModel)::AbstractModel @@ -101,7 +93,10 @@ Returns the list of available known variable domains. """ function offset end -abstract type Sense end +@doc raw""" + Sense + +""" abstract type Sense end @doc raw""" sense(model)::Sense @@ -121,7 +116,8 @@ abstract type Sense end """ function description end @doc raw""" - metadata(model) + metadata(model::AbstractModel) + metadata(sampleset::SampleSet) """ function metadata end @doc raw""" @@ -179,8 +175,8 @@ Returns the set of variables of a given model. """ function variable_map end @doc raw""" -variable_inv(model)::Dict{Int,V} where {V} -variable_inv(model, i::Integer)::V where {V} + variable_inv(model)::Dict{Int,V} where {V} + variable_inv(model, i::Integer)::V where {V} """ function variable_inv end @@ -369,15 +365,13 @@ If a second parameter, an integer, is present, then the set of neighbors of that @doc raw""" cast( - source_sense::Sense, - source_domain::Domain, - target_sense::Sense, - target_domain::Domain, - x::Any - ) + sense_route::Pair{A,B}, + domain_route::Pair{X,Y}, + data, + ) where {A<:Sense,B<:Sense,X<:Domain,Y<:Domain} cast(::S, ::S, model::AbstractModel) where {S<:Sense} - cast(::S1, ::S2, model::AbstractModel) where {S1<:Sense,S2<:Sense} + cast(::A, ::B, model::AbstractModel) where {A<:Sense,B<:Sense} Recasting the sense of a model preserves its meaning: @@ -391,14 +385,14 @@ Recasting the sense of a model preserves its meaning: The linear terms, quadratic terms and constant offset of a model have its signs reversed. cast(::S, ::S, s::Sample) where {S<:Sense} - cast(::Sense, ::Sense, s::Sample) where {S1<:Sense,S2<:Sense} + cast(::A, ::B, s::Sample) where {A<:Sense,B<:Sense} cast(::S, ::S, ω::SampleSet) where {S<:Sense} - cast(::Sense, ::Sense, ω::SampleSet) where {S1<:Sense,S2<:Sense} + cast(::A, ::B, ω::SampleSet) where {A<:Sense,B<:Sense} cast(target, model::AbstractModel) - cast(source, target, ψ::Vector{U}) - cast(source, target, Ψ::Vector{Vector{U}}) - cast(source, target, ω::SampleSet) + cast(route, ψ::Vector{U}) + cast(route, Ψ::Vector{Vector{U}}) + cast(route, ω::SampleSet) Returns a new object, switching its domain from `source` to `target`. @@ -427,4 +421,5 @@ Reverses the sign of the objective value. @doc raw""" supports_read(::Type{F}) where {F<:AbstractFormat} + """ function supports_write end \ No newline at end of file diff --git a/src/library/sampleset.jl b/src/library/sampleset.jl index 435611b4..7fe93f14 100644 --- a/src/library/sampleset.jl +++ b/src/library/sampleset.jl @@ -1,12 +1,14 @@ -function cast(::D, ::D, ψ::Vector{U}) where {D<:Domain,U<:Integer} +function cast(::Pair{D,D}, ψ::Vector{U}) where {U<:Integer,D<:Domain} return copy(ψ) end -cast(::BoolDomain, ::SpinDomain, ψ::Vector{U}) where {U<:Integer} = (2 .* ψ) .- 1 -cast(::SpinDomain, ::BoolDomain, ψ::Vector{U}) where {U<:Integer} = (ψ .+ 1) .÷ 2 +cast(::Pair{BoolDomain,SpinDomain}, x::Integer) = (2 * x) - 1 +cast(::Pair{SpinDomain,BoolDomain}, s::Integer) = (s + 1) ÷ 2 +cast(::Pair{BoolDomain,SpinDomain}, ψ::Vector{U}) where {U<:Integer} = (2 .* ψ) .- 1 +cast(::Pair{SpinDomain,BoolDomain}, ψ::Vector{U}) where {U<:Integer} = (ψ .+ 1) .÷ 2 -function cast(source::Domain, target::Domain, Ψ::Vector{Vector{U}}) where {U<:Integer} - return cast.(source, target, Ψ) +function cast(route::Pair{X,Y}, Ψ::Vector{Vector{U}}) where {U<:Integer,X<:Domain,Y<:Domain} + return cast.(route, Ψ) end @doc raw""" @@ -92,15 +94,15 @@ function format(data::Vector{Sample{T,U}}) where {T,U} return sort(collect(values(cache))) end -function cast(source::Domain, target::Domain, s::Sample{T,U}) where {T,U} - return Sample{T,U}(cast(source, target, state(s)), value(s), reads(s)) +function cast(route::Pair{X,Y}, s::Sample{T,U}) where {T,U,X<:Domain,Y<:Domain} + return Sample{T,U}(cast(route, state(s)), value(s), reads(s)) end -function cast(::S, ::S, s::Sample{T,U}) where {S<:Sense,T,U} +function cast(::Pair{S,S}, s::Sample{T,U}) where {S<:Sense,T,U} return Sample{T,U}(state(s), value(s), reads(s)) end -function cast(::S1, ::S2, s::Sample{T,U}) where {S1<:Sense,S2<:Sense,T,U} +function cast(::Pair{A,B}, s::Sample{T,U}) where {T,U,A<:Sense,B<:Sense} return Sample{T,U}(state(s), -value(s), reads(s)) end @@ -189,18 +191,19 @@ reads(ω::AbstractSampleSet) = sum(reads.(ω)) @doc raw""" SampleSet{T,U}( data::Vector{Sample{T,U}}, - metadata::Dict{String, Any}, + metadata::Dict{String,Any}, ) where {T,U} It compresses repeated states by adding up the `reads` field. -It was inspired by [1], with a few tweaks. +It was inspired by [^dwave], with a few tweaks. !!! info A `SampleSet{T,U}` was designed to be read-only. It is optimized to support queries over the solution set. ## References -[1] [ocean docs](https://docs.ocean.dwavesys.com/en/stable/docs_dimod/reference/S.html#dimod.SampleSet) +[^dwave]: + [ocean docs](https://docs.ocean.dwavesys.com/en/stable/docs_dimod/reference/S.html#dimod.SampleSet) """ struct SampleSet{T,U} <: AbstractSampleSet{T,U} data::Vector{Sample{T,U}} metadata::Dict{String,Any} @@ -265,16 +268,10 @@ Base.iterate(ω::SampleSet, i::Integer) = iterate(ω.data, i) metadata(ω::SampleSet) = ω.metadata -function cast(source::Domain, target::Domain, ω::SampleSet{T,U}) where {T,U} - return SampleSet{T,U}( - Vector{Sample{T,U}}(cast.(source, target, ω)), - deepcopy(metadata(ω)), - ) +function cast(route::Pair{A,B}, ω::SampleSet{T,U}) where {T,U,A<:Sense,B<:Sense} + return SampleSet{T,U}(Vector{Sample{T,U}}(cast.(route, ω)), deepcopy(metadata(ω))) end -function cast(source::Sense, target::Sense, ω::SampleSet{T,U}) where {T,U} - return SampleSet{T,U}( - Vector{Sample{T,U}}(cast.(source, target, ω)), - deepcopy(metadata(ω)), - ) -end \ No newline at end of file +function cast(route::Pair{X,Y}, ω::SampleSet{T,U}) where {T,U,X<:Domain,Y<:Domain} + return SampleSet{T,U}(Vector{Sample{T,U}}(cast.(route, ω)), deepcopy(metadata(ω))) +end diff --git a/src/model/abstract.jl b/src/model/abstract.jl index 4880cb6f..aa28d73a 100644 --- a/src/model/abstract.jl +++ b/src/model/abstract.jl @@ -40,13 +40,20 @@ function variable_inv(model::AbstractModel, i::Integer) end end +function warm_start(model::AbstractModel{V,T}, i::Integer) where {V,T} + return warm_start(model, variable_inv(model, i)) +end + +function warm_start(model::AbstractModel{V,T}, v::V) where {V,T} + return get(warm_start(model), v, nothing) +end + # ~*~ Model's Normal Forms ~*~ # function qubo(model::AbstractModel, type::Type = Dict) n = domain_size(model) L, Q, α, β = cast( - domain(model), - Domain(:bool), + domain(model) => Domain(:bool), linear_terms(model), quadratic_terms(model), scale(model), @@ -149,8 +156,7 @@ function ising(model::AbstractModel, type::Type = Dict) n = domain_size(model) L, Q, α, β = cast( - domain(model), - Domain(:spin), + domain(model) => Domain(:spin), linear_terms(model), quadratic_terms(model), scale(model), @@ -436,9 +442,9 @@ end # -* Casting Fallback *- # function cast(target::Sense, model::AbstractModel) - return cast(sense(model), target, model) + return cast(sense(model) => target, model) end function cast(target::Domain, model::AbstractModel) - return cast(domain(model), target, model) + return cast(domain(model) => target, model) end \ No newline at end of file diff --git a/src/model/model.jl b/src/model/model.jl index 6ea9d84e..8ef6cf13 100644 --- a/src/model/model.jl +++ b/src/model/model.jl @@ -28,8 +28,9 @@ By choosing `V = MOI.VariableIndex` and `T` matching `Optimizer{T}` the hard wor id::Union{Int,Nothing} version::Union{VersionNumber,Nothing} description::Union{String,Nothing} - metadata::Union{Dict{String,Any},Nothing} + metadata::Dict{String,Any} # ~*~ Solutions ~*~ + warm_start::Dict{V,U} sampleset::SampleSet{T,U} function Model{V,T,U}( @@ -50,13 +51,16 @@ By choosing `V = MOI.VariableIndex` and `T` matching `Optimizer{T}` the hard wor description::Union{String,Nothing} = nothing, metadata::Union{Dict{String,Any},Nothing} = nothing, # ~*~ Solutions ~*~ + warm_start::Union{Dict{V,U},Nothing} = nothing, sampleset::Union{SampleSet{T,U},Nothing} = nothing, ) where {V,T,U} - scale = isnothing(scale) ? one(T) : scale - offset = isnothing(offset) ? zero(T) : offset - sense = isnothing(sense) ? Sense(:min) : Sense(sense) - domain = isnothing(domain) ? nothing : Domain(domain) - sampleset = isnothing(sampleset) ? SampleSet{T,U}() : sampleset + scale = isnothing(scale) ? one(T) : scale + offset = isnothing(offset) ? zero(T) : offset + sense = isnothing(sense) ? Sense(:min) : Sense(sense) + domain = isnothing(domain) ? nothing : Domain(domain) + metadata = isnothing(metadata) ? Dict{String,Any}() : metadata + warm_start = isnothing(warm_start) ? Dict{V,U}() : warm_start + sampleset = isnothing(sampleset) ? SampleSet{T,U}() : sampleset return new{V,T,U}( linear_terms, @@ -71,6 +75,7 @@ By choosing `V = MOI.VariableIndex` and `T` matching `Optimizer{T}` the hard wor version, description, metadata, + warm_start, sampleset, ) end @@ -100,8 +105,11 @@ function Model{V,T,U}( variable_map, variable_inv = _build_mapping(_variable_set) - linear_terms, quadratic_terms = - _map_terms(_linear_terms, _quadratic_terms, variable_map) + linear_terms, quadratic_terms = _map_terms( + _linear_terms, + _quadratic_terms, + variable_map, + ) return Model{V,T,U}(linear_terms, quadratic_terms, variable_map, variable_inv; kws...) end @@ -134,8 +142,9 @@ function Base.empty!(model::Model{V,T,U}) where {V,T,U} model.id = nothing model.version = nothing model.description = nothing - model.metadata = nothing - model.sampleset = SampleSet{T,U}() + empty!(model.metadata) + empty!(model.warm_start) + empty!(model.sampleset) return model end @@ -158,6 +167,7 @@ function Base.copy(model::Model{V,T,U}) where {V,T,U} version = version(model), description = description(model), metadata = deepcopy(metadata(model)), + warm_start = deepcopy(warm_start(model)), sampleset = copy(sampleset(model)), ) end @@ -176,12 +186,12 @@ id(model::Model) = model.id version(model::Model) = model.version description(model::Model) = model.description metadata(model::Model) = model.metadata +warm_start(model::Model) = model.warm_start sampleset(model::Model) = model.sampleset -function cast(source::Domain, target::Domain, model::Model{V,T,U}) where {V,T,U} +function cast(route::Pair{X,Y}, model::Model{V,T,U}) where {V,T,U,X<:Domain,Y<:Domain} L, Q, α, β = cast( - source, - target, + route, linear_terms(model), quadratic_terms(model), scale(model), @@ -201,14 +211,13 @@ function cast(source::Domain, target::Domain, model::Model{V,T,U}) where {V,T,U} version = version(model), description = description(model), metadata = metadata(model), - sampleset = cast(source, target, sampleset(model)), + sampleset = cast(route, sampleset(model)), ) end -function cast(source::Sense, target::Sense, model::Model{V,T,U}) where {V,T,U} +function cast(route::Pair{A,B}, model::Model{V,T,U}) where {V,T,U,A<:Sense,B<:Sense} L, Q, α, β = cast( - source, - target, + route, linear_terms(model), quadratic_terms(model), scale(model), @@ -228,7 +237,7 @@ function cast(source::Sense, target::Sense, model::Model{V,T,U}) where {V,T,U} version = version(model), description = description(model), metadata = deepcopy(metadata(model)), - sampleset = cast(source, target, sampleset(model)), + sampleset = cast(route, sampleset(model)), ) end @@ -245,9 +254,10 @@ function Base.copy!(target::Model{V,T,U}, source::Model{V,T,U}) where {V,T,U} target.version = version(source) target.description = description(source) target.metadata = deepcopy(metadata(source)) + target.warm_start = deepcopy(warm_start(source)) target.sampleset = copy(sampleset(source)) return target end -const StandardModel = Model{Int,Float64,Int} \ No newline at end of file +const StandardModel = Model{Int,Float64,Int} diff --git a/test/unit/interface/generic.jl b/test/unit/interface/generic.jl index ace7d104..818cfb32 100644 --- a/test/unit/interface/generic.jl +++ b/test/unit/interface/generic.jl @@ -3,26 +3,26 @@ function test_cast() L̄ = Dict{Int,Float64}(1 => 10, 2 => 11, 3 => 12) L = Dict{Int,Float64}(1 => -10, 2 => -11, 3 => -12) - @test cast(Min, Min, L̄) == L̄ - @test cast(Max, Max, L̄) == L̄ - @test cast(Min, Min, L) == L - @test cast(Max, Max, L) == L - @test cast(Min, Max, L̄) == L - @test cast(Max, Min, L̄) == L - @test cast(Min, Max, L) == L̄ - @test cast(Max, Min, L) == L̄ + @test cast(Min => Min, L̄) == L̄ + @test cast(Max => Max, L̄) == L̄ + @test cast(Min => Min, L) == L + @test cast(Max => Max, L) == L + @test cast(Min => Max, L̄) == L + @test cast(Max => Min, L̄) == L + @test cast(Min => Max, L) == L̄ + @test cast(Max => Min, L) == L̄ Q̄ = Dict{Tuple{Int,Int},Float64}((1, 1) => 1.0, (2, 2) => 2.0, (3, 3) => 3.0) Q = Dict{Tuple{Int,Int},Float64}((1, 1) => -1.0, (2, 2) => -2.0, (3, 3) => -3.0) - @test cast(Min, Min, Q̄) == Q̄ - @test cast(Max, Max, Q̄) == Q̄ - @test cast(Min, Min, Q) == Q - @test cast(Max, Max, Q) == Q - @test cast(Min, Max, Q̄) == Q - @test cast(Max, Min, Q̄) == Q - @test cast(Min, Max, Q) == Q̄ - @test cast(Max, Min, Q) == Q̄ + @test cast(Min => Min, Q̄) == Q̄ + @test cast(Max => Max, Q̄) == Q̄ + @test cast(Min => Min, Q) == Q + @test cast(Max => Max, Q) == Q + @test cast(Min => Max, Q̄) == Q + @test cast(Max => Min, Q̄) == Q + @test cast(Min => Max, Q) == Q̄ + @test cast(Max => Min, Q) == Q̄ ᾱ = 1.0 α = 1.0 @@ -30,53 +30,15 @@ function test_cast() β̄ = 1.0 β = -1.0 - @test cast(Min, Min, L̄, Q̄, ᾱ, β̄) == (L̄, Q̄, ᾱ, β̄) - @test cast(Max, Max, L̄, Q̄, ᾱ, β̄) == (L̄, Q̄, ᾱ, β̄) - @test cast(Min, Min, L, Q, α, β) == (L, Q, α, β) - @test cast(Max, Max, L, Q, α, β) == (L, Q, α, β) - @test cast(Min, Max, L̄, Q̄, ᾱ, β̄) == (L, Q, α, β) - @test cast(Max, Min, L̄, Q̄, ᾱ, β̄) == (L, Q, α, β) - @test cast(Min, Max, L, Q, α, β) == (L̄, Q̄, ᾱ, β̄) - @test cast(Max, Min, L, Q, α, β) == (L̄, Q̄, ᾱ, β̄) + @test cast(Min => Min, L̄, Q̄, ᾱ, β̄) == (L̄, Q̄, ᾱ, β̄) + @test cast(Max => Max, L̄, Q̄, ᾱ, β̄) == (L̄, Q̄, ᾱ, β̄) + @test cast(Min => Min, L, Q, α, β) == (L, Q, α, β) + @test cast(Max => Max, L, Q, α, β) == (L, Q, α, β) + @test cast(Min => Max, L̄, Q̄, ᾱ, β̄) == (L, Q, α, β) + @test cast(Max => Min, L̄, Q̄, ᾱ, β̄) == (L, Q, α, β) + @test cast(Min => Max, L, Q, α, β) == (L̄, Q̄, ᾱ, β̄) + @test cast(Max => Min, L, Q, α, β) == (L̄, Q̄, ᾱ, β̄) end - - # sampletest = QUBOTools.Sample([0, 1], 5.0, 3) - # swappedsample = QUBOTools.cast(Min, Max, sampletest) - - # @test QUBOTools.value(sampletest) == -QUBOTools.value(swappedsample) - - - # V = Symbol - # U = Int - # T = Float64 - - # bool_states = [[0, 1], [0, 0], [1, 0], [1, 1]] - - # reads = [2, 1, 3, 4] - # values = [0.0, 2.0, 4.0, 6.0] - # bool_samples1 = [QUBOTools.Sample(s...) for s in zip(bool_states, values, reads)] - # bool_samples2 = [QUBOTools.Sample(s...) for s in zip(bool_states, -values, reads)] - - # model1 = QUBOTools.Model{V,T,U}( - # Dict{V,T}(:x => 1.0, :y => -1.0), - # Dict{Tuple{V,V},T}((:x, :y) => 2.0); - # scale = 2.0, - # offset = 1.0, - # domain = 𝔹, - # id = 1, - # version = v"0.1.0", - # description = "This is a Bool ModelWrapper", - # metadata = Dict{String,Any}("meta" => "data", "type" => "bool"), - # sampleset = QUBOTools.SampleSet(bool_samples1), - # ) - - - # swappedmodel1 = QUBOTools.cast(Max, model1) - - # @test QUBOTools.offset(swappedmodel1) == -QUBOTools.offset(model1) - # @test first(QUBOTools.qubo(swappedmodel1, Matrix)) == - # -first(QUBOTools.qubo(model1, Matrix)) - end function test_generic() diff --git a/test/unit/library/sampleset.jl b/test/unit/library/sampleset.jl index 9b0f8e0f..56bb5f9e 100644 --- a/test/unit/library/sampleset.jl +++ b/test/unit/library/sampleset.jl @@ -13,29 +13,29 @@ function test_samples() @testset "States" begin # ~ Short Circuits ~ # - @test QUBOTools.cast(𝕊, 𝕊, ψ) == ψ - @test QUBOTools.cast(𝕊, 𝕊, ϕ) == ϕ - @test QUBOTools.cast(𝕊, 𝕊, Ψ) == Ψ - @test QUBOTools.cast(𝕊, 𝕊, Φ) == Φ - @test QUBOTools.cast(𝔹, 𝔹, ψ) == ψ - @test QUBOTools.cast(𝔹, 𝔹, ϕ) == ϕ - @test QUBOTools.cast(𝔹, 𝔹, Ψ) == Ψ - @test QUBOTools.cast(𝔹, 𝔹, Φ) == Φ - - @test QUBOTools.cast(𝕊, 𝕊, [Φ, Ψ]) == [Φ, Ψ] - @test QUBOTools.cast(𝕊, 𝕊, [ϕ, ψ]) == [ϕ, ψ] - @test QUBOTools.cast(𝔹, 𝔹, [Φ, Ψ]) == [Φ, Ψ] - @test QUBOTools.cast(𝔹, 𝔹, [ϕ, ψ]) == [ϕ, ψ] + @test QUBOTools.cast(𝕊 => 𝕊, ψ) == ψ + @test QUBOTools.cast(𝕊 => 𝕊, ϕ) == ϕ + @test QUBOTools.cast(𝕊 => 𝕊, Ψ) == Ψ + @test QUBOTools.cast(𝕊 => 𝕊, Φ) == Φ + @test QUBOTools.cast(𝔹 => 𝔹, ψ) == ψ + @test QUBOTools.cast(𝔹 => 𝔹, ϕ) == ϕ + @test QUBOTools.cast(𝔹 => 𝔹, Ψ) == Ψ + @test QUBOTools.cast(𝔹 => 𝔹, Φ) == Φ + + @test QUBOTools.cast(𝕊 => 𝕊, [Φ, Ψ]) == [Φ, Ψ] + @test QUBOTools.cast(𝕊 => 𝕊, [ϕ, ψ]) == [ϕ, ψ] + @test QUBOTools.cast(𝔹 => 𝔹, [Φ, Ψ]) == [Φ, Ψ] + @test QUBOTools.cast(𝔹 => 𝔹, [ϕ, ψ]) == [ϕ, ψ] # ~ State Conversion ~ # - @test QUBOTools.cast(𝔹, 𝕊, Φ) == ϕ - @test QUBOTools.cast(𝔹, 𝕊, Ψ) == ψ - @test QUBOTools.cast(𝕊, 𝔹, ϕ) == Φ - @test QUBOTools.cast(𝕊, 𝔹, ψ) == Ψ + @test QUBOTools.cast(𝔹 => 𝕊, Φ) == ϕ + @test QUBOTools.cast(𝔹 => 𝕊, Ψ) == ψ + @test QUBOTools.cast(𝕊 => 𝔹, ϕ) == Φ + @test QUBOTools.cast(𝕊 => 𝔹, ψ) == Ψ # ~ Multiple States Conversion ~ # - @test QUBOTools.cast(𝔹, 𝕊, [Φ, Ψ]) == [ϕ, ψ] - @test QUBOTools.cast(𝕊, 𝔹, [ϕ, ψ]) == [Φ, Ψ] + @test QUBOTools.cast(𝔹 => 𝕊, [Φ, Ψ]) == [ϕ, ψ] + @test QUBOTools.cast(𝕊 => 𝔹, [ϕ, ψ]) == [Φ, Ψ] end @testset "Samples" begin @@ -261,12 +261,12 @@ function test_samples() @test_throws Exception value(spin_set, 5) # ~ cast ~ # - @test cast(𝕊, 𝕊, bool_set) == bool_set - @test cast(𝔹, 𝔹, bool_set) == bool_set - @test cast(𝕊, 𝕊, spin_set) == spin_set - @test cast(𝔹, 𝔹, spin_set) == spin_set - @test cast(𝔹, 𝕊, bool_set) == spin_set - @test cast(𝕊, 𝔹, spin_set) == bool_set + @test cast(𝕊 => 𝕊, bool_set) == bool_set + @test cast(𝔹 => 𝔹, bool_set) == bool_set + @test cast(𝕊 => 𝕊, spin_set) == spin_set + @test cast(𝔹 => 𝔹, spin_set) == spin_set + @test cast(𝔹 => 𝕊, bool_set) == spin_set + @test cast(𝕊 => 𝔹, spin_set) == bool_set end end end \ No newline at end of file