R/054_atoms_affine_diff.R

Defines functions .cvxr_diff_Expression cvxr_diff

Documented in cvxr_diff

#####
## DO NOT EDIT THIS FILE!! EDIT THE SOURCE INSTEAD: rsrc_tree/atoms/affine/diff.R
#####

## CVXPY SOURCE: atoms/affine/diff.py
## diff -- kth order differences along an axis
##
## In CVXPY, diff is a pure function (not an Atom class).
## It uses iterative slicing: x[1:] - x[:-1] repeated k times.
## In R, diff() is an S3 generic, so we register our method in .onLoad().

#' Compute kth Order Differences of an Expression
#'
#' Takes in an expression and returns an expression with the kth order
#' differences along the given axis. The output shape is the same as the
#' input except the size along the specified axis is reduced by k.
#'
#' @param x An Expression or numeric value.
#' @param k Integer. The number of times values are differenced. Default is 1.
#'   (Mapped from R's `lag` argument in diff.default; use `differences` for
#'   repeated differencing which maps to `k` here.)
#' @param axis Integer. The axis along which the difference is taken.
#'   2 = along rows/down columns (default), 1 = along columns/across rows.
#' @returns An Expression representing the kth order differences.
#' @export
cvxr_diff <- function(x, k = 1L, axis = 2L) {
  x <- as_expr(x)
  k <- as.integer(k)
  axis <- as.integer(axis)

  ## Validate axis
  if (axis < 1L || axis > 2L) {
    cli_abort("{.arg axis} must be 1 or 2, got {.val {axis}}.")
  }

  ## Validate k
  dim_len <- x@shape[3L - axis]
  if (k < 0L) {
    cli_abort("{.arg k} must be non-negative, got {.val {k}}.")
  }
  if (k >= dim_len) {
    cli_abort("{.arg k} must be less than the size along axis ({dim_len}), got {.val {k}}.")
  }

  ## k = 0 returns x unchanged
  if (k == 0L) return(x)

  ## Apply k iterations of first-order difference along axis
  for (i in seq_len(k)) {
    n <- x@shape[3L - axis]
    if (axis == 2L) {
      ## Difference along rows: x[2:n, ] - x[1:(n-1), ]
      x <- x[2L:n, ] - x[1L:(n - 1L), ]
    } else {
      ## Difference along columns: x[, 2:n] - x[, 1:(n-1)]
      x <- x[, 2L:n] - x[, 1L:(n - 1L)]
    }
  }
  x
}

## S3 method for diff() dispatching on CVXR::Expression
## Registered in .onLoad() via registerS3method("diff", "CVXR::Expression", ...)
## R's diff() generic has signature: diff(x, lag = 1, differences = 1, ...)
## We map: lag -> k (first differencing step), differences -> repeated application
.cvxr_diff_Expression <- function(x, lag = 1L, differences = 1L, ..., axis = 2L) {
  ## In CVXPY, k means "number of times differenced" which matches R's `differences`
  ## R's `lag` means "step size" (diff at distance lag), which CVXPY doesn't support.
  ## For simplicity: if lag != 1, abort; use differences as k.
  lag <- as.integer(lag)
  if (lag != 1L) {
    cli_abort("CVXR {.fn diff} does not support {.arg lag} != 1. Use {.fn cvxr_diff} for full control.")
  }
  cvxr_diff(x, k = as.integer(differences), axis = axis)
}

Try the CVXR package in your browser

Any scripts or data that you put into this service are public.

CVXR documentation built on March 6, 2026, 9:10 a.m.