--- title: "11 - Linear algebra in `caracas`" author: Mikkel Meyer Andersen and Søren Højsgaard date: "`r date()`" output: rmarkdown::html_vignette: toc: true toc_depth: 3 number_sections: true vignette: > %\VignetteIndexEntry{11 - Linear algebra in `caracas`} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` # Introduction ```{r, message=FALSE, echo=FALSE} library(caracas) ##packageVersion("caracas") ``` ```{r, include = FALSE} inline_code <- function(x) { x } if (!has_sympy()) { # SymPy not available, so the chunks shall not be evaluated knitr::opts_chunk$set(eval = FALSE) inline_code <- function(x) { deparse(substitute(x)) } } ``` This vignette is based on `caracas` version `r packageVersion("caracas")`. `caracas` is avavailable on CRAN at [https://cran.r-project.org/package=caracas] and on github at [https://github.com/r-cas/caracas]. # Elementary matrix operations ## Creating matrices / vectors We now show different ways to create a symbolic matrix: ```{r} A <- matrix(c("a", "b", "0", "1"), 2, 2) %>% as_sym() A A <- matrix_(c("a", "b", "0", "1"), 2, 2) # note the '_' postfix A A <- as_sym("[[a, 0], [b, 1]]") A A2 <- matrix_(c("a", "b", "c", "1"), 2, 2) A2 B <- matrix_(c("a", "b", "0", "c", "c", "a"), 2, 3) B b <- matrix_(c("b1", "b2"), nrow = 2) D <- diag_(c("a", "b")) # note the '_' postfix D ``` Note that a vector is a matrix in which one of the dimensions is one. ## Matrix-matrix sum and product ```{r} A + A2 A %*% B ``` ## Hadamard (elementwise) product ```{r} A * A2 ``` ## Vector operations ```{r} x <- as_sym(paste0("x", 1:3)) x x + x 1 / x x / x ``` ## Reciprocal matrix ```{r} reciprocal_matrix(A2) reciprocal_matrix(A2, num = "2*a") ``` ## Matrix inverse; solve system of linear equations Solve $Ax=b$ for $x$: ```{r} inv(A) x <- solve_lin(A, b) x A %*% x ## Sanity check ``` ## Generalized (Penrose-Moore) inverse; solve system of linear equations [TBW] ```{r} M <- as_sym("[[1, 2, 3], [4, 5, 6]]") pinv(M) B <- as_sym("[[7], [8]]") B z <- do_la(M, "pinv_solve", B) print(z, rowvec = FALSE) # Do not print column vectors as transposed row vectors ``` # More special linear algebra functionality Below we present convenient functions for performing linear algebra operations. If you need a function in SymPy for which we have not supplied a convinience function (see ), you can still call it with the `do_la()` (short for "do linear algebra") function presented at the end of this section. ## QR decomposition ```{r} A <- matrix(c("a", "0", "0", "1"), 2, 2) %>% as_sym() A qr_res <- QRdecomposition(A) qr_res$Q qr_res$R ``` ## Eigenvalues and eigenvectors ```{r} eigenval(A) ``` ```{r} evec <- eigenvec(A) evec evec1 <- evec[[1]]$eigvec evec1 simplify(evec1) lapply(evec, function(l) simplify(l$eigvec)) ``` ## Inverse, Penrose-Moore pseudo inverse ```{r} inv(A) pinv(cbind(A, A)) # pseudo inverse ``` ## Additional functionality for linear algebra `do_la` short for "do linear algebra" ```{r} args(do_la) ``` The above functions can be called: ```{r} do_la(A, "QRdecomposition") # == QRdecomposition(A) do_la(A, "inv") # == inv(A) do_la(A, "eigenvec") # == eigenvec(A) do_la(A, "eigenvals") # == eigenval(A) ``` ### Characteristic polynomial ```{r} cp <- do_la(A, "charpoly") cp as_expr(cp) ``` ### Rank ```{r} do_la(A, "rank") ``` ### Cofactor ```{r} A <- matrix(c("a", "b", "0", "1"), 2, 2) %>% as_sym() A do_la(A, "cofactor", 0, 1) do_la(A, "cofactor_matrix") ``` ### Echelon form ```{r} do_la(cbind(A, A), "echelon_form") ``` ### Cholesky factorisation ```{r} B <- as_sym("[[9, 3*I], [-3*I, 5]]") B do_la(B, "cholesky") ``` ### Gram Schmidt ```{r} B <- t(as_sym("[[ 2, 3, 5 ], [3, 6, 2], [8, 3, 6]]")) do_la(B, "GramSchmidt") ``` ### Reduced row-echelon form (rref) ```{r} B <- t(as_sym("[[ 2, 3, 5 ], [4, 6, 10], [8, 3, 6] ]")) B B_rref <- do_la(B, "rref") B_rref ``` ### Column space, row space and null space ```{r} B <- matrix(c(1, 3, 0, -2, -6, 0, 3, 9, 6), nrow = 3) %>% as_sym() B columnspace(B) rowspace(B) x <- nullspace(B) x rref(B) B %*% x ``` ### Singular values, svd ```{r} B <- t(as_sym("[[ 2, 3, 5 ], [4, 6, 10], [8, 3, 6], [8, 3, 6] ]")) B singular_values(B) ```