···1default: build check
23-# Build the Huub solver
4build:
5 cargo build
6- cbindgen --config cbindgen_types.toml --crate ipdos-types --output c/ipdos_types.h
7- cbindgen --config cbindgen_template.toml --crate ipdos-solver-template --output c/ipdos_solver_template.c
89# Check the codebase using all CI linters
10check:
···1default: build check
23+# Build packages and header files
4build:
5 cargo build
6+ cbindgen --config cbindgen_types.toml --crate fznso-types --output c/fznso_types.h
7+ cbindgen --config cbindgen_template.toml --crate fznso-solver-template --output c/fznso_solver_template.c
89# Check the codebase using all CI linters
10check:
+6-6
README.md
···1-# IPDOS: An Incremental Protocol for Decision and Optimization Solvers
23## Introduction
45## Common Functionality
67-Although solvers are able to define their own functionality using the IPDOS protocol, we advocate for the following common functionality to be implemented by different solvers.
8This will allow for a more consistent user experience when interacting with different solvers.
9Even if a solver does not implement all of these functions, we recommend that the solvers do not use the same name for different functionality.
1011### Common Options
1213-A solver will expose its available options through `ipdos_option_list`.
14We recommend that solvers eagerly implement the following options:
1516- `all_optimal` (`bool`, default: `false`): If set to `true`, the solver will after finding an optimal solution, continue to search for other solutions with the same objective value.
17- `fixed_search` (`bool`, default: `false`): If set to `true`, the solver will strictly follow the search order defined by the user.
18- `intermediate` (`bool`, default: `false`): If set to `true` for a problem with an objective strategy set, the solver will trigger its `on_solution` callback when it finds an intermediate solution.
19- Afterward, the solver will continue the search until it finds the next solution, or it proves that no better solutions exist (returning the `IpdosComplete` status).
20- `threads` (`int`, default: `1`): For multithreaded solvers, this option will set the number of threads to use.
21- `time_limit` (`int`, default: `-1`): If set to a positive integer, the solver will abandon the search after the specified number of milliseconds.
22- `random_seed` (`opt int`, default: `<>`): If set to a positive integer, the solver will use the given value as the seed for its random number generator.
···2526### Common Constraints
2728-A solver will expose the constraints that can be used in a `IpdosModel` through `ipdos_constraint_list`.
29We encourage solvers to support the constraints using the names and definitions from the [FlatZinc Builtins](https://docs.minizinc.dev/en/stable/lib-flatzinc.html).
30Other MiniZinc (global) constraints are also encouraged to be implemented, using the `fzn_` prefix.
3132### Common Objective Strategies
3334-A solver will expose the objective strategies that can be used in a `IpdosModel` through `ipdos_objective_list`.
35We encourage solvers to support the following objective strategies if possible:
3637- `lex_maximize_int` (`list of var int`) | `lex_maximize_float` (`list of var float`): The solver will maximize the list of decision variables in lexicographical order, i.e., the first variable is maximized first, then the second variable, etc.
···1+# Flat White Vitriol (FZnSO) - An incremental solver protocol for combinatorial solving using shared objects
23## Introduction
45## Common Functionality
67+Although solvers are able to define their own functionality using the FZnSO protocol, we advocate for the following common functionality to be implemented by different solvers.
8This will allow for a more consistent user experience when interacting with different solvers.
9Even if a solver does not implement all of these functions, we recommend that the solvers do not use the same name for different functionality.
1011### Common Options
1213+A solver will expose its available options through `fznso_option_list`.
14We recommend that solvers eagerly implement the following options:
1516- `all_optimal` (`bool`, default: `false`): If set to `true`, the solver will after finding an optimal solution, continue to search for other solutions with the same objective value.
17- `fixed_search` (`bool`, default: `false`): If set to `true`, the solver will strictly follow the search order defined by the user.
18- `intermediate` (`bool`, default: `false`): If set to `true` for a problem with an objective strategy set, the solver will trigger its `on_solution` callback when it finds an intermediate solution.
19+ Afterward, the solver will continue the search until it finds the next solution, or it proves that no better solutions exist (returning the `FznsoComplete` status).
20- `threads` (`int`, default: `1`): For multithreaded solvers, this option will set the number of threads to use.
21- `time_limit` (`int`, default: `-1`): If set to a positive integer, the solver will abandon the search after the specified number of milliseconds.
22- `random_seed` (`opt int`, default: `<>`): If set to a positive integer, the solver will use the given value as the seed for its random number generator.
···2526### Common Constraints
2728+A solver will expose the constraints that can be used in a `FznsoModel` through `fznso_constraint_list`.
29We encourage solvers to support the constraints using the names and definitions from the [FlatZinc Builtins](https://docs.minizinc.dev/en/stable/lib-flatzinc.html).
30Other MiniZinc (global) constraints are also encouraged to be implemented, using the `fzn_` prefix.
3132### Common Objective Strategies
3334+A solver will expose the objective strategies that can be used in a `FznsoModel` through `fznso_objective_list`.
35We encourage solvers to support the following objective strategies if possible:
3637- `lex_maximize_int` (`list of var int`) | `lex_maximize_float` (`list of var float`): The solver will maximize the list of decision variables in lexicographical order, i.e., the first variable is maximized first, then the second variable, etc.
···1+#ifndef fznso_types_h
2+#define fznso_types_h
3+4+#include <stdbool.h>
5+#include <stdint.h>
6+7+// Representation of the base type of a value.
8+typedef enum FznsoTypeBase {
9+ // Boolean type
10+ FznsoTypeBaseBool,
11+ // Integer numeric type
12+ FznsoTypeBaseInt,
13+ // Floating point numeric type
14+ FznsoTypeBaseFloat,
15+ // Character string type
16+ FznsoTypeBaseString,
17+} FznsoTypeBase;
18+19+// Enumerated type used to mark the kind of [`FznsoValue`]. This is used to
20+// determine which "get" method in [`FznsoValueMethods`] is safe to call.
21+typedef enum FznsoValueKind {
22+ // No value is available.
23+ FznsoValueAbsent,
24+ // The value is available using [`FznsoValueMethods::get_decision`].
25+ FznsoValueDecision,
26+ // The value is available using [`FznsoValueMethods::get_constraint`].
27+ FznsoValueConstraint,
28+ // The value is available using [`FznsoValueMethods::get_bool`].
29+ FznsoValueBool,
30+ // The value is available using [`FznsoValueMethods::get_int`].
31+ FznsoValueInt,
32+ // The value is available using [`FznsoValueMethods::get_float`].
33+ FznsoValueFloat,
34+ // The value is available using [`FznsoValueMethods::get_string`].
35+ FznsoValueString,
36+ // Sets of integers are represented using a range list. The number of
37+ // ranges is available using [`FznsoValueMethods::len`], and the ranges can
38+ // be accessed using [`FznsoValueMethods::get_range_int`].
39+ FznsoValueSetInt,
40+ // Sets of floats are represented using a range list. The number of
41+ // ranges is available using [`FznsoValueMethods::len`], and the ranges can
42+ // be accessed using [`FznsoValueMethods::get_range_float`].
43+ FznsoValueSetFloat,
44+ // The length of the list can be accessed using
45+ // [`FznsoValueMethods::len`], and elements in the list can be
46+ // accessed using [`FznsoValueMethods::get_element`]
47+ FznsoValueList,
48+} FznsoValueKind;
49+50+// The status returned by `fznso_solver_run`, indicating whether the solver
51+// completed its search.
52+typedef enum FznsoStatus {
53+ // The solver explored the full search space and yielded all relevant
54+ // solutions.
55+ FznsoComplete,
56+ // The solver did not explore the full search space due to a timeout or
57+ // other termination condition. Additional (better) solutions might be
58+ // possible.
59+ FznsoIncomplete,
60+ // An error occurred during the solver's execution.
61+ //
62+ // [`fznso_solver_read_error`] can be used to retrieve the error message.
63+ FznsoError,
64+} FznsoStatus;
65+66+// The handle to a the data of a solution instance.
67+//
68+// This type is opaque to the user. Only pointers of this type are ever used.
69+//
70+// In implementation of the FZnSO interface, a pointer is generally cast to
71+// this type, i.e. `(FznsoSolutionData*) my_solution`. A similar cast can be
72+// used to cast the pointer back to the original type, e.g. `(MySolution*)
73+// fznso_solution`.
74+typedef void FznsoAnnotation;
75+76+// Representation of a type to signal and check whether an argument takes the
77+// correct type.
78+typedef struct FznsoType {
79+ // Whether the type is a list of values.
80+ bool list_of;
81+ // Whether the argument can be or contain decision variables (represented
82+ // as decision indexes).
83+ bool decision;
84+ // Whether expected type is an set of values of the base type.
85+ bool set_of;
86+ // Whether the expected type is optional (and can take the value of
87+ // [`FznsoValueKind::FznsoValueAbsent`]).
88+ bool opt;
89+ // The expected base type of the argument.
90+ enum FznsoTypeBase base;
91+} FznsoType;
92+93+// Representation of a type of constraint, discerned by its identifier and the
94+// types of its arguments.
95+typedef struct FznsoConstraintType {
96+ // The identifier of the constraint type.
97+ const char *ident;
98+ // The number of expected arguments for the constraint type.
99+ size_t arg_len;
100+ // The types of the expected arguments for the constraint type.
101+ const struct FznsoType *arg_types;
102+} FznsoConstraintType;
103+104+// A list of [`FznsoConstraintType`]s.
105+//
106+// This type is for example used to return from [`fznso_constraint_list`].
107+typedef struct FznsoConstraintList {
108+ // The number of elements in the `constraints` array.
109+ size_t len;
110+ // An array of constraint types.
111+ const struct FznsoConstraintType *constraints;
112+} FznsoConstraintList;
113+114+// The handle of a model instance.
115+//
116+// This type is opaque to the user. Only pointers of this type are ever used.
117+//
118+// In implementation of the FZnSO interface, a pointer is generally cast to
119+// this type, i.e. `(FznsoModelData*) my_model`. A similar cast can be used to
120+// cast the pointer back to the original type, e.g. `(MyModel*) fznso_model`.
121+typedef void FznsoModel;
122+123+// The type of a value used as an argument or solution assignment.
124+//
125+// This type is opaque to the user. Only pointers of this type are ever used.
126+//
127+// In implementation of the FZnSO interface, a pointer is generally cast to
128+// this type, e.g. `(FznsoValue*) my_value`. A similar cast can be used to cast
129+// the pointer back to the original type, e.g. `(MyValue*) fznso_value`.
130+typedef void FznsoValue;
131+132+// Wrapper type for the indexes that represent decision variables in the model.
133+typedef size_t FznsoDecisionIdx;
134+135+// Wrapper type for the indexes that represent constraints in the model.
136+typedef size_t FznsoConstraintIdx;
137+138+// A struct containing the function pointers to interact with a
139+// [`FznsoValue`]
140+typedef struct FznsoValueMethods {
141+ // Function callback that returns the kind of the value.
142+ enum FznsoValueKind (*kind)(const FznsoValue*);
143+ // Function callback that returns the length of the value.
144+ //
145+ // In case [`FznsoValueMethods::kind`] returns
146+ // [`FznsoValueKind::FznsoValueList`], the length is the number of elements
147+ // in the list, accessible using [`FznsoValueMethods::get_element`].
148+ //
149+ // In case [`FznsoValueMethods::kind`] returns
150+ // [`FznsoValueKind::FznsoValueSetInt`] or
151+ // [`FznsoValueKind::FznsoValueSetFloat`], the length is the number of
152+ // ranges in the set, accessible using
153+ // [`FznsoValueMethods::get_range_int`] or
154+ // [`FznsoValueMethods::get_range_float`].
155+ //
156+ // # Panics
157+ //
158+ // This function callback may panic if [`FznsoValueMethods::kind`] does not
159+ // return [`FznsoValueKind::FznsoValueList`],
160+ // [`FznsoValueKind::FznsoValueSetInt`], or
161+ // [`FznsoValueKind::FznsoValueSetFloat`].
162+ size_t (*len)(const FznsoValue*);
163+ // Function callback that returns the decision variable index contained in
164+ // the value.
165+ //
166+ // # Panics
167+ //
168+ // This function callback may panic if [`FznsoValueMethods::kind`] does not
169+ // return [`FznsoValueKind::FznsoValueDecision`].
170+ FznsoDecisionIdx (*get_decision)(const FznsoValue*);
171+ // Function callback that returns the constraint index contained in the
172+ // value.
173+ //
174+ // # Panics
175+ //
176+ // This function callback may panic if [`FznsoValueMethods::kind`] does not
177+ // return [`FznsoValueKind::FznsoValueConstraint`].
178+ FznsoConstraintIdx (*get_constraint)(const FznsoValue*);
179+ // Function callback that returns the integer value contained in the value.
180+ //
181+ // # Panics
182+ //
183+ // This function callback may panic if [`FznsoValueMethods::kind`] does not
184+ // return [`FznsoValueKind::FznsoValueInt`].
185+ int64_t (*get_int)(const FznsoValue*);
186+ // Function callback that returns the floating point value contained in the
187+ // value.
188+ //
189+ // # Panics
190+ //
191+ // This function callback may panic if [`FznsoValueMethods::kind`] does not
192+ // return [`FznsoValueKind::FznsoValueFloat`].
193+ double (*get_float)(const FznsoValue*);
194+ // Function callback that returns the string pointer value contained in the
195+ // value.
196+ //
197+ // # Panics
198+ //
199+ // This function callback may panic if [`FznsoValueMethods::kind`] does not
200+ // return [`FznsoValueKind::FznsoValueString`].
201+ const char *(*get_string)(const FznsoValue*);
202+ // Function callback that returns the Boolean value contained in the value.
203+ //
204+ // # Panics
205+ //
206+ // This function callback may panic if [`FznsoValueMethods::kind`] does not
207+ // return [`FznsoValueKind::FznsoValueBool`].
208+ bool (*get_bool)(const FznsoValue*);
209+ // Function callback that returns a range from a range list representing
210+ // the integer set contained in the value.
211+ //
212+ // # Panics
213+ //
214+ // This function callback may panic if [`FznsoValueMethods::kind`] does not
215+ // return [`FznsoValueKind::FznsoValueSetInt`].
216+ int64_t ((*get_range_int)(const FznsoValue*, size_t index))[2];
217+ // Function callback that returns a range from a range list representing
218+ // the floating point set contained in the value.
219+ //
220+ // # Panics
221+ //
222+ // This function callback may panic if [`FznsoValueMethods::kind`] does not
223+ // return [`FznsoValueKind::FznsoValueSetFloat`].
224+ double ((*get_range_float)(const FznsoValue*, size_t index))[2];
225+ // Function callback that returns an element from the list contained in the
226+ // value.
227+ //
228+ // # Panics
229+ //
230+ // This function callback may panic if [`FznsoValueMethods::kind`] does not
231+ // return [`FznsoValueKind::FznsoValueList`].
232+ struct FznsoValueRef (*get_element)(const FznsoValue*, size_t index);
233+} FznsoValueMethods;
234+235+// Handle for a value
236+//
237+// The caller can use the `get_value` function to retrieve the value of the
238+// used decision variables.
239+typedef struct FznsoValueRef {
240+ // The data pointer to be the first argument of `get_value`.
241+ const FznsoValue *data;
242+ // Reference to the structure containing the function callbacks used to
243+ // interact with the value.
244+ const struct FznsoValueMethods *methods;
245+} FznsoValueRef;
246+247+// A struct containing the function pointers to interact with the
248+// [`FznsoModel`]
249+typedef struct FznsoModelMethods {
250+ // Returns the current number of model layers currently contained in the
251+ // model.
252+ //
253+ // Layers provides a way for the modelling user to add and retract
254+ size_t (*layer_len)(const FznsoModel *model);
255+ // Returns the number of layers that have been unchanged since the last
256+ // call to [`fznso_solver_run`].
257+ //
258+ // Unchanged layers must be consecutive starting from layer 0.
259+ size_t (*layer_unchanged)(const FznsoModel *model);
260+ // Returns the number of permanent layers in the model.
261+ //
262+ // Permanent layers are laid out must be consecutive starting from layer 0.
263+ // Under no circumstances can they be retracted. As such, the solver can
264+ // assume that the number of permanent layers only ever increases.
265+ //
266+ // Permanent layers can, however, still be found to be redundant, allowing
267+ // the solver to remove the decision variables and constraints in these
268+ // layers, if convenient. This is signaled using [`layer_redundant_len`]
269+ // and [`layer_redundant_index`].
270+ size_t (*layer_permanent)(const FznsoModel *model);
271+ // Returns the number of permanent layers that have been marked as
272+ // redundant.
273+ //
274+ // The solver can remove the decision variables and constraints in these
275+ // layers, if convenient. Once a layer is marked as redundant, it can
276+ // forever be considered redundant. As such, the solver can assume that
277+ // the number of redundant layers only ever increases.
278+ size_t (*layer_redundant_len)(const FznsoModel *model);
279+ // Returns the index of the n-th permanent layer that has been marked as
280+ // redundant.
281+ //
282+ // The `n` argument must be less than the value returned by
283+ // [`layer_redundant_len`].
284+ size_t (*layer_redundant_index)(const FznsoModel *model, size_t n);
285+ // Retrieve the number of decisions currently contained in the model.
286+ size_t (*decision_len)(const FznsoModel *model);
287+ // Retrieve the decision index of the last decision variable in the layer.
288+ //
289+ // This can be equivalent to `decision_layer_end` of `layer-1` if the layer
290+ // does not add any new decisions.
291+ size_t (*decision_layer_end)(const FznsoModel *model, size_t layer);
292+ // Retrieve the domain of the given decision.
293+ //
294+ // Note that the the value might have [`FznsoValueKind::FznsoValueAbsent`]
295+ // if the decision variable does not have an explicit domain.
296+ struct FznsoValueRef (*decision_domain)(const FznsoModel *model, FznsoDecisionIdx decision);
297+ // Retrieve the name of a decision variable, if it exists.
298+ //
299+ // Note that names are only available for debugging purposes. Decisions are
300+ // identified using their index in the model. If the decision variable does
301+ // not have a name, this function returns a null pointer.
302+ const char *(*decision_name)(const FznsoModel *model, FznsoDecisionIdx decision);
303+ // Check whether the decision variable is defined by a constraint.
304+ bool (*decision_defined)(const FznsoModel *model, FznsoDecisionIdx decision);
305+ // Retrieve the number of annotations of a constraint.
306+ size_t (*decision_annotation_len)(const FznsoModel *model, FznsoDecisionIdx decision);
307+ // Retrieve the value of the constraint's annotation at the given index.
308+ //
309+ // The `index` argument must be less than the value returned by
310+ // [`decision_annotation_len`] for the given decision variable.
311+ const FznsoAnnotation *(*decision_annotation)(const FznsoModel *model,
312+ FznsoDecisionIdx decision,
313+ size_t index);
314+ // Retrieve the number of constraints currently contained in the model.
315+ size_t (*constraint_len)(const FznsoModel *model);
316+ // Retrieve the constraint index of the first new constraint in the layer.
317+ //
318+ // This can be equivalent to `constraint_len` if the layer does not add any
319+ // new constraints.
320+ size_t (*constraint_layer_end)(const FznsoModel *model);
321+ // Retrieve the identifier of a constraint.
322+ //
323+ // The returned pointer can be assumed to have the the same lifetime as the
324+ // model reference and must be valid UTF8.
325+ const char *(*constraint_ident)(const FznsoModel *model, FznsoConstraintIdx constraint);
326+ // Retrieve the number of arguments of a constraint.
327+ size_t (*constraint_argument_len)(const FznsoModel *model, FznsoConstraintIdx constraint);
328+ // Retrieve the value of the constraint's argument at the given index.
329+ //
330+ // The `index` argument must be less than the value returned by
331+ // `constraint_argument_len` for the given constraint.
332+ struct FznsoValueRef (*constraint_argument)(const FznsoModel *model,
333+ FznsoConstraintIdx constraint,
334+ size_t index);
335+ // Check whether the decision variable is functionally defined by a
336+ // constraint.
337+ //
338+ // This function returns a [`FznsoValue`] that is either
339+ // [`FznsoValueKind::FznsoValueDecision`] if it defined a decision variable
340+ // or [`FznsoValueKind::FznsoValueAbsent`] otherwise.
341+ struct FznsoValueRef (*constraint_defines)(const FznsoModel *model, FznsoConstraintIdx constraint);
342+ // Retrieve the number of annotations on a constraint.
343+ size_t (*constraint_annotation_len)(const FznsoModel *model, FznsoConstraintIdx constraint);
344+ // Retrieve the annotation on a constraint at the given index.
345+ //
346+ // The `index` argument must be less than the value returned by
347+ // `constraint_annotation_len` for the given constraint.
348+ const FznsoAnnotation *(*constraint_annotation)(const FznsoModel *model,
349+ FznsoConstraintIdx constraint,
350+ size_t index);
351+ // Request the identifier of the type of objective strategy to be used when
352+ // solving the model.
353+ //
354+ // Note that the function can return a null pointer if the model does not
355+ // have an objective strategy.
356+ const char *(*objective_ident)(const FznsoModel *model);
357+ // Retrieve the argument of the objective strategy.
358+ struct FznsoValueRef (*objective_arg)(const FznsoModel *model);
359+ // Retrieve the number of annotations on an objective
360+ size_t (*objective_annotation_len)(const FznsoModel *model);
361+ // Retrieve the annotation on the objective at the given index.
362+ //
363+ // The `index` argument must be less than the value returned by
364+ // `objective_annotation_len`.
365+ const FznsoAnnotation *(*objective_annotation)(const FznsoModel *model, size_t index);
366+ // Retrieve the identifier of an annotation.
367+ //
368+ // The returned pointer can be assumed to have the the same lifetime as the
369+ // annotation reference and must be valid UTF8.
370+ const char *(*annotation_ident)(const FznsoAnnotation *ann);
371+ // Retrieve the number of arguments of an annotation.
372+ size_t (*annotation_argument_len)(const FznsoAnnotation *ann);
373+ // Retrieve the value of the annotation's argument at the given index.
374+ //
375+ // The `index` argument must be less than the value returned by
376+ // `annotation_argument_len` for the given annotation.
377+ struct FznsoValueRef (*annotation_argument)(const FznsoAnnotation *ann, size_t index);
378+} FznsoModelMethods;
379+380+// An interface to a model instance used to communicate with the solver.
381+//
382+// The solver can use the included function callbacks to interact with the
383+// model.
384+typedef struct FznsoModelRef {
385+ // The handle to the data of the model instance.
386+ const FznsoModel *data;
387+ // Reference to the structure containing the function callbacks used to
388+ // interact with the model.
389+ const struct FznsoModelMethods *methods;
390+} FznsoModelRef;
391+392+// Representation of a type of objective strategies, discerned by its
393+// identifier and the type of its argument.
394+typedef struct FznsoObjective {
395+ // The identifier of the objective type.
396+ const char *ident;
397+ // The type of the expected argument for the constraint type.
398+ struct FznsoType arg_type;
399+} FznsoObjective;
400+401+// A list of [`FznsoObjective`]s.
402+//
403+// This type is, for example, used to return from [`fznso_objective_list`].
404+typedef struct FznsoObjectiveList {
405+ // The number of elements in the `options` array.
406+ size_t len;
407+ // An array of option definitions.
408+ const struct FznsoObjective *options;
409+} FznsoObjectiveList;
410+411+// The definition of an option that is available to be set for the solver.
412+typedef struct FznsoOption {
413+ // The identifier used to set the option or get the current value of the
414+ // option.
415+ const char *ident;
416+ // The type of value that is expected for this option.
417+ struct FznsoValueRef arg_ty;
418+ // The default value for this option.
419+ struct FznsoType arg_def;
420+} FznsoOption;
421+422+// A list of [`FznsoOption`]s.
423+//
424+// This type is, for example, used to return from [`fznso_option_list`].
425+typedef struct FznsoOptionList {
426+ // The number of elements in the `options` array.
427+ size_t len;
428+ // An array of option definitions.
429+ const struct FznsoOption *options;
430+} FznsoOptionList;
431+432+// The handle to a the data of a solution instance.
433+//
434+// This type is opaque to the user. Only pointers of this type are ever used.
435+//
436+// In implementation of the FZnSO interface, a pointer is generally cast to
437+// this type, i.e. `(FznsoSolutionData*) my_solution`. A similar cast can be
438+// used to cast the pointer back to the original type, e.g. `(MySolution*)
439+// fznso_solution`.
440+typedef void FznsoSolution;
441+442+// A struct containing the function pointers to interact with a
443+// [`FznsoSolution`]
444+typedef struct FznsoSolutionMethods {
445+ // Function callback to retrieve the value assigned to a decision variable
446+ // in the solution.
447+ struct FznsoValueRef (*get_value)(const FznsoSolution *data, size_t decision_index);
448+ // Function callback to retrieve the statistical information made available
449+ // by the solver about the search process so far.
450+ struct FznsoValueRef (*get_statistic)(const FznsoSolution *data, const char *ident);
451+} FznsoSolutionMethods;
452+453+// Handle for a solution emitted by the solver.
454+typedef struct FznsoSolutionRef {
455+ // The data pointer to be the first argument of `get_value`.
456+ const FznsoSolution *data;
457+ // Reference to the structure containing the function callbacks used to
458+ // interact with the solution.
459+ const struct FznsoSolutionMethods *methods;
460+} FznsoSolutionRef;
461+462+// The handle to a solver instance.
463+//
464+// This type is opaque to the user. Only pointers of this type are ever used.
465+//
466+// In implementation of the FZnSO interface, a pointer is generally cast to
467+// this type, i.e. `(FznsoSolver*) my_solver`. A similar cast can be used to
468+// cast the pointer back to the original type, e.g. `(MySolverType*)
469+// fznso_solver`.
470+typedef void FznsoSolver;
471+472+// The definition of statistical information that is made available by the
473+// solver.
474+typedef struct FznsoStatistic {
475+ // The identifier used to retrieve the statistical information from the
476+ // solver or a solution.
477+ const char *ident;
478+ // The type of value that is expected for this option.
479+ struct FznsoValueRef ty;
480+ // Whether the statistical information is available as part of solutions.
481+ bool solution;
482+ // Whether the statistical information is generally available from the
483+ // solver instance.
484+ bool solver;
485+} FznsoStatistic;
486+487+// A list of [`FznsoStatistic`]s.
488+//
489+// This type is, for example, used to return from [`fznso_statistic_list`].
490+typedef struct FznsoStatisticList {
491+ // The number of elements in the `stats` array.
492+ size_t len;
493+ // An array of statistical information definitions.
494+ const struct FznsoStatistic *stats;
495+} FznsoStatisticList;
496+497+// A list of [`FznsoType`]s.
498+//
499+// This type is for example used to return from [`fznso_decision_list`].
500+typedef struct FznsoTypeList {
501+ // The number of elements in the `constraints` array.
502+ size_t len;
503+ // An array of constraint types.
504+ const struct FznsoType *types;
505+} FznsoTypeList;
506+507+#endif /* fznso_types_h */
···1-#include "ipdos_types.h"
23// Returns the list of available constraint that can be added to the solver.
4-IpdosConstraintList ipdos_constraint_list(void);
56// Returns the list of types for which decision variable can be created by the
7// solver.
8-IpdosTypeList ipdos_decision_list(void);
910// Returns the list of available objective that can be achieved by the solver.
11-IpdosObjectiveList ipdos_objective_list(void);
1213// Returns the list of available options that can be set of the solver.
14-IpdosOptionList ipdos_option_list(void);
1516// Create a new solver instance
17-IpdosSolver *ipdos_solver_create(void);
1819// Free a solver instance, releasing all resources associated with it.
20//
21// The pointer to the solver instance will be invalid after this function has
22// been called.
23-void ipdos_solver_free(IpdosSolver *solver);
2425// Get the current value of an option for the solver.
26//
27// Note that this is only valid to be called with options named by
28-// `ipdos_option_list`.
29-IpdosValueRef ipdos_solver_option_get(const IpdosSolver *solver, const char *ident);
3031// Set the current value of an option for the solver.
32//
33// Note that this is only valid to be called with options named by
34-// `ipdos_option_list`, and the value must be of the correct type.
35-bool ipdos_solver_option_set(IpdosSolver *solver, const char *ident, IpdosValueRef value);
3637// Read an error message from the solver.
38//
39// This function is expected to be called after solver interactions signal an
40-// error has occurred. For example, if [`ipdos_solver_run`] returns
41-// [`IpdosError`] or [`ipdos_solver_push`] returns `false`.
42-void ipdos_solver_read_error(IpdosSolver *solver,
43 void *context,
44 void (*read_error)(void *context, const char *error));
4546// Run the solver with the given model
47-IpdosStatus ipdos_solver_run(IpdosSolver *solver,
48- IpdosModelRef model,
49 void *context,
50- void (*on_solution)(void *context, IpdosSolutionRef solution));
5152// Returns the list of available statistical information that can be requested
53// from the solver and its solutions.
54-IpdosStatisticList ipdos_statistic_list(void);
···1+#include "fznso_types.h"
23// Returns the list of available constraint that can be added to the solver.
4+FznsoConstraintList fznso_constraint_list(void);
56// Returns the list of types for which decision variable can be created by the
7// solver.
8+FznsoTypeList fznso_decision_list(void);
910// Returns the list of available objective that can be achieved by the solver.
11+FznsoObjectiveList fznso_objective_list(void);
1213// Returns the list of available options that can be set of the solver.
14+FznsoOptionList fznso_option_list(void);
1516// Create a new solver instance
17+FznsoSolver *fznso_solver_create(void);
1819// Free a solver instance, releasing all resources associated with it.
20//
21// The pointer to the solver instance will be invalid after this function has
22// been called.
23+void fznso_solver_free(FznsoSolver *solver);
2425// Get the current value of an option for the solver.
26//
27// Note that this is only valid to be called with options named by
28+// `fznso_option_list`.
29+FznsoValueRef fznso_solver_option_get(const FznsoSolver *solver, const char *ident);
3031// Set the current value of an option for the solver.
32//
33// Note that this is only valid to be called with options named by
34+// `fznso_option_list`, and the value must be of the correct type.
35+bool fznso_solver_option_set(FznsoSolver *solver, const char *ident, FznsoValueRef value);
3637// Read an error message from the solver.
38//
39// This function is expected to be called after solver interactions signal an
40+// error has occurred. For example, if [`fznso_solver_run`] returns
41+// [`FznsoError`] or [`fznso_solver_push`] returns `false`.
42+void fznso_solver_read_error(FznsoSolver *solver,
43 void *context,
44 void (*read_error)(void *context, const char *error));
4546// Run the solver with the given model
47+FznsoStatus fznso_solver_run(FznsoSolver *solver,
48+ FznsoModelRef model,
49 void *context,
50+ void (*on_solution)(void *context, FznsoSolutionRef solution));
5152// Returns the list of available statistical information that can be requested
53// from the solver and its solutions.
54+FznsoStatisticList fznso_statistic_list(void);
-507
c/ipdos_types.h
···1-#ifndef ipdos_types_h
2-#define ipdos_types_h
3-4-#include <stdbool.h>
5-#include <stdint.h>
6-7-// The status returned by `ipdos_solver_run`, indicating whether the solver
8-// completed its search.
9-typedef enum IpdosStatus {
10- // The solver explored the full search space and yielded all relevant
11- // solutions.
12- IpdosComplete,
13- // The solver did not explore the full search space due to a timeout or
14- // other termination condition. Additional (better) solutions might be
15- // possible.
16- IpdosIncomplete,
17- // An error occurred during the solver's execution.
18- //
19- // [`ipdos_solver_read_error`] can be used to retrieve the error message.
20- IpdosError,
21-} IpdosStatus;
22-23-// Representation of the base type of a value.
24-typedef enum IpdosTypeBase {
25- // Boolean type
26- IpdosTypeBaseBool,
27- // Integer numeric type
28- IpdosTypeBaseInt,
29- // Floating point numeric type
30- IpdosTypeBaseFloat,
31- // Character string type
32- IpdosTypeBaseString,
33-} IpdosTypeBase;
34-35-// Enumerated type used to mark the kind of [`IpdosValue`]. This is used to
36-// determine which "get" method in [`IpdosValueMethods`] is safe to call.
37-typedef enum IpdosValueKind {
38- // No value is available.
39- IpdosValueAbsent,
40- // The value is available using [`IpdosValueMethods::get_decision`].
41- IpdosValueDecision,
42- // The value is available using [`IpdosValueMethods::get_constraint`].
43- IpdosValueConstraint,
44- // The value is available using [`IpdosValueMethods::get_bool`].
45- IpdosValueBool,
46- // The value is available using [`IpdosValueMethods::get_int`].
47- IpdosValueInt,
48- // The value is available using [`IpdosValueMethods::get_float`].
49- IpdosValueFloat,
50- // The value is available using [`IpdosValueMethods::get_string`].
51- IpdosValueString,
52- // Sets of integers are represented using a range list. The number of
53- // ranges is available using [`IpdosValueMethods::len`], and the ranges can
54- // be accessed using [`IpdosValueMethods::get_range_int`].
55- IpdosValueSetInt,
56- // Sets of floats are represented using a range list. The number of
57- // ranges is available using [`IpdosValueMethods::len`], and the ranges can
58- // be accessed using [`IpdosValueMethods::get_range_float`].
59- IpdosValueSetFloat,
60- // The length of the list can be accessed using
61- // [`IpdosValueMethods::len`], and elements in the list can be
62- // accessed using [`IpdosValueMethods::get_element`]
63- IpdosValueList,
64-} IpdosValueKind;
65-66-// The handle to a the data of a solution instance.
67-//
68-// This type is opaque to the user. Only pointers of this type are ever used.
69-//
70-// In implementation of the IPDOS interface, a pointer is generally cast to
71-// this type, i.e. `(IpdosSolutionData*) my_solution`. A similar cast can be
72-// used to cast the pointer back to the original type, e.g. `(MySolution*)
73-// ipdos_solution`.
74-typedef void IpdosAnnotation;
75-76-// Representation of a type to signal and check whether an argument takes the
77-// correct type.
78-typedef struct IpdosType {
79- // Whether the type is a list of values.
80- bool list_of;
81- // Whether the argument can be or contain decision variables (represented
82- // as decision indexes).
83- bool decision;
84- // Whether expected type is an set of values of the base type.
85- bool set_of;
86- // Whether the expected type is optional (and can take the value of
87- // [`IpdosValueKind::IpdosValueAbsent`]).
88- bool opt;
89- // The expected base type of the argument.
90- enum IpdosTypeBase base;
91-} IpdosType;
92-93-// Representation of a type of constraint, discerned by its identifier and the
94-// types of its arguments.
95-typedef struct IpdosConstraintType {
96- // The identifier of the constraint type.
97- const char *ident;
98- // The number of expected arguments for the constraint type.
99- size_t arg_len;
100- // The types of the expected arguments for the constraint type.
101- const struct IpdosType *arg_types;
102-} IpdosConstraintType;
103-104-// A list of [`IpdosConstraintType`]s.
105-//
106-// This type is for example used to return from [`ipdos_constraint_list`].
107-typedef struct IpdosConstraintList {
108- // The number of elements in the `constraints` array.
109- size_t len;
110- // An array of constraint types.
111- const struct IpdosConstraintType *constraints;
112-} IpdosConstraintList;
113-114-// The handle of a model instance.
115-//
116-// This type is opaque to the user. Only pointers of this type are ever used.
117-//
118-// In implementation of the IPDOS interface, a pointer is generally cast to
119-// this type, i.e. `(IpdosModelData*) my_model`. A similar cast can be used to
120-// cast the pointer back to the original type, e.g. `(MyModel*) ipdos_model`.
121-typedef void IpdosModel;
122-123-// The type of a value used as an argument or solution assignment.
124-//
125-// This type is opaque to the user. Only pointers of this type are ever used.
126-//
127-// In implementation of the IPDOS interface, a pointer is generally cast to
128-// this type, e.g. `(IpdosValue*) my_value`. A similar cast can be used to cast
129-// the pointer back to the original type, e.g. `(MyValue*) ipdos_value`.
130-typedef void IpdosValue;
131-132-// Wrapper type for the indexes that represent decision variables in the model.
133-typedef size_t IpdosDecisionIdx;
134-135-// Wrapper type for the indexes that represent constraints in the model.
136-typedef size_t IpdosConstraintIdx;
137-138-// A struct containing the function pointers to interact with a
139-// [`IpdosValue`]
140-typedef struct IpdosValueMethods {
141- // Function callback that returns the kind of the value.
142- enum IpdosValueKind (*kind)(const IpdosValue*);
143- // Function callback that returns the length of the value.
144- //
145- // In case [`IpdosValueMethods::kind`] returns
146- // [`IpdosValueKind::IpdosValueList`], the length is the number of elements
147- // in the list, accessible using [`IpdosValueMethods::get_element`].
148- //
149- // In case [`IpdosValueMethods::kind`] returns
150- // [`IpdosValueKind::IpdosValueSetInt`] or
151- // [`IpdosValueKind::IpdosValueSetFloat`], the length is the number of
152- // ranges in the set, accessible using
153- // [`IpdosValueMethods::get_range_int`] or
154- // [`IpdosValueMethods::get_range_float`].
155- //
156- // # Panics
157- //
158- // This function callback may panic if [`IpdosValueMethods::kind`] does not
159- // return [`IpdosValueKind::IpdosValueList`],
160- // [`IpdosValueKind::IpdosValueSetInt`], or
161- // [`IpdosValueKind::IpdosValueSetFloat`].
162- size_t (*len)(const IpdosValue*);
163- // Function callback that returns the decision variable index contained in
164- // the value.
165- //
166- // # Panics
167- //
168- // This function callback may panic if [`IpdosValueMethods::kind`] does not
169- // return [`IpdosValueKind::IpdosValueDecision`].
170- IpdosDecisionIdx (*get_decision)(const IpdosValue*);
171- // Function callback that returns the constraint index contained in the
172- // value.
173- //
174- // # Panics
175- //
176- // This function callback may panic if [`IpdosValueMethods::kind`] does not
177- // return [`IpdosValueKind::IpdosValueConstraint`].
178- IpdosConstraintIdx (*get_constraint)(const IpdosValue*);
179- // Function callback that returns the integer value contained in the value.
180- //
181- // # Panics
182- //
183- // This function callback may panic if [`IpdosValueMethods::kind`] does not
184- // return [`IpdosValueKind::IpdosValueInt`].
185- int64_t (*get_int)(const IpdosValue*);
186- // Function callback that returns the floating point value contained in the
187- // value.
188- //
189- // # Panics
190- //
191- // This function callback may panic if [`IpdosValueMethods::kind`] does not
192- // return [`IpdosValueKind::IpdosValueFloat`].
193- double (*get_float)(const IpdosValue*);
194- // Function callback that returns the string pointer value contained in the
195- // value.
196- //
197- // # Panics
198- //
199- // This function callback may panic if [`IpdosValueMethods::kind`] does not
200- // return [`IpdosValueKind::IpdosValueString`].
201- const char *(*get_string)(const IpdosValue*);
202- // Function callback that returns the Boolean value contained in the value.
203- //
204- // # Panics
205- //
206- // This function callback may panic if [`IpdosValueMethods::kind`] does not
207- // return [`IpdosValueKind::IpdosValueBool`].
208- bool (*get_bool)(const IpdosValue*);
209- // Function callback that returns a range from a range list representing
210- // the integer set contained in the value.
211- //
212- // # Panics
213- //
214- // This function callback may panic if [`IpdosValueMethods::kind`] does not
215- // return [`IpdosValueKind::IpdosValueSetInt`].
216- int64_t ((*get_range_int)(const IpdosValue*, size_t index))[2];
217- // Function callback that returns a range from a range list representing
218- // the floating point set contained in the value.
219- //
220- // # Panics
221- //
222- // This function callback may panic if [`IpdosValueMethods::kind`] does not
223- // return [`IpdosValueKind::IpdosValueSetFloat`].
224- double ((*get_range_float)(const IpdosValue*, size_t index))[2];
225- // Function callback that returns an element from the list contained in the
226- // value.
227- //
228- // # Panics
229- //
230- // This function callback may panic if [`IpdosValueMethods::kind`] does not
231- // return [`IpdosValueKind::IpdosValueList`].
232- struct IpdosValueRef (*get_element)(const IpdosValue*, size_t index);
233-} IpdosValueMethods;
234-235-// Handle for a value
236-//
237-// The caller can use the `get_value` function to retrieve the value of the
238-// used decision variables.
239-typedef struct IpdosValueRef {
240- // The data pointer to be the first argument of `get_value`.
241- const IpdosValue *data;
242- // Reference to the structure containing the function callbacks used to
243- // interact with the value.
244- const struct IpdosValueMethods *methods;
245-} IpdosValueRef;
246-247-// A struct containing the function pointers to interact with the
248-// [`IpdosModel`]
249-typedef struct IpdosModelMethods {
250- // Returns the current number of model layers currently contained in the
251- // model.
252- //
253- // Layers provides a way for the modelling user to add and retract
254- size_t (*layer_len)(const IpdosModel *model);
255- // Returns the number of layers that have been unchanged since the last
256- // call to [`ipdos_solver_run`].
257- //
258- // Unchanged layers must be consecutive starting from layer 0.
259- size_t (*layer_unchanged)(const IpdosModel *model);
260- // Returns the number of permanent layers in the model.
261- //
262- // Permanent layers are laid out must be consecutive starting from layer 0.
263- // Under no circumstances can they be retracted. As such, the solver can
264- // assume that the number of permanent layers only ever increases.
265- //
266- // Permanent layers can, however, still be found to be redundant, allowing
267- // the solver to remove the decision variables and constraints in these
268- // layers, if convenient. This is signaled using [`layer_redundant_len`]
269- // and [`layer_redundant_index`].
270- size_t (*layer_permanent)(const IpdosModel *model);
271- // Returns the number of permanent layers that have been marked as
272- // redundant.
273- //
274- // The solver can remove the decision variables and constraints in these
275- // layers, if convenient. Once a layer is marked as redundant, it can
276- // forever be considered redundant. As such, the solver can assume that
277- // the number of redundant layers only ever increases.
278- size_t (*layer_redundant_len)(const IpdosModel *model);
279- // Returns the index of the n-th permanent layer that has been marked as
280- // redundant.
281- //
282- // The `n` argument must be less than the value returned by
283- // [`layer_redundant_len`].
284- size_t (*layer_redundant_index)(const IpdosModel *model, size_t n);
285- // Retrieve the number of decisions currently contained in the model.
286- size_t (*decision_len)(const IpdosModel *model);
287- // Retrieve the decision index of the last decision variable in the layer.
288- //
289- // This can be equivalent to `decision_layer_end` of `layer-1` if the layer
290- // does not add any new decisions.
291- size_t (*decision_layer_end)(const IpdosModel *model, size_t layer);
292- // Retrieve the domain of the given decision.
293- //
294- // Note that the the value might have [`IpdosValueKind::IpdosValueAbsent`]
295- // if the decision variable does not have an explicit domain.
296- struct IpdosValueRef (*decision_domain)(const IpdosModel *model, IpdosDecisionIdx decision);
297- // Retrieve the name of a decision variable, if it exists.
298- //
299- // Note that names are only available for debugging purposes. Decisions are
300- // identified using their index in the model. If the decision variable does
301- // not have a name, this function returns a null pointer.
302- const char *(*decision_name)(const IpdosModel *model, IpdosDecisionIdx decision);
303- // Check whether the decision variable is defined by a constraint.
304- bool (*decision_defined)(const IpdosModel *model, IpdosDecisionIdx decision);
305- // Retrieve the number of annotations of a constraint.
306- size_t (*decision_annotation_len)(const IpdosModel *model, IpdosDecisionIdx decision);
307- // Retrieve the value of the constraint's annotation at the given index.
308- //
309- // The `index` argument must be less than the value returned by
310- // [`decision_annotation_len`] for the given decision variable.
311- const IpdosAnnotation *(*decision_annotation)(const IpdosModel *model,
312- IpdosDecisionIdx decision,
313- size_t index);
314- // Retrieve the number of constraints currently contained in the model.
315- size_t (*constraint_len)(const IpdosModel *model);
316- // Retrieve the constraint index of the first new constraint in the layer.
317- //
318- // This can be equivalent to `constraint_len` if the layer does not add any
319- // new constraints.
320- size_t (*constraint_layer_end)(const IpdosModel *model);
321- // Retrieve the identifier of a constraint.
322- //
323- // The returned pointer can be assumed to have the the same lifetime as the
324- // model reference and must be valid UTF8.
325- const char *(*constraint_ident)(const IpdosModel *model, IpdosConstraintIdx constraint);
326- // Retrieve the number of arguments of a constraint.
327- size_t (*constraint_argument_len)(const IpdosModel *model, IpdosConstraintIdx constraint);
328- // Retrieve the value of the constraint's argument at the given index.
329- //
330- // The `index` argument must be less than the value returned by
331- // `constraint_argument_len` for the given constraint.
332- struct IpdosValueRef (*constraint_argument)(const IpdosModel *model,
333- IpdosConstraintIdx constraint,
334- size_t index);
335- // Check whether the decision variable is functionally defined by a
336- // constraint.
337- //
338- // This function returns a [`IpdosValue`] that is either
339- // [`IpdosValueKind::IpdosValueDecision`] if it defined a decision variable
340- // or [`IpdosValueKind::IpdosValueAbsent`] otherwise.
341- struct IpdosValueRef (*constraint_defines)(const IpdosModel *model, IpdosConstraintIdx constraint);
342- // Retrieve the number of annotations on a constraint.
343- size_t (*constraint_annotation_len)(const IpdosModel *model, IpdosConstraintIdx constraint);
344- // Retrieve the annotation on a constraint at the given index.
345- //
346- // The `index` argument must be less than the value returned by
347- // `constraint_annotation_len` for the given constraint.
348- const IpdosAnnotation *(*constraint_annotation)(const IpdosModel *model,
349- IpdosConstraintIdx constraint,
350- size_t index);
351- // Request the identifier of the type of objective strategy to be used when
352- // solving the model.
353- //
354- // Note that the function can return a null pointer if the model does not
355- // have an objective strategy.
356- const char *(*objective_ident)(const IpdosModel *model);
357- // Retrieve the argument of the objective strategy.
358- struct IpdosValueRef (*objective_arg)(const IpdosModel *model);
359- // Retrieve the number of annotations on an objective
360- size_t (*objective_annotation_len)(const IpdosModel *model);
361- // Retrieve the annotation on the objective at the given index.
362- //
363- // The `index` argument must be less than the value returned by
364- // `objective_annotation_len`.
365- const IpdosAnnotation *(*objective_annotation)(const IpdosModel *model, size_t index);
366- // Retrieve the identifier of an annotation.
367- //
368- // The returned pointer can be assumed to have the the same lifetime as the
369- // annotation reference and must be valid UTF8.
370- const char *(*annotation_ident)(const IpdosAnnotation *ann);
371- // Retrieve the number of arguments of an annotation.
372- size_t (*annotation_argument_len)(const IpdosAnnotation *ann);
373- // Retrieve the value of the annotation's argument at the given index.
374- //
375- // The `index` argument must be less than the value returned by
376- // `annotation_argument_len` for the given annotation.
377- struct IpdosValueRef (*annotation_argument)(const IpdosAnnotation *ann, size_t index);
378-} IpdosModelMethods;
379-380-// An interface to a model instance used to communicate with the solver.
381-//
382-// The solver can use the included function callbacks to interact with the
383-// model.
384-typedef struct IpdosModelRef {
385- // The handle to the data of the model instance.
386- const IpdosModel *data;
387- // Reference to the structure containing the function callbacks used to
388- // interact with the model.
389- const struct IpdosModelMethods *methods;
390-} IpdosModelRef;
391-392-// Representation of a type of objective strategies, discerned by its
393-// identifier and the type of its argument.
394-typedef struct IpdosObjective {
395- // The identifier of the objective type.
396- const char *ident;
397- // The type of the expected argument for the constraint type.
398- struct IpdosType arg_type;
399-} IpdosObjective;
400-401-// A list of [`IpdosObjective`]s.
402-//
403-// This type is, for example, used to return from [`ipdos_objective_list`].
404-typedef struct IpdosObjectiveList {
405- // The number of elements in the `options` array.
406- size_t len;
407- // An array of option definitions.
408- const struct IpdosObjective *options;
409-} IpdosObjectiveList;
410-411-// The definition of an option that is available to be set for the solver.
412-typedef struct IpdosOption {
413- // The identifier used to set the option or get the current value of the
414- // option.
415- const char *ident;
416- // The type of value that is expected for this option.
417- struct IpdosValueRef arg_ty;
418- // The default value for this option.
419- struct IpdosType arg_def;
420-} IpdosOption;
421-422-// A list of [`IpdosOption`]s.
423-//
424-// This type is, for example, used to return from [`ipdos_option_list`].
425-typedef struct IpdosOptionList {
426- // The number of elements in the `options` array.
427- size_t len;
428- // An array of option definitions.
429- const struct IpdosOption *options;
430-} IpdosOptionList;
431-432-// The handle to a the data of a solution instance.
433-//
434-// This type is opaque to the user. Only pointers of this type are ever used.
435-//
436-// In implementation of the IPDOS interface, a pointer is generally cast to
437-// this type, i.e. `(IpdosSolutionData*) my_solution`. A similar cast can be
438-// used to cast the pointer back to the original type, e.g. `(MySolution*)
439-// ipdos_solution`.
440-typedef void IpdosSolution;
441-442-// A struct containing the function pointers to interact with a
443-// [`IpdosSolution`]
444-typedef struct IpdosSolutionMethods {
445- // Function callback to retrieve the value assigned to a decision variable
446- // in the solution.
447- struct IpdosValueRef (*get_value)(const IpdosSolution *data, size_t decision_index);
448- // Function callback to retrieve the statistical information made available
449- // by the solver about the search process so far.
450- struct IpdosValueRef (*get_statistic)(const IpdosSolution *data, const char *ident);
451-} IpdosSolutionMethods;
452-453-// Handle for a solution emitted by the solver.
454-typedef struct IpdosSolutionRef {
455- // The data pointer to be the first argument of `get_value`.
456- const IpdosSolution *data;
457- // Reference to the structure containing the function callbacks used to
458- // interact with the solution.
459- const struct IpdosSolutionMethods *methods;
460-} IpdosSolutionRef;
461-462-// The handle to a solver instance.
463-//
464-// This type is opaque to the user. Only pointers of this type are ever used.
465-//
466-// In implementation of the IPDOS interface, a pointer is generally cast to
467-// this type, i.e. `(IpdosSolver*) my_solver`. A similar cast can be used to
468-// cast the pointer back to the original type, e.g. `(MySolverType*)
469-// ipdos_solver`.
470-typedef void IpdosSolver;
471-472-// The definition of statistical information that is made available by the
473-// solver.
474-typedef struct IpdosStatistic {
475- // The identifier used to retrieve the statistical information from the
476- // solver or a solution.
477- const char *ident;
478- // The type of value that is expected for this option.
479- struct IpdosValueRef ty;
480- // Whether the statistical information is available as part of solutions.
481- bool solution;
482- // Whether the statistical information is generally available from the
483- // solver instance.
484- bool solver;
485-} IpdosStatistic;
486-487-// A list of [`IpdosStatistic`]s.
488-//
489-// This type is, for example, used to return from [`ipdos_statistic_list`].
490-typedef struct IpdosStatisticList {
491- // The number of elements in the `stats` array.
492- size_t len;
493- // An array of statistical information definitions.
494- const struct IpdosStatistic *stats;
495-} IpdosStatisticList;
496-497-// A list of [`IpdosType`]s.
498-//
499-// This type is for example used to return from [`ipdos_decision_list`].
500-typedef struct IpdosTypeList {
501- // The number of elements in the `constraints` array.
502- size_t len;
503- // An array of constraint types.
504- const struct IpdosType *types;
505-} IpdosTypeList;
506-507-#endif /* ipdos_types_h */
···1-//! IPDOS Protocol Solver Template
2//!
3-//! This crate defines the solver functionality to be implemented IPDOS
4//! protocol, which allows the incremental usage of solvers that can solve
5//! decision and optimization problems. The goal of the interface is to easily
6//! use different solvers in a unified way, and to allow the dynamic loading of
···89use core::ffi;
1011-use ipdos_types::{
12- IpdosConstraintList, IpdosModelRef, IpdosObjectiveList, IpdosOptionList, IpdosSolutionRef,
13- IpdosSolver, IpdosStatisticList, IpdosStatus, IpdosTypeList, IpdosValueRef,
14};
1516#[unsafe(no_mangle)]
17/// Returns the list of available constraint that can be added to the solver.
18-pub extern "C" fn ipdos_constraint_list() -> IpdosConstraintList<'static> {
19 unimplemented!()
20}
2122#[unsafe(no_mangle)]
23/// Returns the list of types for which decision variable can be created by the
24/// solver.
25-pub extern "C" fn ipdos_decision_list() -> IpdosTypeList<'static> {
26 unimplemented!()
27}
2829#[unsafe(no_mangle)]
30/// Returns the list of available objective that can be achieved by the solver.
31-pub extern "C" fn ipdos_objective_list() -> IpdosObjectiveList<'static> {
32 unimplemented!()
33}
3435#[unsafe(no_mangle)]
36/// Returns the list of available options that can be set of the solver.
37-pub extern "C" fn ipdos_option_list() -> IpdosOptionList<'static> {
38 unimplemented!()
39}
4041#[unsafe(no_mangle)]
42/// Create a new solver instance
43-pub extern "C" fn ipdos_solver_create() -> *mut IpdosSolver {
44 unimplemented!()
45}
46···49/// The pointer to the solver instance will be invalid after this function has
50/// been called.
51#[unsafe(no_mangle)]
52-pub extern "C" fn ipdos_solver_free(solver: *mut IpdosSolver) {
53 let _ = solver;
54 unimplemented!()
55}
···58/// Get the current value of an option for the solver.
59///
60/// Note that this is only valid to be called with options named by
61-/// `ipdos_option_list`.
62-pub extern "C" fn ipdos_solver_option_get(
63- solver: &IpdosSolver,
64 ident: *const ffi::c_char,
65-) -> IpdosValueRef<'_> {
66 let _ = solver;
67 let _ = ident;
68 unimplemented!()
···72/// Set the current value of an option for the solver.
73///
74/// Note that this is only valid to be called with options named by
75-/// `ipdos_option_list`, and the value must be of the correct type.
76-pub extern "C" fn ipdos_solver_option_set(
77- solver: &mut IpdosSolver,
78 ident: *const ffi::c_char,
79- value: IpdosValueRef<'_>,
80) -> bool {
81 let _ = solver;
82 let _ = ident;
···88/// Read an error message from the solver.
89///
90/// This function is expected to be called after solver interactions signal an
91-/// error has occurred. For example, if [`ipdos_solver_run`] returns
92-/// [`IpdosError`] or [`ipdos_solver_push`] returns `false`.
93-pub extern "C" fn ipdos_solver_read_error(
94- solver: &mut IpdosSolver,
95 context: &mut ffi::c_void,
96 read_error: extern "C" fn(context: &mut ffi::c_void, error: *const ffi::c_char),
97) {
···103104#[unsafe(no_mangle)]
105/// Run the solver with the given model
106-pub extern "C" fn ipdos_solver_run(
107- solver: &mut IpdosSolver,
108- model: IpdosModelRef,
109 context: &mut ffi::c_void,
110- on_solution: extern "C" fn(context: &mut ffi::c_void, solution: IpdosSolutionRef),
111-) -> IpdosStatus {
112 let _ = solver;
113 let _ = model;
114 let _ = context;
···119#[unsafe(no_mangle)]
120/// Returns the list of available statistical information that can be requested
121/// from the solver and its solutions.
122-pub extern "C" fn ipdos_statistic_list() -> IpdosStatisticList<'static> {
123 unimplemented!()
124}
···1+//! FZnSO Protocol Solver Template
2//!
3+//! This crate defines the solver functionality to be implemented FZnSO
4//! protocol, which allows the incremental usage of solvers that can solve
5//! decision and optimization problems. The goal of the interface is to easily
6//! use different solvers in a unified way, and to allow the dynamic loading of
···89use core::ffi;
1011+use fznso_types::{
12+ FznsoConstraintList, FznsoModelRef, FznsoObjectiveList, FznsoOptionList, FznsoSolutionRef,
13+ FznsoSolver, FznsoStatisticList, FznsoStatus, FznsoTypeList, FznsoValueRef,
14};
1516#[unsafe(no_mangle)]
17/// Returns the list of available constraint that can be added to the solver.
18+pub extern "C" fn fznso_constraint_list() -> FznsoConstraintList<'static> {
19 unimplemented!()
20}
2122#[unsafe(no_mangle)]
23/// Returns the list of types for which decision variable can be created by the
24/// solver.
25+pub extern "C" fn fznso_decision_list() -> FznsoTypeList<'static> {
26 unimplemented!()
27}
2829#[unsafe(no_mangle)]
30/// Returns the list of available objective that can be achieved by the solver.
31+pub extern "C" fn fznso_objective_list() -> FznsoObjectiveList<'static> {
32 unimplemented!()
33}
3435#[unsafe(no_mangle)]
36/// Returns the list of available options that can be set of the solver.
37+pub extern "C" fn fznso_option_list() -> FznsoOptionList<'static> {
38 unimplemented!()
39}
4041#[unsafe(no_mangle)]
42/// Create a new solver instance
43+pub extern "C" fn fznso_solver_create() -> *mut FznsoSolver {
44 unimplemented!()
45}
46···49/// The pointer to the solver instance will be invalid after this function has
50/// been called.
51#[unsafe(no_mangle)]
52+pub extern "C" fn fznso_solver_free(solver: *mut FznsoSolver) {
53 let _ = solver;
54 unimplemented!()
55}
···58/// Get the current value of an option for the solver.
59///
60/// Note that this is only valid to be called with options named by
61+/// `fznso_option_list`.
62+pub extern "C" fn fznso_solver_option_get(
63+ solver: &FznsoSolver,
64 ident: *const ffi::c_char,
65+) -> FznsoValueRef<'_> {
66 let _ = solver;
67 let _ = ident;
68 unimplemented!()
···72/// Set the current value of an option for the solver.
73///
74/// Note that this is only valid to be called with options named by
75+/// `fznso_option_list`, and the value must be of the correct type.
76+pub extern "C" fn fznso_solver_option_set(
77+ solver: &mut FznsoSolver,
78 ident: *const ffi::c_char,
79+ value: FznsoValueRef<'_>,
80) -> bool {
81 let _ = solver;
82 let _ = ident;
···88/// Read an error message from the solver.
89///
90/// This function is expected to be called after solver interactions signal an
91+/// error has occurred. For example, if [`fznso_solver_run`] returns
92+/// [`FznsoError`] or [`fznso_solver_push`] returns `false`.
93+pub extern "C" fn fznso_solver_read_error(
94+ solver: &mut FznsoSolver,
95 context: &mut ffi::c_void,
96 read_error: extern "C" fn(context: &mut ffi::c_void, error: *const ffi::c_char),
97) {
···103104#[unsafe(no_mangle)]
105/// Run the solver with the given model
106+pub extern "C" fn fznso_solver_run(
107+ solver: &mut FznsoSolver,
108+ model: FznsoModelRef,
109 context: &mut ffi::c_void,
110+ on_solution: extern "C" fn(context: &mut ffi::c_void, solution: FznsoSolutionRef),
111+) -> FznsoStatus {
112 let _ = solver;
113 let _ = model;
114 let _ = context;
···119#[unsafe(no_mangle)]
120/// Returns the list of available statistical information that can be requested
121/// from the solver and its solutions.
122+pub extern "C" fn fznso_statistic_list() -> FznsoStatisticList<'static> {
123 unimplemented!()
124}
···1-//! IPDOS Protocol Types
2//!
3-//! This crate defines the types of the IPDOS protocol, which allows the
4//! incremental usage of solvers that can solve decision and optimization
5//! problems. The goal of the interface is to easily use different solvers in a
6//! unified way, and to allow the dynamic loading of solver libraries (as DLLs).
···15///
16/// This type is opaque to the user. Only pointers of this type are ever used.
17///
18-/// In implementation of the IPDOS interface, a pointer is generally cast to
19-/// this type, i.e. `(IpdosSolutionData*) my_solution`. A similar cast can be
20/// used to cast the pointer back to the original type, e.g. `(MySolution*)
21-/// ipdos_solution`.
22-pub struct IpdosAnnotation(ffi::c_void);
2324#[repr(transparent)]
25#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
26/// Wrapper type for the indexes that represent constraints in the model.
27-pub struct IpdosConstraintIdx(pub usize);
2829#[repr(C)]
30#[derive(Clone, Debug)]
31-/// A list of [`IpdosConstraintType`]s.
32///
33-/// This type is for example used to return from [`ipdos_constraint_list`].
34-pub struct IpdosConstraintList<'a> {
35 /// The number of elements in the `constraints` array.
36 pub len: usize,
37 /// An array of constraint types.
38- pub constraints: *const IpdosConstraintType<'a>,
39 /// The lifetime for which the `constraints` attribute is allocated.
40 pub lifetime: PhantomData<&'a ()>,
41}
···44#[derive(Clone, Debug)]
45/// Representation of a type of constraint, discerned by its identifier and the
46/// types of its arguments.
47-pub struct IpdosConstraintType<'a> {
48 /// The identifier of the constraint type.
49 pub ident: *const ffi::c_char,
50 /// The number of expected arguments for the constraint type.
51 pub arg_len: usize,
52 /// The types of the expected arguments for the constraint type.
53- pub arg_types: *const IpdosType,
54 /// The lifetime for which the `ident` and `arg_types` attributes are
55 /// allocated.
56 pub lifetime: PhantomData<&'a ()>,
···59#[repr(transparent)]
60#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
61/// Wrapper type for the indexes that represent decision variables in the model.
62-pub struct IpdosDecisionIdx(pub usize);
6364#[repr(transparent)]
65#[derive(Debug)]
···67///
68/// This type is opaque to the user. Only pointers of this type are ever used.
69///
70-/// In implementation of the IPDOS interface, a pointer is generally cast to
71-/// this type, i.e. `(IpdosModelData*) my_model`. A similar cast can be used to
72-/// cast the pointer back to the original type, e.g. `(MyModel*) ipdos_model`.
73-pub struct IpdosModel(ffi::c_void);
7475#[repr(C)]
76#[derive(Debug)]
77/// A struct containing the function pointers to interact with the
78-/// [`IpdosModel`]
79-pub struct IpdosModelMethods {
80 /// Returns the current number of model layers currently contained in the
81 /// model.
82 ///
83 /// Layers provides a way for the modelling user to add and retract
84- layer_len: extern "C" fn(model: &IpdosModel) -> usize,
85 /// Returns the number of layers that have been unchanged since the last
86- /// call to [`ipdos_solver_run`].
87 ///
88 /// Unchanged layers must be consecutive starting from layer 0.
89- layer_unchanged: extern "C" fn(model: &IpdosModel) -> usize,
90 /// Returns the number of permanent layers in the model.
91 ///
92 /// Permanent layers are laid out must be consecutive starting from layer 0.
···97 /// the solver to remove the decision variables and constraints in these
98 /// layers, if convenient. This is signaled using [`layer_redundant_len`]
99 /// and [`layer_redundant_index`].
100- layer_permanent: extern "C" fn(model: &IpdosModel) -> usize,
101 /// Returns the number of permanent layers that have been marked as
102 /// redundant.
103 ///
···105 /// layers, if convenient. Once a layer is marked as redundant, it can
106 /// forever be considered redundant. As such, the solver can assume that
107 /// the number of redundant layers only ever increases.
108- layer_redundant_len: extern "C" fn(model: &IpdosModel) -> usize,
109 /// Returns the index of the n-th permanent layer that has been marked as
110 /// redundant.
111 ///
112 /// The `n` argument must be less than the value returned by
113 /// [`layer_redundant_len`].
114- layer_redundant_index: extern "C" fn(model: &IpdosModel, n: usize) -> usize,
115116 /// Retrieve the number of decisions currently contained in the model.
117- decision_len: extern "C" fn(model: &IpdosModel) -> usize,
118 /// Retrieve the decision index of the last decision variable in the layer.
119 ///
120 /// This can be equivalent to `decision_layer_end` of `layer-1` if the layer
121 /// does not add any new decisions.
122- decision_layer_end: extern "C" fn(model: &IpdosModel, layer: usize) -> usize,
123 /// Retrieve the domain of the given decision.
124 ///
125- /// Note that the the value might have [`IpdosValueKind::IpdosValueAbsent`]
126 /// if the decision variable does not have an explicit domain.
127 decision_domain:
128- extern "C" fn(model: &IpdosModel, decision: IpdosDecisionIdx) -> IpdosValueRef<'_>,
129 /// Retrieve the name of a decision variable, if it exists.
130 ///
131 /// Note that names are only available for debugging purposes. Decisions are
132 /// identified using their index in the model. If the decision variable does
133 /// not have a name, this function returns a null pointer.
134 decision_name:
135- extern "C" fn(model: &IpdosModel, decision: IpdosDecisionIdx) -> *const ffi::c_char,
136 /// Check whether the decision variable is defined by a constraint.
137- decision_defined: extern "C" fn(model: &IpdosModel, decision: IpdosDecisionIdx) -> bool,
138 /// Retrieve the number of annotations of a constraint.
139- decision_annotation_len: extern "C" fn(model: &IpdosModel, decision: IpdosDecisionIdx) -> usize,
140 /// Retrieve the value of the constraint's annotation at the given index.
141 ///
142 /// The `index` argument must be less than the value returned by
143 /// [`decision_annotation_len`] for the given decision variable.
144 decision_annotation: extern "C" fn(
145- model: &IpdosModel,
146- decision: IpdosDecisionIdx,
147 index: usize,
148- ) -> &IpdosAnnotation,
149150 /// Retrieve the number of constraints currently contained in the model.
151- constraint_len: extern "C" fn(model: &IpdosModel) -> usize,
152 /// Retrieve the constraint index of the first new constraint in the layer.
153 ///
154 /// This can be equivalent to `constraint_len` if the layer does not add any
155 /// new constraints.
156- constraint_layer_end: extern "C" fn(model: &IpdosModel) -> usize,
157 /// Retrieve the identifier of a constraint.
158 ///
159 /// The returned pointer can be assumed to have the the same lifetime as the
160 /// model reference and must be valid UTF8.
161 constraint_ident:
162- extern "C" fn(model: &IpdosModel, constraint: IpdosConstraintIdx) -> *const ffi::c_char,
163 /// Retrieve the number of arguments of a constraint.
164 constraint_argument_len:
165- extern "C" fn(model: &IpdosModel, constraint: IpdosConstraintIdx) -> usize,
166 /// Retrieve the value of the constraint's argument at the given index.
167 ///
168 /// The `index` argument must be less than the value returned by
169 /// `constraint_argument_len` for the given constraint.
170 constraint_argument: extern "C" fn(
171- model: &IpdosModel,
172- constraint: IpdosConstraintIdx,
173 index: usize,
174- ) -> IpdosValueRef<'_>,
175 /// Check whether the decision variable is functionally defined by a
176 /// constraint.
177 ///
178- /// This function returns a [`IpdosValue`] that is either
179- /// [`IpdosValueKind::IpdosValueDecision`] if it defined a decision variable
180- /// or [`IpdosValueKind::IpdosValueAbsent`] otherwise.
181 constraint_defines:
182- extern "C" fn(model: &IpdosModel, constraint: IpdosConstraintIdx) -> IpdosValueRef<'_>,
183 /// Retrieve the number of annotations on a constraint.
184 constraint_annotation_len:
185- extern "C" fn(model: &IpdosModel, constraint: IpdosConstraintIdx) -> usize,
186 /// Retrieve the annotation on a constraint at the given index.
187 ///
188 /// The `index` argument must be less than the value returned by
189 /// `constraint_annotation_len` for the given constraint.
190 constraint_annotation: extern "C" fn(
191- model: &IpdosModel,
192- constraint: IpdosConstraintIdx,
193 index: usize,
194- ) -> &IpdosAnnotation,
195196 /// Request the identifier of the type of objective strategy to be used when
197 /// solving the model.
198 ///
199 /// Note that the function can return a null pointer if the model does not
200 /// have an objective strategy.
201- objective_ident: extern "C" fn(model: &IpdosModel) -> *const ffi::c_char,
202 /// Retrieve the argument of the objective strategy.
203- objective_arg: extern "C" fn(model: &IpdosModel) -> IpdosValueRef<'_>,
204 /// Retrieve the number of annotations on an objective
205- objective_annotation_len: extern "C" fn(model: &IpdosModel) -> usize,
206 /// Retrieve the annotation on the objective at the given index.
207 ///
208 /// The `index` argument must be less than the value returned by
209 /// `objective_annotation_len`.
210- objective_annotation: extern "C" fn(model: &IpdosModel, index: usize) -> &IpdosAnnotation,
211212 /// Retrieve the identifier of an annotation.
213 ///
214 /// The returned pointer can be assumed to have the the same lifetime as the
215 /// annotation reference and must be valid UTF8.
216- annotation_ident: extern "C" fn(ann: &IpdosAnnotation) -> *const ffi::c_char,
217 /// Retrieve the number of arguments of an annotation.
218- annotation_argument_len: extern "C" fn(ann: &IpdosAnnotation) -> usize,
219 /// Retrieve the value of the annotation's argument at the given index.
220 ///
221 /// The `index` argument must be less than the value returned by
222 /// `annotation_argument_len` for the given annotation.
223- annotation_argument: extern "C" fn(ann: &IpdosAnnotation, index: usize) -> IpdosValueRef<'_>,
224}
225226#[repr(C)]
···229///
230/// The solver can use the included function callbacks to interact with the
231/// model.
232-pub struct IpdosModelRef<'a> {
233 /// The handle to the data of the model instance.
234- data: &'a IpdosModel,
235 /// Reference to the structure containing the function callbacks used to
236 /// interact with the model.
237- methods: &'static IpdosModelMethods,
238}
239240#[repr(C)]
241#[derive(Clone, Debug)]
242/// Representation of a type of objective strategies, discerned by its
243/// identifier and the type of its argument.
244-pub struct IpdosObjective<'a> {
245 /// The identifier of the objective type.
246 pub ident: *const ffi::c_char,
247 /// The type of the expected argument for the constraint type.
248- pub arg_type: IpdosType,
249 /// The lifetime for which the `ident` attribute is allocated.
250 pub lifetime: PhantomData<&'a ()>,
251}
252253#[repr(C)]
254#[derive(Clone, Debug)]
255-/// A list of [`IpdosObjective`]s.
256///
257-/// This type is, for example, used to return from [`ipdos_objective_list`].
258-pub struct IpdosObjectiveList<'a> {
259 /// The number of elements in the `options` array.
260 pub len: usize,
261 /// An array of option definitions.
262- pub options: *const IpdosObjective<'a>,
263 /// The lifetime of the `options` attribute.
264 pub lifetime: PhantomData<&'a ()>,
265}
···267#[repr(C)]
268#[derive(Clone, Debug)]
269/// The definition of an option that is available to be set for the solver.
270-pub struct IpdosOption<'a> {
271 /// The identifier used to set the option or get the current value of the
272 /// option.
273 pub ident: *const ffi::c_char,
274 /// The type of value that is expected for this option.
275- pub arg_ty: IpdosValueRef<'a>,
276 /// The default value for this option.
277- pub arg_def: IpdosType,
278 /// The lifetime of the `ident` attribute.
279 pub lifetime: PhantomData<&'a ()>,
280}
281282#[repr(C)]
283#[derive(Clone, Debug)]
284-/// A list of [`IpdosOption`]s.
285///
286-/// This type is, for example, used to return from [`ipdos_option_list`].
287-pub struct IpdosOptionList<'a> {
288 /// The number of elements in the `options` array.
289 pub len: usize,
290 /// An array of option definitions.
291- pub options: *const IpdosOption<'a>,
292 /// The lifetime of the `options` attribute.
293 pub lifetime: PhantomData<&'a ()>,
294}
···299///
300/// This type is opaque to the user. Only pointers of this type are ever used.
301///
302-/// In implementation of the IPDOS interface, a pointer is generally cast to
303-/// this type, i.e. `(IpdosSolutionData*) my_solution`. A similar cast can be
304/// used to cast the pointer back to the original type, e.g. `(MySolution*)
305-/// ipdos_solution`.
306-pub struct IpdosSolution(ffi::c_void);
307308#[repr(C)]
309#[derive(Clone, Debug)]
310/// A struct containing the function pointers to interact with a
311-/// [`IpdosSolution`]
312-pub struct IpdosSolutionMethods {
313 /// Function callback to retrieve the value assigned to a decision variable
314 /// in the solution.
315- get_value: extern "C" fn(data: &IpdosSolution, decision_index: usize) -> IpdosValueRef<'_>,
316 /// Function callback to retrieve the statistical information made available
317 /// by the solver about the search process so far.
318 get_statistic:
319- extern "C" fn(data: &IpdosSolution, ident: *const ffi::c_char) -> IpdosValueRef<'_>,
320}
321322#[repr(C)]
323#[derive(Clone, Debug)]
324/// Handle for a solution emitted by the solver.
325-pub struct IpdosSolutionRef<'a> {
326 /// The data pointer to be the first argument of `get_value`.
327- data: &'a IpdosSolution,
328 /// Reference to the structure containing the function callbacks used to
329 /// interact with the solution.
330- methods: &'static IpdosSolutionMethods,
331}
332333#[repr(transparent)]
···336///
337/// This type is opaque to the user. Only pointers of this type are ever used.
338///
339-/// In implementation of the IPDOS interface, a pointer is generally cast to
340-/// this type, i.e. `(IpdosSolver*) my_solver`. A similar cast can be used to
341/// cast the pointer back to the original type, e.g. `(MySolverType*)
342-/// ipdos_solver`.
343-pub struct IpdosSolver(ffi::c_void);
344345#[repr(C)]
346#[derive(Clone, Debug)]
347/// The definition of statistical information that is made available by the
348/// solver.
349-pub struct IpdosStatistic<'a> {
350 /// The identifier used to retrieve the statistical information from the
351 /// solver or a solution.
352 pub ident: *const ffi::c_char,
353 /// The type of value that is expected for this option.
354- pub ty: IpdosValueRef<'a>,
355 /// Whether the statistical information is available as part of solutions.
356 pub solution: bool,
357 /// Whether the statistical information is generally available from the
···363364#[repr(C)]
365#[derive(Clone, Debug)]
366-/// A list of [`IpdosStatistic`]s.
367///
368-/// This type is, for example, used to return from [`ipdos_statistic_list`].
369-pub struct IpdosStatisticList<'a> {
370 /// The number of elements in the `stats` array.
371 pub len: usize,
372 /// An array of statistical information definitions.
373- pub stats: *const IpdosStatistic<'a>,
374 /// The lifetime of the `stats` attribute.
375 pub lifetime: PhantomData<&'a ()>,
376}
377378#[repr(C)]
379#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
380-/// The status returned by `ipdos_solver_run`, indicating whether the solver
381/// completed its search.
382-pub enum IpdosStatus {
383 /// The solver explored the full search space and yielded all relevant
384 /// solutions.
385- IpdosComplete,
386 /// The solver did not explore the full search space due to a timeout or
387 /// other termination condition. Additional (better) solutions might be
388 /// possible.
389- IpdosIncomplete,
390 /// An error occurred during the solver's execution.
391 ///
392- /// [`ipdos_solver_read_error`] can be used to retrieve the error message.
393- IpdosError,
394}
395396#[repr(C)]
397#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
398/// Representation of a type to signal and check whether an argument takes the
399/// correct type.
400-pub struct IpdosType {
401 /// Whether the type is a list of values.
402 pub list_of: bool,
403 /// Whether the argument can be or contain decision variables (represented
···406 /// Whether expected type is an set of values of the base type.
407 pub set_of: bool,
408 /// Whether the expected type is optional (and can take the value of
409- /// [`IpdosValueKind::IpdosValueAbsent`]).
410 pub opt: bool,
411 /// The expected base type of the argument.
412- pub base: IpdosTypeBase,
413}
414415#[repr(C)]
416#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
417/// Representation of the base type of a value.
418-pub enum IpdosTypeBase {
419 /// Boolean type
420- IpdosTypeBaseBool,
421 /// Integer numeric type
422- IpdosTypeBaseInt,
423 /// Floating point numeric type
424- IpdosTypeBaseFloat,
425 /// Character string type
426- IpdosTypeBaseString,
427}
428429#[repr(C)]
430#[derive(Clone, Debug)]
431-/// A list of [`IpdosType`]s.
432///
433-/// This type is for example used to return from [`ipdos_decision_list`].
434-pub struct IpdosTypeList<'a> {
435 /// The number of elements in the `constraints` array.
436 pub len: usize,
437 /// An array of constraint types.
438- pub types: *const IpdosType,
439 /// The lifetime for which the `types` attribute is allocated.
440 pub lifetime: PhantomData<&'a ()>,
441}
···446///
447/// This type is opaque to the user. Only pointers of this type are ever used.
448///
449-/// In implementation of the IPDOS interface, a pointer is generally cast to
450-/// this type, e.g. `(IpdosValue*) my_value`. A similar cast can be used to cast
451-/// the pointer back to the original type, e.g. `(MyValue*) ipdos_value`.
452-pub struct IpdosValue(ffi::c_void);
453454#[repr(C)]
455#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
456-/// Enumerated type used to mark the kind of [`IpdosValue`]. This is used to
457-/// determine which "get" method in [`IpdosValueMethods`] is safe to call.
458-pub enum IpdosValueKind {
459 /// No value is available.
460- IpdosValueAbsent,
461- /// The value is available using [`IpdosValueMethods::get_decision`].
462- IpdosValueDecision,
463- /// The value is available using [`IpdosValueMethods::get_constraint`].
464- IpdosValueConstraint,
465- /// The value is available using [`IpdosValueMethods::get_bool`].
466- IpdosValueBool,
467- /// The value is available using [`IpdosValueMethods::get_int`].
468- IpdosValueInt,
469- /// The value is available using [`IpdosValueMethods::get_float`].
470- IpdosValueFloat,
471- /// The value is available using [`IpdosValueMethods::get_string`].
472- IpdosValueString,
473 /// Sets of integers are represented using a range list. The number of
474- /// ranges is available using [`IpdosValueMethods::len`], and the ranges can
475- /// be accessed using [`IpdosValueMethods::get_range_int`].
476- IpdosValueSetInt,
477 /// Sets of floats are represented using a range list. The number of
478- /// ranges is available using [`IpdosValueMethods::len`], and the ranges can
479- /// be accessed using [`IpdosValueMethods::get_range_float`].
480- IpdosValueSetFloat,
481 /// The length of the list can be accessed using
482- /// [`IpdosValueMethods::len`], and elements in the list can be
483- /// accessed using [`IpdosValueMethods::get_element`]
484- IpdosValueList,
485}
486487#[repr(C)]
488#[derive(Clone, Debug)]
489/// A struct containing the function pointers to interact with a
490-/// [`IpdosValue`]
491-pub struct IpdosValueMethods {
492 /// Function callback that returns the kind of the value.
493- kind: extern "C" fn(&IpdosValue) -> IpdosValueKind,
494 /// Function callback that returns the length of the value.
495 ///
496- /// In case [`IpdosValueMethods::kind`] returns
497- /// [`IpdosValueKind::IpdosValueList`], the length is the number of elements
498- /// in the list, accessible using [`IpdosValueMethods::get_element`].
499 ///
500- /// In case [`IpdosValueMethods::kind`] returns
501- /// [`IpdosValueKind::IpdosValueSetInt`] or
502- /// [`IpdosValueKind::IpdosValueSetFloat`], the length is the number of
503 /// ranges in the set, accessible using
504- /// [`IpdosValueMethods::get_range_int`] or
505- /// [`IpdosValueMethods::get_range_float`].
506 ///
507 /// # Panics
508 ///
509- /// This function callback may panic if [`IpdosValueMethods::kind`] does not
510- /// return [`IpdosValueKind::IpdosValueList`],
511- /// [`IpdosValueKind::IpdosValueSetInt`], or
512- /// [`IpdosValueKind::IpdosValueSetFloat`].
513- len: extern "C" fn(&IpdosValue) -> usize,
514 /// Function callback that returns the decision variable index contained in
515 /// the value.
516 ///
517 /// # Panics
518 ///
519- /// This function callback may panic if [`IpdosValueMethods::kind`] does not
520- /// return [`IpdosValueKind::IpdosValueDecision`].
521- get_decision: extern "C" fn(&IpdosValue) -> IpdosDecisionIdx,
522 /// Function callback that returns the constraint index contained in the
523 /// value.
524 ///
525 /// # Panics
526 ///
527- /// This function callback may panic if [`IpdosValueMethods::kind`] does not
528- /// return [`IpdosValueKind::IpdosValueConstraint`].
529- get_constraint: extern "C" fn(&IpdosValue) -> IpdosConstraintIdx,
530 /// Function callback that returns the integer value contained in the value.
531 ///
532 /// # Panics
533 ///
534- /// This function callback may panic if [`IpdosValueMethods::kind`] does not
535- /// return [`IpdosValueKind::IpdosValueInt`].
536- get_int: extern "C" fn(&IpdosValue) -> i64,
537 /// Function callback that returns the floating point value contained in the
538 /// value.
539 ///
540 /// # Panics
541 ///
542- /// This function callback may panic if [`IpdosValueMethods::kind`] does not
543- /// return [`IpdosValueKind::IpdosValueFloat`].
544- get_float: extern "C" fn(&IpdosValue) -> f64,
545 /// Function callback that returns the string pointer value contained in the
546 /// value.
547 ///
548 /// # Panics
549 ///
550- /// This function callback may panic if [`IpdosValueMethods::kind`] does not
551- /// return [`IpdosValueKind::IpdosValueString`].
552- get_string: extern "C" fn(&IpdosValue) -> *const ffi::c_char,
553 /// Function callback that returns the Boolean value contained in the value.
554 ///
555 /// # Panics
556 ///
557- /// This function callback may panic if [`IpdosValueMethods::kind`] does not
558- /// return [`IpdosValueKind::IpdosValueBool`].
559- get_bool: extern "C" fn(&IpdosValue) -> bool,
560 /// Function callback that returns a range from a range list representing
561 /// the integer set contained in the value.
562 ///
563 /// # Panics
564 ///
565- /// This function callback may panic if [`IpdosValueMethods::kind`] does not
566- /// return [`IpdosValueKind::IpdosValueSetInt`].
567- get_range_int: extern "C" fn(&IpdosValue, index: usize) -> [i64; 2],
568 /// Function callback that returns a range from a range list representing
569 /// the floating point set contained in the value.
570 ///
571 /// # Panics
572 ///
573- /// This function callback may panic if [`IpdosValueMethods::kind`] does not
574- /// return [`IpdosValueKind::IpdosValueSetFloat`].
575- get_range_float: extern "C" fn(&IpdosValue, index: usize) -> [f64; 2],
576 /// Function callback that returns an element from the list contained in the
577 /// value.
578 ///
579 /// # Panics
580 ///
581- /// This function callback may panic if [`IpdosValueMethods::kind`] does not
582- /// return [`IpdosValueKind::IpdosValueList`].
583- get_element: extern "C" fn(&IpdosValue, index: usize) -> IpdosValueRef<'_>,
584}
585586#[repr(C)]
···589///
590/// The caller can use the `get_value` function to retrieve the value of the
591/// used decision variables.
592-pub struct IpdosValueRef<'a> {
593 /// The data pointer to be the first argument of `get_value`.
594- data: &'a IpdosValue,
595 /// Reference to the structure containing the function callbacks used to
596 /// interact with the value.
597- methods: &'static IpdosValueMethods,
598}
599600#[cfg(test)]
601mod tests {
602- use crate::{IpdosModelRef, IpdosSolutionRef, IpdosType, IpdosValueRef};
603604 #[test]
605 fn memory() {
606- assert_eq!(size_of::<IpdosModelRef>(), size_of::<u128>());
607- assert_eq!(size_of::<IpdosSolutionRef>(), size_of::<u128>());
608- assert_eq!(size_of::<IpdosType>(), size_of::<u64>());
609- assert_eq!(size_of::<IpdosValueRef>(), size_of::<u128>());
610 }
611}
···1+//! FZnSO Protocol Types
2//!
3+//! This crate defines the types of the FZnSO protocol, which allows the
4//! incremental usage of solvers that can solve decision and optimization
5//! problems. The goal of the interface is to easily use different solvers in a
6//! unified way, and to allow the dynamic loading of solver libraries (as DLLs).
···15///
16/// This type is opaque to the user. Only pointers of this type are ever used.
17///
18+/// In implementation of the FZnSO interface, a pointer is generally cast to
19+/// this type, i.e. `(FznsoSolutionData*) my_solution`. A similar cast can be
20/// used to cast the pointer back to the original type, e.g. `(MySolution*)
21+/// fznso_solution`.
22+pub struct FznsoAnnotation(ffi::c_void);
2324#[repr(transparent)]
25#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
26/// Wrapper type for the indexes that represent constraints in the model.
27+pub struct FznsoConstraintIdx(pub usize);
2829#[repr(C)]
30#[derive(Clone, Debug)]
31+/// A list of [`FznsoConstraintType`]s.
32///
33+/// This type is for example used to return from [`fznso_constraint_list`].
34+pub struct FznsoConstraintList<'a> {
35 /// The number of elements in the `constraints` array.
36 pub len: usize,
37 /// An array of constraint types.
38+ pub constraints: *const FznsoConstraintType<'a>,
39 /// The lifetime for which the `constraints` attribute is allocated.
40 pub lifetime: PhantomData<&'a ()>,
41}
···44#[derive(Clone, Debug)]
45/// Representation of a type of constraint, discerned by its identifier and the
46/// types of its arguments.
47+pub struct FznsoConstraintType<'a> {
48 /// The identifier of the constraint type.
49 pub ident: *const ffi::c_char,
50 /// The number of expected arguments for the constraint type.
51 pub arg_len: usize,
52 /// The types of the expected arguments for the constraint type.
53+ pub arg_types: *const FznsoType,
54 /// The lifetime for which the `ident` and `arg_types` attributes are
55 /// allocated.
56 pub lifetime: PhantomData<&'a ()>,
···59#[repr(transparent)]
60#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
61/// Wrapper type for the indexes that represent decision variables in the model.
62+pub struct FznsoDecisionIdx(pub usize);
6364#[repr(transparent)]
65#[derive(Debug)]
···67///
68/// This type is opaque to the user. Only pointers of this type are ever used.
69///
70+/// In implementation of the FZnSO interface, a pointer is generally cast to
71+/// this type, i.e. `(FznsoModelData*) my_model`. A similar cast can be used to
72+/// cast the pointer back to the original type, e.g. `(MyModel*) fznso_model`.
73+pub struct FznsoModel(ffi::c_void);
7475#[repr(C)]
76#[derive(Debug)]
77/// A struct containing the function pointers to interact with the
78+/// [`FznsoModel`]
79+pub struct FznsoModelMethods {
80 /// Returns the current number of model layers currently contained in the
81 /// model.
82 ///
83 /// Layers provides a way for the modelling user to add and retract
84+ layer_len: extern "C" fn(model: &FznsoModel) -> usize,
85 /// Returns the number of layers that have been unchanged since the last
86+ /// call to [`fznso_solver_run`].
87 ///
88 /// Unchanged layers must be consecutive starting from layer 0.
89+ layer_unchanged: extern "C" fn(model: &FznsoModel) -> usize,
90 /// Returns the number of permanent layers in the model.
91 ///
92 /// Permanent layers are laid out must be consecutive starting from layer 0.
···97 /// the solver to remove the decision variables and constraints in these
98 /// layers, if convenient. This is signaled using [`layer_redundant_len`]
99 /// and [`layer_redundant_index`].
100+ layer_permanent: extern "C" fn(model: &FznsoModel) -> usize,
101 /// Returns the number of permanent layers that have been marked as
102 /// redundant.
103 ///
···105 /// layers, if convenient. Once a layer is marked as redundant, it can
106 /// forever be considered redundant. As such, the solver can assume that
107 /// the number of redundant layers only ever increases.
108+ layer_redundant_len: extern "C" fn(model: &FznsoModel) -> usize,
109 /// Returns the index of the n-th permanent layer that has been marked as
110 /// redundant.
111 ///
112 /// The `n` argument must be less than the value returned by
113 /// [`layer_redundant_len`].
114+ layer_redundant_index: extern "C" fn(model: &FznsoModel, n: usize) -> usize,
115116 /// Retrieve the number of decisions currently contained in the model.
117+ decision_len: extern "C" fn(model: &FznsoModel) -> usize,
118 /// Retrieve the decision index of the last decision variable in the layer.
119 ///
120 /// This can be equivalent to `decision_layer_end` of `layer-1` if the layer
121 /// does not add any new decisions.
122+ decision_layer_end: extern "C" fn(model: &FznsoModel, layer: usize) -> usize,
123 /// Retrieve the domain of the given decision.
124 ///
125+ /// Note that the the value might have [`FznsoValueKind::FznsoValueAbsent`]
126 /// if the decision variable does not have an explicit domain.
127 decision_domain:
128+ extern "C" fn(model: &FznsoModel, decision: FznsoDecisionIdx) -> FznsoValueRef<'_>,
129 /// Retrieve the name of a decision variable, if it exists.
130 ///
131 /// Note that names are only available for debugging purposes. Decisions are
132 /// identified using their index in the model. If the decision variable does
133 /// not have a name, this function returns a null pointer.
134 decision_name:
135+ extern "C" fn(model: &FznsoModel, decision: FznsoDecisionIdx) -> *const ffi::c_char,
136 /// Check whether the decision variable is defined by a constraint.
137+ decision_defined: extern "C" fn(model: &FznsoModel, decision: FznsoDecisionIdx) -> bool,
138 /// Retrieve the number of annotations of a constraint.
139+ decision_annotation_len: extern "C" fn(model: &FznsoModel, decision: FznsoDecisionIdx) -> usize,
140 /// Retrieve the value of the constraint's annotation at the given index.
141 ///
142 /// The `index` argument must be less than the value returned by
143 /// [`decision_annotation_len`] for the given decision variable.
144 decision_annotation: extern "C" fn(
145+ model: &FznsoModel,
146+ decision: FznsoDecisionIdx,
147 index: usize,
148+ ) -> &FznsoAnnotation,
149150 /// Retrieve the number of constraints currently contained in the model.
151+ constraint_len: extern "C" fn(model: &FznsoModel) -> usize,
152 /// Retrieve the constraint index of the first new constraint in the layer.
153 ///
154 /// This can be equivalent to `constraint_len` if the layer does not add any
155 /// new constraints.
156+ constraint_layer_end: extern "C" fn(model: &FznsoModel) -> usize,
157 /// Retrieve the identifier of a constraint.
158 ///
159 /// The returned pointer can be assumed to have the the same lifetime as the
160 /// model reference and must be valid UTF8.
161 constraint_ident:
162+ extern "C" fn(model: &FznsoModel, constraint: FznsoConstraintIdx) -> *const ffi::c_char,
163 /// Retrieve the number of arguments of a constraint.
164 constraint_argument_len:
165+ extern "C" fn(model: &FznsoModel, constraint: FznsoConstraintIdx) -> usize,
166 /// Retrieve the value of the constraint's argument at the given index.
167 ///
168 /// The `index` argument must be less than the value returned by
169 /// `constraint_argument_len` for the given constraint.
170 constraint_argument: extern "C" fn(
171+ model: &FznsoModel,
172+ constraint: FznsoConstraintIdx,
173 index: usize,
174+ ) -> FznsoValueRef<'_>,
175 /// Check whether the decision variable is functionally defined by a
176 /// constraint.
177 ///
178+ /// This function returns a [`FznsoValue`] that is either
179+ /// [`FznsoValueKind::FznsoValueDecision`] if it defined a decision variable
180+ /// or [`FznsoValueKind::FznsoValueAbsent`] otherwise.
181 constraint_defines:
182+ extern "C" fn(model: &FznsoModel, constraint: FznsoConstraintIdx) -> FznsoValueRef<'_>,
183 /// Retrieve the number of annotations on a constraint.
184 constraint_annotation_len:
185+ extern "C" fn(model: &FznsoModel, constraint: FznsoConstraintIdx) -> usize,
186 /// Retrieve the annotation on a constraint at the given index.
187 ///
188 /// The `index` argument must be less than the value returned by
189 /// `constraint_annotation_len` for the given constraint.
190 constraint_annotation: extern "C" fn(
191+ model: &FznsoModel,
192+ constraint: FznsoConstraintIdx,
193 index: usize,
194+ ) -> &FznsoAnnotation,
195196 /// Request the identifier of the type of objective strategy to be used when
197 /// solving the model.
198 ///
199 /// Note that the function can return a null pointer if the model does not
200 /// have an objective strategy.
201+ objective_ident: extern "C" fn(model: &FznsoModel) -> *const ffi::c_char,
202 /// Retrieve the argument of the objective strategy.
203+ objective_arg: extern "C" fn(model: &FznsoModel) -> FznsoValueRef<'_>,
204 /// Retrieve the number of annotations on an objective
205+ objective_annotation_len: extern "C" fn(model: &FznsoModel) -> usize,
206 /// Retrieve the annotation on the objective at the given index.
207 ///
208 /// The `index` argument must be less than the value returned by
209 /// `objective_annotation_len`.
210+ objective_annotation: extern "C" fn(model: &FznsoModel, index: usize) -> &FznsoAnnotation,
211212 /// Retrieve the identifier of an annotation.
213 ///
214 /// The returned pointer can be assumed to have the the same lifetime as the
215 /// annotation reference and must be valid UTF8.
216+ annotation_ident: extern "C" fn(ann: &FznsoAnnotation) -> *const ffi::c_char,
217 /// Retrieve the number of arguments of an annotation.
218+ annotation_argument_len: extern "C" fn(ann: &FznsoAnnotation) -> usize,
219 /// Retrieve the value of the annotation's argument at the given index.
220 ///
221 /// The `index` argument must be less than the value returned by
222 /// `annotation_argument_len` for the given annotation.
223+ annotation_argument: extern "C" fn(ann: &FznsoAnnotation, index: usize) -> FznsoValueRef<'_>,
224}
225226#[repr(C)]
···229///
230/// The solver can use the included function callbacks to interact with the
231/// model.
232+pub struct FznsoModelRef<'a> {
233 /// The handle to the data of the model instance.
234+ data: &'a FznsoModel,
235 /// Reference to the structure containing the function callbacks used to
236 /// interact with the model.
237+ methods: &'static FznsoModelMethods,
238}
239240#[repr(C)]
241#[derive(Clone, Debug)]
242/// Representation of a type of objective strategies, discerned by its
243/// identifier and the type of its argument.
244+pub struct FznsoObjective<'a> {
245 /// The identifier of the objective type.
246 pub ident: *const ffi::c_char,
247 /// The type of the expected argument for the constraint type.
248+ pub arg_type: FznsoType,
249 /// The lifetime for which the `ident` attribute is allocated.
250 pub lifetime: PhantomData<&'a ()>,
251}
252253#[repr(C)]
254#[derive(Clone, Debug)]
255+/// A list of [`FznsoObjective`]s.
256///
257+/// This type is, for example, used to return from [`fznso_objective_list`].
258+pub struct FznsoObjectiveList<'a> {
259 /// The number of elements in the `options` array.
260 pub len: usize,
261 /// An array of option definitions.
262+ pub options: *const FznsoObjective<'a>,
263 /// The lifetime of the `options` attribute.
264 pub lifetime: PhantomData<&'a ()>,
265}
···267#[repr(C)]
268#[derive(Clone, Debug)]
269/// The definition of an option that is available to be set for the solver.
270+pub struct FznsoOption<'a> {
271 /// The identifier used to set the option or get the current value of the
272 /// option.
273 pub ident: *const ffi::c_char,
274 /// The type of value that is expected for this option.
275+ pub arg_ty: FznsoValueRef<'a>,
276 /// The default value for this option.
277+ pub arg_def: FznsoType,
278 /// The lifetime of the `ident` attribute.
279 pub lifetime: PhantomData<&'a ()>,
280}
281282#[repr(C)]
283#[derive(Clone, Debug)]
284+/// A list of [`FznsoOption`]s.
285///
286+/// This type is, for example, used to return from [`fznso_option_list`].
287+pub struct FznsoOptionList<'a> {
288 /// The number of elements in the `options` array.
289 pub len: usize,
290 /// An array of option definitions.
291+ pub options: *const FznsoOption<'a>,
292 /// The lifetime of the `options` attribute.
293 pub lifetime: PhantomData<&'a ()>,
294}
···299///
300/// This type is opaque to the user. Only pointers of this type are ever used.
301///
302+/// In implementation of the FZnSO interface, a pointer is generally cast to
303+/// this type, i.e. `(FznsoSolutionData*) my_solution`. A similar cast can be
304/// used to cast the pointer back to the original type, e.g. `(MySolution*)
305+/// fznso_solution`.
306+pub struct FznsoSolution(ffi::c_void);
307308#[repr(C)]
309#[derive(Clone, Debug)]
310/// A struct containing the function pointers to interact with a
311+/// [`FznsoSolution`]
312+pub struct FznsoSolutionMethods {
313 /// Function callback to retrieve the value assigned to a decision variable
314 /// in the solution.
315+ get_value: extern "C" fn(data: &FznsoSolution, decision_index: usize) -> FznsoValueRef<'_>,
316 /// Function callback to retrieve the statistical information made available
317 /// by the solver about the search process so far.
318 get_statistic:
319+ extern "C" fn(data: &FznsoSolution, ident: *const ffi::c_char) -> FznsoValueRef<'_>,
320}
321322#[repr(C)]
323#[derive(Clone, Debug)]
324/// Handle for a solution emitted by the solver.
325+pub struct FznsoSolutionRef<'a> {
326 /// The data pointer to be the first argument of `get_value`.
327+ data: &'a FznsoSolution,
328 /// Reference to the structure containing the function callbacks used to
329 /// interact with the solution.
330+ methods: &'static FznsoSolutionMethods,
331}
332333#[repr(transparent)]
···336///
337/// This type is opaque to the user. Only pointers of this type are ever used.
338///
339+/// In implementation of the FZnSO interface, a pointer is generally cast to
340+/// this type, i.e. `(FznsoSolver*) my_solver`. A similar cast can be used to
341/// cast the pointer back to the original type, e.g. `(MySolverType*)
342+/// fznso_solver`.
343+pub struct FznsoSolver(ffi::c_void);
344345#[repr(C)]
346#[derive(Clone, Debug)]
347/// The definition of statistical information that is made available by the
348/// solver.
349+pub struct FznsoStatistic<'a> {
350 /// The identifier used to retrieve the statistical information from the
351 /// solver or a solution.
352 pub ident: *const ffi::c_char,
353 /// The type of value that is expected for this option.
354+ pub ty: FznsoValueRef<'a>,
355 /// Whether the statistical information is available as part of solutions.
356 pub solution: bool,
357 /// Whether the statistical information is generally available from the
···363364#[repr(C)]
365#[derive(Clone, Debug)]
366+/// A list of [`FznsoStatistic`]s.
367///
368+/// This type is, for example, used to return from [`fznso_statistic_list`].
369+pub struct FznsoStatisticList<'a> {
370 /// The number of elements in the `stats` array.
371 pub len: usize,
372 /// An array of statistical information definitions.
373+ pub stats: *const FznsoStatistic<'a>,
374 /// The lifetime of the `stats` attribute.
375 pub lifetime: PhantomData<&'a ()>,
376}
377378#[repr(C)]
379#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
380+/// The status returned by `fznso_solver_run`, indicating whether the solver
381/// completed its search.
382+pub enum FznsoStatus {
383 /// The solver explored the full search space and yielded all relevant
384 /// solutions.
385+ FznsoComplete,
386 /// The solver did not explore the full search space due to a timeout or
387 /// other termination condition. Additional (better) solutions might be
388 /// possible.
389+ FznsoIncomplete,
390 /// An error occurred during the solver's execution.
391 ///
392+ /// [`fznso_solver_read_error`] can be used to retrieve the error message.
393+ FznsoError,
394}
395396#[repr(C)]
397#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
398/// Representation of a type to signal and check whether an argument takes the
399/// correct type.
400+pub struct FznsoType {
401 /// Whether the type is a list of values.
402 pub list_of: bool,
403 /// Whether the argument can be or contain decision variables (represented
···406 /// Whether expected type is an set of values of the base type.
407 pub set_of: bool,
408 /// Whether the expected type is optional (and can take the value of
409+ /// [`FznsoValueKind::FznsoValueAbsent`]).
410 pub opt: bool,
411 /// The expected base type of the argument.
412+ pub base: FznsoTypeBase,
413}
414415#[repr(C)]
416#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
417/// Representation of the base type of a value.
418+pub enum FznsoTypeBase {
419 /// Boolean type
420+ FznsoTypeBaseBool,
421 /// Integer numeric type
422+ FznsoTypeBaseInt,
423 /// Floating point numeric type
424+ FznsoTypeBaseFloat,
425 /// Character string type
426+ FznsoTypeBaseString,
427}
428429#[repr(C)]
430#[derive(Clone, Debug)]
431+/// A list of [`FznsoType`]s.
432///
433+/// This type is for example used to return from [`fznso_decision_list`].
434+pub struct FznsoTypeList<'a> {
435 /// The number of elements in the `constraints` array.
436 pub len: usize,
437 /// An array of constraint types.
438+ pub types: *const FznsoType,
439 /// The lifetime for which the `types` attribute is allocated.
440 pub lifetime: PhantomData<&'a ()>,
441}
···446///
447/// This type is opaque to the user. Only pointers of this type are ever used.
448///
449+/// In implementation of the FZnSO interface, a pointer is generally cast to
450+/// this type, e.g. `(FznsoValue*) my_value`. A similar cast can be used to cast
451+/// the pointer back to the original type, e.g. `(MyValue*) fznso_value`.
452+pub struct FznsoValue(ffi::c_void);
453454#[repr(C)]
455#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
456+/// Enumerated type used to mark the kind of [`FznsoValue`]. This is used to
457+/// determine which "get" method in [`FznsoValueMethods`] is safe to call.
458+pub enum FznsoValueKind {
459 /// No value is available.
460+ FznsoValueAbsent,
461+ /// The value is available using [`FznsoValueMethods::get_decision`].
462+ FznsoValueDecision,
463+ /// The value is available using [`FznsoValueMethods::get_constraint`].
464+ FznsoValueConstraint,
465+ /// The value is available using [`FznsoValueMethods::get_bool`].
466+ FznsoValueBool,
467+ /// The value is available using [`FznsoValueMethods::get_int`].
468+ FznsoValueInt,
469+ /// The value is available using [`FznsoValueMethods::get_float`].
470+ FznsoValueFloat,
471+ /// The value is available using [`FznsoValueMethods::get_string`].
472+ FznsoValueString,
473 /// Sets of integers are represented using a range list. The number of
474+ /// ranges is available using [`FznsoValueMethods::len`], and the ranges can
475+ /// be accessed using [`FznsoValueMethods::get_range_int`].
476+ FznsoValueSetInt,
477 /// Sets of floats are represented using a range list. The number of
478+ /// ranges is available using [`FznsoValueMethods::len`], and the ranges can
479+ /// be accessed using [`FznsoValueMethods::get_range_float`].
480+ FznsoValueSetFloat,
481 /// The length of the list can be accessed using
482+ /// [`FznsoValueMethods::len`], and elements in the list can be
483+ /// accessed using [`FznsoValueMethods::get_element`]
484+ FznsoValueList,
485}
486487#[repr(C)]
488#[derive(Clone, Debug)]
489/// A struct containing the function pointers to interact with a
490+/// [`FznsoValue`]
491+pub struct FznsoValueMethods {
492 /// Function callback that returns the kind of the value.
493+ kind: extern "C" fn(&FznsoValue) -> FznsoValueKind,
494 /// Function callback that returns the length of the value.
495 ///
496+ /// In case [`FznsoValueMethods::kind`] returns
497+ /// [`FznsoValueKind::FznsoValueList`], the length is the number of elements
498+ /// in the list, accessible using [`FznsoValueMethods::get_element`].
499 ///
500+ /// In case [`FznsoValueMethods::kind`] returns
501+ /// [`FznsoValueKind::FznsoValueSetInt`] or
502+ /// [`FznsoValueKind::FznsoValueSetFloat`], the length is the number of
503 /// ranges in the set, accessible using
504+ /// [`FznsoValueMethods::get_range_int`] or
505+ /// [`FznsoValueMethods::get_range_float`].
506 ///
507 /// # Panics
508 ///
509+ /// This function callback may panic if [`FznsoValueMethods::kind`] does not
510+ /// return [`FznsoValueKind::FznsoValueList`],
511+ /// [`FznsoValueKind::FznsoValueSetInt`], or
512+ /// [`FznsoValueKind::FznsoValueSetFloat`].
513+ len: extern "C" fn(&FznsoValue) -> usize,
514 /// Function callback that returns the decision variable index contained in
515 /// the value.
516 ///
517 /// # Panics
518 ///
519+ /// This function callback may panic if [`FznsoValueMethods::kind`] does not
520+ /// return [`FznsoValueKind::FznsoValueDecision`].
521+ get_decision: extern "C" fn(&FznsoValue) -> FznsoDecisionIdx,
522 /// Function callback that returns the constraint index contained in the
523 /// value.
524 ///
525 /// # Panics
526 ///
527+ /// This function callback may panic if [`FznsoValueMethods::kind`] does not
528+ /// return [`FznsoValueKind::FznsoValueConstraint`].
529+ get_constraint: extern "C" fn(&FznsoValue) -> FznsoConstraintIdx,
530 /// Function callback that returns the integer value contained in the value.
531 ///
532 /// # Panics
533 ///
534+ /// This function callback may panic if [`FznsoValueMethods::kind`] does not
535+ /// return [`FznsoValueKind::FznsoValueInt`].
536+ get_int: extern "C" fn(&FznsoValue) -> i64,
537 /// Function callback that returns the floating point value contained in the
538 /// value.
539 ///
540 /// # Panics
541 ///
542+ /// This function callback may panic if [`FznsoValueMethods::kind`] does not
543+ /// return [`FznsoValueKind::FznsoValueFloat`].
544+ get_float: extern "C" fn(&FznsoValue) -> f64,
545 /// Function callback that returns the string pointer value contained in the
546 /// value.
547 ///
548 /// # Panics
549 ///
550+ /// This function callback may panic if [`FznsoValueMethods::kind`] does not
551+ /// return [`FznsoValueKind::FznsoValueString`].
552+ get_string: extern "C" fn(&FznsoValue) -> *const ffi::c_char,
553 /// Function callback that returns the Boolean value contained in the value.
554 ///
555 /// # Panics
556 ///
557+ /// This function callback may panic if [`FznsoValueMethods::kind`] does not
558+ /// return [`FznsoValueKind::FznsoValueBool`].
559+ get_bool: extern "C" fn(&FznsoValue) -> bool,
560 /// Function callback that returns a range from a range list representing
561 /// the integer set contained in the value.
562 ///
563 /// # Panics
564 ///
565+ /// This function callback may panic if [`FznsoValueMethods::kind`] does not
566+ /// return [`FznsoValueKind::FznsoValueSetInt`].
567+ get_range_int: extern "C" fn(&FznsoValue, index: usize) -> [i64; 2],
568 /// Function callback that returns a range from a range list representing
569 /// the floating point set contained in the value.
570 ///
571 /// # Panics
572 ///
573+ /// This function callback may panic if [`FznsoValueMethods::kind`] does not
574+ /// return [`FznsoValueKind::FznsoValueSetFloat`].
575+ get_range_float: extern "C" fn(&FznsoValue, index: usize) -> [f64; 2],
576 /// Function callback that returns an element from the list contained in the
577 /// value.
578 ///
579 /// # Panics
580 ///
581+ /// This function callback may panic if [`FznsoValueMethods::kind`] does not
582+ /// return [`FznsoValueKind::FznsoValueList`].
583+ get_element: extern "C" fn(&FznsoValue, index: usize) -> FznsoValueRef<'_>,
584}
585586#[repr(C)]
···589///
590/// The caller can use the `get_value` function to retrieve the value of the
591/// used decision variables.
592+pub struct FznsoValueRef<'a> {
593 /// The data pointer to be the first argument of `get_value`.
594+ data: &'a FznsoValue,
595 /// Reference to the structure containing the function callbacks used to
596 /// interact with the value.
597+ methods: &'static FznsoValueMethods,
598}
599600#[cfg(test)]
601mod tests {
602+ use crate::{FznsoModelRef, FznsoSolutionRef, FznsoType, FznsoValueRef};
603604 #[test]
605 fn memory() {
606+ assert_eq!(size_of::<FznsoModelRef>(), size_of::<u128>());
607+ assert_eq!(size_of::<FznsoSolutionRef>(), size_of::<u128>());
608+ assert_eq!(size_of::<FznsoType>(), size_of::<u64>());
609+ assert_eq!(size_of::<FznsoValueRef>(), size_of::<u128>());
610 }
611}