Skip to content

Commit 6f15b76

Browse files
committed
Add QUBOModel + Tests
1 parent 36c7191 commit 6f15b76

File tree

10 files changed

+358
-112
lines changed

10 files changed

+358
-112
lines changed

ext/QUBOTools_MOI/QUBOTools_MOI.jl

+10-8
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,19 @@ module QUBOTools_MOI
33
import QUBOTools
44
import MathOptInterface as MOI
55

6-
const MOIU = MOI.Utilities
7-
const VI = MOI.VariableIndex
8-
const SAF{T} = MOI.ScalarAffineFunction{T}
9-
const SAT{T} = MOI.ScalarAffineTerm{T}
10-
const SQF{T} = MOI.ScalarQuadraticFunction{T}
11-
const SQT{T} = MOI.ScalarQuadraticTerm{T}
6+
const MOIU = MOI.Utilities
7+
const VI = MOI.VariableIndex
8+
const CI{F,S} = MOI.ConstraintIndex{F,S}
9+
const SAF{T} = MOI.ScalarAffineFunction{T}
10+
const SAT{T} = MOI.ScalarAffineTerm{T}
11+
const SQF{T} = MOI.ScalarQuadraticFunction{T}
12+
const SQT{T} = MOI.ScalarQuadraticTerm{T}
1213

1314
include("error.jl")
1415
include("varlt.jl")
15-
include("spin.jl")
16+
include("spin_set.jl")
17+
include("qubo_model.jl")
1618
include("sense.jl")
17-
include("model.jl")
19+
include("model_parser.jl")
1820

1921
end
File renamed without changes.

ext/QUBOTools_MOI/qubo_model.jl

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
const BinaryDomain = Union{MOI.ZeroOne,Spin}
2+
3+
@doc raw"""
4+
QUBOModel{T,C}
5+
6+
This is a MathOptInterface model for QUBO problems.
7+
"""
8+
mutable struct QUBOModel{T,C<:BinaryDomain} <: MOI.ModelLike
9+
objective_function::SQF{T}
10+
objective_sense::MOI.OptimizationSense
11+
variables::Vector{VI}
12+
13+
function QUBOModel{T,C}() where {T,C<:BinaryDomain}
14+
return new{T,C}(SQF{T}(SQT{T}[], SAT{T}[], zero(T)), MOI.MIN_SENSE, VI[])
15+
end
16+
end
17+
18+
function QUBOModel{T}() where {T}
19+
return QUBOModel{T,MOI.ZeroOne}()
20+
end
21+
22+
function QUBOModel()
23+
return QUBOModel{Float64,MOI.ZeroOne}()
24+
end
25+
26+
# MOI Wrapper
27+
function MOI.get(model::QUBOModel, ::MOI.NumberOfVariables)
28+
return length(model.variables)
29+
end
30+
31+
function MOI.add_variable(model::QUBOModel{T,C}) where {T,C<:BinaryDomain}
32+
vi = VI(MOI.get(model, MOI.NumberOfVariables()) + 1)
33+
34+
push!(model.variables, vi)
35+
36+
return vi
37+
end
38+
39+
function MOI.add_constraint(::QUBOModel{T,C}, vi::VI, ::C) where {T,C<:BinaryDomain}
40+
return CI{VI,C}(vi.value)
41+
end
42+
43+
function MOI.is_empty(model::QUBOModel)
44+
return isempty(model.variables) &&
45+
isempty(model.objective_function.quadratic_terms) &&
46+
isempty(model.objective_function.affine_terms) &&
47+
iszero(model.objective_function.constant)
48+
end
49+
50+
function MOI.empty!(model::QUBOModel{T}) where {T}
51+
model.objective_function = SQF{T}(SQT{T}[], SAT{T}[], zero(T))
52+
model.objective_sense = MOI.MIN_SENSE
53+
54+
empty!(model.variables)
55+
56+
return nothing
57+
end
58+
59+
# Support
60+
MOI.supports(
61+
::QUBOModel{T},
62+
::MOI.ObjectiveFunction{F},
63+
) where {T,F<:Union{VI,SAF{T},SQF{T}}} = true
64+
65+
MOI.supports_constraint(::QUBOModel{T,C}, ::Type{VI}, ::Type{C}) where {T,C<:BinaryDomain} = true
66+
MOI.supports_add_constrained_variable(::QUBOModel{T,C}, ::Type{C}) where {T,C<:BinaryDomain} = true
67+
68+
# get & set
69+
function MOI.get(model::QUBOModel, ::MOI.ObjectiveSense)
70+
return model.objective_sense
71+
end
72+
73+
function MOI.set(
74+
model::QUBOModel,
75+
::MOI.ObjectiveSense,
76+
objective_sense::MOI.OptimizationSense,
77+
)
78+
model.objective_sense = objective_sense
79+
80+
return nothing
81+
end
82+
83+
function MOI.get(model::QUBOModel{T}, ::MOI.ObjectiveFunction{SQF{T}}) where {T}
84+
return model.objective_function
85+
end
86+
87+
function MOI.set(model::QUBOModel{T}, ::MOI.ObjectiveFunction{VI}, vi::VI) where {T}
88+
model.objective_function = SQF{T}(SQT{T}[], SAT{T}[SAT{T}(one(T), vi)], zero(T))
89+
90+
return nothing
91+
end
92+
93+
function MOI.set(model::QUBOModel{T}, ::MOI.ObjectiveFunction{SAF{T}}, f::SAF{T}) where {T}
94+
model.objective_function = SQF{T}(SQT{T}[], copy(f.terms), f.constant)
95+
96+
return nothing
97+
end
98+
99+
function MOI.set(model::QUBOModel{T}, ::MOI.ObjectiveFunction{SQF{T}}, f::SQF{T}) where {T}
100+
model.objective_function = SQF{T}( #
101+
copy(f.quadratic_terms),
102+
copy(f.affine_terms),
103+
f.constant,
104+
)
105+
106+
return nothing
107+
end
108+
109+
MOI.get(::QUBOModel{T}, ::MOI.ObjectiveFunctionType) where {T} = SQF{T}
110+
111+
function MOI.get(
112+
model::QUBOModel{T,C},
113+
::MOI.ListOfConstraintTypesPresent,
114+
) where {T,C<:BinaryDomain}
115+
if MOI.is_empty(model)
116+
return []
117+
else
118+
return [(VI, C)]
119+
end
120+
end
121+
122+
function MOI.get(
123+
model::QUBOModel{T,C},
124+
::MOI.ListOfConstraintIndices{VI,C},
125+
) where {T,C<:BinaryDomain}
126+
return [CI{VI,C}(vi.value) for vi in model.variables]
127+
end
128+
129+
function MOI.get(model::QUBOModel, ::MOI.ListOfVariableIndices)
130+
return model.variables
131+
end
132+
133+
function MOI.get(
134+
::QUBOModel{T,C},
135+
::MOI.ConstraintFunction,
136+
ci::CI{VI,C},
137+
) where {T,C<:BinaryDomain}
138+
return VI(ci.value)
139+
end
140+
141+
function MOI.get(
142+
::QUBOModel{T,C},
143+
::MOI.ConstraintSet,
144+
::CI{VI,C},
145+
) where {T,C<:BinaryDomain}
146+
return C()
147+
end
148+
149+
function MOI.get(::QUBOModel{T,C}, ::MOI.VariableName, vi::VI) where {T,C<:BinaryDomain}
150+
if C === MOI.ZeroOne
151+
return "x[$(vi.value)]"
152+
else # C === Spin
153+
return "s[$(vi.value)]"
154+
end
155+
end
156+
157+
# The function takes no arguments and returns the QUBOModel type. Other
158+
# packages will assign its return value to a constant, e.g.,
159+
#
160+
# const QUBOModel = QUBOTools.__moi_qubo_model()
161+
#
162+
QUBOTools.__moi_qubo_model() = QUBOModel

ext/QUBOTools_MOI/spin.jl renamed to ext/QUBOTools_MOI/spin_set.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@ end
1919
# packages call it, assigning its return value to a constant, e.g.,
2020
#
2121
# const Spin = QUBOTools.__moi_spin_set()
22-
22+
#
2323
QUBOTools.__moi_spin_set() = Spin

ext/QUBOTools_MOI/varlt.jl

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
# This will fall back to the integer ordering method.
12
QUBOTools.varlt(u::VI, v::VI) = QUBOTools.varlt(u.value, v.value)

src/QUBOTools.jl

+3-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ include("library/analysis/visualization/energy_frequency.jl")
8484
include("library/analysis/visualization/model_density.jl")
8585
include("library/analysis/visualization/system_layout.jl")
8686

87+
# Extras
8788
# include("extra/dwave/dwave.jl")
88-
include("extra/moi/spin.jl")
89+
include("extra/moi/spin_set.jl")
90+
include("extra/moi/qubo_model.jl")
8991

9092
end # module

src/extra/moi/qubo_model.jl

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
raw"""
2+
__moi_qubo_model
3+
4+
This function has no methods, allowing the MOI extension to provide a QUBO
5+
model type.
6+
7+
```julia
8+
__moi_qubo_model() = QUBOModel
9+
```
10+
11+
The other packages will implement
12+
13+
```julia
14+
const QUBOModel = __moi_qubo_model()
15+
```
16+
17+
"""
18+
function __moi_qubo_model end
File renamed without changes.

0 commit comments

Comments
 (0)