Adjust nanozinc descriptions to match new syntax

This commit is contained in:
Jip J. Dekker 2021-04-07 11:35:27 +10:00
parent eb67f0635d
commit e5e8b9d7ec
No known key found for this signature in database
GPG Key ID: 517DF4A00618C9C3
2 changed files with 67 additions and 73 deletions

View File

@ -1,5 +1,5 @@
\newcommand{\eg}{e.g.,\xspace{}} \newcommand{\eg}{e.g.,\xspace{}}
\newcommand{\ie}{e.g.,\xspace{}} \newcommand{\ie}{i.e.,\xspace{}}
\newcommand{\flatzinc}{\gls{flatzinc}\xspace{}} \newcommand{\flatzinc}{\gls{flatzinc}\xspace{}}
\newcommand{\microzinc}{\gls{microzinc}\xspace{}} \newcommand{\microzinc}{\gls{microzinc}\xspace{}}
\newcommand{\minisearch}{\gls{minisearch}\xspace{}} \newcommand{\minisearch}{\gls{minisearch}\xspace{}}

View File

@ -196,11 +196,10 @@ The translation from \minizinc\ to \microzinc\ involves the following steps:
\subsection{Partial Evaluation of \glsentrytext{nanozinc}}\label{sub:4-partial} \subsection{Partial Evaluation of \glsentrytext{nanozinc}}\label{sub:4-partial}
Each call in a \nanozinc\ program is either a primitive, or it has a Each call in a \nanozinc\ program is either a call to a solver-level predicate,
corresponding \microzinc\ definition. The goal of partial evaluation is to or it has a corresponding \microzinc\ function definition. The goal of partial
transform the \nanozinc\ program into (essentially) \flatzinc, i.e., a program evaluation is to transform the \nanozinc\ program into (essentially) \flatzinc,
where all calls are either solver-level constraint primitives, or defining \ie\ a program where all calls are calls to solver-level predicates.
variables.
To achieve this, we define the semantics of \microzinc\ as a rewriting system To achieve this, we define the semantics of \microzinc\ as a rewriting system
that produces \nanozinc\ calls. Each non-primitive call in a \nanozinc\ program that produces \nanozinc\ calls. Each non-primitive call in a \nanozinc\ program
@ -254,7 +253,7 @@ list of definitions. Each definition binds a variable to the result of a call or
another variable, and it is associated with a list of identifiers of auxiliary another variable, and it is associated with a list of identifiers of auxiliary
constraints. The \nanozinc\ model contains a special definition constraints. The \nanozinc\ model contains a special definition
\mzninline{true}, containing all ``root-context'' constraints of the model, \mzninline{true}, containing all ``root-context'' constraints of the model,
i.e., those that have to hold globally and are not just used to define an \ie\ those that have to hold globally and are not just used to define an
auxiliary variable. Only root-context constraints (attached to \mzninline{true}) auxiliary variable. Only root-context constraints (attached to \mzninline{true})
can effectively constrain the overall problem. Constraints attached to can effectively constrain the overall problem. Constraints attached to
definitions originate from function calls, and since all functions are definitions originate from function calls, and since all functions are
@ -281,17 +280,10 @@ result.
constraint int_gt(z, y); constraint int_gt(z, y);
\end{nzn} \end{nzn}
\jip{Adjust text to match the new \nanozinc\ formatting.} Evaluating the call \mzninline{abs(x)} introduces a new variable \mzninline{z}
The variables \mzninline{x} and \mzninline{y} result in identifiers bound to (with unrestricted domain) and the \mzninline{int_abs} constraint that is used
the special built-in \mzninline{mkvar}, which records the variable's domain in to define \mzninline{z}. The top-level constraint \mzninline{abs(x) > y} is
its arguments. Evaluating the call \mzninline{abs(x)} introduces a new rewritten into \mzninline{int_gt(z, y)} and added as a top-level constraint.
variable \mzninline{z} (with unrestricted domain) and the \mzninline{int_abs}
constraint that is used to define \mzninline{z}, bound to a fresh identifier
\mzninline{b0}. A fresh identifier \mzninline{t} is introduced to capture both
the result \mzninline{z} as well as the list of defining constraints,
\mzninline{[b0]}. The top-level constraint \mzninline{abs(x) > y} is rewritten
into \mzninline{int_gt(t,y)} and bound to fresh identifier \mzninline{b1},
which is added to the root-context definition \mzninline{true}.
\end{example} \end{example}
\subsection{Rewriting Rules} \subsection{Rewriting Rules}
@ -311,7 +303,7 @@ suitable alpha renaming.
\begin{figure*} \begin{figure*}
\centering \centering
\begin{prooftree} \begin{prooftree}
\hypo{\ptinline{F(\(p_1, \ldots{}, p_k\)) = E;} \in{} \Prog{} \text{~where the~} p_i \text{~are fresh}} \hypo{\texttt{function} ~t\texttt{:}~\ptinline{F(\(p_1, \ldots{}, p_k\)) = E;} \in{} \Prog{} \text{~where the~} p_i \text{~are fresh}}
\infer[no rule]1{\Sem{E}{\Prog, \Env_{[p_i \mapsto a_i, \forall{} 1 \leq{} i \leq{} k]}} \Rightarrow \tuple{v, \Env'}} \infer[no rule]1{\Sem{E}{\Prog, \Env_{[p_i \mapsto a_i, \forall{} 1 \leq{} i \leq{} k]}} \Rightarrow \tuple{v, \Env'}}
\infer1[(Call)]{\Sem{F(\(a_1, \ldots, a_k\))}{\Prog, \Env} \Rightarrow{} \tuple{v, \Env'_{[a_i \mapsto p_i, \forall{} 1 \leq{} i \leq{} k]}}} \infer1[(Call)]{\Sem{F(\(a_1, \ldots, a_k\))}{\Prog, \Env} \Rightarrow{} \tuple{v, \Env'_{[a_i \mapsto p_i, \forall{} 1 \leq{} i \leq{} k]}}}
\end{prooftree} \\ \end{prooftree} \\
@ -322,7 +314,7 @@ suitable alpha renaming.
\end{prooftree} \\ \end{prooftree} \\
\bigskip \bigskip
\begin{prooftree} \begin{prooftree}
\hypo{\ptinline{F(\(p_1, \ldots, p_k\));} \in \Prog} \hypo{\texttt{predicate}~\ptinline{F(\(p_1, \ldots, p_k\));} \in \Prog}
\infer1[(CallPredicate)]{\Sem{F(\(a_1, \ldots, a_k\))}{\Prog, \Env_0} \Rightarrow \infer1[(CallPredicate)]{\Sem{F(\(a_1, \ldots, a_k\))}{\Prog, \Env_0} \Rightarrow
\tuple{\texttt{constraint~} \text{F}(v_1, \ldots, v_k), \Env_k}} \tuple{\texttt{constraint~} \text{F}(v_1, \ldots, v_k), \Env_k}}
\end{prooftree} \end{prooftree}
@ -541,8 +533,8 @@ prepended by \texttt{└── }).
(we will come back to this in \cref{sec:4-cse}). Following the rewriting (we will come back to this in \cref{sec:4-cse}). Following the rewriting
rules, the generated \nanozinc\ code will look very similar to the code rules, the generated \nanozinc\ code will look very similar to the code
generated in \cref{ex:4-absnzn}, but with an additional \mzninline{bool_or} generated in \cref{ex:4-absnzn}, but with an additional \mzninline{bool_or}
constraint for the disjunction, which uses the variable \mzninline{b1} that constraint for the disjunction, which uses a variable \mzninline{b} that will
was introduced for \mzninline{abs(x) > y}: be introduced for \mzninline{abs(x) > y}:
\begin{nzn} \begin{nzn}
var true: c; var true: c;
@ -550,24 +542,26 @@ prepended by \texttt{└── }).
var -10..10: y; var -10..10: y;
var int: z; var int: z;
└── constraint int_abs(x, z); └── constraint int_abs(x, z);
var bool: b1; var bool: b;
└── constraint int_gt(z, y); └── constraint int_gt_reif(z, y, b);
constraint bool_or(b1, c); constraint bool_or(b, c);
\end{nzn} \end{nzn}
Since \mzninline{c} is bound to \mzninline{true}, the disjunction Evaluating \mzninline{constraint c} will result in the domain of \mzninline{c}
\mzninline{b2} trivially holds, independent of the value of \mzninline{b1}. to be bound to \mzninline{true}, the disjunction then trivially holds,
The constraint \mzninline{abs(x) > y} is therefore not required. However, the independent of the value of \mzninline{b}. The constraint \mzninline{abs(x) >
rewriting has to choose a particular order in which arguments are evaluated, y} is therefore not required. However, the rewriting has to choose a
so it is always possible that it already evaluated the left hand side before particular order in which arguments are evaluated, so it is always possible
``noticing'' that the disjunction is true. that it already evaluated the left hand side before ``noticing'' that the
disjunction is true.
If the system now simplifies the constraint \mzninline{b2} to \mzninline{true}, If the system now simplifies the constraint \mzninline{bool_or(b, c)} to
the identifier \mzninline{b1} will become unused, since it was only \mzninline{true}, the identifier \mzninline{b} will become unused outside of
referenced from the \mzninline{bool_or} call. Removing \mzninline{b1} leads its auxiliary definitions, since it was only referenced from the
to \mzninline{t} not being used by any constraint, so its definition can be \mzninline{bool_or} call. Removing \mzninline{b} leads will also its defining
removed. This in turn means that \mzninline{b0} is not referenced anywhere constraint, \mzninline{int_gt_reif}, being removed. This in turn means that
and can be removed, and then \mzninline{z}. The resulting \nanozinc\ program \mzninline{z} is not referenced anywhere outside its auxiliary definitions and
can be removed together with its definition. The resulting \nanozinc\ program
is much more compact: is much more compact:
\begin{nzn} \begin{nzn}
@ -580,35 +574,35 @@ prepended by \texttt{└── }).
other parts of the model not shown here and therefore not removed. other parts of the model not shown here and therefore not removed.
\end{example} \end{example}
\jip{adjust text to match the new \nanozinc\ syntax} Note how how counting usage of variables outside its auxiliary definitions
Note how \mzninline{t} acts as a unique name for the result of the let allows us to remove the \mzninline{z} variable --- we could not simply have
expression (and thus the function call) --- we could not simply have used counted the usage of \mzninline{z} in all constraints since the constraint used
\mzninline{z}, because then \mzninline{b0} would have kept \mzninline{z} alive. to define it, \mzninline{int_abs(x, z)}, would have kept it alive.
It is worth noting the difference between the constraints \mzninline{b0} and It is important to notice the difference between constraints that appear at the
\mzninline{b1} in this example: \mzninline{b0} is referenced from the auxiliary top level and constraints that appear as part of the auxiliary definitions of a
constraint list of another variable. This means that it is a constraint that variable. Top-level constraint help define the problem, they are globally
defines the value of a variable, and it can be enforced globally (it must hold, enforced and cannot be removed from the problem unless it can be proved that its
under all circumstances). On the other hand, \mzninline{b1} is referenced as an relationship is already enforced. Constraint in auxiliary definitions, on the
argument to the \mzninline{bool_or} call. This means that the constraint does other hand, are used to define a variable. Auxiliary definitions generally occur
not have to hold globally --- rather, we require the variable \mzninline{b1} to from a functional relationship, like \mzninline{abs(x)} in the example, or from
reflect whether the constraint holds or not, so that the \mzninline{bool_or} the reflection if a constraint holds or not, like \mzninline{abs(x) > y} when
can implement the disjunction. These types of constraints are typically called used in the disjunction with \mzninline{c}. These types of reflection
\emph{reified} in constraint modelling. So \nanozinc\ uses the same syntax for constraints are typically called \glspl{reification}. In this thesis we will
reified and globally true constraints, allocating an identifier (such as follow the same naming standard as \minizinc\ where a \gls{reification} of a
\mzninline{b0} or \mzninline{b1}) for any constraint. Whether the constraint is constraint has the same name as the original constraint with \texttt{\_reif}
reified or not depends on where that identifier appears. appended.
\begin{example} \begin{example}
The importance of the use of auxiliary definitions when removing dead The importance of the use of auxiliary definitions when removing dead
variables and constraints is demonstrated in the following example: variables and constraints is demonstrated in the following example:
\begin{mzn} \begin{mzn}
int n; int: n;
var int: x; var int: x;
function var int: f(var int: x, int: i) = let { function var int: f(var int: x, int: i) = let {
var int: y; var int: y;
constraint y = int_minus(x, i); constraint y = x div i;
} in y; } in y;
constraint [f(x,i) | i in 1..n][1] == 10; constraint [f(x,i) | i in 1..n][1] == 10;
\end{mzn} \end{mzn}
@ -616,22 +610,22 @@ reified or not depends on where that identifier appears.
The rewriting of this instance will initially create the \mzninline{n} The rewriting of this instance will initially create the \mzninline{n}
elements for the array comprehension. Each element is evaluated as a new elements for the array comprehension. Each element is evaluated as a new
variable \mzninline{y} and a constraint to ensure that \mzninline{y} is the variable \mzninline{y} and a constraint to ensure that \mzninline{y} is the
subtraction of \mzninline{x} and \mzninline{i}. Although \mzninline{n} division of \mzninline{x} and \mzninline{i}. Although \mzninline{n} variables
variables are created, only the first variable is constrained to be 10. All are created, only the first variable is constrained to be 10. All other
other variables can thus be removed and the model will stay equisatisfiable. variables can thus be removed and the model will stay equisatisfiable.
In the \nanozinc\ version of this model, each of the subtraction constraints In the \nanozinc\ version of this model, each of the division constraints will
will be added to the list of auxiliary constraints of its corresponding be added to the list of auxiliary constraints of its corresponding
\mzninline{y} variable. When, after evaluating the array access, all of those \mzninline{y} variable. When, after evaluating the array access, all of those
variables except the first are detected to be unused, their removal triggers variables except the first are detected to be unused, their removal triggers
the removal of the subtraction constraints. the removal of the subtraction constraints.
For this example the current \minizinc\ compiler, version 2.3.2, will produce For this example the current \minizinc\ compiler, version 2.5.5, will produce
a \flatzinc\ program that contains the variable \mzninline{x}, \mzninline{n-1} a \flatzinc\ program that contains the variable \mzninline{x}, \mzninline{n-1}
variables \mzninline{y}, and \mzninline{n} constraints for the subtraction. variables \mzninline{y}, and \mzninline{n} constraints for the division.
The first \mzninline{y} variable is directly replaced with the constant 10. The first \mzninline{y} variable is directly replaced with the constant 10.
Using the \nanozinc\ system, only 1 variable, \mzninline{x}, and 1 constraint, Using the \nanozinc\ system, only 1 variable, \mzninline{x}, and 1 constraint,
\mzninline{10 = int_minus(x,1);} is produced. \mzninline{constraint int_minus(x,1,10);} is produced.
\end{example} \end{example}
\paragraph{Implementation} The removal of unused identifiers is taken care of \paragraph{Implementation} The removal of unused identifiers is taken care of
@ -737,7 +731,7 @@ Rewriting a function call that has a \microzinc\ definition and rewriting a
constraint due to propagation are very similar. The interpreter therefore simply constraint due to propagation are very similar. The interpreter therefore simply
interleaves both forms of rewriting. Efficient constraint propagation engines interleaves both forms of rewriting. Efficient constraint propagation engines
``wake up'' a constraint only when one of its variables has received an update ``wake up'' a constraint only when one of its variables has received an update
(i.e., when its domain has been shrunk). To enable this, the interpreter needs (\ie\ when its domain has been shrunk). To enable this, the interpreter needs
to keep a data structure linking variables to the constraints where they appear to keep a data structure linking variables to the constraints where they appear
(in addition to the reverse links from calls to the variables in their (in addition to the reverse links from calls to the variables in their
arguments). These links do not take part in the reference counting. arguments). These links do not take part in the reference counting.
@ -746,14 +740,14 @@ arguments). These links do not take part in the reference counting.
Adding constraint propagation and simplification into the rewriting system means Adding constraint propagation and simplification into the rewriting system means
that the system becomes non-confluent, and some orders of execution may produce that the system becomes non-confluent, and some orders of execution may produce
``better'', i.e., more compact or more efficient, \nanozinc. ``better'', \ie\ more compact or more efficient, \nanozinc.
\begin{example} \begin{example}
The following example is similar to code found in the \minizinc\ libraries of The following example is similar to code found in the \minizinc\ libraries of
MIP solvers. MIP solvers.
\begin{mzn} \begin{mzn}
predicate lq_zero_if_b(var int: x, var bool: b) = function var int: lq_zero_if_b(var int: x, var bool: b) =
x <= ub(x)*(1-b); x <= ub(x)*(1-b);
\end{mzn} \end{mzn}
@ -890,7 +884,7 @@ and the evaluation will proceed as normal with the root context constraint.
Consider the fragment: Consider the fragment:
\begin{mzn} \begin{mzn}
predicate p(var int: x, var int: y) = q(x) /\ r(y); function var bool: p(var int: x, var int: y) = q(x) /\ r(y);
constraint b0 <-> q(x); constraint b0 <-> q(x);
constraint b1 <-> t(x,y); constraint b1 <-> t(x,y);
constraint b1 <-> p(x,y); constraint b1 <-> p(x,y);
@ -906,8 +900,8 @@ and the evaluation will proceed as normal with the root context constraint.
\minizinc\ distinguishes not only between root and reified contexts, but in \minizinc\ distinguishes not only between root and reified contexts, but in
addition recognises constraints in \emph{positive} contexts, also known as addition recognises constraints in \emph{positive} contexts, also known as
\emph{half-reified} \autocite{feydy-2011-half-reif}. We omit the details here \emph{half-reified} \autocite{feydy-2011-half-reif}. A full explanation and
for brevity, but the CSE approach generalises to this extension. discussion of half-reification can be found in \cref{ch:half_reif}.
\section{Experiments}\label{sec:4-experiments} \section{Experiments}\label{sec:4-experiments}
@ -932,9 +926,9 @@ gains that are possible thanks to the new architecture.
As a first experiment, we selected 20 models from the annual \minizinc\ As a first experiment, we selected 20 models from the annual \minizinc\
challenge and compiled 5 instances of each model to \flatzinc, using the current challenge and compiled 5 instances of each model to \flatzinc, using the current
\minizinc\ release version 2.4.3 and the new prototype system. In both cases we \minizinc\ release version 2.4.3 and the new prototype system. In both cases we
use the standard \minizinc\ library of global constraints (i.e., we decompose use the standard \minizinc\ library of global constraints (\ie\ we decompose
those constraints rather than using solver built-ins, in order to stress-test those constraints rather than using solver built-ins, in order to stress-test
the flattening). We measured pure flattening time, i.e., without time required the flattening). We measured pure flattening time, \ie\ without time required
to parse and typecheck in version 2.4.3, and without time required for to parse and typecheck in version 2.4.3, and without time required for
compilation to \microzinc\ in the new system (compilation is usually very fast). compilation to \microzinc\ in the new system (compilation is usually very fast).
Times are averages of 10 runs.\footnote{All models obtained from Times are averages of 10 runs.\footnote{All models obtained from