This document is the specification of the FlatZinc modelling language.
It also includes a definition of the standard command line options a FlatZinc solver should support
in order to work with the minizinc driver program (and the MiniZinc IDE).

FlatZinc is the target constraint modelling language into which MiniZinc
models are translated.
It is a very simple solver independent problem specification language,
requiring minimal implementation effort to support.

Parameter types apply to fixed values that are specified directly in the model.

Variable types apply to values computed by the solver during search. Every parameter type has a corresponding variable type; the variable type being distinguished by a var keyword.

Annotations and strings: annotations can appear on variable declarations, constraints, and on the solve goal. They provide information about how a variable or constraint should be treated by the solver (e.g., whether a variable should be output as part of the result or whether a particular constraint should implemented using domain consistency). Strings may appear as arguments to annotations, but nowhere else.

String literals and literal arrays of string literals can appear as
annotation arguments, but not elsewhere.
Strings have the same syntax as in C programs (namely, they are
delimited by double quotes and the backslash character is used for
escape sequences).

Examples:

"" % The empty string."Hello.""Hello,\nWorld\t\"quoted!\"" % A string with an embedded newline, tab and quotes.

zero or more external predicate declarations (i.e., a non-standard predicate that is supported directly by the target solver);

zero or more parameter declarations;

zero or more variable declarations;

zero or more constraints;

a solve goal

in that order.

FlatZinc uses the UTF-8 character set. Non-ASCII characters can only appear in string literals.

FlatZinc syntax is case sensitive (foo and Foo are different
names).
Identifiers start with a letter ([A-Za-z]) and are followed by
any sequence of letters, digits, or underscores ([A-Za-z0-9_]).
Additionally, identifiers of variable or parameter names may start with an underscore.
Identifiers that correspond to the names of predicates, predicate parameters
and annotations cannot have leading underscores.

Variables have variable types and can be declared with optional assignments.
The assignment can fix a variable to a literal value, or create an alias to another
variable. Arrays of variables always have an assignment, defining them in terms of an array literal
that can contain identifiers of variables or constant literals.
Variables may be declared with zero or more annotations.

where <basic-var-type> and <array-var-type> are variable types, <var-par-identifier> is an identifier,
<annotations> is a (possibly empty) set of annotations, <basic-expr> is an identifier or a literal, and <array-literal> is a literal array
value.

Examples:

var0..9:digit;varbool:b;varsetof1..3:s;var0.0..1.0:x;varint:y::mip;% 'mip' annotation: y should be a MIP variable.array[1..3]ofvar1..10:b=[y,3,digit];

The first alternative searches for any satisfying assignment, the second one searches for an assignment minimizing the given expression, and the third one for an assignment maximizing the expression. The <basic-expr> can be either a variable identifier or a literal value (if the objective function is constant).

A solution consists of a complete assignment where all variables in the
model have been given a fixed value.

Examples:

solvesatisfy;% Find any solution using the default strategy.solveminimizew;% Find a solution minimizing w, using the default strategy.% First label the variables in xs in the order x[1], x[2], ...% trying values in ascending order.solve::int_search(xs,input_order,indomain_min,complete)satisfy;% Find any solution.% First use first-fail on these variables, splitting domains% at each choice point.solve::int_search([x,y,z],first_fail,indomain_split,complete)maximizex;% Find a solution maximizing x.

Annotations are optional suggestions to the solver concerning how
individual variables and constraints should be handled (e.g., a
particular solver may have multiple representations for int variables)
and how search should proceed.
An implementation is free to ignore any annotations it does not
recognise, although it should print a warning on the standard error
stream if it does so.
Annotations are unordered and idempotent: annotations can be reordered
and duplicates can be removed without changing the meaning of the
annotations.

An annotation is prefixed by ::, and either just an identifier or an expression that looks like a predicate call:

where <vars> is the identifier of an array variable or an array literal specifying
the variables to be assigned (ints, bools, or sets respectively). Note that these arrays may contain literal values.

<varchoiceannotation> specifies how the next variable to be assigned is
chosen at each choice point.
Possible choices are as follows (it is recommended that implementations
support the starred options):

input_order

\(\star\)

Choose variables in the order they appear in vars.

first_fail

\(\star\)

Choose the variable with the smallest domain.

anti_first_fail

Choose the variable with the largest domain.

smallest

Choose the variable with the smallest value in its domain.

largest

Choose the variable with the largest value in its domain.

occurrence

Choose the variable with the largest number of attached constraints.

most_constrained

Choose the variable with the smallest domain, breaking ties using the number of constraints.

max_regret

Choose the variable with the largest difference between the two smallest values in its domain.

dom_w_deg

Choose the variable with the smallest value of domain size divided by weighted degree,
where the weighted degree is the number of times the variables been in a constraint which failed

<assignmentannotation> specifies how the chosen variable should be
constrained.
Possible choices are as follows (it is recommended that implementations
support at least the starred options):

indomain_min

\(\star\)

Assign the smallest value in the variable’s domain.

indomain_max

\(\star\)

Assign the largest value in the variable’s domain.

indomain_middle

Assign the value in the variable’s domain closest to the mean of its current bounds.

indomain_median

Assign the middle value in the variable’s domain.

indomain

Nondeterministically assign values to the variable in ascending order.

indomain_random

Assign a random value from the variable’s domain.

indomain_split

Bisect the variable’s domain, excluding the upper half first.

indomain_reverse_split

Bisect the variable’s domain, excluding the lower half first.

indomain_interval

If the variable’s domain consists of several contiguous intervals,
reduce the domain to the first interval. Otherwise just split the variable’s domain.

Of course, not all assignment strategies make sense for all search
annotations (e.g., bool_search and indomain_split).

Model output is specified through variable annotations.
Non-array output variables are annotated with
output_var.
Array output variables are annotated with
output_array([\(x_1\)..\(x_2\), ... ])
where \(x_1\)..\(x_2\), ... are the index set ranges of the
original MiniZinc array (which
may have had multiple dimensions and/or index sets that do not start at
1). See Section 4.3.2 for details on the output format.

(The defines_var annotation should appear on exactly one
constraint.)
This allows a solver to represent x internally as a representation
of y+z rather than as a separate constrained variable.
The is_defined_var annotation on the declaration of x
provides “early warning” to the solver that such an option is
available.

An implementation must output values for all and only the variables
annotated with output_var or output_array (output
annotations must not appear on parameters). Output must be printed to
the standard output stream.

For example:

var1..10:x::output_var;var1..10:y;% y is not output.% Output zs as a "flat" representation of a 2D array:array[1..4]ofvarint:zs::output_array([1..2,1..2]);

All non-error output must be sent to the standard output stream.

Output must take the following form:

<var-par-identifier>=<basic-literal-expr>;

or, for array variables,

<var-par-identifier>=array<N>d(<a>..<b>, ...,[<y1>, <y2>, ... <yk>]);

where <N> is the number of index sets specified in the
corresponding output_array annotation,
<a>..<b>, ... are the index set ranges,
and <y1>,<y2>, ... <yk> are literals of the element type.

Using this format, the output of a FlatZinc model solution is
suitable for input to a MiniZinc model as a data file (this is why
parameters are not included in the output).

Implementations must ensure that all model variables (not
just the output variables) have satisfying assignments before printing a
solution.

The output for a solution must be terminated with ten consecutive
minus signs on a separate line: ----------.

Multiple solutions may be output, one after the other, as search
proceeds. How many solutions should be output depends on the mode the solver is run in as controlled by the -a command line flag (see Section 4.3.4).

If at least one solution has been found and search then terminates
having explored the whole search space, then ten
consecutive equals signs should be printed on a separate line:
==========.

If no solutions have been found and search terminates having explored
the whole search space, then =====UNSATISFIABLE===== should be
printed on a separate line.

If the objective of an optimization problem is unbounded, then
=====UNBOUNDED===== should be printed on a separate line.

If no solutions have been found and search terminates having
not explored the whole search space, then
=====UNKNOWN===== should be printed on a separate line.

Implementations may output further information about the solution(s),
or lack thereof, in the form of FlatZinc comments.

FlatZinc solvers can output statistics in a standard format so that it can be read by scripts,
for example, in order to run experiments and automatically aggregate the results.
Statistics should be printed to the standard output stream in the form of FlatZinc comments that follow a specific format.
Statistics can be output at any time during the solving, i.e., before the first solution, between solutions,
and after the search has finished. Statistics output corresponding to a solution should be the last one
before its ‘———-‘ separator.

Each value should be output on a line of its own in the following format:

%%%mzn-stat: <name>=<value>

Each block of statistics is terminated by a line of its own with the following format:

Constraints in FlatZinc can call standard predicates as well as solver-specific predicates. Standard predicates are the ones that the MiniZinc compiler assumes to be present in all solvers. Without further customisation, the compiler will try to compile the entire model into a set of these standard predicates.

Solvers can use custom predicates and redefine standard predicates by supplying a solver specific library of predicate declarations. Examples of such libraries can be found in the binary distribution of MiniZinc, inside the share/minizinc/gecode and share/minizinc/chuffed directories.

The solver-specific library needs to be made available to the MiniZinc compiler by specifying its location in the solver’s configuration file, see Section 4.3.5.

FlatZinc solvers need to support the predicates listed as FlatZinc builtins in the library reference documentation, see Section 4.2.5.

Any standard predicate that is not supported by a solver needs to be redefined. This can be achieved by placing a file called redefinitions.mzn in the solver’s MiniZinc library, which can contain alternative definitions of predicates, or define them as unsupported using the abort predicate.

Example for a redefinitions.mzn:

% Redefine float_sinh function in terms of exppredicatefloat_sinh(varfloat:a,varfloat:b)=b==(exp(a)-exp(-a))/2.0;% Mark float_tanh as unsupportedpredicatefloat_tanh(varfloat:a,varfloat:b)=abort("The builtin float_tanh is not supported by this solver.");

The redefinition can use the full MiniZinc language. Note, however, that redefining builtin predicates in terms of MiniZinc expressions can lead to problems if the MiniZinc compiler translates the high-level expression back to the redefined builtin.

The reference documentation (Section 4.2.5) also contains sections on builtins that were added in later versions of MiniZinc. In order to maintain backwards compatibility with solvers that don’t support these, they are organised in redefinition files with a version number attached, such as redefinitions-2.0.mzn. In order to declare support for these builtins, the solver-specific library must contain the corresponding redefinitions file, with the predicates either redefined in terms of other predicates, or declared as supported natively by the solver by providing a predicate declaration without a body.

Example for a redefinitions-2.0.mzn that declares native support for the predicates added in MiniZinc 2.0:

Many solvers have built-in support for some of the constraints in the MiniZinc standard library. But without declaring which constraints they support, MiniZinc will assume that they don’t support any except for the standard FlatZinc builtins mentioned in the section above.

A solver can declare that it supports a non-standard constraint by overriding one of the files of the standard library in its own solver-specific library. For example, assume that a solver supports the all_different constraint on integer variables. In the standard library, this constraint is defined in the file fzn_all_different_int.mzn, with the following implementation:

When a MiniZinc model that contains the all_different constraint is now compiled with the OptiSolve library, the generated FlatZinc will contain calls to the newly defined predicate optisolve_alldifferent.

Note: The solver-specific library has been reorganised for MiniZinc version 2.3.0. Previously, a solver library would contain e.g. the file bin_packing.mzn in order to override the bin_packing constraint. With version 2.3.0, this is still possible (in order to maintain backwards compatibility). However, the predicate bin_packing from file bin_packing.mzn now delegates to the predicate fzn_bin_packing in fzn_bin_packing.mzn. This enables the bin_packing predicate to check that the arguments are correct using assertions, before delegating to the solver-specific predicate. If your solver still uses the old library layout (i.e., overriding bin_packing.mzn instead of fzn_bin_packing.mzn), you should consider updating it to the new standard.

A reified constraint is a constraint that is not simply enforced, but whose truth value is bound to a Boolean variable. For example, a MiniZinc expression varbool:b=all_different(x); would constrain b to be true if and only if the variables x take pairwise different values.

If a predicate is called in such a reified context, the MiniZinc compiler will try to find a version of the predicate with _reif added to its identifier and an additional varbool argument. For the above example, the compiler will try to generate the following FlatZinc code:

varbool:b;constraintall_different_reif(x,b);

If the _reif predicate does not exist, the compiler will try to use the definition of the original predicate. However, this may not be ideal: the original definition may make use of free variables in a let expression (which is not allowed in reified contexts), or it may lead to inefficient solving.

When a reified constraint is used in a positive context (see Section 2.3.6), the MiniZinc compiler can use a special version, called a half-reified predicate and identified by an _imp suffix, instead of the _reif predicate. Half-reified predicates essentially represent constraints that are implied by a Boolean variable rather than being equivalent to one. This typically leads to simpler translations or more efficient propagation (e.g., a half-reified all_different only needs to check whether it is false, but it never has to implement the negation of the actual constraint).

For example, constrainty=0\/all_different(x) might be translated as follows:

MiniZinc will decide whether to use half-reification case by case based on the availability of the _imp predicate. As for reified constraints, it may be benefitial to provide specialised half-reified versions if the solver supports them.

In order for a solver to be available to MiniZinc, it has to be described in a solver configuration file. This is a simple file, in JSON or .dzn format, that contains some basic information such as the solver’s name, version, where its library of global constraints can be found, and a path to its executable.
Examples are given in section Solver Backends in User Manual.

A solver configuration file must have file extension .msc (for MiniZinc Solver Configuration), and can be placed in any of the following locations:

In the minizinc/solvers/ directory of the MiniZinc installation. If you install MiniZinc from the binary distribution, this directory can be found at /usr/share/minizinc/solvers on Linux systems, inside the MiniZincIDE application on macOS system, and in the Program Files\MiniZinc IDE (bundled) folder on Windows.

In the directory $HOME/.minizinc/solvers on Linux and macOS systems, and the Application Data directory on Windows systems.

In any directory listed on the MZN_SOLVER_PATH environment variable (directories are separated by : on Linux and macOS, and by ; on Windows systems).

In any directory listed in the mzn_solver_path option of the global or user-specific configuration file (see Section 3.1.4)

Alternatively, you can use the MiniZinc IDE to create solver configuration files, see Section 3.2.5.2 for details.

Solver configuration files must be valid JSON or .dzn files. As a JSON file, it must be an object with certain fields. As a .dzn file, it must consist of assignment items.

For example, a simple solver configuration in JSON format could look like this:

executable (string, required): The executable for this solver that can run FlatZinc files. This can be just a file name (in which case the solver has to be on the current PATH), or an absolute path to the executable, or a relative path (which is interpreted relative to the location of the configuration file).

mznlib (string, default ""): The solver-specific library of global constraints and redefinitions. This should be the name of a directory (either an absolute path or a relative path, interpreted relative to the location of the configuration file). For solvers whose libraries are installed in the same location as the MiniZinc standard library, this can also take the form -G, e.g., -Ggecode (this is mostly the case for solvers that ship with the MiniZinc binary distribution).

tags (list of strings, default empty): Each solver can have one or more tags that describe its features in an abstract way. Tags can be used for selecting a solver using the --solver option. There is no fixed list of tags, however we recommend using the following tags if they match the solver’s behaviour:

"cp": for Constraint Programming solvers

"mip": for Mixed Integer Programming solvers

"float": for solvers that support float variables

"api": for solvers that use the internal C++ API

stdFlags (list of strings, default empty): Which of the standard solver command line flags are supported by this solver. The standard flags are -a, -n, -s, -v, -p, -r, -f, -t.

extraFlags (list of list of strings, default empty): Extra command line flags supported by the solver. Each entry must be a list of four strings. The first string is the name of the option (e.g. "--special-algorithm"). The second string is a description that can be used to generate help output (e.g. "which special algorithm to use"). The third string specifies the type of the argument ("int", "bool", "float", "string" or "opt"). The fourth string is the default value. The following types have an additional extended syntax:

"int:n:m" where n and m are integers, gives lower and upper bounds for the supported values

"float:n:m" where n and m are floating point numbers, gives lower and upper bounds for the supported values

"bool:onstring:offstring" specifies strings to add to the command line flag to turn it on (onstring) and off (offstring). E.g., ["-interrupt","whether to catch Ctrl-C","bool:false:true","true"] specifies a command line option that can be called as -interrupt true or -interrupt false. The standard behaviour (just "bool") means that the option is either added to the command line or not.

"opt:first option:second option:...:last option" specifies a list of possible values for the option

supportsMzn (bool, default false): Whether the solver can run MiniZinc directly (i.e., it implements its own compilation or interpretation of the model).

supportsFzn (bool, default true): Whether the solver can run FlatZinc. This should be the case for most solvers

needsSolns2Out (bool, default true): Whether the output of the solver needs to be passed through the MiniZinc output processor.

needsMznExecutable (bool, default false): Whether the solver needs to know the location of the MiniZinc executable. If true, it will be passed to the solver using the mzn-executable option.

needsStdlibDir (bool, default false): Whether the solver needs to know the location of the MiniZinc standard library directory. If true, it will be passed to the solver using the stdlib-dir option.

isGUIApplication (bool, default false): Whether the solver has its own graphical user interface, which means that MiniZinc will detach from the process and not wait for it to finish or to produce any output.

This is the full grammar for FlatZinc. It is a proper subset of the MiniZinc grammar (see Section 4.1.14). However, instead of specifying all the cases in the MiniZinc grammar that do not apply to FlatZinc, the BNF syntax below contains only the relevant syntactic constructs. It uses the same notation as in Section 4.1.2.