% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/set_method_epsilon_constraint.R
\name{set_method_epsilon_constraint}
\alias{set_method_epsilon_constraint}
\title{Set the epsilon-constraint multi-objective method}
\usage{
set_method_epsilon_constraint(
  x,
  primary,
  eps = NULL,
  aliases = NULL,
  mode = c("manual", "auto"),
  n_points = 10,
  include_extremes = TRUE,
  lexicographic = TRUE,
  lexicographic_tol = 1e-08
)
}
\arguments{
\item{x}{A \code{Problem} object.}

\item{primary}{Character string giving the alias of the primary objective to
optimize directly.}

\item{eps}{Optional epsilon specification used only in \code{mode = "manual"}.
It may be:
\itemize{
\item a named numeric vector, defining epsilon values for a single run,
\item or a named list of numeric vectors, defining epsilon values for a
grid of runs.
}
Names must correspond exactly to the constrained objective aliases.}

\item{aliases}{Optional character vector of objective aliases to include.
By default, all registered objective aliases are used. The value of
\code{primary} must be included in \code{aliases}.}

\item{mode}{Character string. Must be either \code{"manual"} or
\code{"auto"}.}

\item{n_points}{Integer scalar used only in \code{mode = "auto"}. Number of
epsilon points to generate automatically for the constrained objective.
Must be at least 2.}

\item{include_extremes}{Logical scalar used only in \code{mode = "auto"}. If
\code{TRUE}, include extreme epsilon values in the automatically generated
grid.}

\item{lexicographic}{Logical scalar used only in \code{mode = "auto"}. If
\code{TRUE}, compute extreme points lexicographically.}

\item{lexicographic_tol}{Numeric scalar \eqn{\ge 0}. Tolerance used in
lexicographic extreme-point computation.}
}
\value{
An updated \code{Problem} object with the epsilon-constraint method
configuration stored in \code{x$data$method}.

In manual mode, \code{x$data$method$runs} contains the explicit
epsilon-design grid.

In automatic mode, \code{x$data$method$runs} is \code{NULL} until the grid is
generated later during \code{\link{solve}}.
}
\description{
Configure a \code{Problem} object to be solved with the
epsilon-constraint multi-objective method.

In this method, one objective is designated as the \emph{primary} objective
and is optimized directly, while the remaining objectives are transformed
into \eqn{\varepsilon}-constraints.

Two operating modes are supported:
\itemize{
\item \strong{manual mode}: the user supplies the \eqn{\varepsilon}-levels
explicitly,
\item \strong{automatic mode}: the \eqn{\varepsilon}-levels are generated
later during \code{\link{solve}} from extreme-point or payoff information.
}

This function does not solve the problem. It stores the method configuration
in \code{x$data$method}, to be used later by \code{\link{solve}}.
}
\details{
Use this method when one objective should be optimized directly while the
remaining objectives are controlled through explicit performance thresholds.

\strong{General idea}

Suppose that \eqn{m \ge 2} objective functions have already been registered
in the problem:
\deqn{
f_1(x), f_2(x), \dots, f_m(x).
}

The epsilon-constraint method selects one of them as the primary objective,
say \eqn{f_p(x)}, and treats the remaining objectives as constrained
objectives.

For a fixed vector of epsilon levels, the method solves subproblems in which
the primary objective is optimized directly and the remaining objectives are
imposed through epsilon constraints.

A representative formulation is:

\deqn{
\max \; f_p(x)
}

subject to

\deqn{
f_k(x) \ge \varepsilon_k, \qquad k \in \mathcal{C},
}

together with all original feasibility constraints of the planning problem,
where \eqn{\mathcal{C}} is the set of constrained objectives.

Depending on objective sense, the internal implementation may transform
minimization objectives into equivalent constrained forms, but the method
always follows the same principle:
\itemize{
\item one objective is optimized directly,
\item all remaining objectives are imposed through
\eqn{\varepsilon}-constraints.
}

By solving the problem repeatedly for different epsilon levels, the method
generates a set of efficient trade-off solutions.

\strong{Atomic objectives requirement}

The epsilon-constraint method can only be used with atomic objectives that
have already been registered under aliases. These aliases are typically
created by calling objective setters with an \code{alias} argument, for
example:
\preformatted{
x <- x |>
  add_objective_max_benefit(alias = "benefit") |>
  add_objective_min_cost(alias = "cost") |>
  add_objective_min_fragmentation(alias = "frag")
}

The \code{primary} argument selects which registered objective is optimized
directly. The remaining aliases are treated as constrained objectives.

\strong{Manual mode}

In \code{mode = "manual"}, the user must provide \code{eps}.

The \code{eps} argument can be supplied as:
\itemize{
\item a named numeric vector, defining a single run,
\item or a named list of numeric vectors, defining a grid of runs.
}

The names of \code{eps} must correspond exactly to the constrained objective
aliases, that is, to all aliases in \code{aliases} except \code{primary}.

If the constrained objectives are
\eqn{\mathcal{C} = \{c_1, \dots, c_q\}}, then manual mode creates a design
grid containing all combinations of the supplied epsilon levels for the
constrained objectives.

Each row of this grid defines one subproblem to be solved later.

\strong{Important:} manual mode supports \strong{two or more objectives}.
In particular, it can be used with:
\itemize{
\item 2 objectives: 1 primary + 1 constrained objective,
\item 3 or more objectives: 1 primary + multiple constrained objectives.
}

Thus, manual mode is the general way to use the epsilon-constraint method
when more than two objectives are involved.

In manual mode, the generated design grid is stored immediately in
\code{x$data$method$runs}. Its epsilon columns are named
\code{eps_<alias>}, for example \code{eps_frag}.

\strong{Automatic mode}

In \code{mode = "auto"}, the user omits \code{eps} and instead supplies
\code{n_points}.

In this case, the epsilon grid is not built immediately. Instead, it is
constructed later during \code{\link{solve}} using extreme-point or
payoff-table information.

In the current implementation, automatic mode supports
\strong{exactly two objectives only}:
\itemize{
\item one primary objective,
\item one constrained objective.
}

Therefore, if \code{mode = "auto"}, then \code{aliases} must contain exactly
two objective aliases. Problems with three or more objectives must use
\code{mode = "manual"}.

If \code{include_extremes = TRUE}, the automatically generated grid includes
the extreme values of the constrained objective. Otherwise, only interior
values are used.

If \code{lexicographic = TRUE}, the extreme points used to generate the grid
are computed lexicographically. In that case, one objective is optimized
first, and then the second objective is optimized while constraining the
first to remain within \code{lexicographic_tol} of its optimum.

\strong{Stored configuration}

The configured method stores:
\itemize{
\item \code{name = "epsilon_constraint"},
\item \code{mode},
\item \code{primary},
\item \code{aliases},
\item \code{constrained},
\item epsilon design information,
\item lexicographic configuration.
}

In manual mode, \code{x$data$method$runs} contains the explicit design grid.

In automatic mode, \code{x$data$method$runs} is initially \code{NULL} and is
generated later during \code{\link{solve}}.

For more than two objectives, automatic grid generation is currently
unavailable because the number of epsilon combinations grows rapidly and
requires explicit user control.
}
\examples{
# Small toy problem
pu_tbl <- data.frame(
  id = 1:4,
  cost = c(1, 2, 3, 4)
)

feat_tbl <- data.frame(
  id = 1:2,
  name = c("feature_1", "feature_2")
)

dist_feat_tbl <- data.frame(
  pu = c(1, 1, 2, 3, 4),
  feature = c(1, 2, 2, 1, 2),
  amount = c(5, 2, 3, 4, 1)
)

actions_df <- data.frame(
  id = c("conservation", "restoration"),
  name = c("conservation", "restoration")
)

effects_df <- data.frame(
  pu = c(1, 2, 3, 4, 1, 2, 3, 4),
  action = c("conservation", "conservation", "conservation", "conservation",
             "restoration", "restoration", "restoration", "restoration"),
  feature = c(1, 1, 1, 1, 2, 2, 2, 2),
  benefit = c(2, 1, 0, 1, 3, 0, 1, 2),
  loss = c(0, 0, 1, 0, 0, 1, 0, 0)
)

x <- create_problem(
  pu = pu_tbl,
  features = feat_tbl,
  dist_features = dist_feat_tbl,
  cost = "cost"
) |>
  add_actions(actions_df, cost = c(conservation = 1, restoration = 2)) |>
  add_effects(effects_df) |>
  add_objective_min_cost(alias = "cost") |>
  add_objective_max_benefit(alias = "benefit") |>
  add_objective_min_loss(alias = "loss")

# Manual mode with one constrained objective
x1 <- set_method_epsilon_constraint(
  x,
  primary = "benefit",
  aliases = c("benefit", "cost"),
  mode = "manual",
  eps = c(cost = 5)
)

x1$data$method

# Manual mode with multiple epsilon values
x2 <- set_method_epsilon_constraint(
  x,
  primary = "benefit",
  aliases = c("benefit", "cost"),
  mode = "manual",
  eps = list(cost = c(4, 6, 8))
)

x2$data$method$runs

# Manual mode with more than two objectives
x3 <- set_method_epsilon_constraint(
  x,
  primary = "benefit",
  aliases = c("benefit", "cost", "loss"),
  mode = "manual",
  eps = list(
    cost = c(4, 6),
    loss = c(0, 1)
  )
)

x3$data$method$runs

# Automatic mode currently supports exactly two objectives
x4 <- set_method_epsilon_constraint(
  x,
  primary = "benefit",
  aliases = c("benefit", "cost"),
  mode = "auto",
  n_points = 5,
  include_extremes = TRUE,
  lexicographic = TRUE,
  lexicographic_tol = 1e-8
)

x4$data$method

}
\seealso{
\code{\link{set_method_augmecon}},
\code{\link{set_method_weighted_sum}},
\code{\link{solve}}
}
