% User manual of the mpformulation package
% Compile with: latexmk -pdf mpformulation-doc.tex

\documentclass[11pt]{article}

\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage[margin=2.5cm]{geometry}
\usepackage{microtype}
\usepackage{amssymb}
\usepackage[fleqn,tbtags]{mathtools}
\usepackage{booktabs}
\usepackage{array}
\usepackage{xcolor}
\usepackage[most]{tcolorbox}
\tcbuselibrary{listings}
\usepackage{mpformulation}
\usepackage[colorlinks,linkcolor=blue!50!black,urlcolor=blue!50!black]{hyperref}
\usepackage[nameinlink,capitalise,noabbrev]{cleveref}
\hypersetup{pdftitle={The mpformulation package},pdfauthor={FYP},
  pdfsubject={Typesetting optimization models in LaTeX}}

% ---------------------------------------------------------------------------
% Markup for the manual
% ---------------------------------------------------------------------------
\newcommand{\pkg}[1]{\textsf{#1}}
\newcommand{\cs}[1]{\texttt{\textbackslash#1}}
\newcommand{\key}[1]{\texttt{#1}}
\newcommand{\meta}[1]{\ensuremath{\langle}\textit{#1}\ensuremath{\rangle}}
\newcommand{\marg}[1]{\texttt{\{}\meta{#1}\texttt{\}}}
\newcommand{\oarg}[1]{\texttt{[}\meta{#1}\texttt{]}}

\lstdefinestyle{ltx}{
  language=[LaTeX]TeX,
  basicstyle=\ttfamily\small,
  breaklines=true,
  columns=fullflexible,
  keepspaces=true,
  commentstyle=\color{gray},
  texcsstyle=*\color{blue!55!black},
  moretexcs={constraint,lastconstraint,objective,subjectto,mpsetup,constraintsetup,
    constraintNameFormat,mathclap,forall},
}

% Code above, result below
\newtcblisting{example}{
  enhanced, breakable,
  colback=white, colframe=black!25, boxrule=0.4pt, arc=1pt,
  listing and text,
  listing options={style=ltx},
  segmentation style={black!25, solid},
  left=6pt, right=6pt,
}

% Code on the left, result on the right (a column of about 7 cm,
% close to one column of a two-column journal)
\newtcblisting{narrowexample}{
  enhanced,
  colback=white, colframe=black!25, boxrule=0.4pt, arc=1pt,
  listing side text,
  lefthand ratio=0.52,
  listing options={style=ltx},
  segmentation style={black!25, solid},
  left=6pt, right=6pt,
}

% Source code only
\newtcblisting{code}{
  colback=black!3, colframe=black!25, boxrule=0.4pt, arc=1pt,
  listing only,
  listing options={style=ltx},
  left=6pt, right=6pt,
}

\setlength{\parindent}{0pt}
\setlength{\parskip}{0.5\baselineskip}

\title{The \pkg{mpformulation} package\\[0.3em]
  \large Typesetting optimization models in \LaTeX}
\date{Version 2.0 --- September 28, 2026\\[1.5em]
  \small \copyright\ 2025--2026 FYP\\[0.3em]
  Report bugs and comments to
  \href{mailto:mpformulation.sty@gmail.com}{\texttt{mpformulation.sty@gmail.com}}}

\begin{document}

\maketitle

\begin{abstract}
  \noindent
  The \pkg{mpformulation} package typesets mathematical programs the way they
  appear in operations research journals: an objective function, a
  ``subject to'' line, and one constraint per line with its quantifier
  (\(\forall i \in I\)) flushed right and an equation number in the margin.
  Four commands and one environment cover the common cases. When a
  constraint is too wide, for instance in a two-column journal, the package
  shortens the indent, breaks the quantifier at its commas, or moves it to
  the next line, without any change to the source.
\end{abstract}

\tableofcontents

% ===========================================================================
\section{Introduction}
% ===========================================================================

Optimization models follow a well-established pattern: a model name, an
objective, the words ``subject to'', then a list of constraints. Each
constraint has two parts: an \emph{expression}, the relation itself (such
as \(x_{ij} \leq y_i\)), and a \emph{quantifier}, the set of indices over
which it holds (such as \(\forall i \in I,\ j \in J\)). Readers expect
the relations to start on a common left edge, the quantifiers to be
aligned on the right, and every constraint to carry a number they can
refer to.

The usual \LaTeX\ tools do not produce this layout directly. With
\texttt{align}, the quantifiers must be pushed right by hand
(\verb|\qquad\forall i|), they are not aligned with each other, and a long
constraint in a narrow column overflows or needs manual rework. Tables give
alignment but lose equation numbering and cross-references.

\pkg{mpformulation} separates the two parts of a constraint, so that the
package, not the author, decides where they go:
\begin{itemize}
  \item the expression starts at a fixed indent, the quantifier is flushed right, and the
    number is placed after the quantifier;
  \item the model name and the objective are aligned with the constraints;
  \item equation numbers use the standard \texttt{equation} counter, so
    \cs{label}, \cs{eqref}, \cs{cref} work as usual;
  \item constraints too wide for the line are reorganized automatically
    (\cref{sec:long}).
\end{itemize}

The first sections teach the package by example. The complete list of
commands and options is in \cref{sec:reference}.

% ===========================================================================
\section{Getting started}\label{sec:start}
% ===========================================================================

Load the package in the preamble:
\begin{code}
\usepackage{mpformulation}
\end{code}
It loads \pkg{amsmath} and \pkg{keyval}. \pkg{mathtools} (for
\cs{mathclap}) and \pkg{cleveref} are optional and used in some examples.

A model is written inside a \texttt{mpformulation} environment. Here is the
binary knapsack problem:

\begin{example}
\begin{mpformulation}
  \objective[MODEL1:objective]{KP}{Maximize}{\sum_{j \in J} p_j x_j}
  \constraint[MODEL1:constr1]{\sum_{j \in J} w_j x_j \leq W}{}
  \constraint[MODEL1:constr2]{x_j \in \{0, 1\}}{\forall j \in J}
\end{mpformulation}
Constraint~\eqref{MODEL1:constr1} bounds the total weight.
\end{example}

The pattern is always the same:
\begin{itemize}
  \item \cs{objective}\oarg{label}\marg{name}\marg{sense}\marg{expression}
    writes the objective line; ``subject to'' is added automatically before
    the first constraint;
  \item \cs{constraint}\oarg{label}\marg{expression}\marg{quantifier} writes one
    constraint; the quantifier may be empty. The last constraint before
    \verb|\end{mpformulation}| is detected and ends with a period.
\end{itemize}
The optional \meta{label} both numbers the line and labels it.

% ===========================================================================
\section{Writing constraints}\label{sec:constraints}
% ===========================================================================

\subsection{Expression and quantifier}

The first mandatory argument of \cs{constraint} is the expression, typeset in
display style (sums have their limits below). The second is the quantifier,
typeset in text style and flushed right. Both are in math mode: do not add
\verb|$|.

Separate the index sets of a quantifier with \verb|,\,| (a comma and a thin
space). The comma is more than punctuation: it is where the package may
break a long quantifier (\cref{sec:long}).

\begin{example}
\begin{mpformulation}
  \constraint[MODEL2:constr1]{\sum_{i \in I} x_{ij} = 1}{\forall j \in J}
  \constraint[MODEL2:constr2]{x_{ij} \leq y_i}{\forall i \in I,\, j \in J}
  \constraint[MODEL2:constr3]{y_i \in \{0, 1\}}{\forall i \in I}
\end{mpformulation}
\end{example}

\subsection{Numbering and cross-references}

A constraint is numbered only when it has a label. Without the optional
argument (or with an empty one), the line is not numbered and the
\texttt{equation} counter is not incremented. Numbers follow the document
numbering, including \cs{numberwithin}.

\begin{example}
\begin{mpformulation}
  \constraint[MODEL3:constr1]{x_{ij} \leq y_i}{\forall i \in I,\, j \in J}
  \constraint{x_{ij} \geq 0}{\forall i \in I,\, j \in J}
  \constraint[MODEL3:constr2]{y_i \in \{0, 1\}}{\forall i \in I}
\end{mpformulation}
Nonnegativity is not numbered; \cref{MODEL3:constr2} defines the binary
variables and \eqref{MODEL3:constr1} links them to $x$.
\end{example}

\subsection{Punctuation}

Many journals punctuate models as sentences: a comma after each relation
and a period at the end. Three options control this:
\key{expr\_suffix} is appended to every expression, \key{quant\_suffix} to every quantifier
except the last, and \key{last\_suffix} (default ``.'') to the quantifier of the
last constraint.

The last constraint is the one directly followed by
\verb|\end{mpformulation}| (spaces, comments and blank lines in between are
ignored). To mark it yourself, for instance when a model is split over two
environments or written outside the environment, use \cs{lastconstraint}
instead of \cs{constraint}; \key{last\_auto=false} turns the detection
off.

\begin{example}
\begin{mpformulation}[expr_suffix={\;,}, quant_suffix={;}]
  \constraint[MODEL4:constr1]{\sum_{i \in I} x_{ij} = 1}{\forall j \in J}
  \constraint[MODEL4:constr2]{x_{ij} \leq y_i}{\forall i \in I,\, j \in J}
\end{mpformulation}
\end{example}
\mpsetup{expr_suffix={}, quant_suffix={}}

The suffix options are global: set them once in the preamble with
\cs{mpsetup} (\cref{sec:setup}) so that all models of a document
agree.

When a constraint has no quantifier, its suffix is attached to the expression, so a last
constraint without quantifier ends as ``\(x \geq 1.\)'' and not with a
period alone in the margin.

\subsection{Numbering the whole model}

By default each labelled line has its own number. Two other schemes are
available through the \key{numbering} option of the environment.
\key{numbering=sub} gives the model one number and numbers its lines
(1a), (1b), \dots, as the \texttt{subequations} environment of
\pkg{amsmath} does. The environment option \key{label} labels the model
itself, and \key{name\_label} labels its name, so that \cs{ref} prints
``(UFLP)''.

\begin{example}
\begin{mpformulation}[numbering=sub, label=MODEL14, name_label=MODEL14:name]
  \objective[MODEL14:objective]{UFLP}{min}{\sum_{i \in I} f_i y_i + \sum_{i \in I} \sum_{j \in J} c_{ij} x_{ij}}
  \constraint[MODEL14:constr1]{\sum_{i \in I} x_{ij} = 1}{\forall j \in J}
  \constraint[MODEL14:constr2]{x_{ij} \leq y_i}{\forall i \in I,\, j \in J}
\end{mpformulation}
Model~\ref{MODEL14:name} is \eqref{MODEL14}; its objective is
\eqref{MODEL14:objective}.
\end{example}

\key{numbering=model} prints a single number for the whole model, on its
first line. Line labels, if any, refer to that number.

\begin{example}
\begin{mpformulation}[numbering=model, label=MODEL15]
  \objective{KP}{max}{\sum_{j \in J} p_j x_j}
  \constraint{\sum_{j \in J} w_j x_j \leq W}{}
  \constraint{x_j \in \{0, 1\}}{\forall j \in J}
\end{mpformulation}
The knapsack problem~\eqref{MODEL15} has a single constraint.
\end{example}

% ===========================================================================
\section{Objective and ``subject to''}\label{sec:objective}
% ===========================================================================

\cs{objective}\oarg{label}\marg{name}\marg{sense}\marg{expression} starts at
the same indent as the constraints, so the model name is aligned with the
relations below. The name is printed in parentheses; leave it empty to omit
it. The sense is ordinary text (\emph{Minimize}, \emph{max}, \dots).

\begin{example}
\begin{mpformulation}
  \objective[MODEL5:objective]{}{min}{\sum_{i \in I} f_i y_i + \sum_{i \in I} \sum_{j \in J} c_{ij} x_{ij}}
  \constraint[MODEL5:constr1]{\sum_{i \in I} x_{ij} = 1}{\forall j \in J}
\end{mpformulation}
\end{example}

The ``subject to'' line is inserted automatically before the first
constraint that follows \cs{objective}; there is nothing to write. To place
it yourself (for instance after a comment line), write \cs{subjectto}: the
automatic line is then skipped. \key{st\_auto=false} turns the automatic
line off, for models written without ``subject to''.

By default the line is indented like the first line of a paragraph, so it
lines up with the text around the model. The key \key{st\_indent} moves it (\verb|0pt| is flush
left; \cs{constraintLeftmargin} aligns it with the constraints), and
\key{st\_text} changes the wording. The model name format is the macro
\cs{constraintNameFormat}.

\begin{example}
\renewcommand{\constraintNameFormat}[1]{\textsc{#1}:}
\begin{mpformulation}[st_text={s.t.}, st_indent=\constraintLeftmargin]
  \objective[MODEL6:objective]{UFLP}{min}{\sum_{i \in I} f_i y_i + \sum_{i \in I} \sum_{j \in J} c_{ij} x_{ij}}
  \constraint[MODEL6:constr1]{x_{ij} \leq y_i}{\forall i \in I,\, j \in J}
\end{mpformulation}
\end{example}
\mpsetup{st_text={subject to}, st_indent=\parindent}

The spaces after the name and after the sense are \key{name\_sep} and
\key{sense\_sep} (both \verb|1em|).

\subsection{Long objectives}

An objective too wide for the line is broken where you put \verb|\\| in the
expression. The continuation lines start under the expression and the
number goes on the last line. As in constraints, the break is optional: it
is used only when the objective does not fit (\key{obj\_break=always}
forces it). Start the continuation with \verb|{}+| to keep the spacing of
the operator.

\begin{narrowexample}
\begin{mpformulation}[indent=1em, numsep=0.5em]
  \objective[MODEL16:objective]{TT}{min}{\sum_{i\in I}\sum_{k\in K} e_{ik}x_{ik} + \mu \sum_{t \in T} z_t \\ {}+ \lambda \sum_{i\in I} L_i}
  \constraint[MODEL16:constr1]{\sum_{k\in K} x_{ik} = 1}{\forall i \in I}
\end{mpformulation}
\end{narrowexample}

\subsection{``subject to'' on the first constraint line}

With \key{st\_inline}, ``subject to'' is written on the line of the first
constraint, and the constraints (and the objective) are moved right if
needed so that it fits.

\begin{example}
\begin{mpformulation}[st_inline]
  \objective[MODEL17:objective]{UFLP}{min}{\sum_{i \in I} f_i y_i + \sum_{i \in I} \sum_{j \in J} c_{ij} x_{ij}}
  \constraint[MODEL17:constr1]{\sum_{i \in I} x_{ij} = 1}{\forall j \in J}
  \constraint[MODEL17:constr2]{x_{ij} \leq y_i}{\forall i \in I,\, j \in J}
\end{mpformulation}
\end{example}
\mpsetup{st_inline=false}

% ===========================================================================
\section{Adjusting the layout}\label{sec:setup}
% ===========================================================================

\subsection{Setting options}

All options are \meta{key}\verb|=|\meta{value} pairs. They can be set for
the whole document or for one model:
\begin{code}
% Preamble: all models of the document
\mpsetup{indent=3em, numsep=3em, expr_suffix={\;,}}

% One model only
\begin{mpformulation}[indent=1em]
  ...
\end{mpformulation}
\end{code}
Options given to the environment are local to it for the lengths and for
\key{numbering}, \key{label}, \key{name\_label}, \key{rel\_align},
\key{quant\_align}, \key{quant\_overflow} and \key{quant\_col}. The text and
behaviour options (the suffixes, \key{st\_text}, \key{st\_indent},
\key{st\_auto}, \key{st\_inline}, \key{last\_auto}, \key{keep\_last} and the
break modes) are global and remain in force after the environment.

\subsection{Horizontal and vertical spacing}

The horizontal layout of a line is:
\begin{center}
  \small
  \begin{tabular}{@{}l@{}}
    \texttt{|<-- indent -->|}\,expression\,\texttt{|<-- at least quant\_gap -->|}\,quantifier\,\texttt{|<-- numsep -->|}\,(n)
  \end{tabular}
\end{center}
\key{indent} (default \verb|6em|) is the space before the expression and the
objective, \key{numsep} (default \verb|2em|) the space between the quantifier and
the number. Vertically, \key{rowsep} (default \verb|0.5\baselineskip|) is
added after each line, and \key{topsep} and \key{bottomsep} (default
\verb|0pt|) before and after the environment.

\begin{example}
\begin{mpformulation}[indent=1em, numsep=1em, rowsep=0pt, bottomsep=6pt]
  \constraint[MODEL7:constr1]{\sum_{i \in I} x_{ij} = 1}{\forall j \in J}
  \constraint[MODEL7:constr2]{x_{ij} \leq y_i}{\forall i \in I,\, j \in J}
\end{mpformulation}
Text after the model.
\end{example}

\subsection{Aligning on the relation}

With \key{rel\_align}, the constraints of an environment are aligned on
their relation symbol (\(=\), \(\leq\), \(\geq\), \(\in\), \dots). The
package splits each expression at its first relation outside braces; to choose
another point, put \verb|&| before the relation. Constraints whose expression
contains \verb|\\| are not aligned. The environment is measured before
it is typeset, so the alignment is right on the first \LaTeX\ run.

\begin{example}
\begin{mpformulation}[rel_align]
  \constraint[MODEL18:constr1]{\sum_{i \in I} x_{ij} = 1}{\forall j \in J}
  \constraint[MODEL18:constr2]{x_{ij} \leq y_i}{\forall i \in I,\, j \in J}
  \constraint[MODEL18:constr3]{t_{i,j+1} - t_{ij} & \geq H^{\min}}{\forall i \in I,\, j \in J}
  \constraint[MODEL18:constr4]{y_i \in \{0, 1\}}{\forall i \in I}
\end{mpformulation}
\end{example}

\subsection{Left-aligned quantifiers}

By default the quantifiers are flushed right. With \key{quant\_align=left},
they start at a common column instead, just after the widest expression of
the environment. An expression that reaches the column has its quantifier
on the next line, still at the column. A quantifier too wide for the room
left after the column is written unbroken on the next line, starting under
the expression (indented by \key{expr\_cont\_indent}); it is wrapped at its
commas only if it does not fit there either. With
\key{quant\_overflow=wrap}, it is wrapped at the column instead, each line
starting at the column.

\begin{example}
\begin{mpformulation}[quant_align=left, indent=3em, numsep=1em]
  \constraint[MODEL19:constr1]{\sum_{i \in I} x_{ij} = 1}{\forall j \in J}
  \constraint[MODEL19:constr2]{x_{ij} \leq y_i}{\forall i \in I,\, j \in J}
  \constraint[MODEL19:constr3]{t_{i+1,s} - t_{is} \geq H^{\min}}{\forall i \in I,\, s \in S,\, i < n}
  \constraint[MODEL19:constr4]{y_i \in \{0, 1\}}{\forall i \in I}
\end{mpformulation}
\end{example}

The column is computed from the widest expression of the environment,
which is measured before it is typeset: the alignment is right on the first
\LaTeX\ run. The column is never placed
beyond \key{quant\_col\_max} (default \verb|0.6\linewidth|), so that one
long expression does not squeeze all quantifiers; \key{quant\_col} sets the
column explicitly, as a distance from the left edge of the text.

In a narrow column, the default keeps each quantifier on one line:

\begin{narrowexample}
\begin{mpformulation}[quant_align=left, indent=1em, numsep=0.5em]
  \constraint[MODEL20:constr1]{x_{ij} \le y_i}{\forall i \in I,\, j \in J}
  \constraint[MODEL20:constr2]{t_{i+1,s} - t_{is} \geq H}{\forall i \in I,\, s \in S,\, i < n,\, k \in K}
  \constraint[MODEL20:constr3]{\sum_{s \in S_p} (1 - h_s) + \sum_{s \in \bar{S}_p} h_s \geq 1}{\forall p \in \Pi,\, b \in B}
\end{mpformulation}
\end{narrowexample}

The same model with \key{quant\_overflow=wrap}:

\begin{narrowexample}
\begin{mpformulation}[quant_align=left, indent=1em, numsep=0.5em, quant_overflow=wrap]
  \constraint[MODEL21:constr1]{x_{ij} \le y_i}{\forall i \in I,\, j \in J}
  \constraint[MODEL21:constr2]{t_{i+1,s} - t_{is} \geq H}{\forall i \in I,\, s \in S,\, i < n,\, k \in K}
  \constraint[MODEL21:constr3]{\sum_{s \in S_p} (1 - h_s) + \sum_{s \in \bar{S}_p} h_s \geq 1}{\forall p \in \Pi,\, b \in B}
\end{mpformulation}
\end{narrowexample}

% ===========================================================================
\section{Long constraints and narrow columns}\label{sec:long}
% ===========================================================================

A model that fits a one-column page often does not fit a two-column
journal. \pkg{mpformulation} measures every line and, when it is too wide,
tries the following layouts in order, keeping the first that fits:
\begin{enumerate}
  \item \textbf{Shrink the indent.} The line stays on one row; the indent is
    reduced as much as needed, down to \key{min\_indent} (default
    \verb|0pt|).
  \item \textbf{Break the quantifier.} The quantifier is split over several lines
    at its commas, next to the expression.
  \item \textbf{Move the quantifier below.} The expression stays alone on the first
    line; the quantifier goes right-aligned on the line below.
  \item \textbf{Break the expression.} Only if the expression itself is too wide and
    contains a break point \verb|\\| written by the author.
\end{enumerate}
The equation number is always on the last line, as with the \texttt{tbtags}
option of \pkg{mathtools}. The lines of one constraint are kept on the same
page.

The examples of this section are typeset in a column of about 7\,cm.

\subsection{Shrinking the indent}

\begin{narrowexample}
\begin{mpformulation}[indent=3em, numsep=0.5em]
  \constraint[MODEL8:constr1]{x_{ij} \leq y_i}{\forall i \in I,\, j \in J}
  \constraint[MODEL8:constr2]{\sum_{j \in J} d_j x_{ij} \leq Q_i y_i}{\forall i \in I}
\end{mpformulation}
\end{narrowexample}

The second constraint does not fit with the \verb|3em| indent, so it starts
further left. Set \key{min\_indent} equal to \key{indent} to forbid this.

\subsection{Breaking the quantifier automatically}

A quantifier that does not fit is broken at its commas. Lines are filled
from left to right, each broken line ends with its comma, and spacing
commands such as \verb|\,| at the start of a new line are dropped. Commas
inside \verb|{}|, \verb|()|, \verb|[]|, \verb|\{\}| and
\verb|\langle\rangle| are never break points, so \((i, j)\) and
\(\{1, 2, 3\}\) stay together.

\begin{narrowexample}
\begin{mpformulation}[indent=1em, numsep=0.5em]
  \constraint[MODEL9:constr1]{\sum_{k \in K} x_{ijk} \leq 1}{\forall (i, j) \in A,\, t \in \{1, \dots, T\},\, s \in S}
\end{mpformulation}
\end{narrowexample}

\subsection{Choosing the break yourself}

To decide where a quantifier breaks, put \verb|\\| there. The break is
\emph{optional}: it is used only if the quantifier does not fit on one line,
otherwise \verb|\\| is replaced by a space. With \key{quant\_break=always}
every \verb|\\| is honored.

\begin{narrowexample}
\begin{mpformulation}[indent=1em, numsep=0.5em]
  \constraint[MODEL10:constr1]{y_i \le 1}{\forall i \in I,\\ \forall t \in T}
  \constraint[MODEL10:constr2]{h_{bd} - h_{b,d-1} \geq z_{qd}}{\forall b \in B,\, q \in Q^b,\\ d \in D}
\end{mpformulation}
\end{narrowexample}

The first constraint fits, so its \verb|\\| is ignored. In the second, the
break is taken at \verb|\\| rather than at the first comma.

\subsection{Moving the quantifier below}

When the expression leaves too little room even for a broken quantifier, the
quantifier moves to the next line, flushed right.

\begin{narrowexample}
\begin{mpformulation}[indent=1em, numsep=0.5em]
  \constraint[MODEL11:constr1]{\sum_{s \in S_p} (1 - h_s) + \sum_{s \in \bar{S}_p} h_s + \sum_{q \in Q} w_q \geq 1}{\forall p \in \Pi,\, b \in B}
\end{mpformulation}
\end{narrowexample}

\subsection{Breaking the expression}

A relation wider than the column cannot be broken automatically: good
break points depend on the meaning of the formula. Mark one with \verb|\\|
in the expression. It is used only as a last resort, and the continuation is
indented by \key{expr\_cont\_indent} (default \verb|2em|). Start the
continuation with \verb|{}+| or \verb|{}\geq| so that the operator keeps its
spacing.

\begin{narrowexample}
\begin{mpformulation}[indent=1em, numsep=0.5em]
  \constraint[MODEL12:constr1]{\sum_{s \in S_p} (1 - h_s) + \sum_{s \in \bar{S}_p} h_s \\ {}+ \sum_{q \in Q} w_q + \sum_{r \in R} u_r \geq 1}{\forall p \in \Pi,\, b \in B}
\end{mpformulation}
\end{narrowexample}

The quantifier is placed on the last expression line if it fits there (broken at
its commas if needed), otherwise below. With \key{expr\_break=always}, every
\verb|\\| in the expression is honored even when the line would fit.

\subsection{Fine-tuning}

\begin{description}
  \item[\key{quant\_gap}] (default \verb|1em|) Minimum space between expression and
    quantifier. A smaller value keeps more quantifiers on the expression line.
  \item[\key{min\_indent}] (default \verb|0pt|) Smallest indent a too-wide
    line may use.
  \item[\key{quant\_break}] \key{auto} (default): optional \verb|\\| and
    automatic breaks at commas; \key{manual}: optional \verb|\\| only;
    \key{always}: every \verb|\\| is a break, no automatic break.
  \item[\key{expr\_break}] \key{auto} (default) or \key{always}.
\end{description}

If no layout fits (an expression wider than the column without \verb|\\|, or a
quantifier piece without a comma), the line overflows into the margin and
\LaTeX\ reports an overfull \cs{hbox}.

% ===========================================================================
\section{Models across pages}\label{sec:pages}
% ===========================================================================

A long model may run over several pages (or columns): the page can break
between any two constraints, and the numbering continues. The package
prevents the breaks that a typesetter would reject:
\begin{itemize}
  \item never after the objective or after ``subject to'': the objective,
    ``subject to'' and the first constraint are always on the same page;
  \item never inside a constraint set on several lines;
  \item never before the last constraint, so that it is not left alone at
    the top of a page (\key{keep\_last=false} allows it).
\end{itemize}
To force a break between two constraints, write \cs{pagebreak} between
them.

% ===========================================================================
\section{A complete example}\label{sec:complete}
% ===========================================================================

The following model schedules trains that run each section of a line in an
economic (\(E\)) or fast (\(R\)) mode. The layout options are given to the
environment so that the example is self-contained; in a paper, put them once
in the preamble with \cs{mpsetup}.

\begin{example}
\begin{mpformulation}[rowsep=0.8\baselineskip, numsep=3em, indent=3em, bottomsep=10pt, expr_suffix={\;,}]
  \objective[MODEL13:objective]{TT}{Minimize}{\sum_{i\in I}\sum_{j\in J}\sum_{k\in K} e_{jk}x_{ijk} + \lambda\sum_{i\in I}L_i}
  \constraint[MODEL13:constr1]{\sum_{k\in K} x_{ijk} = 1}{\forall i \in I,\, j \in J}
  \constraint[MODEL13:constr2]{t_{i,j+1} = t_{ij} + \sum_{k\in K} r_{jk}x_{ijk}}{\forall i \in I,\, j \in J}
  \constraint[MODEL13:constr3]{t_{i+1,s} - t_{is} \geq H^{\min}}{\forall i \in I,\, s \in S,\, i < n}
  \constraint[MODEL13:constr4]{t_{i+1,s} - t_{is} \leq H^{\max}}{\forall i \in I,\, s \in S,\, i < n}
  \constraint[MODEL13:constr5]{t_{i1} \geq \bar{t}_i - \Delta}{\forall i \in I}
  \constraint[MODEL13:constr6]{t_{i1} \leq \bar{t}_i + \Delta}{\forall i \in I}
  \constraint[MODEL13:constr7]{L_i \geq t_{im} - \bar{a}_i}{\forall i \in I}
  \constraint[MODEL13:constr8]{\sum_{j\in J} x_{ijR} \leq R^{\max}}{\forall i \in I}
  \constraint[MODEL13:constr9]{x_{ijE} = 0}{\forall i \in I^P,\, j \in J}
  \constraint[MODEL13:constr10]{x_{ijE} + x_{i,j+1,R} \leq 1}{\forall i \in I,\, j \in J,\, j < m-1}
  \constraint[MODEL13:constr11]{x_{ijR} + x_{i,j+1,E} \leq 1}{\forall i \in I,\, j \in J,\, j < m-1}
  \constraint[MODEL13:constr12]{t_{i,j^*+1} \leq B + M(1-q_i)}{\forall i \in I}
  \constraint[MODEL13:constr13]{t_{ij^*} \geq C - Mq_i}{\forall i \in I}
\end{mpformulation}
The objective~\eqref{MODEL13:objective} is minimized subject to
constraints~\labelcref{MODEL13:constr1}--\labelcref{MODEL13:constr13}.
\end{example}
\mpsetup{expr_suffix={}}

% ===========================================================================
\section{Reference}\label{sec:reference}
% ===========================================================================

\subsection{Commands and environment}

\begin{description}
  \item[\texttt{\textbackslash begin\{mpformulation\}}\oarg{options}
    \dots\ \texttt{\textbackslash end\{mpformulation\}}]\mbox{}\\
    Applies \meta{options}, adds \key{topsep} before and \key{bottomsep}
    after the block. The commands below also work outside the environment.
    The former name \texttt{constraints} is accepted for the environment.
  \item[\cs{constraint}\oarg{label}\marg{expression}\marg{quantifier}]\mbox{}\\
    One constraint. \meta{expression} in display style followed by the expression suffix;
    \meta{quantifier} in text style followed by the quantifier suffix. Numbered and
    labelled if \meta{label} is not empty. \verb|\\| in \meta{expression} or
    \meta{quantifier} is an optional break. Inside the environment, a
    \cs{constraint} directly followed by \verb|\end| takes the last-line
    suffix.
  \item[\cs{lastconstraint}\oarg{label}\marg{expression}\marg{quantifier}]\mbox{}\\
    As \cs{constraint}, with the last-line suffix. Optional inside the
    environment, where the last constraint is detected (see
    \key{last\_auto}). Alias: \cs{constraintlast}.
  \item[\cs{objective}\oarg{label}\marg{name}\marg{sense}\marg{expression}]\mbox{}\\
    Objective line at the constraints indent: formatted \meta{name} (omitted
    if empty), \meta{sense} in text, \meta{expression} in display style.
    Numbered if \meta{label} is not empty. \verb|\\| in \meta{expression}
    is an optional break (see \key{obj\_break}).
  \item[\cs{subjectto}]\mbox{}\\
    The ``subject to'' line. Optional: it is inserted automatically before
    the first constraint after \cs{objective} (see \key{st\_auto}).
  \item[\cs{mpsetup}\marg{options}]\mbox{}\\
    Sets options for the rest of the document (or the current group).
    Alias: \cs{constraintsetup}.
\end{description}

\subsection{Options}

\begin{center}
\small
\begin{tabular}{@{}lll>{\raggedright\arraybackslash}p{7.2cm}@{}}
  \toprule
  Key & Type & Default & Meaning \\
  \midrule
  \key{indent}          & length & \verb|6em|               & Indent of the expression and of the objective \\
  \key{numsep}          & length & \verb|2em|               & Space between quantifier and equation number \\
  \key{rowsep}          & length & \verb|0.5\baselineskip|  & Vertical space after each line \\
  \key{topsep}          & length & \verb|0pt|               & Space before the environment \\
  \key{bottomsep}       & length & \verb|0pt|               & Space after the environment \\
  \midrule
  \key{expr\_suffix}     & text   & empty                    & Appended to every expression (in math mode) \\
  \key{quant\_suffix}     & text   & empty                    & Appended to the quantifier of \cs{constraint} \\
  \key{last\_suffix}    & text   & \verb|.|                 & Appended to the quantifier of the last constraint \\
  \key{last\_auto}      & boolean & \key{true}             & Detect the last constraint before \verb|\end{mpformulation}| \\
  \midrule
  \key{name\_sep}       & length & \verb|1em|               & Space after the model name \\
  \key{sense\_sep}      & length & \verb|1em|               & Space after the sense \\
  \key{st\_text}        & text   & \texttt{subject to}      & Text of \cs{subjectto} \\
  \key{st\_indent}      & length & \cs{parindent}           & Indent of \cs{subjectto} from the text edge, evaluated when used \\
  \key{st\_auto}        & boolean & \key{true}             & Insert ``subject to'' automatically after \cs{objective} \\
  \midrule
  \key{quant\_gap}        & length & \verb|1em|               & Minimum space between expression and quantifier \\
  \key{min\_indent}     & length & \verb|0pt|               & Smallest indent of a too-wide line \\
  \key{quant\_break}      & choice & \key{auto}               & \key{auto}, \key{manual} or \key{always} (\cref{sec:long}) \\
  \key{expr\_break}      & choice & \key{auto}               & \key{auto} or \key{always} \\
  \key{expr\_cont\_indent} & length & \verb|2em|             & Extra indent of expression continuation lines \\
  \key{obj\_break}      & choice & \key{auto}               & \key{auto} or \key{always}: use of \verb|\\| in the objective \\
  \midrule
  \key{numbering}       & choice & \key{line}               & \key{line}, \key{sub} (1a, 1b, \dots) or \key{model} (one number) \\
  \key{label}           & text   & empty                    & Label of the model number (environment only) \\
  \key{name\_label}     & text   & empty                    & Label of the model name (environment only) \\
  \key{st\_inline}      & boolean & \key{false}             & ``subject to'' on the first constraint line \\
  \key{rel\_align}      & boolean & \key{false}             & Align the constraints on their relation symbol \\
  \key{keep\_last}      & boolean & \key{true}              & No page break before the last constraint \\
  \key{quant\_align}    & choice & \key{right}              & \key{right} (flushed right) or \key{left} (common column, wrapped) \\
  \key{quant\_overflow} & choice & \key{below}              & Left-aligned quantifier too wide after the column: \key{below} (unbroken on the next line) or \key{wrap} (wrapped at the column) \\
  \key{quant\_col}      & length & auto                     & Column of left-aligned quantifiers (environment only) \\
  \key{quant\_col\_max} & length & \verb|0.6\linewidth|     & Largest automatic column, evaluated when used \\
  \bottomrule
\end{tabular}
\end{center}

\subsection{Macros and lengths}

The options are stored in the following lengths and macros, which may also
be changed directly with \cs{setlength} or \cs{renewcommand}.

\begin{center}
\small
\begin{tabular}{@{}ll@{\qquad}ll@{}}
  \toprule
  Option & Stored in & Option & Stored in \\
  \midrule
  \key{indent}       & \cs{constraintLeftmargin} & \key{expr\_suffix}  & \cs{constraintExprSuffix} \\
  \key{numsep}       & \cs{constraintEqspace}    & \key{quant\_suffix}  & \cs{constraintQuantSuffix} \\
  \key{rowsep}       & \cs{constraintSep}        & \key{last\_suffix} & \cs{constraintLastSuffix} \\
  \key{topsep}       & \cs{constraintTopsep}     & \key{st\_text}     & \cs{constraintSubjecttoText} \\
  \key{bottomsep}    & \cs{constraintBottomsep}  & \key{st\_indent}   & \cs{constraintSubjecttoIndent} \\
  \key{name\_sep}    & \cs{constraintNameSep}    & \key{quant\_gap}     & \cs{constraintQuantGap} \\
  \key{sense\_sep}   & \cs{constraintSenseSep}   & \key{min\_indent}  & \cs{constraintMinIndent} \\
  \key{expr\_cont\_indent} & \cs{constraintExprContIndent} & & \\
  \bottomrule
\end{tabular}
\end{center}

The model name is formatted by \cs{constraintNameFormat}\marg{name}, which
defaults to \verb|(#1)|.

\subsection{Former option names}

The package was developed under the name \pkg{constraints} up to version
1.12. Documents written for earlier versions keep working once they load
\pkg{mpformulation}: the \texttt{constraints} environment and
\cs{constraintsetup} remain available, and the former option names are
accepted as aliases. The former macros \cs{constraintLHSsuffix},
\cs{constraintRHSsuffix}, \cs{constraintRHSlastsuffix} are still set by the
options, and \cs{constraintRHSgap}, \cs{constraintLHScontIndent} are the same
lengths as \cs{constraintQuantGap}, \cs{constraintExprContIndent}.

\begin{center}
\small
\begin{tabular}{@{}ll@{}}
  \toprule
  Former name & Current name \\
  \midrule
  \key{sep}                         & \key{rowsep} \\
  \key{eqspace}                     & \key{numsep} \\
  \key{leftmargin}                  & \key{indent} \\
  \key{suffix\_left}, \key{suffix}, \key{lhs\_suffix} & \key{expr\_suffix} \\
  \key{suffix\_right}, \key{rhs\_suffix}             & \key{quant\_suffix} \\
  \key{rhs\_gap}                    & \key{quant\_gap} \\
  \key{rhs\_break}                  & \key{quant\_break} \\
  \key{lhs\_break}                  & \key{expr\_break} \\
  \key{lhs\_cont\_indent}           & \key{expr\_cont\_indent} \\
  \key{suffix\_right\_last}         & \key{last\_suffix} \\
  \key{subjectto\_indent}           & \key{st\_indent} \\
  \key{subjectto\_text}             & \key{st\_text} \\
  \bottomrule
\end{tabular}
\end{center}

% ===========================================================================
\section{Limitations}\label{sec:limitations}
% ===========================================================================

\begin{itemize}
  \item The model is not a display environment: \cs{abovedisplayskip} is not
    used (use \key{topsep}).
  \item Relation alignment (\key{rel\_align}) does not apply to
    constraints whose expression contains \verb|\\|.
  \item The body of the environment is read as an argument: verbatim
    commands such as \cs{verb} cannot be used inside it. With
    \key{rel\_align} or \key{quant\_align=left}, the body is typeset twice
    (a measuring pass, then the real one), so commands with global side
    effects written between the constraints are executed twice.
  \item Equation numbers are always on the right; the \texttt{leqno} option
    is ignored.
  \item Automatic breaks happen only at commas of the quantifier. A comma that is
    not a separator must be braced (\verb|x_{i,j}|).
  \item \cs{objective} is broken only at the \verb|\\| written by the
    author.
  \item \key{numbering=sub} and \key{numbering=model} number the whole
    environment; a group of constraints inside a model cannot be
    sub-numbered separately.
  \item The text options (suffixes, \key{st\_text}, \key{st\_indent},
    \key{last\_auto}, \key{st\_auto}, \key{st\_inline}, \key{keep\_last},
    break modes) are global, even when given to the environment;
    \key{numbering}, \key{label}, \key{name\_label} and \key{rel\_align}
    are local.
  \item The default \key{numsep} is \verb|2em| in both one- and two-column
    documents; set it explicitly for narrow columns.
  \item The package requires \LaTeX\ 2021-06-01 or later.
\end{itemize}

% ===========================================================================
\section{Change history}
% ===========================================================================

\begin{description}
  \item[2.0 (2026/09/28)] Package renamed \pkg{mpformulation} (formerly
    \pkg{constraints}), as it now formats whole models; environment
    \texttt{mpformulation} and command \cs{mpsetup}. The former package
    name, environment name and \cs{constraintsetup} still work.
  \item[1.12 (2026/09/28)] Left-aligned quantifiers too wide for the room
    after the column go unbroken below the expression instead of being
    wrapped; option \key{quant\_overflow}.
  \item[1.11 (2026/09/28)] Relation alignment and left-aligned quantifiers
    are right on the first run: the environment is measured before it is
    typeset (no \texttt{.aux} file and no second run needed).
  \item[1.10 (2026/09/28)] Left-aligned quantifiers at a common column,
    wrapped when needed: options \key{quant\_align}, \key{quant\_col},
    \key{quant\_col\_max}.
  \item[1.9 (2026/09/28)] Options and macros renamed after the two parts
    of a constraint, the expression and the quantifier (for example
    \key{expr\_suffix} and \key{quant\_suffix} instead of
    \key{lhs\_suffix} and \key{rhs\_suffix}); see \cref{sec:reference}.
    Former names kept as aliases.
  \item[1.8 (2026/09/28)] Model numbering (\key{numbering}, \key{label},
    \key{name\_label}); objective broken at \verb|\\| (\key{obj\_break});
    \key{st\_inline}; relation alignment (\key{rel\_align}); no page break
    after the objective and ``subject to'', nor before the last constraint
    (\key{keep\_last}); suffix attached to the LHS when the RHS is empty.
  \item[1.7 (2026/09/28)] Last constraint detected automatically;
    option \key{last\_auto}.
  \item[1.6 (2026/09/28)] ``subject to'' inserted automatically after
    \cs{objective}; option \key{st\_auto}.
  \item[1.5 (2026/09/28)] Layout fallback for long constraints: shrinking
    indent, RHS below the LHS, optional \verb|\\| in the LHS; equation
    number on the last line. Options \key{min\_indent}, \key{lhs\_break},
    \key{lhs\_cont\_indent}.
  \item[1.4 (2026/09/28)] Automatic breaking of the RHS at its commas;
    \key{rhs\_break=manual}.
  \item[1.3 (2026/09/28)] \verb|\\| in the RHS becomes an optional break;
    options \key{rhs\_gap}, \key{rhs\_break}.
  \item[1.2 (2026/09/28)] Shorter option names; former names kept as
    aliases.
  \item[1.1 (2026/09/28)] \cs{objective} and \cs{subjectto}.
  \item[1.0 (2025/09/07)] First version.
\end{description}

\section*{License}

\copyright\ 2025--2026 FYP. This work may be distributed and/or modified under the conditions of the
\LaTeX\ Project Public License, either version 1.3 of this license or (at
your option) any later version.

\end{document}
