|
| 1 | +# OPL Schema |
| 2 | + |
| 3 | +The OPL schema catalogs optimization **problems**, **suites**, **generators**, and their **implementations** in a single, machine-readable format. |
| 4 | + |
| 5 | +Three design choices shape everything below: |
| 6 | + |
| 7 | +1. **One flat library, keyed by ID.** |
| 8 | + Every entity lives in a `Library` dict. |
| 9 | + Suites reference problems, problems reference implementations using their respective ID. |
| 10 | + There is no embedding of problems or implementations within suites to facilitate reuse. |
| 11 | + F.e. an implementation might be referenced by multiple problems or suites. |
| 12 | +2. **Numeric fields accept a scalar, a set, or a range.** |
| 13 | + A problem may have exactly `2` objectives, one of `{2, 3, 5}`, or any value in `{min: 2, max: 50}`. |
| 14 | + The same union type is used for variable dimensions and constraint counts. |
| 15 | +3. **Three-valued logic for yes/no fields.** |
| 16 | + Many boolean fields (f.e. `hard`, `allows_partial_evaluation`, ...) [`YesNoSome`](#yesnosome) as their value. |
| 17 | + We lose some expressive power but simplify the data entry. |
| 18 | + If we force authors to decide on yes or no, then we would need more complex structures for variables, constraints etc. and that would make the usual case unnecessarily complex. |
| 19 | + |
| 20 | +## Contents |
| 21 | + |
| 22 | +- [Library](#library) |
| 23 | +- [Thing types](#thing-types) |
| 24 | + - [Implementation](#implementation) |
| 25 | + - [ProblemLike](#problemlike) (shared fields) |
| 26 | + - [Problem](#problem) |
| 27 | + - [Suite](#suite) |
| 28 | + - [Generator](#generator) |
| 29 | +- [Shared building blocks](#shared-building-blocks) |
| 30 | + - [Variable](#variable) / [VariableType](#variabletype) |
| 31 | + - [Constraint](#constraint) / [ConstraintType](#constrainttype) |
| 32 | + - [Reference](#reference) / [Link](#link) |
| 33 | + - [ValueRange](#valuerange) |
| 34 | + - [YesNoSome](#yesnosome) |
| 35 | + |
| 36 | +--- |
| 37 | + |
| 38 | +## Library |
| 39 | + |
| 40 | +A `Library` is a dict from ID to a [Thing](#thing-types). |
| 41 | +IDs are free-form but must be unique and the convention is to add a prefix marking the type to avoid collisions: |
| 42 | + |
| 43 | +| Prefix | Type | |
| 44 | +|---------|------------------| |
| 45 | +| `impl_` | Implementation | |
| 46 | +| `fn_` | Problem | |
| 47 | +| `suite_`| Suite | |
| 48 | +| `gen_` | Generator | |
| 49 | + |
| 50 | +On load the library validates that every ID referenced by a suite (`problems`) or problem (`implementations`) exists and has the correct type. Suites also have their `fidelity_levels` auto-populated from their problems. |
| 51 | + |
| 52 | +```yaml |
| 53 | +impl_coco: |
| 54 | + type: implementation |
| 55 | + name: COCO |
| 56 | + description: Comparing Continuous Optimisers |
| 57 | +fn_sphere: |
| 58 | + type: problem |
| 59 | + name: Sphere |
| 60 | + objectives: [1] |
| 61 | + implementations: [impl_coco] |
| 62 | +suite_bbob: |
| 63 | + type: suite |
| 64 | + name: BBOB |
| 65 | + problems: [fn_sphere] |
| 66 | +``` |
| 67 | +
|
| 68 | +--- |
| 69 | +
|
| 70 | +## Thing types |
| 71 | +
|
| 72 | +All entities inherit from `Thing`, which only carries a discriminator: |
| 73 | + |
| 74 | +```yaml |
| 75 | +type: problem # or: suite | generator | implementation |
| 76 | +``` |
| 77 | + |
| 78 | +We want to have as flat a structure as possible to make exploring and searching OPL as easy as possible. |
| 79 | +That's one of the reasonst the top level object is a dictionary of dissimilar things. |
| 80 | +But we need to be able to tell them apart so we have a `type` field to discriminate between them. |
| 81 | + |
| 82 | +### Implementation |
| 83 | + |
| 84 | +A pointer to code that implements one or more problems. |
| 85 | +Intentionally minimal so that the schema describes *what* a problem is, not how to run it. |
| 86 | +There are separate files which contain curated usage examples for problems or suites keyed by their respective IDs. |
| 87 | + |
| 88 | +| Field | Type | Notes | |
| 89 | +|-------------------|-----------------------------------|----------------------------------------------| |
| 90 | +| `name` | str | required | |
| 91 | +| `description` | str | required | |
| 92 | +| `language` | str? (e.g. `python`, `c`) | | |
| 93 | +| `links` | list of [Link](#link)? | repo, release, docs… | |
| 94 | +| `evaluation_time` | str? | free-form ("8 minutes", "fast") | |
| 95 | +| `requirements` | str or list of str? | URL to requirements file or list of packages | |
| 96 | + |
| 97 | +```yaml |
| 98 | +impl_coco: |
| 99 | + type: implementation |
| 100 | + name: COCO |
| 101 | + description: Comparing Continuous Optimisers benchmarking platform |
| 102 | + language: c |
| 103 | + links: |
| 104 | + - {type: repository, url: https://github.com/numbbo/coco-experiment} |
| 105 | +impl_py_cocoex: |
| 106 | + type: implementation |
| 107 | + name: Python bindings for COCO |
| 108 | + description: The Python bindings for the experimental part of the COCO framework |
| 109 | + language: Python |
| 110 | + links: |
| 111 | + - {type: source, url: https://github.com/numbbo/coco-experiment/tree/main/build/python} |
| 112 | + - {type: package, url: https://pypi.org/project/coco-experiment/} |
| 113 | +``` |
| 114 | + |
| 115 | +### ProblemLike |
| 116 | + |
| 117 | +Fields shared by [Problem](#problem), [Suite](#suite), and [Generator](#generator). |
| 118 | +The schema deliberately puts most descriptive fields here so suites can be characterised without explicitly having to add all problems in the suite. |
| 119 | + |
| 120 | +| Field | Type | Notes | |
| 121 | +|------------------------------------------|------------------------------------------------|----------------------------------------------------| |
| 122 | +| `name` | str | required | |
| 123 | +| `long_name` | str? | | |
| 124 | +| `description` | str? (markdown) | longer prose | |
| 125 | +| `tags` | set of str? | free-form keywords | |
| 126 | +| `references` | set of [Reference](#reference)? | | |
| 127 | +| `implementations` | set of IDs? | must resolve to [Implementation](#implementation)s | |
| 128 | +| `objectives` | set of int? | e.g. `{1}`, `{2, 3}` — **not** a ValueRange | |
| 129 | +| `variables` | set of [Variable](#variable)? | | |
| 130 | +| `constraints` | set of [Constraint](#constraint)? | omit entirely for unconstrained | |
| 131 | +| `dynamic_type` | set of str? | `{"no"}`, `{"time-varying"}`… | |
| 132 | +| `noise_type` | set of str? | `{"none"}`, `{"gaussian"}`… | |
| 133 | +| `allows_partial_evaluation` | [YesNoSome](#yesnosome)? | | |
| 134 | +| `can_evaluate_objectives_independently` | [YesNoSome](#yesnosome)? | | |
| 135 | +| `modality` | set of str? | `{"unimodal"}`, `{"multimodal"}` | |
| 136 | +| `fidelity_levels` | set of int? | `{1}` = single-fidelity, `{1,2}` = multi-fidelity | |
| 137 | +| `code_examples` | set of str? | paths to example scripts | |
| 138 | +| `source` | set of str? | `{"artificial"}`, `{"real-world"}` | |
| 139 | + |
| 140 | +> `objectives` is a set of integers because we don't assume extreme scalability in this property so explicit enumeration is fine. |
| 141 | +> Dimensions of variables on the other hand are ranges because here problems often are scalable over wide ranges. |
| 142 | + |
| 143 | +### Problem |
| 144 | + |
| 145 | +One optimization problem (possibly parameterised by instances). |
| 146 | + |
| 147 | +Adds: |
| 148 | + |
| 149 | +| Field | Type | Notes | |
| 150 | +|-------------|--------------------------------------------|--------------------------------------------| |
| 151 | +| `instances` | [ValueRange](#valuerange) or list of str? | e.g. `{min: 1, max: 15}` or named variants | |
| 152 | + |
| 153 | +```yaml |
| 154 | +fn_sphere: |
| 155 | + type: problem |
| 156 | + name: Sphere |
| 157 | + objectives: [1] |
| 158 | + variables: [{type: continuous, dim: {min: 2, max: 40}}] |
| 159 | + modality: [unimodal] |
| 160 | + source: [artificial] |
| 161 | + instances: {min: 1, max: 15} |
| 162 | + implementations: [impl_coco] |
| 163 | +``` |
| 164 | + |
| 165 | +### Suite |
| 166 | + |
| 167 | +A curated, fixed collection of problems. |
| 168 | + |
| 169 | +Adds: |
| 170 | + |
| 171 | +| Field | Type | Notes | |
| 172 | +|------------|--------------|-----------------------------------------------| |
| 173 | +| `problems` | set of IDs? | must resolve to [Problem](#problem)s | |
| 174 | + |
| 175 | +`fidelity_levels` is auto-unioned from member problems at validation time. |
| 176 | + |
| 177 | +```yaml |
| 178 | +suite_bbob: |
| 179 | + type: suite |
| 180 | + name: BBOB |
| 181 | + problems: [fn_sphere, fn_rosenbrock, fn_rastrigin] |
| 182 | + objectives: [1] |
| 183 | + source: [artificial] |
| 184 | + implementations: [impl_coco] |
| 185 | +``` |
| 186 | + |
| 187 | +### Generator |
| 188 | + |
| 189 | +A parametric family of problems — unlike a [Suite](#suite), the member problems are not enumerated. Uses the same fields as [ProblemLike](#problemlike) with no additions; the distinction from [Problem](#problem) is that a generator produces instances on demand. |
| 190 | + |
| 191 | +```yaml |
| 192 | +gen_mpm2: |
| 193 | + type: generator |
| 194 | + name: MPM2 |
| 195 | + description: Multiple peaks model, second instantiation |
| 196 | + objectives: [1] |
| 197 | + variables: [{type: continuous, dim: {min: 1}}] |
| 198 | + modality: [multimodal] |
| 199 | +``` |
| 200 | + |
| 201 | +--- |
| 202 | + |
| 203 | +## Shared building blocks |
| 204 | + |
| 205 | +### Variable |
| 206 | + |
| 207 | +A group of decision variables of the same type. |
| 208 | +Multi-type problems list multiple entries. |
| 209 | +While you can have multiple entries of the same type, this should be justified in some way like when you can evaluate the problem on only one subset of variables. |
| 210 | + |
| 211 | +| Field | Type | Default | |
| 212 | +|--------|-----------------------------------------------|----------------------| |
| 213 | +| `type` | [VariableType](#variabletype) | `unknown` | |
| 214 | +| `dim` | int, set of int, [ValueRange](#valuerange), or null | `0` | |
| 215 | + |
| 216 | +```yaml |
| 217 | +variables: |
| 218 | + - {type: continuous, dim: 10} |
| 219 | + - {type: integer, dim: {min: 1, max: 5}} |
| 220 | +``` |
| 221 | + |
| 222 | +### VariableType |
| 223 | + |
| 224 | +`continuous | integer | binary | categorical | unknown`. |
| 225 | +Use `unknown` for permutation/combinatorial problems the schema doesn't yet distinguish **and** add an appropriate tag. |
| 226 | +We are actively watching for unknown variable types and are open to extending the above list if there is a critical mass of problems to justify it. |
| 227 | + |
| 228 | +### Constraint |
| 229 | + |
| 230 | +A group of constraints. |
| 231 | +To indicate that the problem is unconstrained, you need an _empty_ `constraints` field. |
| 232 | +A missing `constraints` field or if it is set to `null` means it is not known if unconstrained. |
| 233 | + |
| 234 | +| Field | Type | Notes | |
| 235 | +|------------|-----------------------------------------------|------------------------------------| |
| 236 | +| `type` | [ConstraintType](#constrainttype) | default `unknown` | |
| 237 | +| `hard` | [YesNoSome](#yesnosome)? | hard vs. soft | |
| 238 | +| `equality` | [YesNoSome](#yesnosome)? | equality vs. inequality | |
| 239 | +| `number` | int, set of int, [ValueRange](#valuerange), null | | |
| 240 | + |
| 241 | +```yaml |
| 242 | +constraints: |
| 243 | + - {type: box, hard: yes, number: 10} |
| 244 | + - {type: linear, hard: some, equality: no, number: {min: 1}} |
| 245 | +``` |
| 246 | + |
| 247 | +### ConstraintType |
| 248 | + |
| 249 | +`box | linear | function | unknown`. `function` covers non-linear/black-box constraints. |
| 250 | + |
| 251 | +### Reference |
| 252 | + |
| 253 | +Bibliographic pointer. |
| 254 | +Requires a `title` and `authors` and optionally includes a `link` to the material. |
| 255 | + |
| 256 | +```yaml |
| 257 | +references: |
| 258 | + - title: "Honey Badger Algorithm: New metaheuristic algorithm for solving optimization problems." |
| 259 | + authors: |
| 260 | + - Fatma A. Hashim |
| 261 | + - Essam H. Houssein |
| 262 | + - Kashif Hussain |
| 263 | + - Mai S. Mabrouk |
| 264 | + - Walid Al-Atabany |
| 265 | + link: {type: doi, url: "https://doi.org/10.1016/j.matcom.2021.08.013"] |
| 266 | +``` |
| 267 | + |
| 268 | +### Link |
| 269 | + |
| 270 | +`{type?: str, url: str}`. |
| 271 | +`type` is free-form (`repository`, `arxiv`, `paper`, `doi`, ...). |
| 272 | +`url` is a URL to some resource. |
| 273 | + |
| 274 | +If `type` is `doi`, please use the full URL (starting with `https://doi.org/...`) instead of the raw DOI. |
| 275 | + |
| 276 | +### ValueRange |
| 277 | + |
| 278 | +An inclusive numeric range type. |
| 279 | +At least one of `min`/`max` must be given. |
| 280 | +If `min` is given and `max` is missing, it does not imply that there is no upper bound. |
| 281 | +There might be one, it is just not known. |
| 282 | +The same applies for the case where `max` is given and `min` is missing. |
| 283 | + |
| 284 | +```yaml |
| 285 | +dim: {min: 2} # 2 or more |
| 286 | +dim: {min: 2, max: 40} # between 2 and 40 |
| 287 | +dim: {max: 100} # up to 100 |
| 288 | +``` |
| 289 | + |
| 290 | +Used by `Variable.dim`, `Constraint.number`, `Problem.instances`. |
| 291 | + |
| 292 | +### YesNoSome |
| 293 | + |
| 294 | +Three-valued flag: `yes | no | some | ?` (the last serialises as the literal `'?'` string, meaning unknown). |
| 295 | +`some` captures the common case where *part* of something has some property. |
| 296 | +For example only some constraints might hard but we don't know the exact number of hard and soft constraints, only the total number. |
| 297 | + |
| 298 | +```yaml |
| 299 | +constraints: [{type: box, hard: some}] |
| 300 | +allows_partial_evaluation: "?" |
| 301 | +``` |
0 commit comments