Skip to content

Commit 9466984

Browse files
authored
[FileFormats.MOF] update to [email protected] (#1954)
* [FileFormats.MOF] update to [email protected] * Fix format and docs
1 parent a60994e commit 9466984

File tree

8 files changed

+380
-11
lines changed

8 files changed

+380
-11
lines changed

docs/src/submodules/FileFormats/overview.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ julia> print(read("file.mof.json", String))
9595
"name": "MathOptFormat Model",
9696
"version": {
9797
"major": 1,
98-
"minor": 0
98+
"minor": 1
9999
},
100100
"variables": [
101101
{
@@ -231,7 +231,7 @@ julia> good_model = JSON.parse("""
231231
{
232232
"version": {
233233
"major": 1,
234-
"minor": 0
234+
"minor": 1
235235
},
236236
"variables": [{"name": "x"}],
237237
"objective": {"sense": "feasibility"},
@@ -250,7 +250,7 @@ julia> bad_model = JSON.parse("""
250250
{
251251
"version": {
252252
"major": 1,
253-
"minor": 0
253+
"minor": 1
254254
},
255255
"variables": [{"NaMe": "x"}],
256256
"objective": {"sense": "feasibility"},

src/FileFormats/MOF/MOF.jl

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ import MathOptInterface
1313

1414
const MOI = MathOptInterface
1515

16-
const SCHEMA_PATH = joinpath(@__DIR__, "mof.1.0.schema.json")
17-
const VERSION = v"1.0"
18-
const SUPPORTED_VERSIONS = (v"1.0", v"0.6", v"0.5", v"0.4")
16+
const SCHEMA_PATH = joinpath(@__DIR__, "mof.1.1.schema.json")
17+
const VERSION = v"1.1"
18+
const SUPPORTED_VERSIONS = (v"1.1", v"1.0", v"0.6", v"0.5", v"0.4")
1919

2020
const OrderedObject = OrderedCollections.OrderedDict{String,Any}
2121
const UnorderedObject = Dict{String,Any}
@@ -63,8 +63,23 @@ MOI.Utilities.@model(
6363
MOI.LogDetConeSquare,
6464
MOI.PositiveSemidefiniteConeTriangle,
6565
MOI.PositiveSemidefiniteConeSquare,
66+
MOI.AllDifferent,
67+
MOI.Circuit,
68+
MOI.CountAtLeast,
69+
MOI.CountBelongs,
70+
MOI.CountDistinct,
71+
MOI.CountGreaterThan,
72+
MOI.Cumulative,
73+
MOI.Path,
74+
),
75+
(
76+
MOI.PowerCone,
77+
MOI.DualPowerCone,
78+
MOI.SOS1,
79+
MOI.SOS2,
80+
MOI.BinPacking,
81+
MOI.Table,
6682
),
67-
(MOI.PowerCone, MOI.DualPowerCone, MOI.SOS1, MOI.SOS2),
6883
(Nonlinear,),
6984
(MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction),
7085
(MOI.VectorOfVariables,),

src/FileFormats/MOF/mof.1.0.schema.json renamed to src/FileFormats/MOF/mof.1.1.schema.json

Lines changed: 168 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"$schema": "https://json-schema.org/schema#",
3-
"$id": "https://jump.dev/MathOptFormat/schemas/mof.1.0.schema.json",
3+
"$id": "https://jump.dev/MathOptFormat/schemas/mof.1.1.schema.json",
44
"title": "The schema for MathOptFormat",
55
"type": "object",
66
"required": ["version", "variables", "objective", "constraints"],
@@ -11,7 +11,7 @@
1111
"required": ["minor", "major"],
1212
"properties": {
1313
"minor": {
14-
"const": 0
14+
"const": 1
1515
},
1616
"major": {
1717
"const": 1
@@ -872,6 +872,172 @@
872872
"minimum": 2
873873
}
874874
}
875+
}, {
876+
"description": "The set {x in Z^d} such that no two elements in x take the same value and dimension=d.",
877+
"examples": ["{\"type\": \"AllDifferent\", \"dimension\": 2}"],
878+
"required": ["dimension"],
879+
"properties": {
880+
"type": {
881+
"const": "AllDifferent"
882+
},
883+
"dimension": {
884+
"type": "integer",
885+
"minimum": 1
886+
}
887+
}
888+
}, {
889+
"description": "The set `{x in Z^d}` where `d = length(w)`, such that each item `i` in `1:d` of weight `w[i]` is put into bin `x[i]`, and the total weight of each bin does not exceed `c`.",
890+
"examples": ["{\"type\": \"BinPacking\", \"capacity\": 3.0, \"weights\": [1.0, 2.0, 3.0]}"],
891+
"required": ["capacity", "weights"],
892+
"properties": {
893+
"type": {
894+
"const": "BinPacking"
895+
},
896+
"capacity": {
897+
"type": "number"
898+
},
899+
"weights": {
900+
"type": "array",
901+
"items": {
902+
"type": "number"
903+
}
904+
}
905+
}
906+
}, {
907+
"description": "The set `{x in {1..d}^d}` that constraints `x` to be a circuit, such that `x_i = j` means that `j` is the successor of `i`, and `dimension = d`.",
908+
"examples": ["{\"type\": \"Circuit\", \"dimension\": 3}"],
909+
"required": ["dimension"],
910+
"properties": {
911+
"type": {
912+
"const": "Circuit"
913+
},
914+
"dimension": {
915+
"type": "integer",
916+
"minimum": 1
917+
}
918+
}
919+
}, {
920+
"description": "The set `{x in Z^{d_1 + d_2 + ldots d_N}}`, where `x` is partitioned into `N` subsets (`{x_1, ldots, x_{d_1}}`, `{x_{d_1 + 1}, ldots, x_{d_1 + d_2}}` and so on), and at least `n` elements of each subset take one of the values in `set`.",
921+
"examples": ["{\"type\": \"CountAtLeast\", \"n\": 1, \"partitions\": [2, 2], \"set\": [3]}"],
922+
"required": ["n", "partitions", "set"],
923+
"properties": {
924+
"type": {
925+
"const": "CountAtLeast"
926+
},
927+
"n": {
928+
"type": "integer",
929+
"minimum": 0
930+
},
931+
"partitions": {
932+
"type": "array",
933+
"items": {
934+
"type": "integer"
935+
}
936+
},
937+
"set": {
938+
"type": "array",
939+
"items": {
940+
"type": "integer"
941+
}
942+
}
943+
}
944+
}, {
945+
"description": "The set `{(n, x) in Z^{1+d}}`, such that `n` elements of the vector `x` take on of the values in `set` and `dimension = 1 + d`.",
946+
"examples": ["{\"type\": \"CountBelongs\", \"dimension\": 3, \"set\": [3, 4, 5]}"],
947+
"required": ["dimension", "set"],
948+
"properties": {
949+
"type": {
950+
"const": "CountBelongs"
951+
},
952+
"dimension": {
953+
"type": "integer",
954+
"minimum": 1
955+
},
956+
"set": {
957+
"type": "array",
958+
"items": {
959+
"type": "integer"
960+
}
961+
}
962+
}
963+
}, {
964+
"description": "The set `{(n, x) in Z^{1+d}}`, such that the number of distinct values in `x` is `n` and `dimension = 1 + d`.",
965+
"examples": ["{\"type\": \"CountDistinct\", \"dimension\": 3}"],
966+
"required": ["dimension"],
967+
"properties": {
968+
"type": {
969+
"const": "CountDistinct"
970+
},
971+
"dimension": {
972+
"type": "integer",
973+
"minimum": 1
974+
}
975+
}
976+
}, {
977+
"description": "The set `{(c, y, x) in Z^{1+1+d}}`, such that `c` is strictly greater than the number of occurances of `y` in `x` and `dimension = 1 + 1 + d`.",
978+
"examples": ["{\"type\": \"CountGreaterThan\", \"dimension\": 3}"],
979+
"required": ["dimension"],
980+
"properties": {
981+
"type": {
982+
"const": "CountGreaterThan"
983+
},
984+
"dimension": {
985+
"type": "integer",
986+
"minimum": 1
987+
}
988+
}
989+
}, {
990+
"description": "The set `{(s, d, r, b) in Z^{3n+1}}`, representing the `cumulative` global constraint, where `n == length(s) == length(r) == length(b)` and `dimension = 3n + 1`. `Cumulative` requires that a set of tasks given by start times `s`, durations `d`, and resource requirements `r`, never requires more than the global resource bound `b` at any one time.",
991+
"examples": ["{\"type\": \"Cumulative\", \"dimension\": 10}"],
992+
"required": ["dimension"],
993+
"properties": {
994+
"type": {
995+
"const": "Cumulative"
996+
},
997+
"dimension": {
998+
"type": "integer",
999+
"minimum": 1
1000+
}
1001+
}
1002+
}, {
1003+
"description": "Given a graph comprised of a set of nodes `1..N` and a set of arcs `1..E` represented by an edge from node `from[i]` to node `to[i]`, `Path` constrains the set `(s, t, ns, es) in (1..N)times(1..E)times{0,1}^Ntimes{0,1}^E`, to form subgraph that is a path from node `s` to node `t`, where node `n` is in the path if `ns[n]` is `1`, and edge `e` is in the path if `es[e]` is `1`. The path must be acyclic, and it must traverse all nodes `n` for which `ns[n]` is `1`, and all edges `e` for which `es[e]` is `1`.",
1004+
"examples": ["{\"type\": \"Path\", \"from\": [1, 1, 2, 2, 3], \"to\": [2, 3, 3, 4, 4]}"],
1005+
"required": ["from", "to"],
1006+
"properties": {
1007+
"type": {
1008+
"const": "Path"
1009+
},
1010+
"from": {
1011+
"type": "array",
1012+
"items": {
1013+
"type": "integer"
1014+
}
1015+
},
1016+
"to": {
1017+
"type": "array",
1018+
"items": {
1019+
"type": "integer"
1020+
}
1021+
}
1022+
}
1023+
}, {
1024+
"description": "The set `{x in R^d}` where `d = size(table, 2)`, such that `x` belongs to one row of `table`. That is, there exists some `j` in `1:size(table, 1)`, such that `x[i] = table[j, i]` for all `i=1:size(table, 2)`.",
1025+
"examples": ["{\"type\": \"Table\", \"table\": [[1, 1, 0], [0, 1, 1]]}"],
1026+
"required": ["table"],
1027+
"properties": {
1028+
"type": {
1029+
"const": "Table"
1030+
},
1031+
"table": {
1032+
"type": "array",
1033+
"items": {
1034+
"type": "array",
1035+
"items": {
1036+
"type": "number"
1037+
}
1038+
}
1039+
}
1040+
}
8751041
}]
8761042
}
8771043
}

src/FileFormats/MOF/read.jl

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,16 @@ end
371371
IndicatorSet, # Required for v0.6
372372
Indicator, # Required for v1.0
373373
Complements,
374+
AllDifferent,
375+
Circuit,
376+
CountAtLeast,
377+
CountBelongs,
378+
CountDistinct,
379+
CountGreaterThan,
380+
Cumulative,
381+
Path,
382+
BinPacking,
383+
Table,
374384
)
375385

376386
"""
@@ -509,6 +519,42 @@ function set_to_moi(::Val{:Complements}, object::Object)
509519
return MOI.Complements(object["dimension"])
510520
end
511521

522+
function set_to_moi(::Val{:AllDifferent}, object::Object)
523+
return MOI.AllDifferent(object["dimension"])
524+
end
525+
526+
function set_to_moi(::Val{:Circuit}, object::Object)
527+
return MOI.Circuit(object["dimension"])
528+
end
529+
530+
function set_to_moi(::Val{:CountAtLeast}, object::Object)
531+
return MOI.CountAtLeast(
532+
object["n"],
533+
convert(Vector{Int}, object["partitions"]),
534+
Set{Int}(object["set"]),
535+
)
536+
end
537+
538+
function set_to_moi(::Val{:CountBelongs}, object::Object)
539+
return MOI.CountBelongs(object["dimension"], Set{Int}(object["set"]))
540+
end
541+
542+
function set_to_moi(::Val{:CountDistinct}, object::Object)
543+
return MOI.CountDistinct(object["dimension"])
544+
end
545+
546+
function set_to_moi(::Val{:CountGreaterThan}, object::Object)
547+
return MOI.CountGreaterThan(object["dimension"])
548+
end
549+
550+
function set_to_moi(::Val{:Cumulative}, object::Object)
551+
return MOI.Cumulative(object["dimension"])
552+
end
553+
554+
function set_to_moi(::Val{:Path}, object::Object)
555+
return MOI.Path(Int.(object["from"]), Int.(object["to"]))
556+
end
557+
512558
# ========== Typed vector sets ==========
513559

514560
function set_to_moi(::Val{:PowerCone}, object::Object)
@@ -538,3 +584,15 @@ function set_to_moi(::Union{Val{:Indicator},Val{:IndicatorSet}}, object::Object)
538584
return MOI.Indicator{MOI.ACTIVATE_ON_ZERO}(set)
539585
end
540586
end
587+
588+
function set_to_moi(::Val{:BinPacking}, object::Object)
589+
return MOI.BinPacking(
590+
convert(Float64, object["capacity"]),
591+
convert(Vector{Float64}, object["weights"]),
592+
)
593+
end
594+
595+
function set_to_moi(::Val{:Table}, object::Object)
596+
table = convert(Matrix{Float64}, vcat([t' for t in object["table"]]...))
597+
return MOI.Table(table)
598+
end

src/FileFormats/MOF/write.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,11 +291,21 @@ function head_name(::Type{MOI.PositiveSemidefiniteConeSquare})
291291
end
292292
head_name(::Type{MOI.Complements}) = "Complements"
293293

294+
head_name(::Type{MOI.AllDifferent}) = "AllDifferent"
295+
head_name(::Type{MOI.Circuit}) = "Circuit"
296+
head_name(::Type{MOI.CountAtLeast}) = "CountAtLeast"
297+
head_name(::Type{MOI.CountBelongs}) = "CountBelongs"
298+
head_name(::Type{MOI.CountDistinct}) = "CountDistinct"
299+
head_name(::Type{MOI.CountGreaterThan}) = "CountGreaterThan"
300+
head_name(::Type{MOI.Cumulative}) = "Cumulative"
301+
head_name(::Type{MOI.Path}) = "Path"
302+
294303
# ========== Typed vector sets ==========
295304
head_name(::Type{<:MOI.PowerCone}) = "PowerCone"
296305
head_name(::Type{<:MOI.DualPowerCone}) = "DualPowerCone"
297306
head_name(::Type{<:MOI.SOS1}) = "SOS1"
298307
head_name(::Type{<:MOI.SOS2}) = "SOS2"
308+
head_name(::Type{<:MOI.BinPacking}) = "BinPacking"
299309

300310
function moi_to_object(
301311
set::MOI.Indicator{I,S},
@@ -308,3 +318,13 @@ function moi_to_object(
308318
"activate_on" => (I == MOI.ACTIVATE_ON_ONE) ? "one" : "zero",
309319
)
310320
end
321+
322+
function moi_to_object(
323+
set::MOI.Table{T},
324+
::Dict{MOI.VariableIndex,String},
325+
) where {T}
326+
return OrderedObject(
327+
"type" => "Table",
328+
"table" => [set.table[i, :] for i in 1:size(set.table, 1)],
329+
)
330+
end

0 commit comments

Comments
 (0)