This question is an extension of Using an array environment inside an xparse command. I was advised to make a separate question for the extension. I would like to thank egreg very much for his help. I have two more features that I would like to implement, and I was wondering if I could get just a little more assistance from the community.
In particular, I would like to support box constraints and enumerated constraints. Before egreg gave his solution using LaTeX3, my constraint command was a macro with signature mmmggo. The first three arguments represented a standard constraint; the fourth and fifth arguments represented the additional information in a box constraint; and the sixth argument represented the enumeration for an enumerated constraint. My attempt to get these features working in shown below (the failed portions are commented out).
A couple of notes about my motivation for certain choices: I would like to make the constraints readable in usage, this is why I prefer formatting constraints using the constraint command given below; if none of the constraints are enumerated, I want to prevent the \qquad used to set off the enumerations from being printed to preserve the horizontal centering of the problem. I consider the box-constraint issue mostly resolved (I can always just include the additional information for the box constraint in the third argument as shown below). However, I would really like the abilities to
- have the enumeration be an optional argument, and
- suppress the
\qquadused to set off the enumerations when no enumerated constraints are used (to preserve the horizontal centering of the optimization problem).
\documentclass{article}
\usepackage{amsmath}
\usepackage{array}
\usepackage{xparse}
\ExplSyntaxOn
% allocate the variables for an optimization problem
\tl_new:N \l_optprob_operator_tl
\tl_new:N \l_optprob_variable_tl
\tl_new:N \l_optprob_objective_tl
\tl_new:N \l_optprob_constraints_tl
% define the keys
\keys_define:nn{optprob}
{
operator .tl_set:N = \l_optprob_operator_tl,
variable .tl_set:N = \l_optprob_variable_tl,
objective .tl_set:N = \l_optprob_objective_tl,
constraint .code:n = \optprob_add_constraint:nnnnnn #1,
% constraint .code:n = \constraint{#1}
}
\NewDocumentCommand{\optimizationproblem}{m}
{
% clear the variables
\tl_clear:N \l_optprob_operator_tl
\tl_clear:N \l_optprob_variable_tl
\tl_clear:N \l_optprob_objective_tl
\tl_clear:N \l_optprob_constraints_tl
% get the keys
\keys_set:nn{optprob}{#1}
% print the optimization problem
\tl_if_empty:NTF \l_optprob_objective_tl
{
% feasibility problem
\begin{array}[t]{@{}r@{}>{{}}c<{{}}@{}l@{}l}
\l_optprob_constraints_tl
\end{array}
}
{
% optimization problem
\begin{array}{c@{{}\mathrel{:}{}}l}
\displaystyle\operatorname*{\l_optprob_operator_tl}\sb{\l_optprob_variable_tl} &
\l_optprob_objective_tl \\[2ex]
\tl_if_empty:NF \l_optprob_constraints_tl
{
% constrained optimization problem
\textnormal{subject~to} &
\begin{array}[t]{@{}r@{}>{{}}c<{{}}@{}l@{}l}
\l_optprob_constraints_tl
\end{array}
}
\end{array}
}
}
\NewDocumentCommand{\constraint}{mmmggo}
{
\IfValueTF{#4}
{
\IfValueTF{#6}
{
#1 & #2 & #3 #4 #5 & \qquad #6 \\
}
{
#1 & #2 & #3 #4 #5 \\
}
}
{
\IfValue{#6}
{
#1 & #2 & #3 & \qquad #6 \\
}
{
#1 & #2 & #3 \\
}
}
}
% helper function to process the constraints
\cs_new_protected:Npn \optprob_add_constraint:nnnnnn #1 #2 #3 #4
{
\tl_put_right:Nn \l_optprob_constraints_tl {#1 & #2 & #3 & \qquad #4 \\}
}
\ExplSyntaxOff
\begin{document}
\[
\optimizationproblem
{
operator = minimize,
variable = x \in \mathbf{R}^{n},
objective = c^{T} x,
constraint = {A_{i} x}{=}{b_{i}}{i = 1 , \ldots , m},
% constraint = {A_{i} x}{=}{b_{i}}[i = 1 , \ldots , m],
constraint = {F_{j} x}{\leq}{g_{j}}{j = 1 , \ldots , m},
% constraint = {F_{j} x}{\geq}{g_{j}}[j = 1 , \ldots , m],
constraint = {0}{\leq}{x \leq 1}{},
% constraint = {0}{\leq}{x}{\leq}{1},
}
\]
\end{document}
