Class CanonicalConstraint

java.lang.Object
de.labathome.trustconstr.CanonicalConstraint

public final class CanonicalConstraint extends Object
Canonical-form constraint
     f_eq(x)   = 0
     f_ineq(x) ≤ 0
 
Mirrors scipy's CanonicalConstraint (scipy/optimize/_trustregion_constr/canonical_constraint.py).

The Java port already canonicalises bounds-form constraints inline inside LinearConstraint and NonlinearConstraint (see those classes' 4-block ineq ordering: less | greater | interval-upper | interval-lower). This class wraps that machinery into the scipy-shape API for parity with test_canonical_constraint.py.

The class itself is immutable; all factory methods produce a new instance carrying lambdas that delegate to the underlying constraint objects.

  • Field Details

    • nEq

      public final int nEq
      Number of canonical equality rows.
    • nIneq

      public final int nIneq
      Number of canonical inequality rows.
    • keepFeasible

      public final boolean[] keepFeasible
      Per-canonical-inequality-row strict-feasibility flags (length nIneq). Mirrors scipy's keep_feasible attribute.
  • Method Details

    • fun

      public EqIneqSplit fun(Matrix x)
      Evaluate the canonical equality and inequality residuals at x.
      Parameters:
      x - current iterate (n x 1)
      Returns:
      (cEq, cIneq) where cEq is nEq x 1 and cIneq is nIneq x 1
    • jac

      public EqIneqSplit jac(Matrix x)
      Evaluate the canonical equality and inequality Jacobians at x.
      Parameters:
      x - current iterate (n x 1)
      Returns:
      (JEq, JIneq) where JEq is nEq x n and JIneq is nIneq x n
    • hess

      public Matrix hess(Matrix x, double[] vEq, double[] vIneq)
      Evaluate the constraint Hessian-of-Lagrangian at x.
      Parameters:
      x - current iterate (n x 1)
      vEq - equality multipliers, length nEq; may be null when nEq is zero
      vIneq - inequality multipliers, length nIneq; may be null when nIneq is zero
      Returns:
      summed Hessian contribution (n x n); zeros for linear and empty constraints
    • empty

      public static CanonicalConstraint empty(int n)
      Construct an empty canonical constraint -- zero rows of each kind. The Jacobians are returned as 0 x n matrices, the Hessian as an n x n zero matrix. Mirrors scipy's CanonicalConstraint.empty(n).
      Parameters:
      n - number of decision variables
      Returns:
      an empty canonical constraint sized for n variables
    • fromLinearConstraint

      public static CanonicalConstraint fromLinearConstraint(LinearConstraint lc)
      Wrap a LinearConstraint as a canonical constraint. The underlying row classification (equal / less / greater / interval-upper / interval-lower) is already done by LinearConstraint; this factory just exposes its constrEq/constrIneq/jacEq/ jacIneq via the scipy-shape API.

      Linear constraints have zero constraint Hessian, so hess(...) returns an n x n zero matrix.

      Parameters:
      lc - underlying linear constraint
      Returns:
      canonical wrapper over lc
    • fromNonlinearConstraint

      public static CanonicalConstraint fromNonlinearConstraint(NonlinearConstraint nc, int n)
      Wrap a NonlinearConstraint as a canonical constraint. Mirrors the dispatch done by scipy's from_PreparedConstraint on a constraint that came from a user-supplied NonlinearConstraint.

      If the underlying constraint was constructed without an analytic hess, hess(x, vEq, vIneq) returns an n x n zero matrix (no Hessian contribution).

      Parameters:
      nc - underlying nonlinear constraint
      n - number of decision variables (cannot be inferred from NonlinearConstraint, which only knows the constraint-output dimension m)
      Returns:
      canonical wrapper over nc
    • fromBounds

      public static CanonicalConstraint fromBounds(Bounds bounds)
      Promote Bounds into a canonical constraint via LinearConstraint.fromBounds(Bounds). Mirrors scipy's PreparedConstraint(bounds, ...) -> from_PreparedConstraint shortcut.
      Parameters:
      bounds - box bounds on the decision variables
      Returns:
      canonical constraint enforcing lb ≤ x ≤ ub
    • fromPreparedConstraint

      public static CanonicalConstraint fromPreparedConstraint(PreparedConstraint pc)
      Build a canonical constraint from a PreparedConstraint. Mirrors scipy's CanonicalConstraint.from_PreparedConstraint: dispatches on the original source constraint type carried by PreparedConstraint.source().
      Parameters:
      pc - prepared constraint with cached f, J at x0
      Returns:
      canonical wrapper over the source constraint
      Throws:
      IllegalArgumentException - if the source is not one of LinearConstraint, NonlinearConstraint, or Bounds
    • concatenate

      public static CanonicalConstraint concatenate(List<CanonicalConstraint> sources, boolean sparseJacobian)
      Concatenate a list of canonical constraints into one. Equality blocks are stacked first across all sources, then inequality blocks across all sources. Mirrors scipy's CanonicalConstraint.concatenate(canonical_constraints, sparse_jacobian).

      The resulting Jacobian's storage layout follows sparseJacobian: true produces a SparseMatrix, false produces a dense Matrix. The summed Hessian is the (matrix) sum of each source's Hessian applied to its slice of the multipliers.

      Parameters:
      sources - canonical constraints to concatenate; row order follows the list order
      sparseJacobian - if true, the combined Jacobian is built as a SparseMatrix; otherwise dense
      Returns:
      concatenated canonical constraint
    • initialConstraintsAsCanonical

      public static CanonicalConstraint.InitialCanonical initialConstraintsAsCanonical(int n, List<CanonicalConstraint> canonicals, Matrix x0, boolean sparseJacobian)
      Stack the canonical residuals and Jacobians of every constraint in canonicals at the starting iterate x0. Mirrors scipy's top-level initial_constraints_as_canonical(n, prepared_constraints, sparse_jacobian) function.

      scipy avoids re-evaluating each constraint at x0 by reusing the cached f, J stored in PreparedConstraint; the Java port currently re-evaluates because PreparedConstraint does not yet cache (Phase 2). Numerically the result is identical.

      Parameters:
      n - number of decision variables (used to size the empty Jacobians when canonicals is empty)
      canonicals - canonical constraints to evaluate and stack
      x0 - starting iterate (n x 1)
      sparseJacobian - if true, the combined Jacobian is built as a SparseMatrix; otherwise dense
      Returns:
      stacked residuals and Jacobians
    • initialConstraintsAsCanonical

      public static CanonicalConstraint.InitialCanonical initialConstraintsAsCanonical(int n, List<PreparedConstraint> prepared, boolean sparseJacobian)
      scipy-shape overload taking a list of PreparedConstraints. Mirrors scipy's initial_constraints_as_canonical(n, prepared_constraints, sparse_jacobian).

      Each prepared constraint is converted to a CanonicalConstraint via fromPreparedConstraint(de.labathome.trustconstr.records.PreparedConstraint), and the resulting canonicals are stacked. The cached iterate x0 from the first prepared constraint is used to evaluate the stacked residuals and Jacobians.

      Parameters:
      n - number of decision variables
      prepared - prepared constraints
      sparseJacobian - if true, the combined Jacobian is built sparse; otherwise dense
      Returns:
      stacked residuals and Jacobians at x0