Skip to content

Commit

Permalink
Merge pull request #33 from psrenergy/px/domain-attribute
Browse files Browse the repository at this point in the history
Rewrite Interface
  • Loading branch information
pedromxavier authored Jan 6, 2023
2 parents b10838b + 8486167 commit 3c05d5f
Show file tree
Hide file tree
Showing 48 changed files with 1,027 additions and 1,047 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.5.4"
version = "0.6.0"

[deps]
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ flowchart TD;
```

## Backend
The `AbstractModel{D}` abstract type is defined, where `D <: VariableDomain`.
The `AbstractModel{D}` abstract type is defined, where `D <: Domain`.
Available variable domains are `BoolDomain` and `SpinDomain`, respectively, $x \in \mathbb{B} = \lbrace 0, 1 \rbrace$ and $s \in \lbrace -1, 1 \rbrace$.
Conversion between domains follows the identity

Expand Down
4 changes: 2 additions & 2 deletions docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ QUBOTools.backend

### Variable System
```@docs
QUBOTools.varcmp
QUBOTools.varlt
```

### Variable Domains
```@docs
QUBOTools.VariableDomain
QUBOTools.Domain
QUBOTools.BoolDomain
QUBOTools.SpinDomain
QUBOTools.UnknownDomain
Expand Down
8 changes: 4 additions & 4 deletions src/QUBOTools.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ using InteractiveUtils: subtypes

# ~*~ Variable comparison ~*~ #
@doc raw"""
varcmp(x::V, y::V) where {V}
varlt(x::V, y::V) where {V}
This function exists to define an arbitrary ordering for a given type and was created to address [1].
There is no predefined comparison between instances MOI's `VariableIndex` type.
[1] https://github.com/jump-dev/MathOptInterface.jl/issues/1985
""" function varcmp end
""" function varlt end

varcmp(x::V, y::V) where {V} = isless(x, y)
varlt(x::V, y::V) where {V} = isless(x, y)

const = varcmp # \prec[tab]
const = varlt # \prec[tab]
const = -1 # \uparrow[tab]
const = +1 # \downarrow[tab]

Expand Down
40 changes: 30 additions & 10 deletions src/formats/bqpjson/format.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,41 @@ const _BQPJSON_SCHEMA = JSONSchema.Schema(JSON.parsefile(_BQPJSON_SCHEMA
const _BQPJSON_VERSION_LIST = VersionNumber[v"1.0.0"]
const _BQPJSON_VERSION_LATEST = _BQPJSON_VERSION_LIST[end]

_BQPJSON_VARIABLE_DOMAIN(::Type{BoolDomain}) = "boolean"
_BQPJSON_VARIABLE_DOMAIN(::Type{SpinDomain}) = "spin"
_BQPJSON_VARIABLE_DOMAIN(::BoolDomain) = "boolean"
_BQPJSON_VARIABLE_DOMAIN(::SpinDomain) = "spin"

_BQPJSON_VALIDATE_DOMAIN(x::Integer, ::Type{BoolDomain}) = (x == 0) || (x == 1)
_BQPJSON_VALIDATE_DOMAIN(s::Integer, ::Type{SpinDomain}) = (s == ) || (s == )
_BQPJSON_VALIDATE_DOMAIN(x::Integer, ::BoolDomain) = (x == 0) || (x == 1)
_BQPJSON_VALIDATE_DOMAIN(s::Integer, ::SpinDomain) = (s == ) || (s == )

@doc raw"""
BQPJSON{D}() where {D<:VariableDomain}
BQPJSON
Precise and detailed information found in the [bqpjson docs](https://bqpjson.readthedocs.io)
""" struct BQPJSON{D} <: AbstractFormat{D} end
""" struct BQPJSON <: AbstractFormat
domain::Union{BoolDomain,SpinDomain,Nothing}
indent::Int

BQPJSON(domain::Union{Symbol,Domain}) = new(Domain(domain))

function BQPJSON(
dom::Union{BoolDomain,SpinDomain,Nothing} = nothing,
sty::Nothing = nothing;
indent::Integer = 0,
)
return new(dom, indent)
end
end

domain(fmt::BQPJSON) = fmt.domain

supports_domain(::Type{BQPJSON}, ::Nothing) = true
supports_domain(::Type{BQPJSON}, ::BoolDomain) = true
supports_domain(::Type{BQPJSON}, ::SpinDomain) = true

infer_format(::Val{:json}) = BQPJSON(nothing, nothing)
infer_format(::Val{:bool}, ::Val{:json}) = BQPJSON(𝔹, nothing)
infer_format(::Val{:spin}, ::Val{:json}) = BQPJSON(𝕊, nothing)

infer_format(::Val{:json}) = BQPJSON{UnknownDomain}()
infer_format(::Val{:bool}, ::Val{:json}) = BQPJSON{BoolDomain}()
infer_format(::Val{:spin}, ::Val{:json}) = BQPJSON{SpinDomain}()

include("parser.jl")
include("printer.jl")
include("printer.jl")
100 changes: 53 additions & 47 deletions src/formats/bqpjson/parser.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,53 @@
function read_model(io::IO, fmt::BQPJSON)
json_data = JSON.parse(io)
report = JSONSchema.validate(_BQPJSON_SCHEMA, json_data)

if !isnothing(report)
codec_error("Schema violation:\n$(report)")
end

data = Dict{Symbol,Any}(
:id => json_data["id"],
:scale => json_data["scale"],
:offset => json_data["offset"],
:variable_set => Set{Int}(json_data["variable_ids"]),
:linear_terms => Dict{Int,Float64}(),
:quadratic_terms => Dict{Tuple{Int,Int},Float64}(),
:description => get(json_data, "description", nothing),
:metadata => deepcopy(json_data["metadata"]),
)

_parse_version!(fmt, data, json_data)
_parse_domain!(fmt, data, json_data)
_parse_terms!(fmt, data, json_data)
_parse_solutions!(fmt, data, json_data)

target_domain = something(domain(fmt), data[:domain])

L, Q, α, β = swap_domain(
data[:domain],
target_domain,
data[:linear_terms],
data[:quadratic_terms],
data[:scale],
data[:offset],
)

return StandardModel(
L,
Q;
scale = α,
offset = β,
sense = Sense(:min),
domain = target_domain,
id = data[:id],
version = data[:version],
description = data[:description],
metadata = data[:metadata],
sampleset = data[:sampleset],
)
end

function _parse_version!(::BQPJSON, data::Dict{Symbol,Any}, json_data::Dict{String,Any})
bqpjson_version = VersionNumber(json_data["version"])

Expand All @@ -14,9 +64,9 @@ function _parse_domain!(::BQPJSON, data::Dict{Symbol,Any}, json_data::Dict{Strin
bqpjson_domain = json_data["variable_domain"]

if bqpjson_domain == "boolean"
data[:domain] = BoolDomain
data[:domain] = BoolDomain()
elseif bqpjson_domain == "spin"
data[:domain] = SpinDomain
data[:domain] = SpinDomain()
else
codec_error("Inconsistent variable domain '$variable_domain'")
end
Expand Down Expand Up @@ -110,51 +160,7 @@ function _parse_solutions!(::BQPJSON, data::Dict{Symbol,Any}, json_data::Dict{St
end
end

data[:sampleset] = SampleSet{Float64,Int}(samples)
data[:sampleset] = SampleSet{Float64,Int}(samples, solution_metadata)

return nothing
end

function read_model(io::IO, fmt::BQPJSON{D}) where {D}
json_data = JSON.parse(io)
report = JSONSchema.validate(_BQPJSON_SCHEMA, json_data)

if !isnothing(report)
codec_error("Schema violation:\n$(report)")
end

data = Dict{Symbol,Any}(
:id => json_data["id"],
:scale => json_data["scale"],
:offset => json_data["offset"],
:variable_set => Set{Int}(json_data["variable_ids"]),
:linear_terms => Dict{Int,Float64}(),
:quadratic_terms => Dict{Tuple{Int,Int},Float64}(),
:description => get(json_data, "description", nothing),
:metadata => deepcopy(json_data["metadata"]),
)

_parse_version!(fmt, data, json_data)
_parse_domain!(fmt, data, json_data)
_parse_terms!(fmt, data, json_data)
_parse_solutions!(fmt, data, json_data)

model = StandardModel{data[:domain]}(
data[:linear_terms],
data[:quadratic_terms];
scale = data[:scale],
offset = data[:offset],
id = data[:id],
version = data[:version],
description = data[:description],
metadata = data[:metadata],
sampleset = data[:sampleset],
)

if D === UnknownDomain
return model
else
return convert(StandardModel{D}, model)
end
end

10 changes: 3 additions & 7 deletions src/formats/bqpjson/printer.jl
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
function write_model(io::IO, model::AbstractModel{D}, ::BQPJSON{UnknownDomain}) where {D}
return write_model(io, model, BQPJSON{D}())
end

function write_model(io::IO, model::AbstractModel{D}, ::BQPJSON{D}) where {D<:VariableDomain}
function write_model(io::IO, model::AbstractModel, fmt::BQPJSON)
data = Dict{Symbol,Any}(
:linear_terms => Dict{String,Any}[],
:quadratic_terms => Dict{String,Any}[],
:offset => offset(model),
:scale => scale(model),
:id => id(model),
:version => version(model),
:variable_domain => _BQPJSON_VARIABLE_DOMAIN(D),
:variable_domain => _BQPJSON_VARIABLE_DOMAIN(domain(model)),
:variable_ids => variables(model),
:description => description(model),
:metadata => metadata(model),
Expand Down Expand Up @@ -90,7 +86,7 @@ function write_model(io::IO, model::AbstractModel{D}, ::BQPJSON{D}) where {D<:Va
json_data["solutions"] = solutions
end

JSON.print(io, json_data)
JSON.print(io, json_data, fmt.indent)

return nothing
end
41 changes: 0 additions & 41 deletions src/formats/error.jl

This file was deleted.

3 changes: 0 additions & 3 deletions src/formats/formats.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
include("error.jl")
include("interface.jl")

# ~ Supported Formats ~ #
include("bqpjson/format.jl")
include("hfs/format.jl")
Expand Down
6 changes: 3 additions & 3 deletions src/formats/hfs/chimera.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,16 @@ There is an edge from ``v_p`` to ``v_q`` if at least one of the following holds:
end
end

function Chimera(model::AbstractModel{D}, fmt::HFS{D}) where {D}
function Chimera(model::AbstractModel, fmt::HFS)
return Chimera(model, fmt.chimera_cell_size, fmt.chimera_degree, fmt.chimera_precision)
end

function Chimera(
model::AbstractModel{D},
model::AbstractModel,
chimera_cell_size::Union{Integer,Nothing} = nothing,
chimera_degree::Union{Integer,Nothing} = nothing,
chimera_precision::Union{Integer,Nothing} = nothing,
) where {D}
)
variable_set = QUBOTools.variable_set(model)
linear_terms = QUBOTools.linear_terms(model)
quadratic_terms = QUBOTools.quadratic_terms(model)
Expand Down
18 changes: 11 additions & 7 deletions src/formats/hfs/format.jl
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
@doc raw"""
HFS{BoolDomain}
HFS
This format offers a description for the setup of chimera graphs.
""" struct HFS{D<:𝔹} <: AbstractFormat{D}
""" struct HFS <: AbstractFormat
chimera_cell_size::Union{Int,Nothing}
chimera_precision::Union{Int,Nothing}
chimera_degree::Union{Int,Nothing}

function HFS{D}(;
function HFS(
dom::BoolDomain = BoolDomain(),
sty::Nothing = nothing;
chimera_cell_size::Union{Int,Nothing} = nothing,
chimera_precision::Union{Int,Nothing} = nothing,
chimera_degree::Union{Int,Nothing} = nothing,
) where {D}
return new{D}(chimera_cell_size, chimera_precision, chimera_degree)
)
return new(chimera_cell_size, chimera_precision, chimera_degree)
end
end

HFS(args...; kws...) = HFS{𝔹}(args...; kws...)
domain(::HFS) = BoolDomain()

infer_format(::Val{:hfs}) = HFS()
supports_domain(::Type{HFS}, ::BoolDomain) = true

infer_format(::Val{:hfs}) = HFS(𝔹, nothing)

include("chimera.jl")
include("parser.jl")
Expand Down
2 changes: 1 addition & 1 deletion src/formats/hfs/printer.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function write_model(io::IO, model::AbstractModel{D}, fmt::HFS{D}) where {D}
function write_model(io::IO, model::AbstractModel, fmt::HFS)
if isempty(model)
return write(io, "0 0")
end
Expand Down
Loading

2 comments on commit 3c05d5f

@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/75235

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.6.0 -m "<description of version>" 3c05d5f0b525331fbeacdf592cd9f7a11fbd404b
git push origin v0.6.0

Please sign in to comment.