process_qp: Prepare Quadratic Programming Constraints for lgspline

View source: R/process_qp.R

process_qpR Documentation

Prepare Quadratic Programming Constraints for lgspline

Description

Builds the linear inequality system used for shape-restricted fitting. The helper collects built-in range, derivative-sign, second-derivative, and monotonicity restrictions, together with any user-supplied custom constraint functions, and returns the resulting \mathbf{C}^{\top}\boldsymbol{\beta} \ge \mathbf{c} objects.

This logic was refactored out of lgspline.fit so the constraint construction can be reviewed and tested on its own. Existing calls that pass TRUE/FALSE for derivative flags remain backward-compatible.

Usage

process_qp(
  X,
  K,
  p_expansions,
  order_list,
  colnm_expansions,
  expansion_scales,
  power1_cols,
  power2_cols,
  nonspline_cols,
  interaction_single_cols,
  interaction_quad_cols,
  triplet_cols,
  include_2way_interactions,
  include_3way_interactions,
  include_quadratic_interactions,
  family,
  mean_y,
  sd_y,
  N_obs,
  qp_observations = NULL,
  qp_positive_derivative = FALSE,
  qp_negative_derivative = FALSE,
  qp_positive_2ndderivative = FALSE,
  qp_negative_2ndderivative = FALSE,
  qp_monotonic_increase = FALSE,
  qp_monotonic_decrease = FALSE,
  qp_range_upper = NULL,
  qp_range_lower = NULL,
  qp_Amat_fxn = NULL,
  qp_bvec_fxn = NULL,
  qp_meq_fxn = NULL,
  qp_Amat = NULL,
  qp_bvec = NULL,
  qp_meq = 0,
  qr_pivot_inequality_constraints = FALSE,
  parallel_qr_qp = FALSE,
  all_derivatives_fxn = NULL,
  og_cols = NULL,
  cl = NULL,
  include_warnings = TRUE,
  ...
)

Arguments

X

List of per-partition design matrices.

K

Integer. Number of interior knots.

p_expansions

Integer. Number of basis expansions per partition.

order_list

List of per-partition observation index vectors.

colnm_expansions

Character vector of expansion column names.

expansion_scales

Numeric vector of expansion standardization scales.

power1_cols

Integer vector of linear-term column indices.

power2_cols

Integer vector of quadratic-term column indices.

nonspline_cols

Integer vector of non-spline linear column indices.

interaction_single_cols

Integer vector of linear-by-linear interaction column indices.

interaction_quad_cols

Integer vector of linear-by-quadratic interaction column indices.

triplet_cols

Integer vector of three-way interaction column indices.

include_2way_interactions

Logical switch controlling whether two-way interactions are included in derivative construction.

include_3way_interactions

Logical switch controlling whether three-way interactions are included in derivative construction.

include_quadratic_interactions

Logical switch controlling whether quadratic interactions are included in derivative construction.

family

GLM family object.

mean_y, sd_y

Numeric scalars for response standardization.

N_obs

Integer. Total sample size.

qp_observations

Optional observation subset. Supply either a single integer vector to thin every active built-in QP constraint the same way, or a named list keyed by "var:qp_<type>" (or bare "qp_<type>") to give different constraints different subsets. Known types are qp_range_lower, qp_range_upper, qp_positive_derivative, qp_negative_derivative, qp_positive_2ndderivative, qp_negative_2ndderivative, qp_monotonic_increase, and qp_monotonic_decrease. For range and monotonicity, use the bare keys such as "qp_range_lower" and "qp_monotonic_increase" because those constraints are variable-independent; prefixed versions are still accepted and unioned internally. Unknown keyed entries are ignored with a warning when include_warnings = TRUE.

qp_positive_derivative, qp_negative_derivative

Logical scalar, character vector, or integer vector. See section Per-Variable Derivative Constraints.

qp_positive_2ndderivative, qp_negative_2ndderivative

Same as above but for second derivatives.

qp_monotonic_increase, qp_monotonic_decrease

Logical. Constrain fitted values to be monotonic in observation order.

qp_range_upper, qp_range_lower

Optional numeric upper/lower bounds for fitted values.

qp_Amat_fxn, qp_bvec_fxn, qp_meq_fxn

Optional user-supplied constraint-generating functions.

qp_Amat, qp_bvec, qp_meq

Optional pre-built QP objects. Their presence marks QP handling as active, but this helper does not append them to the built-in constraints it constructs; they are expected to be handled outside this constructor.

qr_pivot_inequality_constraints

Logical. If TRUE, partition-local inequality columns are thinned to QR pivot columns before the final solve.QP objects are stacked. Leading equality columns are left untouched; built-in range and monotonicity blocks are also left untouched; and columns spanning multiple partitions are left untouched.

parallel_qr_qp

Logical. If TRUE and a cluster is supplied in cl, the partition-local QR pivot steps used by qr_pivot_inequality_constraints are parallelized across partitions.

all_derivatives_fxn

Function to compute derivatives from expansion matrices (the all_derivatives closure from lgspline.fit).

og_cols

Optional character vector of original predictor column names.

cl

Optional parallel cluster object used only when parallel_qr_qp = TRUE.

include_warnings

Logical. Whether to issue warnings.

...

Additional arguments forwarded to custom constraint functions.

Value

A list with components:

qp_Amat

P \times M combined constraint matrix.

qp_bvec

Numeric vector of length M.

qp_meq

Integer. Number of leading equality constraints.

quadprog

Logical. TRUE if any QP constraints are active.

Per-Variable Derivative Constraints

The arguments qp_positive_derivative, qp_negative_derivative, qp_positive_2ndderivative, and qp_negative_2ndderivative now accept three forms:

FALSE

No constraint (default).

TRUE

Constrain all predictor variables (backward compatible with previous behavior).

Character or integer vector

Constrain only the specified predictor variables. Character entries are resolved via og_cols; integer entries refer to column positions in the predictor matrix.

This allows, for example, enforcing a nonnegative first derivative for "Dose" and a nonpositive first derivative for "Time" simultaneously:

  lgspline(...,
           qp_positive_derivative = "Dose",
           qp_negative_derivative = "Time")

The arguments qp_monotonic_increase and qp_monotonic_decrease remain TRUE/FALSE only, because they constrain fitted values in observation order (not per-variable).

Examples

## Not run: 
## Standalone verification: simple 1-D monotonic increase
set.seed(1234)
t <- seq(-5, 5, length.out = 200)
y <- 3 * sin(t) + t + rnorm(200, 0, 0.5)

## Fit with positive first-derivative constraint on all variables
fit1 <- lgspline(t, y, K = 3,
                 qp_positive_derivative = TRUE)

## Verify: first derivative should be >= 0 everywhere
derivs1 <- predict(fit1, new_predictors = sort(t),
                   take_first_derivatives = TRUE)
stopifnot(all(derivs1$first_deriv >= -1e-8))

## Fit with monotonic increase (observation-order)
fit2 <- lgspline(t, y, K = 3,
                 qp_monotonic_increase = TRUE)
preds2 <- predict(fit2, new_predictors = sort(t))
stopifnot(all(diff(preds2) >= -1e-8))

## Per-variable constraints: 2-D example
t1 <- runif(500, -5, 5)
t2 <- runif(500, -5, 5)
y2 <- t1 + sin(t2) + rnorm(500, 0, 0.5)
dat2 <- data.frame(t1 = t1, t2 = t2, y = y2)

## Constrain t1 to have positive derivative, t2 to have negative
fit3 <- lgspline(y ~ spl(t1, t2), data = dat2, K = 2,
                 qp_positive_derivative = "t1",
                 qp_negative_derivative = "t2")

## Verify per-variable derivatives
newdat <- expand.grid(t1 = seq(-4, 4, length.out = 50),
                      t2 = seq(-4, 4, length.out = 50))
d3 <- predict(fit3, new_predictors = newdat,
              take_first_derivatives = TRUE)

## t1 derivative should be >= 0
stopifnot(all(unlist(d3$first_deriv[["_1_"]]) >= -1e-6))
## t2 derivative should be <= 0
stopifnot(all(unlist(d3$first_deriv[["_2_"]]) <= 1e-6))

## Numeric column indices work identically
fit4 <- lgspline(y ~ spl(t1, t2), data = dat2, K = 2,
                 qp_positive_derivative = 1,
                 qp_negative_derivative = 2)

## Range + derivative constraints simultaneously
fit5 <- lgspline(t, y, K = 3,
                 qp_positive_derivative = TRUE,
                 qp_range_lower = -5,
                 qp_range_upper = 15)
preds5 <- predict(fit5)
stopifnot(all(preds5 >= -5 - 1e-6))
stopifnot(all(preds5 <= 15 + 1e-6))

## End(Not run)


lgspline documentation built on May 8, 2026, 5:07 p.m.