Nothing
#####
## DO NOT EDIT THIS FILE!! EDIT THE SOURCE INSTEAD: rsrc_tree/atoms/affine/kron.R
#####
## CVXPY SOURCE: atoms/affine/kron.py
## Kron -- Kronecker product (one arg must be constant)
Kron <- new_class("Kron", parent = AffAtom, package = "CVXR",
constructor = function(a, b, id = NULL) {
if (FALSE) new_object(S7_object()) ## S7 static-check guard
if (is.null(id)) id <- next_expr_id()
a <- as_expr(a)
b <- as_expr(b)
## At least one must be constant
if (!is_constant(a) && !is_constant(b)) {
cli_abort("At least one argument to {.fn kron} must be constant.")
}
shape <- c(.shape(a)[1L] * .shape(b)[1L], .shape(a)[2L] * .shape(b)[2L])
obj <- .fast_new(Kron, S7_object(),
id = as.integer(id),
.cache = new.env(parent = emptyenv()),
args = list(a, b),
shape = shape
)
obj
}
)
method(shape_from_args, Kron) <- function(x) {
a <- .args(x)[[1L]]; b <- .args(x)[[2L]]
c(.shape(a)[1L] * .shape(b)[1L], .shape(a)[2L] * .shape(b)[2L])
}
# -- sign: same as multiplication (CVXPY kron.py line 72-75) ------
method(sign_from_args, Kron) <- function(x) {
mul_sign(.args(x)[[1L]], .args(x)[[2L]])
}
# -- monotonicity (CVXPY kron.py lines 77-87) --------------------
method(is_incr, Kron) <- function(x, idx, ...) {
cst_loc <- if (is_constant(.args(x)[[1L]])) 1L else 2L
is_nonneg(.args(x)[[cst_loc]])
}
method(is_decr, Kron) <- function(x, idx, ...) {
cst_loc <- if (is_constant(.args(x)[[1L]])) 1L else 2L
is_nonpos(.args(x)[[cst_loc]])
}
# -- is_nsd: PSD (x) NSD is NSD (CVXPY kron.py lines 96-102) ------
## A *sufficient* condition, exactly as upstream states it: one argument PSD and
## the other NSD makes the Kronecker product NSD.
##
## There is deliberately NO is_psd method here, and that is not an oversight.
## Upstream's is_psd (kron.py:88-94, both-PSD or both-NSD) is already covered by
## `AffAtom`'s monotonicity-based propagation -- verified, `is_psd(kron(I, I))`
## and `is_psd(kron(-I, -I))` are both TRUE without it -- so an override could
## only narrow what CVXR deduces. is_nsd was the one case AffAtom loses: before
## this, `is_nsd` returned FALSE for EVERY Kron (checked across a 27-cell grid of
## PSD/NSD/indefinite/plain operands), so this method is purely additive and
## cannot turn an existing TRUE into FALSE.
method(is_nsd, Kron) <- function(x) {
a <- .args(x)[[1L]]
b <- .args(x)[[2L]]
(is_psd(a) && is_nsd(b)) || (is_nsd(a) && is_psd(b))
}
# -- log-log: affine (CVXPY kron.py) -----------------------------
method(is_atom_log_log_convex, Kron) <- function(x) TRUE
method(is_atom_log_log_concave, Kron) <- function(x) TRUE
method(numeric_value, Kron) <- function(x, values, ...) {
kronecker(values[[1L]], values[[2L]])
}
# -- DPP: kron is NOT DPP when the "data" arg is parametric ------
## The C++ get_kron_mat/get_kron_l_mat handlers use get_constant_data()
## and cannot handle PARAM LinOp nodes. CVXPY has the same limitation
## (see comment in get_kronr_mat: "doesn't properly canonicalize ...
## Parameters"). Return FALSE when the constant arg has parameters.
method(is_dpp, Kron) <- function(x, context = "dcp") {
cst_idx <- if (is_constant(.args(x)[[1L]])) 1L else 2L
cst_arg <- .args(x)[[cst_idx]]
if (length(parameters(cst_arg)) > 0L) return(FALSE)
## Fall back to default DPP check for the non-constant arg
if (identical(tolower(context), "dgp")) with_dpp_scope(is_dgp(x))
else with_dpp_scope(is_dcp(x))
}
method(graph_implementation, Kron) <- function(x, arg_objs, shape, data = NULL, ...) {
## Determine which arg is constant
if (is_constant(.args(x)[[1L]])) {
list(kron_r_linop(arg_objs[[1L]], arg_objs[[2L]], shape), list())
} else {
list(kron_l_linop(arg_objs[[1L]], arg_objs[[2L]], shape), list())
}
}
#' Kronecker product of two expressions
#'
#' @param a An Expression (one must be constant)
#' @param b An Expression
#' @returns A Kron atom
#' @export
kron <- function(a, b) {
Kron(a, b)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.