\section{Advanced Usage}

CUDF-based solvers understand user preferences and use them to select
a best solution. Compared with \aptget, this gives the user a greater
flexibility to define ``optimal'' solutions for installation problems,
for instance to minimize the number of new packages that are
installed, or to minimize the total installation size the packages to
upgrade.

\subsection{Optimization Criteria}

\subsubsection{Using Optimization Criteria}

Each CUDF solver understands a basic optimization language, and some of
them implement extensions to this basic language to implement more
sophisticated optimization criteria. \aptcudf, that is the bridge
between \aptget{} and the CUDF solver, associates to each \aptget{}
command an optimization criterion that can be either configured at
each invocation using one \aptget{} configuration option or by using
the configuration file (\texttt{/etc/apt-cudf.conf} ) of \aptcudf{}
(see Section~\ref{sec:defining:criteria} for their precise meaning):

\begin{verbatim}
solver: *
upgrade: -count(new),-count(removed),-count(notuptodate)
dist-upgrade: -count(notuptodate),-count(new)
install: -count(removed),-count(changed)
remove: -count(removed),-count(changed)
trendy: -count(removed),-count(notuptodate),-count(unsat_recommends),-count(new)
paranoid: -count(removed),-count(changed)
\end{verbatim}

The field \texttt{solver} defines the (comma-separated) list of solvers
to which this stanza applies. The symbol ``*'' indicates that this
stanza applies to all solvers that do not have a specific stanza.

Each field of the stanza defines the default optimization criterion.
If one field name coincides with a standard apt-get action, like
\texttt{install}, \texttt{remove}, \texttt{upgrade} or \texttt{dist-upgrade},
then the corresponding
criterion will be used by the external solver. Otherwise, the field is
interpreted as a short-cut definition that can be used on the
\aptget{} command line.

Using the configuration option of \aptget{}
\texttt{APT::Solver::aspcud::Preferences}, the user can pass a
specific optimization criterion on the command line overwriting the
default. For example :

\begin{verbatim}
 apt-get -s --solver aspcud install totem -o "APT::Solver::aspcud::Preferences=trendy"
\end{verbatim}

\subsubsection{Defining Optimization Criteria}
\label{sec:defining:criteria}

\paragraph{Sets of packages}
The measurements that may be used in optimization criteria are taken
on selected sets of packages in order to measure the quality of a
proposed solution. In this context, when we speak of \textit{package}
we mean a package in a specific version. That is, a package with name
$p$ and version $1$ is considered a different package then the one
with the same name $p$ and different version $2$. We will denote with $I$
the set of packages (always name \emph{and} version) that are initially in
state \textit{installed} on the machine, and with $S$ the set of packages
that are in state \textit{installed} as a result of the \aptget{} action.

\begin{description}
\item[solution] the set $S$
\item[changed] the symmetric difference between $I$ and $S$, that is the set
  of packages that are either in $I$ and not in $S$, or in $S$ and not in $I$.
\item[new] the set of packages in $S$ for which no package with the same
  name is in $I$.
\item[removed] the set of packages in $I$ for which no package with the same
  name is in $S$.
\item[up] the set of of packages in $S$ for which a package with the same name
  but smaller version is in $I$.
\item[down] the set of of packages in $S$ for which a package with the same name
  but greater version is in $I$.
\end{description}

\paragraph{Measurements on sets of packages}
Several ways to measure sets are defined. All these measurements yield an
integer value. Here, $X$ can be any of the sets defined above:

\begin{description}
\item[count(X)] the number of elements of set $X$
\item[sum(X,f)] where $f$ is an integer package property. Yields the sum
  of all $f$-values of all the packages in $X$.
  
  Example: sum(solution,Installed-Size) is the size taken up by all
  installed packages when the \aptget{} action has succeeded (as declared
  in the Packages file).
\item[notuptodate(X)] the number of packages in $X$ whose version is not the
  latest version.
  
  Example: notuptodate(solution) is the number of packages that will be
  installed when the \aptget{} action has succeeded, but not in their
  latest version.
\item[unsat\_recommends(X)] this is the number of recommended
  packages in $X$ that are not in $S$ (or not satisfied in $S$, in
  case the recommendation uses alternatives).
  
  For instance, if package a recommends \texttt{b, c|d|e, e|f|g,
    b|g, h} and if $S$ is $\{a, e, f, h\}$ then one would obtain for
  the package a alone a value of 2 for unsat\_recommends since the
  2nd, 3rd and 5th disjunct of the recommendation are satisfied, and
  the 1st and 4th disjunct are not. If no other package in \(X\)
  contains recommendations that means that, in that case,
  unsat\_recommends(\(X\))=2.
\item[aligned(X,f1,f2)] where $f1$ and $f2$ are integer or string
  properties. This is the number of of different pairs $(x.f1,x.f2)$ for
  packages $x$ in $X$, minus the number of different values $x.f1$ for
  packages $x$ in $X$.

  In other words, we cluster the packages in X according to their
  values at the properties f1 and f2 and count the number of clusters,
  yielding a value v1. Then we do the same when clustering only by the
  property g1, yielding a value v2. The value returned is v1-v2.
\end{description}

\paragraph{Combining Measurements into Criteria}
An optimization criterion is a comma-separated list of signed measurements.

A measurement signed with $+$ means that we seek to maximize this
value, a measurement signed with $-$ that we seek to minimize this
value. To compare two possible solutions we use the signed
measurements from left to right.  If both measurements yield the same
value on both solutions then we continue with the next signed
measurement (or conclude that both solutions are equally good in case
we are at the end of the list). If the measurements are different on
both solutions then we use this measurement to decide which of the
solutions is the better one.

Example 1: \texttt{-count(removed), -count(changed)}, sometimes called
the \emph{paranoid} criterion. It means that we seek to remove as few
packages as possible. If there are several solutions with the same
number of packages to remove then we chose the one which changes the least
number of packages.

Example 2: \texttt{-count(removed),-count(notuptodate),-count(unsat\_recommends),-count(new)},
sometimes called the \emph{trendy} criterion. Here we use the
following priority list of criteria:
\begin{enumerate}
\item remove as few packages as possible
\item have as few packages as possible in a version which is not the latest
  version
\item have as few as possible recommendations of packages that are not satisfied
\item install as few new packages as possible.
\end{enumerate}

\subsection{Pinning}

\subsubsection{Strict Pinning and Its Limitations}
When a package is available in more than one version, \aptget{} uses a
mechanism known as pinning to decide which version should be
installed. However, since this mechanism determines early in the
process which package versions must be considered and which package
versions should be ignored, it has also the consequence of
considerably limiting the search space. This might lead to \aptget{}
with its internal solver not finding a solution even if one might
exist when all packages are considered.

Anther consequence of the strict pinning policy of \aptget{} is that
if a package is specified on the command line with version or suite
annotations, overwriting the pinning strategy for this package, but
not for its dependencies, then the solver might not be able to
find a solution because not all packages are available. 

\subsubsection{Ignoring Pinning}
To circumvent this restriction and to allow the underlying solver to
explore the entire search space, \aptget{} can be configured to let the
CUDF solver ignore the pinning annotation.

The option \texttt{APT::Solver::Strict-Pinning}, when used in
conjunction with an external solver, tells \aptget{} to ignore pinning
information when solving dependencies. This may allow the external
solver to find a solution that is not found by the \aptget{}
internal solver.

\subsubsection{Relaxed Pinning}
Without relaxing the way that pinning information are encoded,
\aptcudf{} with an external CUDF solver would be effectively unable to
do better then \aptget{} because important information is lost on the
way. In order to overcome this limitation, \aptcudf{} has the ability
to reconstruct the user request and to use this information to provide
a possible solution. To this end, \aptcudf{} reads an environment
variable, named \texttt{APT\_GET\_CUDF\_CMDLINE} which the user can
pass along containing the invocation of \aptget.

To make it straightforward for the user, a very simple script called
\texttt{apt-cudf-get} is provided by the \aptcudf{} package.

\begin{verbatim}
#!/bin/sh
export APT_GET_CUDF_CMDLINE="apt-get $* -o APT::Solver::Strict-Pinning=\"false\""
apt-get $* -o APT::Solver::Strict-Pinning="false"
\end{verbatim}

The wrapper is invoked using the same commands as \aptget:

\begin{verbatim}
apt-cudf-get -s --solver aspcud install totem \
    -o "APT::Solver::aspcud::Preferences=-count(new),-count(changed)"
\end{verbatim}
