This release adds major new support for linear algebra, local functions,
sapply(), and OpenMP parallelism, along with a broad round of reliability,
compatibility, and compiler/runtime improvements.
Major new features
Matrix and linear algebra support
-
Added initial matrix / linear algebra support from base R, using the same
BLAS/LAPACK as R. Supported operations now include%*%,t(),
crossprod(),tcrossprod(),outer()withFUN = "*",%o%,
forwardsolve(),backsolve(),diag(),chol(),chol2inv(),
solve(), andqr.solve(). (#77, #79, @mns-nordicals) -
This also adds support for:
drop()for rank 0-2 inputs, including singleton matrices.svd()results via$d,$u, and$v, whether accessed from
s <- svd(x)or directly assvd(x)$d,svd(x)$u, orsvd(x)$v..Machine$double.eps.
Local closures and sapply()
-
Added support for local closures inside compiled functions, including
sapply()lowering with host association for captures and support for
simplify = "array"for higher-rank outputs. -
Example:
f <- function(i) x[i] + 1.0 out <- sapply(seq_along(out), f)
-
This lowering matches R’s copy-on-modify semantics: modifying variables from
the parent scope triggers a copy in the local closure scope. -
Added support for superassignment (
<<-) inside local closures, including
subset targets such asx[i] <<- ..., to explicitly mutate variables in the
enclosing quick function scope. For example:apply_boundary_conditions <- function() { temp[1, ] <<- 0 temp[nx, ] <<- 0 temp[, 1] <<- 0 temp[, ny] <<- 0 NULL } apply_boundary_conditions()
-
Local closures also support optional arguments with
NULLdefaults,
with validation to ensure optional arguments are initialized viais.null()
before use.
Parallel execution
- Added OpenMP parallelization via
declare(parallel())/declare(omp())
for supportedforloops andsapply()calls.
Binding and iteration
-
Added support for
cbind()andrbind()for rank-0/1/2 inputs, with scalar
recycling only and strict length checks for non-scalar inputs. -
Improved lowering for
for (... in <iterable>), including value iteration
such asfor (v in x), and support forrev()wrappers on supported
iterables.
Language and runtime additions
-
Added support for throwing errors with
stop(). (#86) -
Added support for
as.integer()coercion fromdouble,logical, and
integervalues.doubleinputs are truncated toward 0. -
Added support for
tanh()as a unary intrinsic. -
Added support for
rev()for reversing rank-0/1 vectors, including bind(c)
logicals, preservingNAstorage where possible. -
Added support for
abs()in size expressions used bydeclare(type(...)),
for example:
declare(type(x = integer(abs(end - start) + 1L))). -
Improved support for
array(data = ..., dim = ...)for shape construction in
user code.
Compiler and lowering improvements
-
quickr now supports nested compilation scopes with local declaration
emission, enabling block-scoped temporaries and local closures lowered to
internal procedures undercontains.-
This helps in two ways. First, in large compiled functions, declared intermediate
results no longer need to stay live for the full duration of the function,
which can reduce peak memory use. -
Second, it improves handling of large temporaries across compilers. In
particular, LLVM flang may place temporary arrays on the stack by default,
which can cause problems when those temporaries are large. This work also
led to better control over when temporaries need to be emitted as
heap allocatable.
-
-
Example of a block-scoped temporary used for expression subscripting:
out[1] <- ifelse((x > 0.0)[2, 3], 1.0, 0.0)
Reliability, compatibility, and diagnostics
-
Added extensive tests and snapshots covering local closures,
sapply(),
block-scoped temporaries, and package compilation behavior, including
internal procedure name collisions. -
Fixed
[subsetting on scalars with bothdrop = TRUEanddrop = FALSE,
simplifying to Fortran scalars so subsetted scalars in reductions such as
min(m[1, 1], m[2, 1])no longer emitminvalon scalars. (#64) -
Fixed nested scalar
min()/max()in reductions, so clamp-style
expressions likemin(max(x[i], lo), hi)work reliably. -
Fixed an issue where subsetting logical arrays could fail when compiling
quick functions, for example(x > 0)[2, 3]. (#68) -
Fixed a crash when compiling chained or fall-through assignments such as
a <- b <- 1. (#60) -
quick()now supports dotted symbols such asfoo.barfor arguments,
locals, and loop variables. Conflicting names that map to the same Fortran
symbol now error, since Fortran is case-insensitive. -
Fixed C bridge size checks for dotted argument names used in
declare(type(...))size expressions, for example
type(x = double(foo.bar)). -
quick()now gives a helpful error when a function argument is used without
being declared throughdeclare(type(arg = ...)). -
Fixed an error in invalid subscript arity reporting, for example
x[1, 2, 3]on a matrix now errors cleanly instead of failing while
formatting the message.
Breaking changes
- Vector-matrix recycling in arithmetic is now restricted to recycling along
the first axes only.
Platform and toolchain
-
Lowered the minimum supported R version to 4.3.0 and added a backport of
declare()for R < 4.4.0. (#67) -
On macOS, quickr will use LLVM flang (
flang-new) for compilation when
available, for example afterbrew install flang. This is optional and can
be disabled withoptions(quickr.prefer_flang = FALSE).