| Title: | Tabular Matrix Problems via Pseudoinverse Estimation |
|---|---|
| Description: | The Tabular Matrix Problems via Pseudoinverse Estimation (TMPinv) is a two-stage estimation method that reformulates structured table-based systems - such as allocation problems, transaction matrices, and input-output tables - as structured least-squares problems. Based on the Convex Least Squares Programming (CLSP) framework, TMPinv solves systems with row and column constraints, block structure, and optionally reduced dimensionality by (1) constructing a canonical constraint form and applying a pseudoinverse-based projection, followed by (2) a convex-programming refinement stage to improve fit, coherence, and regularization (e.g., via Lasso, Ridge, or Elastic Net). |
| Authors: | Ilya Bolotov [aut, cre] (ORCID: <https://orcid.org/0000-0003-1148-7144>) |
| Maintainer: | Ilya Bolotov <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 2.0.0 |
| Built: | 2026-06-07 23:08:53 UTC |
| Source: | https://github.com/econcz/rtmpinv |
Solve a tabular matrix estimation problem via Convex Least Squares Programming (CLSP).
tmpinv( S = NULL, M = NULL, b_row = NULL, b_col = NULL, b_val = NULL, i = 1L, j = 1L, zero_diagonal = FALSE, reduced = NULL, symmetric = FALSE, bounds = NULL, replace_value = NA_real_, tolerance = sqrt(.Machine$double.eps), iteration_limit = 50L, r = 1L, final = TRUE, alpha = NULL, cond_tolerance = NULL, ... )tmpinv( S = NULL, M = NULL, b_row = NULL, b_col = NULL, b_val = NULL, i = 1L, j = 1L, zero_diagonal = FALSE, reduced = NULL, symmetric = FALSE, bounds = NULL, replace_value = NA_real_, tolerance = sqrt(.Machine$double.eps), iteration_limit = 50L, r = 1L, final = TRUE, alpha = NULL, cond_tolerance = NULL, ... )
S |
numeric matrix of size
|
M |
numeric matrix of size |
b_row |
numeric vector of length |
b_col |
numeric vector of length |
b_val |
numeric vector of length |
i |
integer, default = |
j |
integer, default = |
zero_diagonal |
logical scalar, default = |
reduced |
integer vector of length |
symmetric |
logical scalar, default = |
bounds |
NULL, |
replace_value |
numeric scalar or |
tolerance |
numeric scalar, default = |
iteration_limit |
integer, default = |
r |
integer scalar, default = |
final |
logical scalar, default = |
alpha |
numeric scalar, numeric vector, or |
cond_tolerance |
numeric scalar or |
... |
Additional arguments passed to the rclsp solver. |
An object of class "tmpinv" containing the fitted CLSP
model (tmpinv$model) and solution matrix (tmpinv$x).
In the reduced model, S is ignored. Slack behaviour is
inferred from block-wise marginal totals.
Likewise, M must be a unique row subset of an identity
matrix (diagonal-only). Non-diagonal model matrices cannot be
mapped into reduced blocks.
Internal keyword arguments b_lim and C_lim are
passed to .tmpinv.instance() and contain cell-value
bounds. These arguments are ignored in the reduced model.
## Example 1: AP/TM reconstruction on a symmetric 20x20 matrix ## (10 percent known entries) RNGkind("L'Ecuyer-CMRG") set.seed(123456789) m <- 20L p <- 20L # sample (dataset) X_true <- abs(matrix(rnorm(m * p), nrow = m, ncol = p)) X_true <- 0.5 * (X_true + t(X_true)) # symmetric idx <- sample.int( m * p, size = max(1L, floor(0.1 * (m * p))), # 10 percent known replace = FALSE ) M <- diag(m * p)[idx, , drop = FALSE] b_row <- rowSums(X_true) b_col <- colSums(X_true) b_val <- matrix(as.numeric(X_true)[idx], ncol = 1L) # model (unique MNBLUE estimator) result <- tmpinv( M = M, b_row = b_row, b_col = b_col, b_val = b_val, bounds = c(0, NA), # non-negativity symmetric = TRUE, r = 1L, alpha = 1.0 ) # coefficients print("true X:") print(round(X_true, 4)) print("X_hat:") print(round(result$x, 4)) # numerical stability print("\nNumerical stability:") print(paste(" kappaC :", result$model$kappaC)) print(paste(" kappaB :", result$model$kappaB)) print(paste(" kappaA :", result$model$kappaA)) # diagnostics print("\nGoodness-of-fit:") print(paste(" NRMSE :", result$model$nrmse)) print(paste(" Diagnostic band (min):", min(result$model$x_lower))) print(paste(" Diagnostic band (max):", max(result$model$x_upper))) # bootstrap NRMSE t-test tt <- rclsp::ttest( result$model, sample_size = 30L, seed = 123456789L, distribution = rnorm, partial = TRUE ) print("\nBootstrap t-test:") print(tt) ## Example 2: AP/TM reconstruction on a 40x40 matrix ## with zero diagonal and reduced (20,20) submodels ## (20 percent known entries) RNGkind("L'Ecuyer-CMRG") set.seed(123456789) m <- 40L p <- 40L # sample (dataset) X_true <- abs(matrix(rnorm(m * p), nrow = m, ncol = p)) diag(X_true) <- 0 # zero diagonal idx <- sample.int( m * p, size = max(1L, floor(0.2 * (m * p))), # 20 percent known replace = FALSE ) M <- diag(m * p)[idx, , drop = FALSE] b_row <- rowSums(X_true) b_col <- colSums(X_true) b_val <- matrix(as.numeric(X_true)[idx], ncol = 1L) # model (reduced models of size 20x20) result <- tmpinv( M = M, b_row = b_row, b_col = b_col, b_val = b_val, zero_diagonal = TRUE, reduced = c(20L, 20L), bounds = c(0, NA), r = 1L, alpha = 1.0 ) print("true X:") print(round(X_true, 4)) print("X_hat:") print(round(result$x, 4)) # numerical stability across submodels kC <- sapply(result$model, function(CLSP) CLSP$kappaC) kB <- sapply(result$model, function(CLSP) CLSP$kappaB) kA <- sapply(result$model, function(CLSP) CLSP$kappaA) print("\nNumerical stability (min-max across models):") print(paste(" kappaC :", range(kC))) print(paste(" kappaB :", range(kB))) print(paste(" kappaA :", range(kA))) # diagnostics (min-max) nrmse <- sapply(result$model, function(CLSP) CLSP$nrmse) x_low <- unlist(lapply(result$model, function(CLSP) CLSP$x_lower)) x_up <- unlist(lapply(result$model, function(CLSP) CLSP$x_upper)) print("\nGoodness-of-fit (min-max across models):") print(paste(" NRMSE :", range(nrmse))) print(paste(" Diagnostic band (min):", range(x_low))) print(paste(" Diagnostic band (max):", range(x_up))) # bootstrap t-tests across all block models print("\nBootstrap t-tests:") tests <- lapply( result$model, function(CLSP) rclsp::ttest( CLSP, sample_size = 30L, seed = 123456789L, distribution = rnorm, partial = TRUE ) ) print(tests)## Example 1: AP/TM reconstruction on a symmetric 20x20 matrix ## (10 percent known entries) RNGkind("L'Ecuyer-CMRG") set.seed(123456789) m <- 20L p <- 20L # sample (dataset) X_true <- abs(matrix(rnorm(m * p), nrow = m, ncol = p)) X_true <- 0.5 * (X_true + t(X_true)) # symmetric idx <- sample.int( m * p, size = max(1L, floor(0.1 * (m * p))), # 10 percent known replace = FALSE ) M <- diag(m * p)[idx, , drop = FALSE] b_row <- rowSums(X_true) b_col <- colSums(X_true) b_val <- matrix(as.numeric(X_true)[idx], ncol = 1L) # model (unique MNBLUE estimator) result <- tmpinv( M = M, b_row = b_row, b_col = b_col, b_val = b_val, bounds = c(0, NA), # non-negativity symmetric = TRUE, r = 1L, alpha = 1.0 ) # coefficients print("true X:") print(round(X_true, 4)) print("X_hat:") print(round(result$x, 4)) # numerical stability print("\nNumerical stability:") print(paste(" kappaC :", result$model$kappaC)) print(paste(" kappaB :", result$model$kappaB)) print(paste(" kappaA :", result$model$kappaA)) # diagnostics print("\nGoodness-of-fit:") print(paste(" NRMSE :", result$model$nrmse)) print(paste(" Diagnostic band (min):", min(result$model$x_lower))) print(paste(" Diagnostic band (max):", max(result$model$x_upper))) # bootstrap NRMSE t-test tt <- rclsp::ttest( result$model, sample_size = 30L, seed = 123456789L, distribution = rnorm, partial = TRUE ) print("\nBootstrap t-test:") print(tt) ## Example 2: AP/TM reconstruction on a 40x40 matrix ## with zero diagonal and reduced (20,20) submodels ## (20 percent known entries) RNGkind("L'Ecuyer-CMRG") set.seed(123456789) m <- 40L p <- 40L # sample (dataset) X_true <- abs(matrix(rnorm(m * p), nrow = m, ncol = p)) diag(X_true) <- 0 # zero diagonal idx <- sample.int( m * p, size = max(1L, floor(0.2 * (m * p))), # 20 percent known replace = FALSE ) M <- diag(m * p)[idx, , drop = FALSE] b_row <- rowSums(X_true) b_col <- colSums(X_true) b_val <- matrix(as.numeric(X_true)[idx], ncol = 1L) # model (reduced models of size 20x20) result <- tmpinv( M = M, b_row = b_row, b_col = b_col, b_val = b_val, zero_diagonal = TRUE, reduced = c(20L, 20L), bounds = c(0, NA), r = 1L, alpha = 1.0 ) print("true X:") print(round(X_true, 4)) print("X_hat:") print(round(result$x, 4)) # numerical stability across submodels kC <- sapply(result$model, function(CLSP) CLSP$kappaC) kB <- sapply(result$model, function(CLSP) CLSP$kappaB) kA <- sapply(result$model, function(CLSP) CLSP$kappaA) print("\nNumerical stability (min-max across models):") print(paste(" kappaC :", range(kC))) print(paste(" kappaB :", range(kB))) print(paste(" kappaA :", range(kA))) # diagnostics (min-max) nrmse <- sapply(result$model, function(CLSP) CLSP$nrmse) x_low <- unlist(lapply(result$model, function(CLSP) CLSP$x_lower)) x_up <- unlist(lapply(result$model, function(CLSP) CLSP$x_upper)) print("\nGoodness-of-fit (min-max across models):") print(paste(" NRMSE :", range(nrmse))) print(paste(" Diagnostic band (min):", range(x_low))) print(paste(" Diagnostic band (max):", range(x_up))) # bootstrap t-tests across all block models print("\nBootstrap t-tests:") tests <- lapply( result$model, function(CLSP) rclsp::ttest( CLSP, sample_size = 30L, seed = 123456789L, distribution = rnorm, partial = TRUE ) ) print(tests)