---
title: "4. Matrix inversion by elementary row operations"
author: "Michael Friendly"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{4. Matrix inversion by elementary row operations}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r nomessages, echo = FALSE}
knitr::opts_chunk$set(
  warning = FALSE,
  message = FALSE
)
options(digits=4)
par(mar=c(5,4,1,1)+.1)
```

The following examples illustrate the steps in finding the inverse of a matrix
using *elementary row operations* (EROs):

* Add a multiple of one row to another (`rowadd()`)
* Multiply one row by a constant (`rowmult()`)
* Interchange two rows (`rowswap()`)

These have the properties that they do not change the inverse.  The method used here
is sometimes called the *Gauss-Jordan* method, a form of *Gaussian elimination*.
Another term is *(row-reduced) echelon form*.

Steps:

1.  Adjoin the identity matrix to the right side of A, to give the matrix $[A | I]$
2.  Apply row operations to this matrix until the left ($A$) side is reduced to $I$
3.  The inverse matrix appears in the right ($I$) side

Why this works:  The series of row operations transforms
$$ [A | I] \Rightarrow [A^{-1} A | A^{-1} I] = [I | A^{-1}]$$

 If the matrix is does not have an inverse (is *singular*) a row of all zeros will appear
 in the left ($A$) side.

### Load the `matlib` package


```{r }
library(matlib)
```

### Create a 3 x 3 matrix

```{r create-matrix}
   A <- matrix( c(1, 2, 3,
                  2, 3, 0,
                  0, 1,-2), nrow=3, byrow=TRUE)
```

### Join an identity matrix to A

```{r cbind-I}
   (AI <-  cbind(A, diag(3)))
```

### Apply elementary row operations to reduce A to an identity matrix.
The right three cols will then contain inv(A).
We will do this three ways:

 1. first, just using R arithmetic on the rows of `AI`
 2. using the ERO functions in the `matlib` package
 3. using the `echelon()` function


### 1. Using R arithmetic

```{r solve-manually}
	(AI[2,] <- AI[2,] - 2*AI[1,])     # row 2 <- row 2 - 2 * row 1
	(AI[3,] <- AI[3,] + AI[2,])       # row 3 <- row 3 + row 2
	(AI[2,] <- -1 * AI[2,])           # row 2 <- -1 * row 2
	(AI[3,] <-  -(1/8) * AI[3,])        # row 3 <- -.25 * row 3
```

Now, all elements below the diagonal are zero

```{r solve2}
	AI

      #--continue, making above diagonal == 0
	AI[2,] <- AI[2,] - 6 * AI[3,]     # row 2 <- row 2 - 6 * row 3
	AI[1,] <- AI[1,] - 3 * AI[3,]     # row 1 <- row 1 - 3 * row 3
	AI[1,] <- AI[1,] - 2 * AI[2,]     # row 1 <- row 1 - 2 * row 2

	AI
   #-- last three cols are the inverse
  (AInv <- AI[,-(1:3)])

   #-- compare with inv()
  inv(A)
```

### 2. Do the same, using matlib functions `rowadd()`, `rowmult()` and `rowswap()`

```{r using-rowadd}
   AI <-  cbind(A, diag(3))

   AI <- rowadd(AI, 1, 2, -2)        # row 2 <- row 2 - 2 * row 1
   AI <- rowadd(AI, 2, 3, 1)         # row 3 <- row 3 + row 2
   AI <- rowmult(AI, 2, -1)          # row 1 <- -1 * row 2
   AI <- rowmult(AI, 3, -1/8)        # row 3 <- -.25 * row 3

   # show result so far
   AI

  	#--continue, making above-diagonal == 0
   AI <- rowadd(AI, 3, 2, -6)        # row 2 <- row 2 - 6 * row 3
   AI <- rowadd(AI, 2, 1, -2)        # row 1 <- row 1 - 2 * row 2
   AI <- rowadd(AI, 3, 1, -3)        # row 1 <- row 1 - 3 * row 3
   AI
```

### 3. Using `echelon()`
`echelon()` does all these steps *row by row*, and returns the result

```{r echelon1}
   echelon( cbind(A, diag(3)))
```

It is more interesting to see the steps, using the argument `verbose=TRUE`. In
many cases, it is informative to see the numbers printed as fractions.

```{r echelon2}
   echelon( cbind(A, diag(3)), verbose=TRUE, fractions=TRUE)
```

