lkb-pipeline/core/laurent2.R
allaun e5bfdc0492 feat: LKB compute pipeline + eigensolid receipts
Containerized LKB worker (Dockerfile.lkb), Postgres-backed queue,
auto-deploy timer, and eigensolid convergence check module.

Build: 0 jobs (no Lean build needed)
2026-07-08 20:01:29 -05:00

248 lines
6.8 KiB
R

source("boot.R")
#.libPaths(c("~/R/library", .libPaths()))
#library(Rcpp)
#Rcpp::sourceCpp("src/laurent_ops.cpp")
# ══════════════════════════════════════════════════════════════
# Two-variable Laurent polynomials: Z[q^±1, t^±1]
# Optimized: integer vectors (qe, te) instead of string keys
# No string ops (strsplit, paste0) in multiply/add hot paths
# ══════════════════════════════════════════════════════════════
#' @export
laurent2 <- function(terms = NULL) {
if (is.null(terms) || length(terms) == 0) {
return(structure(list(qe = integer(0), te = integer(0), coef = numeric(0)),
class = "laurent2"))
}
terms <- terms[terms != 0]
if (length(terms) == 0) {
return(structure(list(qe = integer(0), te = integer(0), coef = numeric(0)),
class = "laurent2"))
}
qe <- as.integer(sub(",.*", "", names(terms)))
te <- as.integer(sub(".*,", "", names(terms)))
coef <- as.numeric(terms)
o <- order(qe, te)
qe <- qe[o]; te <- te[o]; coef <- coef[o]
if (length(qe) >= 2) {
j <- 1L
for (i in 2:length(qe)) {
if (qe[i] == qe[j] && te[i] == te[j]) {
coef[j] <- coef[j] + coef[i]
} else {
j <- j + 1L
qe[j] <- qe[i]; te[j] <- te[i]; coef[j] <- coef[i]
}
}
length(qe) <- j; length(te) <- j; length(coef) <- j
}
keep <- coef != 0
if (!any(keep)) {
return(structure(list(qe = integer(0), te = integer(0), coef = numeric(0)),
class = "laurent2"))
}
structure(list(qe = qe[keep], te = te[keep], coef = coef[keep]),
class = "laurent2")
}
#' @export
length.laurent2 <- function(x) length(x$coef)
#' @export
l2_add <- function(a, b) {
if (length(a$coef) == 0) return(b)
if (length(b$coef) == 0) return(a)
r <- l2_add_cpp(a$qe, a$te, a$coef, b$qe, b$te, b$coef)
structure(r, class = "laurent2")
}
l2_mul <- function(a, b) {
if (length(a$coef) == 0 || length(b$coef) == 0) {
return(structure(list(qe = integer(0), te = integer(0), coef = numeric(0)), class = "laurent2"))
}
r <- l2_mul_cpp(a$qe, a$te, a$coef, b$qe, b$te, b$coef)
structure(r, class = "laurent2")
}
l2_equal <- function(a, b) {
if (length(a$coef) != length(b$coef)) return(FALSE)
if (length(a$coef) == 0) return(TRUE)
identical(a$qe, b$qe) && identical(a$te, b$te) && identical(a$coef, b$coef)
}
#' @export
l2_str <- function(x) {
if (length(x$coef) == 0) return("0")
parts <- character(length(x$coef))
for (i in seq_along(x$coef)) {
co <- x$coef[i]; qe <- x$qe[i]; te <- x$te[i]
if (co == 0) next
var <- ""
if (qe != 0) {
if (qe == 1) var <- paste0(var, "q")
else if (qe == -1) var <- paste0(var, "q^-1")
else var <- paste0(var, "q^", qe)
}
if (te != 0) {
if (te == 1) var <- paste0(var, "t")
else if (te == -1) var <- paste0(var, "t^-1")
else var <- paste0(var, "t^", te)
}
if (var == "") {
parts[i] <- as.character(co)
} else if (co == 1) {
parts[i] <- var
} else if (co == -1) {
parts[i] <- paste0("-", var)
} else {
parts[i] <- paste0(co, var)
}
}
parts <- parts[parts != ""]
if (length(parts) == 0) return("0")
result <- paste(parts, collapse = " + ")
gsub("\\+ -", "- ", result)
}
# ── Constants ─────────────────────────────────────────────────
#' @export
l2_zero <- laurent2()
#' @export
l2_one <- laurent2(c("0,0" = 1))
#' @export
l2_q <- laurent2(c("1,0" = 1))
#' @export
l2_t <- laurent2(c("0,1" = 1))
#' @export
l2_qt <- laurent2(c("1,1" = 1))
#' @export
l2_qinv <- laurent2(c("-1,0" = 1))
#' @export
l2_tinv <- laurent2(c("0,-1" = 1))
#' @export
l2_neg_one <- laurent2(c("0,0" = -1))
#' @export
l2_1mq <- laurent2(c("0,0" = 1, "1,0" = -1))
#' @export
l2_1mt <- laurent2(c("0,0" = 1, "0,1" = -1))
#' @export
l2_1mq_td <- function(d) {
r <- c(1, -1)
names(r) <- c(paste0("0,", d), paste0("1,", d))
laurent2(r)
}
#' @export
l2_q_td <- function(d) {
r <- 1
names(r) <- paste0("1,", d)
laurent2(r)
}
#' @export
l2_1mq_1mtd <- function(d) {
if (d == 0) return(laurent2())
r <- c(1, -1, -1, 1)
names(r) <- c("0,0", "1,0", paste0("0,", d), paste0("1,", d))
laurent2(r)
}
# ── Matrix utilities ──────────────────────────────────────────
#' @export
l2_mat_zero <- function(n) {
matrix(rep(list(l2_zero), n * n), nrow = n, ncol = n)
}
#' @export
l2_mat_identity <- function(n) {
m <- l2_mat_zero(n)
for (i in 1:n) m[[i, i]] <- l2_one
m
}
#' @export
l2_mat_mul <- function(A, B) {
n <- nrow(A)
C <- l2_mat_zero(n)
for (i in 1:n) {
for (j in 1:n) {
s <- l2_zero
for (k in 1:n) {
aik <- A[[i, k]]; bkj <- B[[k, j]]
if (length(aik$coef) > 0 && length(bkj$coef) > 0) {
s <- l2_add(s, l2_mul(aik, bkj))
}
}
C[[i, j]] <- s
}
}
C
}
#' @export
l2_mat_equal <- function(A, B) {
n <- nrow(A)
for (i in 1:n) for (j in 1:n) {
if (!l2_equal(A[[i, j]], B[[i, j]])) return(FALSE)
}
TRUE
}
# ── Matrix serialization ──────────────────────────────────────
#' @export
serialize_matrix <- function(m) {
N <- nrow(m)
entries <- character(0)
for (i in 1:N) for (j in 1:N) {
p <- m[[i, j]]
if (length(p$coef) > 0) {
parts <- paste0(p$qe, ",", p$te, "=", p$coef, collapse = ";")
entries <- c(entries, paste0(i, ",", j, ":", parts))
}
}
paste0("N=", N, "\n", paste(entries, collapse = "\n"))
}
#' @export
deserialize_matrix <- function(s) {
if (is.null(s) || is.na(s) || s == "") return(NULL)
lines <- strsplit(s, "\n")[[1]]
N <- as.integer(sub("N=", "", lines[1]))
m <- l2_mat_zero(N)
if (length(lines) < 2) return(m)
for (line in lines[-1]) {
if (line == "") next
colon_pos <- regexpr(":", line)
idx_str <- substr(line, 1, colon_pos - 1)
poly_str <- substr(line, colon_pos + 1, nchar(line))
idx <- as.integer(strsplit(idx_str, ",")[[1]])
pairs <- strsplit(poly_str, ";")[[1]]
keys <- character(length(pairs))
vals <- numeric(length(pairs))
for (pi in seq_along(pairs)) {
eq_pos <- regexpr("=", pairs[pi])
keys[pi] <- substr(pairs[pi], 1, eq_pos - 1)
vals[pi] <- as.numeric(substr(pairs[pi], eq_pos + 1, nchar(pairs[pi])))
}
names(vals) <- keys
m[[idx[1], idx[2]]] <- laurent2(vals)
}
m
}
#' @export
l2_merge_into <- function(r, b) {
if (length(b$coef) == 0) return(r)
l2_add(r, b)
}
#' @export
l2_finalize <- function(r) {
r
}