Skip to content

Commit

Permalink
Redefine cast + add warm_start
Browse files Browse the repository at this point in the history
  • Loading branch information
pedromxavier committed Apr 13, 2023
1 parent 3898bf8 commit 954ba5c
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 206 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ authors = [
"joaquimg <[email protected]>",
"bernalde <[email protected]>"
]
version = "0.6.1"
version = "0.7.0"

[deps]
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
Expand Down
3 changes: 1 addition & 2 deletions src/formats/bqpjson/parser.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
3 changes: 1 addition & 2 deletions src/formats/minizinc/parser.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
15 changes: 4 additions & 11 deletions src/interface/fallback.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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.
"""
)
Expand All @@ -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...)
Expand Down
49 changes: 18 additions & 31 deletions src/interface/generic/cast.jl
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -28,51 +28,47 @@ function cast(::Sense, ::Sense, Q̄::Dict{Tuple{Int,Int},T}) where {T}
end

function cast(
::S,
::S,
::Pair{S,S},
::Dict{Int,T},
::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̄)

return (L, Q, α, β)
end

function cast(
source::Sense,
target::Sense,
route::Pair{A,B},
::Dict{Int,T},
::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},
::Dict{Int,T},
::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̄)

return (L, Q, α, β)
end

function cast(
::SpinDomain,
::BoolDomain,
::Pair{SpinDomain,BoolDomain},
::Dict{Int,T},
::Dict{Tuple{Int,Int},T},
α::T = one(T),
Expand All @@ -97,8 +93,7 @@ function cast(
end

function cast(
::BoolDomain,
::SpinDomain,
::Pair{BoolDomain,SpinDomain},
::Dict{Int,T},
::Dict{Tuple{Int,Int},T},
α::T = one(T),
Expand All @@ -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
43 changes: 19 additions & 24 deletions src/interface/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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"""
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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:
Expand All @@ -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`.
Expand Down Expand Up @@ -427,4 +421,5 @@ Reverses the sign of the objective value.

@doc raw"""
supports_read(::Type{F}) where {F<:AbstractFormat}
""" function supports_write end
43 changes: 20 additions & 23 deletions src/library/sampleset.jl
Original file line number Diff line number Diff line change
@@ -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"""
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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
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
Loading

2 comments on commit 954ba5c

@pedromxavier
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/81517

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.7.0 -m "<description of version>" 954ba5c0e144fbb380ea8109a0d50080533d0b54
git push origin v0.7.0

Please sign in to comment.