tensor/0000755000175100001440000000000015024244460011603 5ustar hornikuserstensor/MD50000644000175100001440000000026715024244460012120 0ustar hornikusersef6f4bc49968c6ccd48b72cbc531aad6 *DESCRIPTION 9fdfeb11f7ddba6f3aab9aaa6b1ac5dd *NAMESPACE 55fb65eea33abde21f3de38c0ed54b98 *R/tensor.R 047709d8cd7a78f5dc73d25ca4ae5d26 *man/tensor.Rd tensor/R/0000755000175100001440000000000007320577016012012 5ustar hornikuserstensor/R/tensor.R0000644000175100001440000000313107320577010013437 0ustar hornikusers"tensor" <- function(A, B, alongA = integer(0), alongB = integer(0)) { A <- as.array(A) dimA <- dim(A) dnA <- dimnames(A) if (nnA <- is.null(dnA)) dnA <- rep(list(NULL), length(dimA)) B <- as.array(B) dimB <- dim(B) dnB <- dimnames(B) if (nnB <- is.null(dnB)) dnB <- rep(list(NULL), length(dimB)) if (length(alongA) != length(alongB)) stop("\"along\" vectors must be same length") # special case of both length zero if (length(alongA) == 0) { R <- as.vector(A) %*% t(as.vector(B)) dim(R) <- c(dimA, dimB) if (!(nnA && nnB)) dimnames(R) <- c(dnA, dnB) return(R) } mtch <- dimA[alongA] == dimB[alongB] if (any(is.na(mtch)) || !all(mtch)) stop("Mismatch in \"along\" dimensions") seqA <- seq(along=dimA) allA <- length(seqA) == length(alongA) permA <- c(seqA[-alongA], alongA) if (!all(seqA == permA)) A <- aperm(A, permA) dim(A) <- c( if (allA) 1 else prod(dimA[-alongA]), prod(dimA[alongA]) ) seqB <- seq(along=dimB) allB <- length(seqB) == length(alongB) permB <- c(alongB, seqB[-alongB]) if (!all(seqB == permB)) B <- aperm(B, permB) dim(B) <- c( prod(dimB[alongB]), if (allB) 1 else prod(dimB[-alongB]) ) R <- A %*% B if (allA && allB) R <- drop(R) else { dim(R) <- c( if (allA) integer(0) else dimA[-alongA], if (allB) integer(0) else dimB[-alongB] ) if (!(nnA && nnB)) dimnames(R) <- c(dnA[-alongA], dnB[-alongB]) } R } "%*t%" <- function(x, y) tensor(x, y, 2, 2) "%t*%" <- function(x, y) tensor(x, y, 1, 1) "%t*t%" <- function(x, y) tensor(x, y, 1, 2) tensor/NAMESPACE0000644000175100001440000000017111750740451013024 0ustar hornikusers# Default NAMESPACE created by R # Remove the previous line if you edit this file # Export all names exportPattern(".") tensor/man/0000755000175100001440000000000007421255442012362 5ustar hornikuserstensor/man/tensor.Rd0000644000175100001440000000471507421255442014172 0ustar hornikusers\name{tensor} \alias{tensor} \alias{\%*t\%} \alias{\%t*\%} \alias{\%t*t\%} \title{Tensor product of arrays} \description{The tensor product of two arrays is notionally an outer product of the arrays collapsed in specific extents by summing along the appropriate diagonals. For example, a matrix product is the tensor product along the second extent of the first matrix and the first extent of the second. Thus \code{A \%*\% B} could also be evaluated as \code{tensor(A, B, 2, 1)}, likewise \code{A \%*\% t(B)} could be \code{tensor(A, B, 2, 2)}.} \usage{ tensor(A, B, alongA = integer(0), alongB = integer(0)) } \arguments{ \item{A, B}{Numerical vectors, matrices or arrays} \item{alongA}{Extents in \code{A} to be collapsed} \item{alongB}{Extents in \code{B} to be collapsed} } \details{This code does the `obvious' thing, which is to perm the "along" extents to the end (for \code{A}) and beginning (for \code{B}) of the two objects and then do a matrix multiplication and reshape.} \value{Generally, an array with dimension comprising the remaining extents of \code{A} concatenated with the remaining extents of \code{B}. If both \code{A} and \code{B} are completely collapsed then the result is a scalar \bold{without} a \code{dim} attribute. This is quite deliberate and consistent with the general rule that the dimension of the result is the sum of the original dimensions less the sum of the collapse dimensions (and so could be zero). A 1D array of length 1 arises in a different set of circumstances, eg if \code{A} is a 1 by 5 matrix and \code{B} is a 5-vector then \code{tensor(A, B, 2, 1)} is a 1D array of length 1.} \section{Shortcuts}{Some special cases of \code{tensor} may be independently useful, and these have got shortcuts as follows. \tabular{ll}{ \%*t\% \tab Matrix product \code{A \%*\% t(B)} \cr \%t*\% \tab Matrix product \code{t(A) \%*\% B} \cr \%t*t\% \tab Matrix product \code{t(A) \%*\% t(B)} } } \author{Jonathan Rougier, \email{J.C.Rougier@durham.ac.uk}} \seealso{\code{\link{matmult}}, \code{\link{aperm}}} \examples{ A <- matrix(1:6, 2, 3) dimnames(A) <- list(happy = LETTERS[1:2], sad = NULL) B <- matrix(1:12, 4, 3) stopifnot(A \%*\% t(B) == tensor(A, B, 2, 2)) A <- A \%o\% A C <- tensor(A, B, 2, 2) stopifnot(all(dim(C) == c(2, 2, 3, 4))) D <- tensor(C, B, c(4, 3), c(1, 2)) stopifnot(all(dim(D) == c(2, 2))) E <- matrix(9:12, 2, 2) s <- tensor(D, E, 1:2, 1:2) stopifnot(s == sum(D * E), is.null(dim(s))) } \keyword{array} tensor/DESCRIPTION0000644000175100001440000000121415024244460013307 0ustar hornikusersPackage: tensor Version: 1.5.1 Title: Tensor Product of Arrays Authors@R: person(given = "Jonathan", family = "Rougier", role = c("aut", "cre"), email = "j.c.rougier@bristol.ac.uk") Description: The tensor product of two arrays is notionally an outer product of the arrays collapsed in specific extents by summing along the appropriate diagonals. License: GPL (>= 2) Packaged: 2025-06-17 10:36:58 UTC; hornik Repository: CRAN Date/Publication: 2025-06-17 10:53:36 UTC NeedsCompilation: no Author: Jonathan Rougier [aut, cre] Maintainer: Jonathan Rougier