Skip to content

Commit f495f7c

Browse files
authored
Fix MOI wrapper (#6)
* Fix MOI wrapper * Add sudoku example * Add test/Project.toml * Fix
1 parent ade0cad commit f495f7c

File tree

10 files changed

+144
-91
lines changed

10 files changed

+144
-91
lines changed

README.md

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,19 @@ JaCoP.jl only proposes an implementation of the interface defined by
88
[ConstraintProgrammingExtensions.jl](https://github.com/dourouc05/ConstraintProgrammingExtensions.jl).
99
It does not provide access to the low-level Java API.
1010

11-
*Note: This wrapper is maintained by the community and is not officially
11+
## Affiliation
12+
13+
This wrapper is maintained by the community and is not officially
1214
supported by the JaCoP project. If you are interested in official support for
13-
JaCoP in Julia, let them know!*
15+
JaCoP in Julia, let them know!
16+
17+
## Installation
1418

15-
Unlike the other packages for constraint programming in Julia, JaCoP.jl
16-
requires Julia 1.6 (due to the `Downloads.jl` standard package).
19+
Install JaCoP as follows:
20+
```julia
21+
import Pkg
22+
Pkg.add("JaCoP")
23+
```
1724

1825
The JaCoP library is automatically downloaded when building this package in a
1926
version that it supports. However, as JaCoP is a Java library, you will need
@@ -22,3 +29,17 @@ a working JVM on your machine that is compatible with
2229
reduces to having access to a JVM in your `PATH` or `JAVA_HOME`
2330
environment variables. (If you want to use your own JaCoP binary, you can
2431
tweak the `deps/deps.jl` that is generated while building the package.)
32+
33+
> [!WARNING]
34+
> JaCoP uses [JavaCall](https://github.com/JuliaInterop/JavaCall.jl) which requires
35+
> launching Julia with [`JULIA_NUM_THREADS=1 JULIA_COPY_STACKS=1 julia`](https://github.com/JuliaInterop/JavaCall.jl?tab=readme-ov-file#macos-and-linux)
36+
> on MaxOS and Linux. See [here](https://github.com/JuliaInterop/JavaCall.jl?tab=readme-ov-file#windows) for Windows.
37+
38+
## Use with JuMP
39+
40+
To use JaCoP with JuMP, use `JaCoP.Optimizer`:
41+
42+
```julia
43+
using JuMP, JaCoP
44+
model = Model(JaCoP.Optimizer)
45+
```

src/MOI/parse.jl

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
function _parse_to_vars(
2-
model::Optimizer,
3-
f::MOI.VectorOfVariables,
4-
)
1+
function _parse_to_vars(model::Optimizer, f::MOI.VectorOfVariables)
52
return [_info(model, v).variable for v in f.variables]
63
end
74

src/MOI/wrapper.jl

Lines changed: 18 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,7 @@ mutable struct VariableInfo
2323
end
2424

2525
function VariableInfo(index::MOI.VariableIndex, variable::Variable)
26-
return VariableInfo(
27-
index,
28-
variable,
29-
"",
30-
INTEGER,
31-
nothing,
32-
nothing,
33-
)
26+
return VariableInfo(index, variable, "", INTEGER, nothing, nothing)
3427
end
3528

3629
mutable struct ConstraintInfo
@@ -113,8 +106,6 @@ mutable struct Optimizer <: MOI.AbstractOptimizer
113106
end
114107
end
115108

116-
Base.show(io::IO, model::Optimizer) = show(io, model.inner)
117-
118109
function MOI.empty!(model::Optimizer)
119110
model.inner = Store()
120111
model.name = ""
@@ -140,12 +131,7 @@ MOI.get(::Optimizer, ::MOI.SolverName) = "JaCoP"
140131
function MOI.supports(
141132
::Optimizer,
142133
::MOI.ObjectiveFunction{F},
143-
) where {
144-
F <: Union{
145-
MOI.VariableIndex,
146-
MOI.ScalarAffineFunction{Float64},
147-
},
148-
}
134+
) where {F <: Union{MOI.VariableIndex, MOI.ScalarAffineFunction{Float64}}}
149135
return true
150136
end
151137

@@ -155,12 +141,8 @@ function MOI.supports_constraint(
155141
::Type{F},
156142
) where {
157143
T <: Union{Int32, Float64},
158-
F <: Union{
159-
MOI.EqualTo{T},
160-
MOI.LessThan{T},
161-
MOI.GreaterThan{T},
162-
MOI.Interval{T},
163-
},
144+
F <:
145+
Union{MOI.EqualTo{T}, MOI.LessThan{T}, MOI.GreaterThan{T}, MOI.Interval{T}},
164146
}
165147
return true
166148
end
@@ -171,56 +153,36 @@ function MOI.supports_constraint(
171153
::Type{F},
172154
) where {
173155
T <: Union{Int32, Float64},
174-
F <:
175-
Union{MOI.EqualTo{T}, MOI.LessThan{T}, MOI.GreaterThan{T}},
156+
F <: Union{MOI.EqualTo{T}, MOI.LessThan{T}, MOI.GreaterThan{T}},
176157
# No interval!
177158
}
178159
return true
179160
end
180161

181-
MOI.supports(::Optimizer, ::MOI.VariableName, ::Type{MOI.VariableIndex}) = true
182-
function MOI.supports(
183-
::Optimizer,
184-
::MOI.ConstraintName,
185-
::Type{<:MOI.ConstraintIndex},
186-
)
187-
return true
188-
end
189-
190-
MOI.supports(::Optimizer, ::MOI.Name) = true
191162
# MOI.supports(::Optimizer, ::MOI.NumberOfThreads) = true
192163
# MOI.supports(::Optimizer, ::MOI.TimeLimitSec) = true
193164
# MOI.supports(::Optimizer, ::MOI.ObjectiveSense) = true
194165
# MOI.supports(::Optimizer, ::MOI.RawOptimizerAttribute) = true
195166

167+
MOI.supports_incremental_interface(::Optimizer) = true
168+
196169
function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike)
197170
return MOI.Utilities.default_copy_to(dest, src)
198171
end
199172

200-
function MOI.get(::Optimizer, ::MOI.ListOfVariableAttributesSet)
201-
return MOI.AbstractVariableAttribute[MOI.VariableName()]
202-
end
203-
204173
function MOI.get(model::Optimizer, ::MOI.ListOfModelAttributesSet)
205174
attributes = Any[MOI.ObjectiveSense()]
206175
typ = MOI.get(model, MOI.ObjectiveFunctionType())
207176
if typ !== nothing
208177
push!(attributes, MOI.ObjectiveFunction{typ}())
209178
end
210-
if MOI.get(model, MOI.Name()) != ""
211-
push!(attributes, MOI.Name())
212-
end
213179
return attributes
214180
end
215181

216-
function MOI.get(::Optimizer, ::MOI.ListOfConstraintAttributesSet)
217-
return MOI.AbstractConstraintAttribute[MOI.ConstraintName()]
218-
end
219-
220182
function MOI.optimize!(model::Optimizer)
221183
int_vars = IntVar[
222-
info.variable for info in values(model.variable_info)
223-
if info.variable isa IntVar
184+
info.variable for
185+
info in values(model.variable_info) if info.variable isa IntVar
224186
]
225187
if isempty(int_vars)
226188
model.termination_status = MOI.OPTIMAL
@@ -231,11 +193,17 @@ function MOI.optimize!(model::Optimizer)
231193
indomain = IndomainMin(())
232194
select = InputOrderSelect(
233195
(Store, Vector{Var}, Indomain),
234-
model.inner, int_vars, indomain,
196+
model.inner,
197+
int_vars,
198+
indomain,
235199
)
236200
result = jcall(
237-
search, "labeling", jboolean, (Store, SelectChoicePoint),
238-
model.inner, select,
201+
search,
202+
"labeling",
203+
jboolean,
204+
(Store, SelectChoicePoint),
205+
model.inner,
206+
select,
239207
)
240208
if result != 0
241209
model.termination_status = MOI.OPTIMAL

src/MOI/wrapper_constraints_cp.jl

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@ function MOI.supports_constraint(
66
::Optimizer,
77
::Type{F},
88
::Type{S},
9-
) where {
10-
F <: MOI.VectorOfVariables,
11-
S <: MOI.AllDifferent,
12-
}
9+
) where {F <: MOI.VectorOfVariables, S <: MOI.AllDifferent}
1310
return true
1411
end
1512

src/MOI/wrapper_constraints_mo.jl

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ function _build_constraint(
88
coeffs, vars, constant = _parse_to_coeffs_vars(model, f)
99
return LinearInt(
1010
(Store, Vector{jint}, Vector{IntVar}, JString, jint),
11-
model.inner, coeffs, vars, ">=", Int32(s.constant - constant),
11+
model.inner,
12+
coeffs,
13+
vars,
14+
">=",
15+
Int32(s.constant - constant),
1216
)
1317
end
1418

@@ -20,7 +24,11 @@ function _build_constraint(
2024
coeffs, vars, constant = _parse_to_coeffs_vars(model, f)
2125
return LinearInt(
2226
(Store, Vector{jint}, Vector{IntVar}, JString, jint),
23-
model.inner, coeffs, vars, "<=", Int32(s.constant - constant),
27+
model.inner,
28+
coeffs,
29+
vars,
30+
"<=",
31+
Int32(s.constant - constant),
2432
)
2533
end
2634

@@ -32,7 +40,11 @@ function _build_constraint(
3240
coeffs, vars, constant = _parse_to_coeffs_vars(model, f)
3341
return LinearInt(
3442
(Store, Vector{jint}, Vector{IntVar}, JString, jint),
35-
model.inner, coeffs, vars, "==", Int32(s.constant - constant),
43+
model.inner,
44+
coeffs,
45+
vars,
46+
"==",
47+
Int32(s.constant - constant),
3648
)
3749
end
3850

src/MOI/wrapper_constraints_singlevar.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ function MOI.add_constraint(
4444
model::Optimizer,
4545
f::MOI.VariableIndex,
4646
s::MOI.EqualTo{T},
47-
) where {T <: Integer}
47+
) where {T <: Real}
4848
v = _info(model, f).variable
4949
constr = XeqC((IntVar, jint), v, Int32(s.value))
5050
jacop_add_constraint_to_store(model.inner, constr)
@@ -59,7 +59,7 @@ function MOI.add_constraint(
5959
model::Optimizer,
6060
f::MOI.VariableIndex,
6161
s::MOI.LessThan{T},
62-
) where {T <: Integer}
62+
) where {T <: Real}
6363
v = _info(model, f).variable
6464
constr = XlteqC((IntVar, jint), v, Int32(s.upper))
6565
jacop_add_constraint_to_store(model.inner, constr)
@@ -73,7 +73,7 @@ function MOI.add_constraint(
7373
model::Optimizer,
7474
f::MOI.VariableIndex,
7575
s::MOI.GreaterThan{T},
76-
) where {T <: Integer}
76+
) where {T <: Real}
7777
v = _info(model, f).variable
7878
constr = XgteqC((IntVar, jint), v, Int32(s.lower))
7979
jacop_add_constraint_to_store(model.inner, constr)
@@ -87,7 +87,7 @@ function MOI.add_constraint(
8787
model::Optimizer,
8888
f::MOI.VariableIndex,
8989
s::MOI.Interval{T},
90-
) where {T <: Integer}
90+
) where {T <: Real}
9191
v = _info(model, f).variable
9292
lb_constr = XgteqC((IntVar, jint), v, Int32(s.lower))
9393
ub_constr = XlteqC((IntVar, jint), v, Int32(s.upper))

src/MOI/wrapper_variables.jl

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,10 @@ function _make_floatvar(
5858
ub::Union{Nothing, Float64}=nothing,
5959
)
6060
v = if lb === nothing && ub === nothing
61-
FloatVar(
62-
(Store,),
63-
model.inner,
64-
)
61+
FloatVar((Store,), model.inner)
6562
else
6663
lb_, ub_ = _sanitise_bounds(lb, ub, Float64)
67-
FloatVar(
68-
(Store, jdouble, jdouble),
69-
model.inner,
70-
lb_,
71-
ub_,
72-
)
64+
FloatVar((Store, jdouble, jdouble), model.inner, lb_, ub_)
7365
end
7466

7567
vindex, cindex = _make_var(model, v, set)
@@ -86,18 +78,10 @@ function _make_intvar(
8678
ub::Int32=typemax(Int32),
8779
)
8880
v = if lb === nothing && ub === nothing
89-
FloatVar(
90-
(Store,),
91-
model.inner,
92-
)
81+
FloatVar((Store,), model.inner)
9382
else
9483
lb_, ub_ = _sanitise_bounds(lb, ub, Int32)
95-
IntVar(
96-
(Store, jint, jint),
97-
model.inner,
98-
lb_,
99-
ub_,
100-
)
84+
IntVar((Store, jint, jint), model.inner, lb_, ub_)
10185
end
10286

10387
vindex, cindex = _make_var(model, v, set)
@@ -113,7 +97,7 @@ function _make_boolvar(model::Optimizer, set::MOI.AbstractScalarSet)
11397
return vindex, cindex
11498
end
11599

116-
function supports_add_constrained_variable(
100+
function MOI.supports_add_constrained_variable(
117101
::Optimizer,
118102
::Type{F},
119103
) where {
@@ -142,7 +126,6 @@ function MOI.add_variable(model::Optimizer)
142126
return vindex
143127
end
144128

145-
146129
function MOI.add_constrained_variable(
147130
model::Optimizer,
148131
set::MOI.GreaterThan{T},

test/Project.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[deps]
2+
ConstraintProgrammingExtensions = "b65d079e-ed98-51d9-b0db-edee61a5c5f8"
3+
JaCoP = "02462d8f-a5b3-44fd-8fd4-3169fe7a24c5"
4+
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
5+
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
6+
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
7+
8+
[sources]
9+
JaCoP = {path = ".."}

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ const COIT = CP.Test
1212

1313
@testset "JaCoP" begin
1414
include("MOI.jl")
15+
include("sudoku.jl")
1516
end

0 commit comments

Comments
 (0)