---
title: "A companion to *David Hestenes and Garret Sobczyk 1987: _Clifford algebra to geometric calculus_*"
output:
  html_document:
    toc: true
    toc_depth: 2
---

```{r setup, include=FALSE}
set.seed(0)
knitr::opts_chunk$set(echo = TRUE)
library("clifford")
library("onion")
library("matlib") # needed for GramSchmidt()
library("partitions") # needed for allbinom()
comp <- function(LHS,RHS){
  c(`Mod(LHS)` = Mod(LHS), `Mod(RHS)`=Mod(RHS), `Mod(LHS-RHS)` = Mod(LHS-RHS))
}
```

\newcommand{\gr}[1]{\left\langle #1\right\rangle}

<p style="text-align: right;">
![](`r system.file("help/figures/clifford.png", package = "clifford")`){width=10%}
</p>


This document goes through Hestenes and Sobczyk illustrating the
various theorems and functions using package idiom.  Each page is a
self-contained document, in which variables are defined at the
beginning.  Direct quotes are shown in <span style="color:
darkblue">dark blue.</span>


# Page 3

```{r p3}
A <- +2 + 5*e(1) -7*e(1:2) + e(3)
B <- -3 + 2*e(3) -7*e(2:3) + e(4)
C <-    + 5*e(2) -e(c(1,3))
A
B
C
```

<span style="color: darkblue">
Addition is commutative:
</span>

$A+B=B+A\qquad (1.1)$

```{r pa}
A+B == B+A
```

<span style="color: darkblue">
Addition and multiplication are associative:</span>

$(A+B)+C =A+(B+C)\qquad (1.2)$

$(AB)C =A(BC)\qquad (1.3)$


```{r}
(A+B)+C == A+(B+C)
(A*B)*C == A*(B*C)
```

<span style="color: darkblue">
Multiplication is distributive with respect to addition:</span>

$A(B+C)=A*B+A*C\qquad (1.4)$

$(B+C)A=BA + CA\qquad (1.5)$

```{r}
A*(B+C) == A*B + A*C
(B+C)*A == B*A + C*A
```

<span style="color: darkblue">
There exist unique additive and multiplicative identities 0 and 1:
</span>

$A+0=A\qquad (1.6)$

$1A=A\qquad (1.7)$


```{r}
A + 0 == A
1*A == A
```

Every multivector has a unique additive inverse $-A$:

$A + (-A)=0\qquad (1.8)$

```{r}
is.zero(A + (-A))
is.zero(A - A ) # same idiom
```

Geometric algebra is set apart by _grades_:

$A=\gr{A}_0+\gr{A}_1+\gr{A}_2+\cdots=\sum_r\gr{A}_r\qquad (1.9)$

```{r}
A
grade(A,0)
grade(A,1)
grade(A,2)
```

\newpage

# Page 4

```{r}
(A <- 3 + 4*e(1) -7*e(3) + 8*e(1:4))
(B <- -e(1:3)  + 6*e(c(1,3,4)))
(V <- e(1) + 5*e(2) -7*e(5))
```

$\ldots$ if $A=\gr{A}_r$ for some positive integer $r$, we say $A$ is
_homogeneous_ of grade $r$

```{r}
is.homog(A)
is.homog(B)
```
<span style="color: darkblue">
The _grade operator_ $\gr{\cdot}_r$ enjoys the properties:</span>

$\gr{A+B}_r=\gr{A}_r+\gr{B}_r\qquad (1.10)$

$\gr{\lambda A}_r=\lambda\gr{A}_r = \gr{A}_r\lambda$~$\qquad$~if $\lambda=\gr{\lambda}_0\qquad (1.11)$

$\gr{\gr{A}_r}=\gr{A}_r\qquad (1.12)$

```{r}
all(grade(A+B,2) == grade(A,2) + grade(B,2),grade(A*4,2) == 4*grade(A,2),grade(grade(A,2),2) == grade(A,2))
```

[a _vector_ is a homogeneous multivector of grade 1].

```{r}
is.1vector(A)
is.1vector(V)
```

<span style="color: darkblue">
the square of any nonzero vector $a$ is $\ldots$ real":</span>

```{r}
V*V
Mod(V)
```

<span style="color: darkblue">
A multivector $A_r$ is called an _$r$-blade_ if it can be factored
into a product of $r$ anticommuting vectors $a_1,\ldots,a_r$:
</span>

$A_r = a_1a_2\ldots a_r,\qquad(1.14a)$

where

$a_ja_k=-a_ka_j$ for $i\neq j$.  In the package we can create blades
as (scalar multiples of) products of basis vectors as in

```{r}
(X <- 4*e(1)*e(2)*e(6))
```

But testing for an object being a blade is not yet implemented:

```{r,error=TRUE}
is.blade(X)
```


# Page 5

```{r}
A <- +2 + 5*e(1) -7*e(1:2) + e(3)
B <- -3 + 2*e(3) -7*e(2:3) + e(4)
C <-      5*e(2)
A
B
C
```

<span style="color: darkblue">We have the two notations
</span>

$A_\overline{r} =\gr{A}_r\qquad (1.15)$


<span style="color: darkblue">Also the scalar grade operator is sufficiently distinctive to merit its own notation
</span>

$\gr{A}=\gr{A}_0=A_\overline{0}\qquad (1.16)$

<span style="color: darkblue">the operation of _reversion_:</span>

$\left(AB\right)^\dagger=B^\dagger A^\dagger\qquad (1.17a)$

$\left(A+B\right)^\dagger=A^\dagger+B^\dagger\qquad (1.17b)$

$\gr{A^\dagger}=\gr{A}\qquad(1.17c)$

$a=a^\dagger,\qquad a=\gr{a}_1\qquad(1.17d)$

In the package we use `rev()` [notation in the package is detailed 
in `rev.Rd`]:

```{r}
rev(A*B) == rev(B)*rev(A)
rev(A+B) == rev(A) + rev(B)
const(A) == const(rev(A))
rev(C)   == C
```

# Page 6


```{r}
A <- +2 + 5*e(1) -7*e(1:2) + e(1:3) - e(1:4)
B <- -3 + 7*e(1:2) +3*e(1:4)
C <-      5*e(2)
A
B
C
```

<span style="color: darkblue">immediate corollaries:</span>

$\gr{AB_rC}_r = \gr{C^\dagger B_rA^\dagger}_r\qquad(1.20c)$

```{r}
grade(A*grade(B,2)*C,2) == grade(rev(C)*grade(B,2)*rev(A),2)
```

<span style="color: darkblue">We define the _inner product_ of
homogenous multivectors by:</span>

$A_r\cdot B=\gr{A_rB_s}_{\left|r-s\right|}$ if $r,s>0\qquad(1.21a)$

$A_r\cdot B_s=0$ if $rs=0\qquad(1.21b)$

For arbitrary multivectors we invoke linearity:

$A\cdot B=\sum_r\sum_sA_\overline{r}\cdot B_\overline{s}\qquad(1.21c)$

In the package:


```{r cdpw}
cliffdotprod(A,B)  # usual idiom A %.% B buggers up rmarkdown
```


<span style="color: darkblue">we define the _outer product_ of
homogenous multivectors by:</span>

$A_r\wedge B_s = \gr{A_rB_s}_{r+s}\qquad(1.22a)$

and in general

$A\wedge B=\sum_r\sum_sA_\overline{r}\wedge B_\overline{s}\qquad(1.22c)$


In the package:

```{r}
A %^% B
```

# Page 7

(many algebraic properties of dot and wedge products)

```{r}
A <- +2 + 5*e(1) -7*e(1:2) + e(1:3) - e(1:4)
B <- -3 + 7*e(1:2) +3*e(1:4)
C <-      5*e(2)
```

$(A\wedge B)C=A\wedge BC\neq A\wedge(BC)$


```{r}
(A %^% B)*C == A %^%  B*C
(A %^% B)*C == A %^% (B*C)
```

$(A\cdot B)C=A\cdot BC\neq A\cdot(BC)$

Note that in package idiom, the inner product is usually denoted `%.%`
but here is `%dot%` (the shorter form causes problems for markdown):

```{r error=TRUE}
A %.% B
```

I have no idea why this occurs.


```{r}
(A %dot% B)*C == A %dot%  B*C
(A %dot% B)*C == A %dot% (B*C)
```


# Page 8

```{r}
a <- as.1vector(1:5)
A <- -7*e(c(1,2)) + e(c(1,3)) - 5*e(c(4,5))
B <-  3*e(c(1,2)) +3*e(c(2,5)) -3*e(c(3,4))
C <-    e(c(2,4)) + 8*e(c(1,5))
```

$A\cdot(B\wedge C) = A\cdot B\wedge C\neq (A\cdot B)\wedge C$


<span style="color: red">Unfortunately the dot product and wedge
product do not have the correct priority:
</span>

```{r}
A %dot% (B %^% C)
A %dot% B %^% C
(A %dot% B) %^% C
c(Mod(A %dot% (B %^% C) - A %dot% B %^% C),Mod((A %dot% B) %^% C - A %dot% B %^% C))
```

<span style="color: darkblue">We say that a multivector $A_+$ is
_even_ if $\gr{A}_r=0$ for all odd values of $r$.  Similarly $A_-$ is
_odd_ of $\gr{A}_r=0$ for even $r$.</span>


$A=A_- + A_+\qquad(1.29)$

In the package:

```{r}
is.even(evenpart(A))
is.odd(oddpart(A))
A == evenpart(A) + oddpart(A)
```

(similarly we have `oddpart()` and `is.odd()`).


If $a$ is a vector and $A$ any multivector:

$aA = a\cdot A + a\wedge A\qquad(1.31)$


```{r}
a*A == a %dot% A + a %^% A
```


# Page 9

```{r p9}
a <- as.1vector(1:5)
b <- as.1vector(c(3,2,7))
```

$a\cdot b=\gr{ab}=\frac{1}{2}(ab + ba)\qquad(1.32)$

```{r p9a}
a %dot% b  # see how it is real
const(a*b)  # or grade(a*b,0)
(a*b + b*a)/2
```

$a\cdot(a_1a_2\ldots a_r) = \sum_{k=1}^r(-1)^{k+1}a\cdot a_k(a_1\ldots\check{a_k}\ldots a_r)\qquad(1.33)$

To illustrate package idiom I will use $n=9$ and $k=6$:

```{r}
a <- as.1vector(rnorm(9))
a1 <- as.1vector(rnorm(9))
a2 <- as.1vector(rnorm(9))
a3 <- as.1vector(rnorm(9))
a4 <- as.1vector(rnorm(9))
a5 <- as.1vector(rnorm(9))
a
```

Then

```{r}
LHS <- a %dot% (a1*a2*a3*a4)
RHS <- (
       +(a %dot% a1)*(   a2*a3*a4)
       -(a %dot% a2)*(a1   *a3*a4)
       +(a %dot% a3)*(a1*a2*   a4)
       -(a %dot% a4)*(a1*a2*a3   )
  )
comp(LHS,RHS)
```

# Page 10

```{r}
a <- as.1vector(rnorm(9))
jj <- GramSchmidt(matrix(rnorm(81),9,9),normalize=FALSE)
max(abs(jj[row(jj) != col(jj)])) # zero -> cols of jj are orthogonal
a1 <- as.1vector(jj[,1])
a2 <- as.1vector(jj[,2])
a3 <- as.1vector(jj[,3])
a4 <- as.1vector(jj[,4])
a1*a2 + a2*a1 # verify anticommutivity
A4 <- a1*a2*a3*a4
```

$a\wedge A_r=aA_r-a\cdot A_r = bA_r\qquad(1.35)$

where $b=a-\sum_{k=1}^ra\cdot a_k a_k^{-1}$.  In package idiom:


```{r}
b <- a - ((a%dot%a1)/a1 + (a%dot%a2)/a2 + (a%dot%a3)/a3 + (a%dot%a4)/a4)
x1 <- a %^% A4
x2 <- a*A4-a %dot% A4
x3 <- b*A4
c(Mod(x1-x2),Mod(x1-x3))
```

the above showing that the discrepancy is zero to within numerical
tolerance.


<span style="color: darkblue">We are now in a position to prove
</span>

$A_rB_s=\gr{A_rB_s}_{|r-s|} + \gr{A_rB_s}_{|r-s|+2}+\cdots + \gr{A_rB_s}_{|r+s|}\qquad(1.36)$

Because of linearity the relation holds for any multivectors.

```{r}
A <- rcliff(d=9,g=3,include.fewer=FALSE)
B <- rcliff(d=9,g=4,include.fewer=FALSE)
p <- A*B
comp(LHS=p, RHS=grade(p,1)+grade(p,3)+grade(p,5)+grade(p,7))
```

# Page 11

```{r}
a <- as.1vector(rnorm(9))

a <- as.1vector(rnorm(9))
jj <- GramSchmidt(matrix(rnorm(81),9,9),normalize=FALSE)
a1 <- as.1vector(jj[,1])
a2 <- as.1vector(jj[,2])
a3 <- as.1vector(jj[,3])
a4 <- as.1vector(jj[,4])
```

$a\cdot(a_1\wedge a_2\wedge\ldots\wedge a_r)=\sum_{k=1}^r(-1)^{k+1}a\cdot a_k a_1\wedge\ldots\wedge\check{a_k}\wedge\ldots\wedge a_r\qquad(1.38)$

```{r}
LHS <- a %dot% (a1 %^% a2 %^% a3 %^% a4)
RHS <- (
       +(a %dot% a1) * (       a2 %^% a3 %^% a4)
       -(a %dot% a2) * (a1        %^% a3 %^% a4)
       +(a %dot% a3) * (a1 %^% a2        %^% a4)
       -(a %dot% a4) * (a1 %^% a2 %^% a3       )
)
comp(LHS,RHS)
```

# Page 12

```{r}
a <- as.1vector(rnorm(6))
Ar <- rcliff(g=3, include.fewer=FALSE)  # r=3
B <- rcliff()  # general multivector
```

<span style="color: darkblue">To our arsenal of formulas, we can add
one more group of identities</span>

$$\begin{aligned}
a\cdot(A_rB) &= a\cdot A_rB + (-1)^rA_ra\cdot B\qquad &(1.41a)\\
&= a\wedge A_rB - (-1)^rA_ra\wedge B\qquad &(1.41b)
\end{aligned}$$

and

$$\begin{aligned}
a\wedge(A_rB) &= a\wedge A_rB + (-1)^rA_ra\cdot B\qquad &(1.41a)\\
&= a\cdot A_rB - (-1)^rA_ra\wedge B\qquad &(1.41b)
\end{aligned}$$


Here we have $r=3$.  For (1.41a) and (1.41b):

```{r}
LHS <- a %dot% (Ar*B)  # note bracketing ; usual idiom would be  a %.% (Ar*B)
RHS1 <- a %dot% Ar*B - Ar*a %dot% B
RHS2 <- a %^% Ar*B + Ar*a %^% B
comp(LHS,RHS1)
comp(LHS,RHS2)
```

For (1.42a) and (1.42b):

```{r}
LHS <- a %^% (Ar*B)  # note bracketing
RHS1 <- a %^% Ar*B + Ar*a %dot% B   # usual idiom a%^% Ar*B + Ar*a%.%B
RHS2 <- a %dot% Ar*B - Ar*a %^% B
c(Mod(LHS),Mod(LHS-RHS1),Mod(LHS-RHS2))
```


# Page 12


```{r}
A <- rcliff(g=4) + as.1vector(rnorm(4))
B <- rcliff(g=4) + as.1vector(rnorm(4))
A
B
```


$A*B=\gr{AB}\qquad(1.44)$

$A*B=\gr{A}\gr{B} + \sum_r\gr{A}_\overline{r}\gr{B}_\overline{r}\qquad(1.46)$


Thus

```{r starstuff}
LHS <- A %star% B
```

```{r rhsstuff}
RHS <- drop(
     const(A) * const(B)                               + 
     grade(A,1,drop=FALSE) %dot% grade(B,1,drop=FALSE) +   
     grade(A,2,drop=FALSE) %dot% grade(B,2,drop=FALSE) +
     grade(A,3,drop=FALSE) %dot% grade(B,3,drop=FALSE) +
     grade(A,4,drop=FALSE) %dot% grade(B,4,drop=FALSE)
    )    
c(LHS,Mod(LHS-RHS))
```

<span style="color: darkblue">we can associate with any multivector
$A$ a unique positive scalar _magnitude_ $|A|$ defined by</span>

$|A|^2=A^\dagger\star A=\sum_r\left|A_\overline{r}\right|^2\geq 0\qquad(1.49)$

In the package, `Mod(x)` is defined as `sqrt(abs(eucprod(x,x)))` and
`eucprod()` is the Euclidean product with
`eucprod(x,y)=grade(x,Conj(y),0)`.  Thus


```{r}
LHS <- Mod(A)^2
RHS <- Conj(A) %star% A
c(LHS,Mod(LHS-RHS))
```

# Page 14

```{R}
A <- rcliff()
B <- rcliff()
C <- rcliff()
```


<span style="color: darkblue">leads immediately to the `law of
cosines':</span>

$\left|A+B\right|^2 = \left|A\right|^2 + 2A^\dagger*B \left|B\right|^2\qquad(1.53a)$

```{r}
LHS <- Mod(A+B)^2
RHS <- Mod(A)^2 + Mod(B)^2 + 2*rev(A) %star% B
c(LHS,RHS-LHS)
```

<span style="color: darkblue">Sometines it is convenient to employ the
_commutator_ product:</span>


$A\times B=\frac{1}{2}(AB-BA)\qquad (1.55)$

```{r e1.55}
A %X% B
```


<span style="color: darkblue">Jacobi identity:</span>

$A\times(B\times C) + B\times(C\times A)+C\times(A\times B)\qquad(1.56c)$


```{r e1.56c}
Mod(A %X% (B %X% C) + B %X% (C %X% A) + C %X% (A %X% B))
```

<span style="color: darkblue">In addition, the commutator is related
to the geometric product by:</span>

$A\times(BC)=(A\times B)C+B(A\times C)\qquad(1.57)$

```{r e1.57}
LHS <- A %X% (B*C)
RHS <- (A %X% B)*C + B*(A %X% C)
c(Mod(LHS),Mod(LHS-RHS))
```

# Page 15

```{r}
a <- as.1vector(rnorm(7))
b <- as.1vector(rnorm(7))
d <- as.1vector(rnorm(7)) # not c
A <- rcliff(n=50,d=5)
A <- A-grade(A,1)   # need <A>_1=0
B <- clifford(asplit(allbinom(5,2),2),rnorm(10))
```


<span style="color: darkblue">we get the Jacobi identity for vectors:</span>

$a\cdot(b\wedge c) + c\cdot(d\wedge a)+c\cdot(a\wedge b)=0\qquad(1.61)$


```{r e1.61}
Mod(a %dot% (b %^% d) + b %dot% (d %^% a) + d %dot% (a %^% b))  # d not c
```

<span style="color: darkblue">Thus we have quite generally</span>

$BA=B\cdot A + B\times A + B\wedge A\qquad (1.63)$



```{r e1.63}
LHS <- B*A
RHS <- B %dot% A + B %X% A + B %^% A
c(Mod(LHS),Mod(LHS-RHS))
```

# Page 16

```{r p16}
A <- rcliff()
B <- clifford(asplit(allbinom(5,2),2),rnorm(10))
C <- rcliff()
a1 <- as.1vector(rnorm(5))
a2 <- as.1vector(rnorm(5))
a3 <- as.1vector(rnorm(5))
b1 <- as.1vector(rnorm(5))
c1 <- as.1vector(rnorm(5))
d1 <- as.1vector(rnorm(5))
```

$B\times(A\cdot C) = (B\times A)\cdot C+ A\cdot(B\times C)\qquad(1.65)$

$B\times(A\wedge C) = (B\times A)\wedge C+ A\wedge(B\times C)\qquad(1.66)$

```{r e1.65}
LHS <- B %X% (A %dot% C)
RHS <- (B %X% A) %dot% C + A %dot% (B %X% C)
c(Mod(LHS),Mod(LHS-RHS))
```

```{r e1.66}
LHS <- B %X% (A %^% C)
RHS <- (B %X% A) %^% C + A %^% (B %X% C)
c(Mod(LHS),Mod(LHS-RHS))
```

$B\times(a_1\wedge\cdots\wedge a_r)=\sum_{k=1}^r(-1)^{k+1}(B\cdot a_k)\wedge a_1\wedge\cdots\check{a_k}\cdots\wedge a_r\qquad (1.67)$

```{r e1.67}
LHS <- B %X% (a1 %^% a2 %^% a3 %^% a4)
RHS <- (
        +(B %dot% a1)        %^% a2 %^% a3 %^% a4 
        -(B %dot% a2) %^% a1        %^% a3 %^% a4  
        +(B %dot% a3) %^% a1 %^% a2        %^% a4  
        -(B %dot% a4) %^% a1 %^% a2 %^% a3
       )	 
c(Mod(LHS),Mod(LHS-RHS))
```

$(a\wedge b)\times(c\wedge d)=a\wedge(b\cdot c\wedge d)-b\wedge(a\cdot c\wedge d)\qquad(1.68)$

```{r e1.68}
LHS <- (a1 %^% b1) %X% (c1 %^% d1)
RHS <- a1 %^% (b1 %dot% (c1 %^% d1)) - b1 %^% (a1 %dot% (c1 %^% d1))
c(Mod(LHS),Mod(LHS-RHS))
```

NB: Bracketing is important here, the wedge product should be carried
out before the dot product.


$(a\wedge b) \times (c\wedge b)=(a\wedge b\wedge c)\cdot b\qquad(1.69)$

```{r e1.69}
LHS <- (a1 %^% b1) %X% (c1 %^% b1)
RHS <- (a1 %^% b1 %^% c1) %dot% b1
c(Mod(LHS),Mod(LHS-RHS))
```

# Page 17

```{r p17}
a1 <- as.1vector(rnorm(4))
a2 <- as.1vector(rnorm(4))
a3 <- as.1vector(rnorm(4))
a4 <- as.1vector(rnorm(4))
```


$a_1\wedge a_2\wedge\cdots\wedge a_n=\lambda I\qquad(2.2)$ 


First establish that the wedge product of these four vectors is a
multiple of $I$:

```{r e2.2}
A <- a1 %^% a2 %^% a3 %^% a4
A
```

Now we take a wedge product of a linear combination of `a1 a2 a3`:

```{r}
c(
Mod((a1 + a2 + a3) %^% (a1-4*a2) %^% (-4*a1 + a2-6*a3) %^% (a2-a3)),
Mod(a1 %^% a2 %^% a3 %^% (rnorm(1)*a1 + rnorm(1)*a2 + rnorm(1)*a3))
)
```

$a_k\wedge A=0\qquad(2.4)$

```{r eq2.4}
c(Mod(a1 %^% A), Mod(a2 %^% A), Mod(a3 %^% A), Mod(a4 %^% A))
```



# Page 18

```{r p18}
a1 <- as.1vector(rnorm(5))
a2 <- as.1vector(rnorm(5))
a3 <- as.1vector(rnorm(5))
a4 <- as.1vector(rnorm(5))
b  <- as.1vector(rnorm(9))
```


$b=bAA^{-1} = (b\cdot A+b\wedge A)A^{-1}$

$b= b_\parallel + b_\perp\qquad(2.8a)$

where

$b_\parallel = P_A(b) = b\cdot AA^{-1}\qquad(2.8b)$

and 

$b_\perp= p_A^\perp(b)=b\wedge AA^{-1}\qquad(2.8c)$

```{r eq2.8b}
A <- a1 %^% a2 %^% a3 %^% a4
A
b_parallel <- (b %dot% A)/A
b_perp <- (b %^% A)/A
zap(b_parallel)
zap(b_perp)
Mod(b-(b_parallel + b_perp))  # zero to numerical precision
```


# Page 19

$\operatorname{dim}\mathcal{G}(A) =
\sum_{r=0}^n\operatorname{dim}\mathcal{G}^r(A)=\sum_{r=0}^n{n\choose r}=2^n$

Try $n=5$:

```{r p16a}
allcliff(5)
nterms(allcliff(7))
```

# Page 20

```{r p20}
A <- as.1vector(rnorm(5)) %^% as.1vector(rnorm(5)) %^% as.1vector(rnorm(5))
I <- A/Mod(A)
Ainv <- -A/eucprod(A)
c(Mod(A*Ainv-1),Mod(Ainv*A-1))
B <- rcliff()
B
```

$P_A(B) = (B\cdot A)\cdot A^{-1} = A^{-1}\cdot(A\cdot B)\qquad(2.9a)$ 

Now the text points out that $P(\gr{B}) = P(\gr{B}_n) = 0$ and indeed:

```{r}
P <- function(B){Ainv %dot% (A %dot% B)}
P(scalar(4444))
P(e(1:3))
```

However, the following equations specify the desired behaviour:

$P(\gr{B}) = \gr{B}\qquad(2.9b)$

$P(\gr{B}_n) = \gr{B}_n\cdot AA^{-1}\qquad(2.9c)$

and Hestenes suggests a couple of ways to ensure desired behaviour.
But in the package, it is easier to use the "fat dot product" `%o%`:


```{r wantedandgot}
x_wanted <- (e(1:3) %dot% A) * Ainv # usual idiom "%.%"
x_got <-  Ainv %o% (A %o% e(1:3))
Mod(x_wanted - x_got)
```

More generally:

```{r discrepancywanted}
disc <- function(B){
  x_wanted <- (B %dot% A) * Ainv # usual idiom "%.%"
  x_got <-  Ainv %o% (A %o% B)
  Mod(x_wanted - x_got)
}

c(
disc(e(c(1,2,3))),
disc(e(c(1,2,4))),
disc(e(c(1,2,5))),
disc(e(c(1,3,4))),
disc(e(c(1,3,5))),
disc(e(c(1,4,5))),
disc(e(c(2,3,4))),
disc(e(c(2,3,5))),
disc(e(c(2,4,5))),
disc(e(c(3,4,5)))
)
```


<span style="color: darkblue">let us consider </span>


$P_A(B_\overline{s})=0\qquad\mbox{if} s>n\qquad(2.10a)$:

```{r defineP}
P <- function(B){Ainv %o% (A %o% B)}
Mod(P(e(1:4))) # should be zero
```

# Page 21


```{r p21}
A <- as.1vector(rnorm(5)) %^% as.1vector(rnorm(5)) %^% as.1vector(rnorm(5))
Ainv <- -A/eucprod(A)
P <- function(B){Ainv %o% (A %o% B)}  # NB %o% not %.% 

(B <- rcliff())
C <- rcliff()
```

$P(\alpha B+\beta C)=\alpha P(A)+\beta P(C)\qquad(2.13a)$

$P(\gr{B}_r)=\gr{P(B)}_r\qquad(2.13b)$

$P(P(B))=P(B)\qquad(2.13c)$

$P(C\wedge B)=P(C)\wedge P(B)\qquad(2.13e)$

$P(BC)=BP(C)\qquad\mbox{if } P(B)\qquad(2.13e)$

```{r p21verify}
comp(P(1.1*B + 2.5234*C), 1.1*P(B) + 2.5234*P(C))
comp(P(grade(B,2)), grade(P(B),2))
comp(P(B),P(P(B)))
comp(P(C %^% B),P(C) %^% P(B))
comp(P(P(B)*C), P(B)*P(C))
```

<span style="color: darkblue">two important special cases </span>

$BA=B\wedge A\qquad(2.14a)$

implies 

$P_{BA}=P_B+P_A\qquad(2.14b)$

and

$P_BP_A=P_AP_B=0\qquad(2.14c)$

```{r p21eq2.14}

A <- e(1) + e(2)
B <- e(1) - e(2)

Ainv <- A/2
Binv <- B/2

comp(A*B, A%^%B)
```

So we would expect $P_{BA}= P_B+P_A$:

```{r pbapbpluspa}
P_A <- function(x){Ainv %o% (A %o% x)} 
P_B <- function(x){Binv %o% (B %o% x)} 
P_AB <- function(x){(Binv*Ainv) %o% ((A*B) %o% x)} 
P_BA <- function(x){(Ainv*Binv) %o% ((B*A) %o% x)} 
P_AP_B <- function(x){P_A(P_B(x))}
P_BP_A <- function(x){P_B(P_A(x))}
x <- rcliff(d=4)

A*Ainv
Ainv*A
B*Binv
Binv*B
(A*B)*(Binv*Ainv)

comp(P_BA(x),P_B(x)+P_A(x))

P_A(x) * P_B(x)  # should be zero
```