diff --git a/books/bookvol10.3.pamphlet b/books/bookvol10.3.pamphlet
index d0892ca..9710e46 100644
--- a/books/bookvol10.3.pamphlet
+++ b/books/bookvol10.3.pamphlet
@@ -29358,16 +29358,16 @@ o )show File
 \cross{FILE}{coerce} &
 \cross{FILE}{flush} &
 \cross{FILE}{hash} &
-\cross{FILE}{iomode} &
-\cross{FILE}{latex} \\
+\cross{FILE}{iomode} \\
+\cross{FILE}{latex} &
 \cross{FILE}{name} &
 \cross{FILE}{open} &
 \cross{FILE}{readIfCan!} &
-\cross{FILE}{read!} &
-\cross{FILE}{reopen!} \\
+\cross{FILE}{read!} \\
+\cross{FILE}{reopen!} &
 \cross{FILE}{write!} &
 \cross{FILE}{?=?} &
-\cross{FILE}{?\~{}=?} &&
+\cross{FILE}{?\~{}=?} &
 \end{tabular}
 
 <<domain FILE File>>=
@@ -41538,6 +41538,1344 @@ GraphImage (): Exports == Implementation where
 
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\section{domain GRAS GrassmannAlgebra}
+<<GrassmannAlgebra.input>>=
+)set break resume
+)sys rm -f GrassmannAlgebra.output
+)spool GrassmannAlgebra.output
+)set message test on
+)set message auto off
+)set break resume
+)clear all
+-- two D Euclidean space
+--S 1 of 32
+B1 := GrassmannAlgebra(2,Fraction(Integer),[[1,0],[0,1]])
+--R 
+--R
+--R   (1)  GrassmannAlgebra(2,Fraction Integer,MATRIX)
+--R                                                                 Type: Domain
+--E 1
+
+-- two D Hyperbolic space
+--S 2 of 32
+B2 := GrassmannAlgebra(2,Fraction(Integer),[[0,1],[1,0]])
+--R 
+--R
+--R   (2)  GrassmannAlgebra(2,Fraction Integer,MATRIX)
+--R                                                                 Type: Domain
+--E 2
+
+-- non-orthogonal
+--S 3 of 32
+B3 := GrassmannAlgebra(2,Expression(Fraction(Integer)),[[1,q],[-q,1]])
+--R 
+--R
+--R   (3)  GrassmannAlgebra(2,Expression Fraction Integer,MATRIX)
+--R                                                                 Type: Domain
+--E 3
+
+-- with anti-symmetric bilinear part
+--S 4 of 32
+B4 := GrassmannAlgebra(2,Expression(Fraction(Integer)),[[0,1/2+q],[1/2-q,0]])
+--R 
+--R
+--R   (4)  GrassmannAlgebra(2,Expression Fraction Integer,MATRIX)
+--R                                                                 Type: Domain
+--E 4
+
+--
+-- the following are results for 2D Euclidean space
+-- wedge for 2D Euclidean space
+--S 5 of 32
+toTable(/\)$B1
+--R 
+--R
+--R        + 1      e      e    e e +
+--R        |         1      2    1 2|
+--R        |                        |
+--R        | e      0     e e    0  |
+--R        |  1            1 2      |
+--R   (5)  |                        |
+--R        | e    - e e    0     0  |
+--R        |  2      1 2            |
+--R        |                        |
+--R        |e e     0      0     0  |
+--R        + 1 2                    +
+--R                     Type: Matrix GrassmannAlgebra(2,Fraction Integer,MATRIX)
+--E 5
+
+--
+-- regression for 2D Euclidean space
+--S 6 of 32
+toTable(\/)$B1
+--R 
+--R
+--R        +0   0   0    1  +
+--R        |                |
+--R        |0   0   1    e  |
+--R        |              1 |
+--R   (6)  |                |
+--R        |0  - 1  0    e  |
+--R        |              2 |
+--R        |                |
+--R        |1  e    e   e e |
+--R        +    1    2   1 2+
+--R                     Type: Matrix GrassmannAlgebra(2,Fraction Integer,MATRIX)
+--E 6
+
+--
+-- clifford multipication for 2D Euclidean space
+--S 7 of 32
+toTable(*)$B1
+--R 
+--R
+--R        + 1      e      e    e e +
+--R        |         1      2    1 2|
+--R        |                        |
+--R        | e      1     e e    e  |
+--R        |  1            1 2    2 |
+--R   (7)  |                        |
+--R        | e    - e e    1    - e |
+--R        |  2      1 2           1|
+--R        |                        |
+--R        |e e    - e     e    - 1 |
+--R        + 1 2      2     1       +
+--R                     Type: Matrix GrassmannAlgebra(2,Fraction Integer,MATRIX)
+--E 7
+
+--
+-- left contraction for 2D Euclidean space
+--S 8 of 32
+toTable(lc)$B1
+--R 
+--R
+--R        +1  e   e   e e +
+--R        |    1   2   1 2|
+--R        |               |
+--R        |0  1   0    e  |
+--R   (8)  |             2 |
+--R        |               |
+--R        |0  0   1   - e |
+--R        |              1|
+--R        |               |
+--R        +0  0   0   - 1 +
+--R                     Type: Matrix GrassmannAlgebra(2,Fraction Integer,MATRIX)
+--E 8
+
+--
+-- right contraction for 2D Euclidean space
+--S 9 of 32
+toTable(rc)$B1
+--R 
+--R
+--R        + 1     0    0    0 +
+--R        |                   |
+--R        | e     1    0    0 |
+--R        |  1                |
+--R   (9)  |                   |
+--R        | e     0    1    0 |
+--R        |  2                |
+--R        |                   |
+--R        |e e   - e   e   - 1|
+--R        + 1 2     2   1     +
+--R                     Type: Matrix GrassmannAlgebra(2,Fraction Integer,MATRIX)
+--E 9
+
+--
+-- dual for 2D Euclidean space
+--S 10 of 32
+toTable(~)$B1
+--R 
+--R
+--R         + 1    e    e    e e +
+--R         |       1    2    1 2|
+--R   (10)  |                    |
+--R         |e e   e   - e   - 1 |
+--R         + 1 2   2     1      +
+--R                     Type: Matrix GrassmannAlgebra(2,Fraction Integer,MATRIX)
+--E 10
+
+--
+-- grade Involution for 2D Euclidean space
+--S 11 of 32
+toTable(gradeInvolution)$B1
+--R 
+--R
+--R         +1   e     e    e e +
+--R         |     1     2    1 2|
+--R   (11)  |                   |
+--R         |1  - e   - e   e e |
+--R         +      1     2   1 2+
+--R                     Type: Matrix GrassmannAlgebra(2,Fraction Integer,MATRIX)
+--E 11
+
+--
+-- the following are results for 2D Hyperbolic space
+-- wedge for 2D Hyperbolic space
+--S 12 of 32
+toTable(/\)$B2
+--R 
+--R
+--R         + 1      e      e    e e +
+--R         |         1      2    1 2|
+--R         |                        |
+--R         | e      0     e e    0  |
+--R         |  1            1 2      |
+--R   (12)  |                        |
+--R         | e    - e e    0     0  |
+--R         |  2      1 2            |
+--R         |                        |
+--R         |e e     0      0     0  |
+--R         + 1 2                    +
+--R                     Type: Matrix GrassmannAlgebra(2,Fraction Integer,MATRIX)
+--E 12
+
+--
+-- regression for 2D Hyperbolic space
+--S 13 of 32
+toTable(\/)$B2
+--R 
+--R
+--R         +0   0   0    1  +
+--R         |                |
+--R         |0   0   1    e  |
+--R         |              1 |
+--R   (13)  |                |
+--R         |0  - 1  0    e  |
+--R         |              2 |
+--R         |                |
+--R         |1  e    e   e e |
+--R         +    1    2   1 2+
+--R                     Type: Matrix GrassmannAlgebra(2,Fraction Integer,MATRIX)
+--E 13
+
+--
+-- clifford multipication for 2D Hyperbolic space
+--S 14 of 32
+toTable(*)$B2
+--R 
+--R
+--R         + 1       e         e      e e +
+--R         |          1         2      1 2|
+--R         |                              |
+--R         | e       0      1 + e e   - e |
+--R         |  1                  1 2     1|
+--R   (14)  |                              |
+--R         | e    1 - e e      0       e  |
+--R         |  2        1 2              2 |
+--R         |                              |
+--R         |e e      e        - e      1  |
+--R         + 1 2      1          2        +
+--R                     Type: Matrix GrassmannAlgebra(2,Fraction Integer,MATRIX)
+--E 14
+
+--
+-- left contraction for 2D Hyperbolic space
+--S 15 of 32
+toTable(lc)$B2
+--R 
+--R
+--R         +1  e   e   e e +
+--R         |    1   2   1 2|
+--R         |               |
+--R         |0  0   1   - e |
+--R   (15)  |              1|
+--R         |               |
+--R         |0  1   0    e  |
+--R         |             2 |
+--R         |               |
+--R         +0  0   0    1  +
+--R                     Type: Matrix GrassmannAlgebra(2,Fraction Integer,MATRIX)
+--E 15
+
+--
+-- right contraction for 2D Hyperbolic space
+--S 16 of 32
+toTable(rc)$B2
+--R 
+--R
+--R         + 1    0    0    0+
+--R         |                 |
+--R         | e    0    1    0|
+--R         |  1              |
+--R   (16)  |                 |
+--R         | e    1    0    0|
+--R         |  2              |
+--R         |                 |
+--R         |e e   e   - e   1|
+--R         + 1 2   1     2   +
+--R                     Type: Matrix GrassmannAlgebra(2,Fraction Integer,MATRIX)
+--E 16
+
+--
+-- dual for 2D Hyperbolic space
+--S 17 of 32
+toTable(~)$B2
+--R 
+--R
+--R         + 1     e    e   e e +
+--R         |        1    2   1 2|
+--R   (17)  |                    |
+--R         |e e   - e   e    1  |
+--R         + 1 2     1   2      +
+--R                     Type: Matrix GrassmannAlgebra(2,Fraction Integer,MATRIX)
+--E 17
+
+--
+-- grade Involution for 2D Euclidean space
+--S 18 of 32
+toTable(gradeInvolution)$B2
+--R 
+--R
+--R         +1   e     e    e e +
+--R         |     1     2    1 2|
+--R   (18)  |                   |
+--R         |1  - e   - e   e e |
+--R         +      1     2   1 2+
+--R                     Type: Matrix GrassmannAlgebra(2,Fraction Integer,MATRIX)
+--E 18
+
+--
+-- the following are results for 2D non-orthogonal
+-- wedge for 2D non-orthogonal space
+--S 19 of 32
+toTable(/\)$B3
+--R 
+--R
+--R         + 1      e      e    e e +
+--R         |         1      2    1 2|
+--R         |                        |
+--R         | e      0     e e    0  |
+--R         |  1            1 2      |
+--R   (19)  |                        |
+--R         | e    - e e    0     0  |
+--R         |  2      1 2            |
+--R         |                        |
+--R         |e e     0      0     0  |
+--R         + 1 2                    +
+--R          Type: Matrix GrassmannAlgebra(2,Expression Fraction Integer,MATRIX)
+--E 19
+
+--
+-- regression for 2D non-orthogonal space
+--S 20 of 32
+toTable(\/)$B3
+--R 
+--R
+--R   (20)
+--R            4     2          3
+--R   [[0,0,0,q  + 2q  + 1 + (2q  + 2q)e e ],
+--R                                     1 2
+--R          4     2          3               4             3
+--R    [0,0,q  + 2q  + 1 + (2q  + 2q)e e ,(- q  + 1)e  + (2q  + 2q)e ],
+--R                                   1 2            1              2
+--R          4     2            3                  3               4
+--R    [0,- q  - 2q  - 1 + (- 2q  - 2q)e e ,0,(- 2q  - 2q)e  + (- q  + 1)e ],
+--R                                     1 2                1              2
+--R
+--R       4     2          3                4             3
+--R     [q  + 2q  + 1 + (2q  + 2q)e e , (- q  + 1)e  + (2q  + 2q)e ,
+--R                                1 2             1              2
+--R           3               4             5     3             4     2
+--R      (- 2q  - 2q)e  + (- q  + 1)e , - 4q  - 8q  - 4q + (- 7q  - 6q  + 1)e e ]
+--R                   1              2                                       1 2
+--R     ]
+--R          Type: Matrix GrassmannAlgebra(2,Expression Fraction Integer,MATRIX)
+--E 20
+
+--
+-- clifford multipication for 2D non-orthogonal space
+--S 21 of 32
+toTable(*)$B3
+--R 
+--R
+--R         + 1        e           e              e e        +
+--R         |           1           2              1 2       |
+--R         |                                                |
+--R         | e         1       q + e e       - q e  + e     |
+--R         |  1                     1 2           1    2    |
+--R   (21)  |                                                |
+--R         | e    - q - e e        1         - e  - q e     |
+--R         |  2          1 2                    1      2    |
+--R         |                                                |
+--R         |                                 2              |
+--R         |e e   - q e  - e   e  - q e   - q  - 1 - 2q e e |
+--R         + 1 2       1    2   1      2                 1 2+
+--R          Type: Matrix GrassmannAlgebra(2,Expression Fraction Integer,MATRIX)
+--E 21
+
+--
+-- left contraction for 2D non-orthogonal space
+--S 22 of 32
+toTable(lc)$B3
+--R 
+--R
+--R         +1  e    e      e e     +
+--R         |    1    2      1 2    |
+--R         |                       |
+--R         |0   1   q   - q e  + e |
+--R         |                 1    2|
+--R   (22)  |                       |
+--R         |0  - q  1   - e  - q e |
+--R         |               1      2|
+--R         |                       |
+--R         |                2      |
+--R         +0   0   0    - q  - 1  +
+--R          Type: Matrix GrassmannAlgebra(2,Expression Fraction Integer,MATRIX)
+--E 22
+
+--
+-- right contraction for 2D non-orthogonal space
+--S 23 of 32
+toTable(rc)$B3
+--R 
+--R
+--R         + 1         0           0         0    +
+--R         |                                      |
+--R         | e         1           q         0    |
+--R         |  1                                   |
+--R         |                                      |
+--R   (23)  | e        - q          1         0    |
+--R         |  2                                   |
+--R         |                                      |
+--R         |                                 2    |
+--R         |e e   - q e  - e   e  - q e   - q  - 1|
+--R         + 1 2       1    2   1      2          +
+--R          Type: Matrix GrassmannAlgebra(2,Expression Fraction Integer,MATRIX)
+--E 23
+
+--
+-- dual for 2D non-orthogonal space
+--S 24 of 32
+toTable(~)$B3
+--R 
+--R
+--R         + 1        e            e               e e        +
+--R         |           1            2               1 2       |
+--R   (24)  |                                                  |
+--R         |                                   2              |
+--R         |e e   - q e  + e   - e  - q e   - q  - 1 - 2q e e |
+--R         + 1 2       1    2     1      2                 1 2+
+--R          Type: Matrix GrassmannAlgebra(2,Expression Fraction Integer,MATRIX)
+--E 24
+
+--
+-- grade Involution for 2D non-orthogonal space
+--S 25 of 32
+toTable(gradeInvolution)$B3
+--R 
+--R
+--R         +1   e     e    e e +
+--R         |     1     2    1 2|
+--R   (25)  |                   |
+--R         |1  - e   - e   e e |
+--R         +      1     2   1 2+
+--R          Type: Matrix GrassmannAlgebra(2,Expression Fraction Integer,MATRIX)
+--E 25
+
+--
+-- the following are results for 2D with anti-symmetric bilinear part
+-- wedge for 2D part anti-symmetric bilinear space
+--S 26 of 32
+toTable(/\)$B4
+--R 
+--R
+--R         + 1      e      e    e e +
+--R         |         1      2    1 2|
+--R         |                        |
+--R         | e      0     e e    0  |
+--R         |  1            1 2      |
+--R   (26)  |                        |
+--R         | e    - e e    0     0  |
+--R         |  2      1 2            |
+--R         |                        |
+--R         |e e     0      0     0  |
+--R         + 1 2                    +
+--R          Type: Matrix GrassmannAlgebra(2,Expression Fraction Integer,MATRIX)
+--E 26
+
+--
+-- regression for 2D part anti-symmetric bilinear space
+--S 27 of 32
+toTable(\/)$B4
+--R 
+--R
+--R   (27)
+--R            4   1  2    1      3   1
+--R   [[0,0,0,q  - - q  + -- + (2q  - - q)e e ],
+--R                2      16          2    1 2
+--R          4   1  2    1      3   1            4    3   1      1
+--R    [0,0,q  - - q  + -- + (2q  - - q)e e ,(- q  - q  + - q + --)e ],
+--R              2      16          2    1 2              4     16  1
+--R          4   1  2    1        3   1              4    3   1      1
+--R    [0,- q  + - q  - -- + (- 2q  + - q)e e ,0,(- q  + q  - - q + --)e ],
+--R              2      16            2    1 2                4     16  2
+--R
+--R       4   1  2    1      3   1             4    3   1      1
+--R     [q  - - q  + -- + (2q  - - q)e e , (- q  - q  + - q + --)e ,
+--R           2      16          2    1 2               4     16  1
+--R          4    3   1      1         5     3   1          4   3  2    1
+--R      (- q  + q  - - q + --)e , - 4q  + 2q  - - q + (- 7q  + - q  + --)e e ]
+--R                   4     16  2                4              2      16  1 2
+--R     ]
+--R          Type: Matrix GrassmannAlgebra(2,Expression Fraction Integer,MATRIX)
+--E 27
+
+--
+-- clifford multipication for 2D part anti-symmetric bilinear space
+--S 28 of 32
+toTable(*)$B4
+--R 
+--R
+--R         + 1          e              e               e e        +
+--R         |             1              2               1 2       |
+--R         |                                                      |
+--R         |                          1                   1       |
+--R         | e          0         q + - + e e      (- q - -)e     |
+--R         |  1                       2    1 2            2  1    |
+--R   (28)  |                                                      |
+--R         |            1                                 1       |
+--R         | e    - q + - - e e        0           (- q + -)e     |
+--R         |  2         2    1 2                          2  2    |
+--R         |                                                      |
+--R         |              1              1         2   1          |
+--R         |e e    (- q + -)e     (- q - -)e    - q  + - - 2q e e |
+--R         + 1 2          2  1           2  2          4       1 2+
+--R          Type: Matrix GrassmannAlgebra(2,Expression Fraction Integer,MATRIX)
+--E 28
+
+--
+-- left contraction for 2D part anti-symmetric bilinear space
+--S 29 of 32
+toTable(lc)$B4
+--R 
+--R
+--R         +1    e       e        e e     +
+--R         |      1       2        1 2    |
+--R         |                              |
+--R         |                1         1   |
+--R         |0     0     q + -  (- q - -)e |
+--R         |                2         2  1|
+--R   (29)  |                              |
+--R         |         1                1   |
+--R         |0  - q + -    0    (- q + -)e |
+--R         |         2                2  2|
+--R         |                              |
+--R         |                       2   1  |
+--R         |0     0       0     - q  + -  |
+--R         +                           4  +
+--R          Type: Matrix GrassmannAlgebra(2,Expression Fraction Integer,MATRIX)
+--E 29
+
+--
+-- right contraction for 2D part anti-symmetric bilinear space
+--S 30 of 32
+toTable(rc)$B4
+--R 
+--R
+--R         + 1         0            0          0    +
+--R         |                                        |
+--R         |                          1             |
+--R         | e         0          q + -        0    |
+--R         |  1                       2             |
+--R         |                                        |
+--R   (30)  |              1                         |
+--R         | e      - q + -         0          0    |
+--R         |  2           2                         |
+--R         |                                        |
+--R         |             1            1        2   1|
+--R         |e e   (- q + -)e   (- q - -)e   - q  + -|
+--R         + 1 2         2  1         2  2         4+
+--R          Type: Matrix GrassmannAlgebra(2,Expression Fraction Integer,MATRIX)
+--E 30
+
+--
+-- dual for 2D part anti-symmetric bilinear space
+--S 31 of 32
+toTable(~)$B4
+--R 
+--R
+--R         + 1        e            e               e e        +
+--R         |           1            2               1 2       |
+--R   (31)  |                                                  |
+--R         |             1            1        2   1          |
+--R         |e e   (- q - -)e   (- q + -)e   - q  + - - 2q e e |
+--R         + 1 2         2  1         2  2         4       1 2+
+--R          Type: Matrix GrassmannAlgebra(2,Expression Fraction Integer,MATRIX)
+--E 31
+
+--
+-- grade Involution for 2D part anti-symmetric bilinear space
+--S 32 of 32
+toTable(gradeInvolution)$B4
+--R 
+--R
+--R         +1   e     e    e e +
+--R         |     1     2    1 2|
+--R   (32)  |                   |
+--R         |1  - e   - e   e e |
+--R         +      1     2   1 2+
+--R          Type: Matrix GrassmannAlgebra(2,Expression Fraction Integer,MATRIX)
+--E 32
+
+)spool
+)lisp (bye)
+@
+<<GrassmannAlgebra.help>>=
+====================================================================
+GrassmannAlgebra
+====================================================================
+
+-- two D Euclidean space
+B1 := GrassmannAlgebra(2,Fraction(Integer),[[1,0],[0,1]])
+
+-- two D Hyperbolic space
+B2 := GrassmannAlgebra(2,Fraction(Integer),[[0,1],[1,0]])
+
+-- non-orthogonal
+B3 := GrassmannAlgebra(2,Expression(Fraction(Integer)),[[1,q],[-q,1]])
+
+-- with anti-symmetric bilinear part
+B4 := GrassmannAlgebra(2,Expression(Fraction(Integer)),[[0,1/2+q],[1/2-q,0]])
+
+--
+-- the following are results for 2D Euclidean space
+-- wedge for 2D Euclidean space
+toTable(/\)$B1
+
+--
+-- regression for 2D Euclidean space
+toTable(\/)$B1
+
+--
+-- clifford multipication for 2D Euclidean space
+toTable(*)$B1
+
+--
+-- left contraction for 2D Euclidean space
+toTable(lc)$B1
+
+--
+-- right contraction for 2D Euclidean space
+toTable(rc)$B1
+
+--
+-- dual for 2D Euclidean space
+toTable(~)$B1
+
+--
+-- grade Involution for 2D Euclidean space
+toTable(gradeInvolution)$B1
+
+--
+-- the following are results for 2D Hyperbolic space
+-- wedge for 2D Hyperbolic space
+toTable(/\)$B2
+
+--
+-- regression for 2D Hyperbolic space
+toTable(\/)$B2
+
+--
+-- clifford multipication for 2D Hyperbolic space
+toTable(*)$B2
+
+--
+-- left contraction for 2D Hyperbolic space
+toTable(lc)$B2
+
+--
+-- right contraction for 2D Hyperbolic space
+toTable(rc)$B2
+
+--
+-- dual for 2D Hyperbolic space
+toTable(~)$B2
+
+--
+-- grade Involution for 2D Euclidean space
+toTable(gradeInvolution)$B2
+
+--
+-- the following are results for 2D non-orthogonal
+-- wedge for 2D non-orthogonal space
+toTable(/\)$B3
+
+--
+-- regression for 2D non-orthogonal space
+toTable(\/)$B3
+
+--
+-- clifford multipication for 2D non-orthogonal space
+toTable(*)$B3
+
+--
+-- left contraction for 2D non-orthogonal space
+toTable(lc)$B3
+
+--
+-- right contraction for 2D non-orthogonal space
+toTable(rc)$B3
+
+--
+-- dual for 2D non-orthogonal space
+toTable(~)$B3
+
+--
+-- grade Involution for 2D non-orthogonal space
+toTable(gradeInvolution)$B3
+
+--
+-- the following are results for 2D with anti-symmetric bilinear part
+-- wedge for 2D part anti-symmetric bilinear space
+toTable(/\)$B4
+
+--
+-- regression for 2D part anti-symmetric bilinear space
+toTable(\/)$B4
+
+--
+-- clifford multipication for 2D part anti-symmetric bilinear space
+toTable(*)$B4
+
+--
+-- left contraction for 2D part anti-symmetric bilinear space
+toTable(lc)$B4
+
+--
+-- right contraction for 2D part anti-symmetric bilinear space
+toTable(rc)$B4
+
+--
+-- dual for 2D part anti-symmetric bilinear space
+toTable(~)$B4
+
+--
+-- grade Involution for 2D part anti-symmetric bilinear space
+toTable(gradeInvolution)$B4
+
+See Also:
+o )show GrassmannAlgebra
+
+@
+\pagehead{GrassmannAlgebra}{GRAS}
+\pagepic{ps/v103grassmannalgebra.ps}{GRAS}{1.00}
+
+{\bf Exports:}\\
+\begin{tabular}{lll}
+\cross{GRAS}{characteristic} &
+\cross{GRAS}{coefficient} &
+\cross{GRAS}{coerce} \\
+\cross{GRAS}{e} &
+\cross{GRAS}{eFromBinaryMap} &
+\cross{GRAS}{ePseudoscalar} \\
+\cross{GRAS}{grade} &
+\cross{GRAS}{gradeInvolution} &
+\cross{GRAS}{hash} \\
+\cross{GRAS}{latex} &
+\cross{GRAS}{lc} &
+\cross{GRAS}{monomial} \\
+\cross{GRAS}{one?} &
+\cross{GRAS}{rc} &
+\cross{GRAS}{recip} \\
+\cross{GRAS}{sample} &
+\cross{GRAS}{subtractIfCan} &
+\cross{GRAS}{toTable} \\
+\cross{GRAS}{zero?} &
+\cross{GRAS}{\~{}?} &
+\cross{GRAS}{?\~{}=?} \\
+\cross{GRAS}{?\^{}?} &
+\cross{GRAS}{?*?} &
+\cross{GRAS}{?**?} \\
+\cross{GRAS}{?+?} &
+\cross{GRAS}{?-?} &
+\cross{GRAS}{-?} \\
+\cross{GRAS}{?$/\backslash{}$?} &
+\cross{GRAS}{?=?} &
+\cross{GRAS}{1} \\
+\cross{GRAS}{0} &
+\cross{GRAS}{?\/?} &
+\end{tabular}
+
+<<domain GRAS GrassmannAlgebra>>=
+)abbrev domain GRAS GrassmannAlgebra
+++ Author: Martin Baker (adapted from a version by Stephen M. Watt)
+++ Date Created: August 1988
+++ Date Last Updated: Dec 2009
+++ Basic Operations: wholeRadix, fractRadix, wholeRagits, fractRagits
+++ Related Domains: QuadraticForm, Quaternion, Complex
+++ Also See:
+++ AMS Classifications:
+++ Keywords: clifford algebra, grassmann algebra, spin algebra
+++ Examples:
+++ References:
+++
+++ Description:
+++ GrassmannAlgebra(n, K, bLin) defines a vector space of dimension \spad{2^n}
+++ over K, given a bilinear form bLin on \spad{K^n}.
+++
+++ If \spad{e[i]}, \spad{1<=i<=n} is a basis for \spad{K^n} then\br
+++ \tab{5}1, \spad{e[i]} (\spad{1<=i<=n}), \spad{e[i1]*e[i2]}\br
+++ \tab{5}(\spad{1<=i1<i2<=n}),...,\spad{e[1]*e[2]*..*e[n]}\br
+++ is a basis for the Clifford Algebra.
+++
+++ The algebra is defined by the relations\br
+++ \tab{5}\spad{e[i]*e[j] = -e[j]*e[i]}  (\spad{i \~~= j}),\br
+++ \tab{5}\spad{e[i]*e[i] = Q(e[i])}
+++
+++ Examples of Clifford Algebras are: gaussians, quaternions, exterior
+++ algebras and spin algebras.
+
+GrassmannAlgebra(n, K, bLin): T == Impl where
+ n: PositiveInteger
+ K: Field
+ bLin: SquareMatrix(n, K)
+
+ PI ==> PositiveInteger
+ NNI==> NonNegativeInteger
+ SINT==> SingleInteger
+
+ T ==> Join(Ring, Algebra(K)) with
+   e: PI -> %
+     ++ e(n) produces the appropriate unit element.
+     ++        iz   z
+     ++ e(1) = 1    e1
+     ++ e(2) = 2    e2
+     ++ e(3) = 4    e3
+   eFromBinaryMap: NNI -> %
+     ++ eFromBinaryMap(n) sets the appropriate unit elements, for example:
+     ++ eFromBinaryMap(0) = 1  (scalar)
+     ++ eFromBinaryMap(1) = e1
+     ++ eFromBinaryMap(2) = e2
+     ++ eFromBinaryMap(3) = e1*e2
+   ePseudoscalar: () -> %
+     ++ unit pseudoscalar
+   grade: (%) -> NNI
+     ++ return the max grade of multivector, for example
+     ++ 1 is grade 0
+     ++ e1 is grade 1
+     ++ e1^e2 is grade 2 and so on
+   monomial: (K, List PI) -> %
+     ++ monomial(c,[i1,i2,...,iN]) produces the value given by
+     ++ \spad{c*e(i1)*e(i2)*...*e(iN)}.
+   coefficient:  (%, List PI) -> K
+     ++ coefficient(x,[i1,i2,...,iN])  extracts the coefficient of
+     ++ \spad{e(i1)*e(i2)*...*e(iN)} in x.
+   recip: % -> Union(%, "failed")
+     ++ recip(x) computes the multiplicative inverse of x or "failed"
+     ++ if x is not invertible.
+   toTable: ((%, %) -> %) -> Matrix %
+     ++ displays multiplication table for binary operation which
+     ++ is represented as a function with two parameters.
+     ++ row number represents first operand in binary order
+     ++ column number represents second operand in binary order
+     ++ could have returned type 'List List %' but matrix displays better
+
+   toTable: ((%) -> %) -> Matrix %
+     ++ displays table of unary function such as inverse, reverse,
+     ++ complement, or dual basis
+     ++ could have returned type 'List List %' but matrix displays better
+     ++
+     ++X toTable(*)$GrassmanAlgebra(2,Fraction(Integer),[[1,0],[0,1]])
+
+   _/_\: (%, %) -> %
+     ++ Implement exterior grassmann product operator
+     ++ need to check precidence when used as an infix operator
+   _\_/: (%, %) -> %
+     ++ Implement regressive inner,meet product operator
+     ++ need to check precidence when used as an infix operator
+   lc: (%, %) -> %
+     ++ left contraction inner product
+   rc: (%, %) -> %
+     ++ right contraction inner product
+   _~: (%) -> %
+     ++ reverse, complement,canonical dual basis
+   gradeInvolution: (%) -> %
+     ++ x = ((-1)^grade(x))*x
+   -- the following are local functions but I added them here
+   -- during debugging only
+   --lcProdTerm: (K,SINT,K,SINT) -> % 
+   --leftMostBase: (SINT) -> SINT
+   --rightMostBase: (SINT) -> SINT
+
+ Impl ==> add
+   Qeelist:Vector K :=  diagonal(bLin)::Vector K --$SquareMatrix
+     ++ contains the diagonal terms of bLin (what the base vectors 
+     ++ square to)
+   dim     :=  2**n
+     ++ the dimension of all the grades from scalar up
+   Rep     := PrimitiveArray K
+     ++ array of Field which can hold the multivector values
+   New     ==> new(dim, 0$K)$Rep
+     ++ macro to create a new multivector
+   x, y, z: %
+     ++ working values for operations
+   c: K
+     ++ field multiplier
+   m: Integer
+     ++ integer multiplier
+
+   characteristic() == characteristic()$K
+   dimension(): CardinalNumber == dim::CardinalNumber
+
+   x = y ==
+       for i in 0..dim-1 repeat
+           if x.i ~= y.i then return false
+       true
+
+   x + y == (z := New; for i in 0..dim-1 repeat z.i := x.i + y.i; z)
+   x - y == (z := New; for i in 0..dim-1 repeat z.i := x.i - y.i; z)
+   - x   == (z := New; for i in 0..dim-1 repeat z.i := - x.i; z)
+   m * x == (z := New; for i in 0..dim-1 repeat z.i := m*x.i; z)
+   c * x == (z := New; for i in 0..dim-1 repeat z.i := c*x.i; z)
+   -- we want module over non-commutative
+   -- but no available signatures for:
+   --x * m == (z := New; for i in 0..dim-1 repeat z.i := x*m.i; z)
+   --x * c == (z := New; for i in 0..dim-1 repeat z.i := x*c.i; z)
+
+   0            == New
+   1            == (z := New; z.0 := 1; z)
+   coerce(m): % == (z := New; z.0 := m::K; z)
+   coerce(c): % == (z := New; z.0 := c; z)
+
+   -- e(n) produces the appropriate unit element.
+   --        iz   z
+   -- e(1) = 1    e1
+   -- e(2) = 2    e2
+   -- e(3) = 4    e3
+   e b ==
+       b::NNI > n => error "No such basis element"
+       iz := 2**((b-1)::NNI)
+       z := New; z.iz := 1; z
+
+   -- eFromBinaryMap(n) sets the appropriate unit elements, for example,
+   -- eFromBinaryMap(0) = 1  (scalar)
+   -- eFromBinaryMap(1) = e1
+   -- eFromBinaryMap(2) = e2
+   -- eFromBinaryMap(3) = e1*e2
+   eFromBinaryMap b ==
+       b >= dim => error "Too big"
+       z := New; z.b := 1; z
+
+   -- unit pseudoscalar
+   ePseudoscalar() ==
+       p := New
+       i := (dim-1)::NNI
+       p.i := 1
+       p
+
+   -- displays multiplication table for binary operation which
+   -- is represented as a function with two parameters.
+   -- row number represents first operand in binary order
+   -- column number represents second operand in binary order
+   -- could have returned type 'List List %' but matrix displays better
+   toTable(fn:(%, %) -> %) ==
+     l: List % := [eFromBinaryMap(i) for i in 0..dim-1]
+     matrix [[fn(k,j) for j in l] for k in l]
+
+   -- displays table of unary function such as inverse, reverse, 
+   -- complement, or dual basis
+   -- could have returned type 'List List %' but matrix displays better
+   toTable(fn:(%) -> %) ==
+     l: List % := [eFromBinaryMap(i) for i in 0..dim-1]
+     matrix [[j for j in l],[fn(k) for k in l]]
+
+   -- return the grade of the term, for example
+   -- 1 is grade 0
+   -- e1 is grade 1
+   -- e1^e2 is grade 2 and so on
+   gradeTerm(b:SINT): NNI ==
+     grade:NNI := 0
+     for i in 0..n-1 repeat
+       if bit?(b,i) then grade := grade + 1
+     grade
+
+   -- return the max grade of multivector, for example
+   -- 1 is grade 0
+   -- e1 is grade 1
+   -- e1^e2 is grade 2 and so on
+   grade(x:%): NNI ==
+     gr:NNI := 0         
+     for ix in 0..dim-1 repeat
+       if x.ix ~= 0 then
+         gr := max(gr,gradeTerm(ix::SINT))
+     gr
+
+   -- implements gradeInvolution for a single term by using:
+   -- x = ((-1)^grade(x))*x
+   gradeInvolutionTerm(mult: K,type1:SINT): % ==
+     resul:% := New; resul.type1:=mult
+     g:NNI := gradeTerm(type1)
+     sign:Integer := (-1$Integer)**g
+     resul := sign*resul
+     resul
+
+   -- implements gradeInvolution for a multivector by involution
+   -- of each term seperately using:
+   -- x = ((-1)^grade(x))*x
+   gradeInvolution(x:%): % ==
+       z := New
+       for ix in 0..dim-1 repeat
+           if x.ix ~= 0 then z := z + gradeInvolutionTerm(x.ix,ix::SINT)
+       z
+
+   -- return the base vector number from binary, for example
+   -- binary for e1 is 001 which returns 1
+   -- binary for e2 is 010 which  returns 2 and so on
+   baseVect(b:SINT): NNI ==
+     for i in 0..n-1 repeat
+       if bit?(b,i) then return i+1
+     0
+
+   -- return a term from bilinear product
+   bilinear(b1:SINT,b2:SINT): K ==
+     bv1 := baseVect(b1)
+     bv2 := baseVect(b2)
+     if bv1 = 0$NNI then return 0
+     if bv2 = 0$NNI then return 0
+     bLin(bv1,bv2)
+
+   -- for a given term, return the base furthest on the left, for example
+   -- e1^e2^e3
+   -- would return e1
+   leftMostBase(b:SINT): SINT ==
+     mask:SINT := 1
+     for i in 0..n-1 repeat
+       if And(mask,b) ~= 0 then return mask
+       mask := shift(mask,1)::SINT
+     0
+
+   -- for a given term, return the base furthest on the right, for example
+   -- e1^e2^e3
+   -- would return e3
+   rightMostBase(b:SINT): SINT ==
+     mask:SINT := shift(1,(n-1)::SINT)$SINT
+     for i in 0..n-1 repeat
+       if And(mask,b) ~= 0 then return mask
+       mask := shift(mask,-1)::SINT
+     0
+
+   -- Implement exterior grassmann product on individual term in a
+   -- multivector and add it to the multivector.
+   exteriorProdTerm(op1mult: K, op1type:SINT, op2mult: K, op2type:SINT): % ==
+     result:% := New
+     -- if common terms return without adding
+     And(op1type,op2type) ~= 0 => result 
+     c := op1mult * op2mult
+     bz := Or(op1type,op2type)-- combine terms from both operands
+     for i in 0..n-1 | bit?(op1type,i) repeat
+       -- Apply rule  ei*ej = -ej*ei for i ~= j
+       k := 0
+       for j in i+1..n-1 | bit?(op1type, j) repeat k := k+1
+       for j in 0..i-1   | bit?(bz, j) repeat k := k+1
+       if odd? k then c := -c
+     result.bz := result.bz + c
+     result
+
+   -- Implement regressive inner,meet product on individual term in a
+   -- multivector and add it to the multivector.
+   regressiveProdTerm(op1mult: K, op1type:SINT, op2mult: K, op2type:SINT): % ==
+     op1 := New; op1.op1type := 1$K
+     op2 := New; op2.op2type := 1$K
+     res := _/_\(op2*ePseudoscalar(),op1*ePseudoscalar()) *ePseudoscalar()
+     res := (op1mult * op2mult)*res
+     res
+
+   -- Implement exterior grassmann product
+   _/_\(x:%,y:%): % ==
+       z := New
+       for ix in 0..dim-1 repeat
+        if x.ix ~= 0 then for iy in 0..dim-1 repeat
+         if y.iy ~= 0 then z:=z + exteriorProdTerm(x.ix,ix::SINT,y.iy,iy::SINT)
+       z
+
+   -- Implement regressive inner,meet product operator
+   _\_/(x:%,y:%): % ==
+       z := New
+       for ix in 0..dim-1 repeat
+        if x.ix ~= 0 then for iy in 0..dim-1 repeat
+         if y.iy ~= 0 then z:=z+regressiveProdTerm(x.ix,ix::SINT,y.iy,iy::SINT)
+       z
+
+   -- see bug 7203 tpd 20091208
+   XOR(x:SINT,y:SINT):SINT == LOGXOR(x,y)$Lisp
+
+   -- Implement left contraction on individual term in a
+   -- multivector and add it to the multivector.
+   lcProdTerm(op1mult: K, op1type:SINT, op2mult: K, op2type:SINT): % ==
+     resul:% := New
+     grade1 := gradeTerm(op1type) -- grade of first operand
+     grade2 := gradeTerm(op2type) -- grade of second operand
+     if grade1 = 0 then -- 1st operand is scalar so return scalar product
+       resul.op2type := resul.op2type + op1mult*op2mult
+       return resul
+     grade2 = 0 => resul -- 2nd operand is scalar so return 0
+     if grade1 = 1 and grade2 = 1 then -- vect _| vect = bilinear
+        -- add scalar term
+       resul.(0$NNI):=resul.(0$NNI)+op1mult*op2mult*bilinear(op1type,op2type)
+       return resul
+     -- 1st operand is vector so apply: x_|(u**v)=(x_|u)**v - u**(x_|v)
+     if grade1 = 1 then 
+       uType:SINT := leftMostBase(op2type) -- highest ^factor
+       vType:SINT := XOR(op2type,uType) -- remaining ^factors
+       inner2:% := New; inner2.vType := 1$K
+       left:% := _/_\(lcProdTerm(op1mult, op1type,op2mult, uType),inner2)
+       inner4:% := New; inner4.uType := 1$K
+       resul := resul + left + _/_\(inner4,lcProdTerm(-op1mult, _
+                                                       op1type,op2mult, vType))
+       return resul
+     -- if none of the above is true then apply:
+     -- (u/\v) _| w = u _| (v _| w)
+     uType:SINT := leftMostBase(op1type) -- highest ^factor
+     vType:SINT := XOR(op1type,uType) -- remaining ^factors
+     inner2:% := New
+     inner2.uType := 1$K
+     resul := resul+ lc(inner2,lcProdTerm(op1mult,vType,op2mult,op2type))
+     resul
+    -- Implement right contraction on individual term in a
+   -- multivector and add it to the multivector.
+   rcProdTerm(op1mult: K, op1type:SINT, op2mult: K, op2type:SINT): % ==
+     resul:% := New
+     grade1 := gradeTerm(op1type) -- grade of first operand
+     grade2 := gradeTerm(op2type) -- grade of second operand
+     if grade2 = 0 then -- 1st operand is scalar so return scalar product
+       resul.op1type := resul.op1type + op1mult*op2mult
+       return resul
+     grade1 = 0 => resul -- 2nd operand is scalar so return 0
+     if grade1 = 1 and grade2 = 1 then -- vect |_ vect = bilinear
+       -- add scalar term
+       resul.(0$NNI):=resul.(0$NNI)+op1mult*op2mult*bilinear(op1type,op2type) 
+       return resul
+     -- 1st operand is vector so apply: (v^u)|_x=v^(u|_x) - (v|_x)^u
+     if grade2 = 1 then 
+       uType:SINT := rightMostBase(op1type) -- lowest ^factor
+       vType:SINT := XOR(op1type,uType) -- remaining ^factors
+       inner2:% := New; inner2.vType := 1$K
+       right:% := _/_\(inner2,rcProdTerm(op1mult, uType,op2mult, op2type))
+       inner4:% := New; inner4.uType := 1$K
+       resul := resul + _/_\(rcProdTerm(op1mult, vType,-op2mult, op2type),_
+         inner4) + right
+       return resul
+     -- if none of the above is true then apply:
+     -- w |_ (v/\u) = (w |_ v) |_ u
+     uType:SINT := rightMostBase(op2type) -- lowest ^factor
+     vType:SINT := XOR(op2type,uType) -- remaining ^factors
+     inner2:% := New
+     inner2.uType := 1$K
+     resul := resul+ rc(rcProdTerm(op1mult,op1type,op2mult,vType),inner2)
+     resul
+
+   -- Implement left contraction inner product
+   lc(x:%,y:%): % ==
+       z := New
+       for ix in 0..dim-1 repeat
+        if x.ix ~= 0 then for iy in 0..dim-1 repeat
+         if y.iy ~= 0 then z := z + lcProdTerm(x.ix,ix::SINT,y.iy,iy::SINT)
+       z
+
+   -- Implement right contraction inner product
+   rc(x:%,y:%): % ==
+       z := New
+       for ix in 0..dim-1 repeat
+        if x.ix ~= 0 then for iy in 0..dim-1 repeat
+         if y.iy ~= 0 then z := z + rcProdTerm(x.ix,ix::SINT,y.iy,iy::SINT)
+       z
+
+   -- Implement Clifford multiplication on individual term in a
+   -- multivector and add it to the multivector.
+   cliffordProdTerm(op1mult: K, op1type:SINT, op2mult: K, op2type:SINT): % ==
+     resul:% := New
+     grade1 := gradeTerm(op1type) -- grade of first operand
+     grade2 := gradeTerm(op2type) -- grade of second operand
+     if grade1 = 0 then -- 1st operand is scalar so return scalar product
+       resul.op2type := resul.op2type + op1mult*op2mult
+       return resul
+     if grade2 = 0 then -- 2nd operand is scalar so return scalar product
+       resul.op1type := resul.op1type + op1mult*op2mult
+       return resul
+     if grade1 = 1 and grade2 = 1 then -- vect * vect = bilinear + x/\y
+       -- add scalar term
+       resul.(0$NNI):=resul.(0$NNI)+op1mult*op2mult*bilinear(op1type,op2type) 
+       -- add exterior term
+       resul := resul + exteriorProdTerm(op1mult,op1type,op2mult,op2type) 
+       return resul
+     if grade1 = 1 then -- 1st operand is vector so apply:
+       -- x*(u/\v) = x /\ u /\ v + x _| (u/\v)
+       -- = x/\u/\v + (x_|u)/\v + gradeinvolution(u) /\ (x _| v)
+       uType:SINT := leftMostBase(op2type) -- highest ^factor
+       vType:SINT := XOR(op2type,uType) -- remaining ^factors
+       xt:% := New; xt.op1type := 1$K
+       ut:% := New; ut.uType := 1$K
+       vt:% := New; vt.vType := 1$K
+       resul := _/_\(xt,exteriorProdTerm(1$K,uType,1$K,vType)) -- x/\u/\v
+       resul := resul+  _/_\(lcProdTerm(1$K,op1type,1$K,uType),vt) --(x _|u)/\v
+       resul := resul+  _/_\(gradeInvolutionTerm(1$K,uType),_
+          lcProdTerm(1$K,op1type,1$K,vType)) -- gradeinvolution(u) /\ (x _| v)
+       resul := (op1mult*op2mult)*resul -- apply 'scalar' multipliers
+       return resul
+     if grade2 = 1 then -- 2nd operand is vector so apply:
+       -- (v/\u)*x = v /\ u /\ x + rc(v/\u,x)
+       -- = v/\u/\x + v/\rc(u,x) +  rc(u, x)/\ gradeinvolution(v)
+       uType:SINT := rightMostBase(op1type) -- lowest ^factor
+       vType:SINT := XOR(op1type,uType) -- remaining ^factors
+       xt:% := New; xt.op2type := 1$K
+       ut:% := New; ut.uType := 1$K
+       vt:% := New; vt.vType := 1$K
+       resul := _/_\(exteriorProdTerm(1$K,vType,1$K,uType),xt) -- v/\u/\x
+       resul := resul+ _/_\(vt,rcProdTerm(1$K,uType,1$K,op2type)) --v/\(u |_ x)
+       resul := resul +  _/_\(rcProdTerm(1$K,vType,1$K,op2type),_
+              gradeInvolutionTerm(1$K,uType)) -- (v |_ x)/\ gradeinvolution(u)
+       resul := (op1mult*op2mult)*resul -- apply 'scalar' multipliers
+       return resul
+     -- if none of the above is true then apply:
+     -- u*v = u/\v + \/(u,v)
+     -- so,
+     -- u/\v = u*v - \/(u,v)
+     -- (u/\v)*w = v*v*w - bilinear(u,v)*w
+     uType:SINT := leftMostBase(op1type) -- highest ^factor
+     vType:SINT := XOR(op1type,uType) -- remaining ^factors
+     ut:% := New; ut.uType := 1$K
+     wt:% := New; wt.op2type := 1$K
+     resul := ut * cliffordProdTerm(1$K,vType,1$K,op2type)
+     resul := resul - bilinear(uType,vType)*wt
+     resul := (op1mult*op2mult)*resul -- apply 'scalar' multipliers
+     resul
+
+   -- Implement Clifford multiplication for orthogonal bases
+   -- on individual term in a multivector and add it to the multivector.
+   -- If the bilinear form is diagonal then this may be
+   -- more efficient than cliffordProdTerm as it does not
+   -- require recursion.
+   -- The ei*ej products could instead be precomputed in
+   -- a (2^n)^2 multiplication table although only 
+   -- practical for low dimension size.
+   cliffordDiagonalTerm(op1mult: K,op1type:SINT,op2mult: K,op2type:SINT): % ==
+       c  := op1mult * op2mult
+       bz := op2type
+       for i in 0..n-1 | bit?(op1type,i) repeat
+           -- Apply rule  ei*ej = -ej*ei for i ~= j
+           k := 0
+           for j in i+1..n-1 | bit?(op1type, j) repeat k := k+1
+           for j in 0..i-1   | bit?(bz, j) repeat k := k+1
+           if odd? k then c := -c
+           -- Apply rule  ei^2 = Q(ei)
+           if bit?(bz,i) then
+               c := c * Qeelist.(i+1)
+               bz:= bz - (2**i)::SINT
+           else
+               bz:= bz + (2**i)::SINT
+       result := New
+       result.bz := result.bz + c
+       result
+
+   x * y ==
+       z := New
+       for ix in 0..dim-1 repeat
+        if x.ix ~= 0 then for iy in 0..dim-1 repeat
+         if y.iy ~= 0 then z := z+cliffordProdTerm(x.ix,ix::SINT,y.iy,iy::SINT)
+       z
+
+   -- Implement reverse, complement,canonical dual basis
+   _~(x:%): % ==
+       x * ePseudoscalar()
+
+   canonMonom(c: K, lb: List PI): Record(coef: K, basel: NNI) ==
+       -- 0. Check input
+       for b in lb repeat b > n => error "No such basis element"
+        -- 1. Apply identity ei*ej = -ej*ei, i ~= j.
+       -- The Rep assumes n is small so bubble sort is ok.
+       -- Using bubble sort keeps the exchange info obvious.
+       wasordered   := false
+       exchanges := 0
+       while not wasordered repeat
+           wasordered := true
+           for i in 1..#lb-1 repeat
+               if lb.i > lb.(i+1) then
+                   t := lb.i; lb.i := lb.(i+1); lb.(i+1) := t
+                   exchanges := exchanges + 1
+                   wasordered := false
+       if odd? exchanges then c := -c
+        -- 2. Prepare the basis element
+       -- Apply identity ei*ei = Q(ei).
+       bz := 0
+       for b in lb repeat
+           bn := (b-1)::NNI
+           if bit?(bz, bn) then
+               c := c * Qeelist bn
+               bz:= ( bz - 2**bn )::NNI
+           else
+               bz:= bz + 2**bn
+       [c, bz::NNI]
+
+   monomial(c, lb) ==
+       r := canonMonom(c, lb)
+       z := New
+       z r.basel := r.coef
+       z
+
+   coefficient(z, lb) ==
+       r := canonMonom(1, lb)
+       r.coef = 0 => error "Cannot take coef of 0"
+       z r.basel/r.coef
+
+   Ex ==> OutputForm
+
+   coerceMonom(c: K, b: NNI): Ex ==
+       b = 0 => c::Ex
+       ml := [sub("e"::Ex, i::Ex) for i in 1..n | bit?(b,i-1)]
+       be := reduce("*", ml)
+       c = 1 => be
+       c::Ex * be
+
+   coerce(x): Ex ==
+       tl := [coerceMonom(x.i,i) for i in 0..dim-1 | x.i ~= 0]
+       null tl => "0"::Ex
+       reduce("+", tl)
+
+   localPowerSets(j:NNI): List(List(PI)) ==
+     l: List List PI := list []
+     j = 0 => l
+     Sm := localPowerSets((j-1)::NNI)
+     Sn: List List PI := []
+     for x in Sm repeat Sn := cons(cons(j pretend PI, x),Sn)
+     append(Sn, Sm)
+
+   powerSets(j:NNI):List List PI == map(reverse, localPowerSets j)
+
+   Pn:List List PI := powerSets(n)
+
+   recip(x: %): Union(%, "failed") ==
+     one:% := 1
+     -- tmp:c := x*yC - 1$C
+     rhsEqs : List K := []
+     lhsEqs: List List K := []
+     lhsEqi: List K
+     for pi in Pn repeat
+       rhsEqs := cons(coefficient(one, pi), rhsEqs)
+
+       lhsEqi := []
+       for pj in Pn repeat
+           lhsEqi := cons(coefficient(x*monomial(1,pj),pi),lhsEqi)
+       lhsEqs := cons(reverse(lhsEqi),lhsEqs)
+     ans := particularSolution(matrix(lhsEqs),
+       vector(rhsEqs))$LinearSystemMatrixPackage(K,Vector K,Vector K,Matrix K)
+     ans case "failed" => "failed"
+     ansP := parts(ans)
+     ansC:% := 0
+     for pj in Pn repeat
+       cj:= first ansP
+       ansP := rest ansP
+       ansC := ansC + cj*monomial(1,pj)
+     ansC
+
+@
+<<GRAS.dotabb>>=
+"GRAS" [color="#88FF44",href="bookvol10.3.pdf#nameddest=GRAS"]
+"IVECTOR" [color="#88FF44",href="bookvol10.3.pdf#nameddest=IVECTOR"]
+"GRAS" -> "IVECTOR"
+
+@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{domain GOPT GuessOption}
 \pagehead{GuessOption}{GOPT}
 \pagepic{ps/v103guessoption.ps}{GOPT}{1.00}
@@ -111839,12 +113177,11 @@ G := basis [v, w]                               -- this family is a basis
 --E 11
 
 --S 12 of 68
-basis? [v,w]
+isBasis? [v,w]
 --R 
 --R
---R   (12)  basis?
---R               [2,1,2],[1,2,1]
---R                                                                 Type: Symbol
+--R   (12)  true
+--R                                                                Type: Boolean
 --E 12
 
 
@@ -112455,18 +113792,91 @@ VFI ==> Vector Fraction Integer
 MFI ==> Matrix Fraction Integer
 VSB ==> VectorSpaceBasis Fraction Integer
 
-bc3 := canonicalBasis 3 :: List VFI
-u : VFI := vector [1,0,-1]
-v : VFI := vector [2,1,2]
-w : VFI := vector [1,2,1]
+Here we build the canonical basis for 3 space. This is a set of unit
+orthogonal vectors aligned with each cartesian axis.
+
+   bc3 := canonicalBasis 3 :: List VFI
+
+     [[1,0,0],[0,1,0],[0,0,1]]
+
+These three vectors are called a basis because any other vector can be
+written as a linear combination of these three. So a new vector
+
+   [v ,v ,v ]
+     1  2  3
+
+is just
+   
+   v  * [1,0,0] + v  * [0,1,0] + v  * [0,0,1]
+    1              2              3
+
+We can build other vectors in this space:
+
+   u : VFI := vector [1,0,-1]
+
+     [1,0,- 1]
+
+   v : VFI := vector [2,1,2]
+
+     [2,1,2]
+
+   w : VFI := vector [1,2,1]
+
+     [1,2,1]
+
+We would like to solve the two simultaneous equations
+
+   x + y + z = 0
+   x - y + z = 0
+
+that is, we want F such that
+  
+   F = {(x,y,z)|x+y+z=x-y+z=0}
+
+So we form the matrix M of thw two equations 
+
+   MF : MFI := matrix [[1,1,1],[1,-1,1]]  
+
+        +1   1   1+
+        |         |
+        +1  - 1  1+
+
+and now we solve for Mx=0, which is known as the nullspace:
+
+  F := nullSpace MF
+
+    VectorSpace [[- 1,0,1]]
+
+We can see that this is a valid solution with x=-1, y=0, z=1 since
+
+    (-1) + (0) + (1) = 0
+    (-1) - (0) + (1) = 0
+
+We can arrive at the same conclusion using the solve function on a
+set of equations:
+
+    2x +  y + 2z = 0
+     x + 2y +  z = 0
+
+by using the call
+
+   solve (matrix [[2,1,2],[1,2,1]]$MFI, vector [0,0,0])    
+
+     [particular= [0,0,0],basis= [[- 1,0,1]]]
+
+
+We can use the vectors u and w above to form the basis for a 2D space:
+
+   G := basis [v, w]
+
+     VectorSpace [[2,1,2],[1,2,1]]
+
+and we can ask if this is a basis:
+
+   isBasis? G
+   
+      true
 
--- F = {(x,y,z)|x+y+z=x-y+z=0}
-MF : MFI := matrix [[1,1,1],[1,-1,1]]  
-F := (nullSpace MF)$VSB                            -- a basis is (-1,0,1)
-solve (matrix [[2,1,2],[1,2,1]]$MFI, vector [0,0,0])    
--- G = vect(v,w)
-G := basis [v, w]                               -- this family is a basis
-basis? [v,w]
 
 -- search (a,b,c) | F = R(a,b,c)
 -- (a,b,c) matchs for v and w, 
@@ -112531,11 +113941,14 @@ test (Mfbc * u = v)
 test (Mfbc * v = w)
 test (Mfbc * w = u)
 
--- 
--- verify some subspaces 
--- 
+Next we verify some subspaces 
+ 
+If matrix A is considered a homogeneous system,
+that is, Ax=0 then A is the set of all vectors which satisfy this
+equation. A is a subspace of R^n. This is called the nullspace of
+the matrix A
 
-H := nullSpace MH
+   H := nullSpace MH
 
 [subspace? (BE, F), subspace? (basis bc3, F), subspace? (GH, 0$VSB),
  subspace? (GH, F), subspace? (GH, G), subspace? (GH, basis H),
@@ -112583,24 +113996,24 @@ o )show VectorSpaceBasis
 
 {\bf Exports:}\\
 \begin{tabular}{llll}
-\cross{basis} &
-\cross{canonicalBasis} &
-\cross{coerce} & 
-\cross{columnSpace} \\
-\cross{complementSpace} &
-\cross{coordinates} &
-\cross{coordinatesIfCan} &
-\cross{intBasis} \\
-\cross{isBasis?} &
-\cross{member?} &
-\cross{nullSpace} &
-\cross{rank} \\
-\cross{subspace?} &
-\cross{sumBasis} &
-\cross{?*?} &
-\cross{?+?} \\
-\cross{?=?} &
-\cross{0} &\\
+\cross{VSBASIS}{basis} &
+\cross{VSBASIS}{canonicalBasis} &
+\cross{VSBASIS}{coerce} & 
+\cross{VSBASIS}{columnSpace} \\
+\cross{VSBASIS}{complementSpace} &
+\cross{VSBASIS}{coordinates} &
+\cross{VSBASIS}{coordinatesIfCan} &
+\cross{VSBASIS}{intBasis} \\
+\cross{VSBASIS}{isBasis?} &
+\cross{VSBASIS}{member?} &
+\cross{VSBASIS}{nullSpace} &
+\cross{VSBASIS}{rank} \\
+\cross{VSBASIS}{subspace?} &
+\cross{VSBASIS}{sumBasis} &
+\cross{VSBASIS}{?*?} &
+\cross{VSBASIS}{?+?} \\
+\cross{VSBASIS}{?=?} &
+\cross{VSBASIS}{0} &\\
 \end{tabular}
 
 <<domain VSBASIS VectorSpaceBasis>>=
@@ -112621,6 +114034,11 @@ VectorSpaceBasis(R : Field) : Exports == Implementation where
         basis : List Vector R -> %
           ++ \spad{basis LV} extracts a basis of the subspace spanned by 
           ++ the \spad{LV} list of vectors.
+          ++
+          ++X u : Vector Fraction Integer := vector [1,0,-1]
+          ++X v : Vector Fraction Integer := vector [2,1,2]
+          ++X G := basis [v, w]
+
         coerce : % -> List Vector R
           ++ \spad{coerce b} retracts a basis to this list of vectors.
         coerce : % -> OutputForm
@@ -112679,18 +114097,29 @@ VectorSpaceBasis(R : Field) : Exports == Implementation where
         rank : % -> NonNegativeInteger
           ++ \spad{rank b} computes the rank of a basis, it's the number of
           ++ vectors in the basis.
+
         isBasis? : List Vector R -> Boolean 
           ++ \spad{isBasis? Lv} tests if a list of vector is a basis, without
           ++ linear relations between the vectors.
+          ++
+          ++X u : Vector Fraction Integer := vector [1,0,-1]
+          ++X v : Vector Fraction Integer := vector [2,1,2]
+          ++X G := basis [v, w]
+          ++X isBasis? G
+
         subspace? : (%, %) -> Boolean
           ++ \spad{subspace?(b1,b2)} tests if the first space is include in 
           ++ the second.
         0 : constant -> %
-          ++ \spad{0} creates the void basis describing the space with the zero 
-          ++ vector. Axiom ignores the length of this zero vector.
+          ++ \spad{0} creates the void basis describing the space with the
+          ++  zero vector. Axiom ignores the length of this zero vector.
+
         canonicalBasis : NonNegativeInteger -> %
           ++ \spad{canonicalBasis n} build the canononical basis of the
-          ++ vector space with \spad{n} coordinates.
+          ++ vector space with \spad{n} coordinates. This is a set of unit
+          ++ orthogonal vectors aligned with each cartesian axis.
+          ++
+          ++X canonicalBasis 3 :: List Vector Fraction Integer
 
         complementSpace : % -> %
           ++ \spad{complementSpace B} build a complement space of the basis
@@ -112782,6 +114211,13 @@ VectorSpaceBasis(R : Field) : Exports == Implementation where
 
         columnSpace M == ((columnSpace M)$(Matrix R))::%
         nullSpace M == ((nullSpace M)$(Matrix R))::%
+        ++ \spad{nullSpace}(A) If matrix A is considered a homogeneous system,
+        ++ that is, Ax=0 then A is the set of all vectors which satisfy this
+        ++ equation. A is a subspace of R^n. This is called the nullspace of
+        ++ the matrix A
+        ++
+        ++ MF:Matrix Fraction Integer:=matrix [[1,1,1],[1,-1,1]]
+        ++ F:=nullSpace MF
 
         -- A basis of the sum of subspaces is a basis extract from the
         -- union of the basis.
@@ -123063,6 +124499,7 @@ Note that this code is not included in the generated catdef.spad file.
 <<domain GSTBL GeneralSparseTable>>
 <<domain GTSET GeneralTriangularSet>>
 <<domain GSERIES GeneralUnivariatePowerSeries>>
+<<domain GRAS GrassmannAlgebra>>
 <<domain GRIMAGE GraphImage>>
 <<domain GOPT GuessOption>>
 
diff --git a/books/bookvol2.pamphlet b/books/bookvol2.pamphlet
index 9c3c4e3..c241ca3 100644
--- a/books/bookvol2.pamphlet
+++ b/books/bookvol2.pamphlet
@@ -504,6 +504,7 @@ which is correct.
  sumBasis : List List Vector R -> %
 
 9) update Exports section for sorted unique set of operations
+    \cross{VSBASIS}{opname}
 
 10) add lowercase name to pagepic:
 
diff --git a/books/bookvol5.pamphlet b/books/bookvol5.pamphlet
index cde2496..27d1824 100644
--- a/books/bookvol5.pamphlet
+++ b/books/bookvol5.pamphlet
@@ -305,13 +305,13 @@ of effort. We would like to acknowledge and thank the following people:
 "An alphabetical listing of contributors to AXIOM:"
 "Cyril Alberga          Roy Adler              Christian Aistleitner"
 "Richard Anderson       George Andrews         S.J. Atkins"
-"Henry Baker            Stephen Balzac         Yurij Baransky"
-"David R. Barton        Gerald Baumgartner     Gilbert Baumslag"
-"Michael Becker         Jay Belanger           David Bindel"
-"Fred Blair             Vladimir Bondarenko    Mark Botch"
-"Alexandre Bouyer       Peter A. Broadbery     Martin Brock"
-"Manuel Bronstein       Stephen Buchwald       Florian Bundschuh"
-"Luanne Burns           William Burge"
+"Henry Baker            Martin Baker           Stephen Balzac"
+"Yurij Baransky         David R. Barton        Gerald Baumgartner"
+"Gilbert Baumslag       Michael Becker         Jay Belanger"
+"David Bindel           Fred Blair             Vladimir Bondarenko"
+"Mark Botch             Alexandre Bouyer       Peter A. Broadbery"
+"Martin Brock           Manuel Bronstein       Stephen Buchwald"
+"Florian Bundschuh      Luanne Burns           William Burge"
 "Quentin Carpent        Robert Caviness        Bruce Char"
 "Ondrej Certik          Cheekai Chin           David V. Chudnovsky"
 "Gregory V. Chudnovsky  Josh Cohen             Christophe Conil"
diff --git a/books/ps/v103grassmannalgebra.ps b/books/ps/v103grassmannalgebra.ps
new file mode 100644
index 0000000..0e03f93
--- /dev/null
+++ b/books/ps/v103grassmannalgebra.ps
@@ -0,0 +1,268 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: Graphviz version 2.20.2 (Mon Mar 30 10:09:11 UTC 2009)
+%%For: (root) root
+%%Title: pic
+%%Pages: (atend)
+%%BoundingBox: (atend)
+%%EndComments
+save
+%%BeginProlog
+/DotDict 200 dict def
+DotDict begin
+
+/setupLatin1 {
+mark
+/EncodingVector 256 array def
+ EncodingVector 0
+
+ISOLatin1Encoding 0 255 getinterval putinterval
+EncodingVector 45 /hyphen put
+
+% Set up ISO Latin 1 character encoding
+/starnetISO {
+        dup dup findfont dup length dict begin
+        { 1 index /FID ne { def }{ pop pop } ifelse
+        } forall
+        /Encoding EncodingVector def
+        currentdict end definefont
+} def
+/Times-Roman starnetISO def
+/Times-Italic starnetISO def
+/Times-Bold starnetISO def
+/Times-BoldItalic starnetISO def
+/Helvetica starnetISO def
+/Helvetica-Oblique starnetISO def
+/Helvetica-Bold starnetISO def
+/Helvetica-BoldOblique starnetISO def
+/Courier starnetISO def
+/Courier-Oblique starnetISO def
+/Courier-Bold starnetISO def
+/Courier-BoldOblique starnetISO def
+cleartomark
+} bind def
+
+%%BeginResource: procset graphviz 0 0
+/coord-font-family /Times-Roman def
+/default-font-family /Times-Roman def
+/coordfont coord-font-family findfont 8 scalefont def
+
+/InvScaleFactor 1.0 def
+/set_scale {
+       dup 1 exch div /InvScaleFactor exch def
+       scale
+} bind def
+
+% styles
+/solid { [] 0 setdash } bind def
+/dashed { [9 InvScaleFactor mul dup ] 0 setdash } bind def
+/dotted { [1 InvScaleFactor mul 6 InvScaleFactor mul] 0 setdash } bind def
+/invis {/fill {newpath} def /stroke {newpath} def /show {pop newpath} def} bind def
+/bold { 2 setlinewidth } bind def
+/filled { } bind def
+/unfilled { } bind def
+/rounded { } bind def
+/diagonals { } bind def
+
+% hooks for setting color 
+/nodecolor { sethsbcolor } bind def
+/edgecolor { sethsbcolor } bind def
+/graphcolor { sethsbcolor } bind def
+/nopcolor {pop pop pop} bind def
+
+/beginpage {	% i j npages
+	/npages exch def
+	/j exch def
+	/i exch def
+	/str 10 string def
+	npages 1 gt {
+		gsave
+			coordfont setfont
+			0 0 moveto
+			(\() show i str cvs show (,) show j str cvs show (\)) show
+		grestore
+	} if
+} bind def
+
+/set_font {
+	findfont exch
+	scalefont setfont
+} def
+
+% draw text fitted to its expected width
+/alignedtext {			% width text
+	/text exch def
+	/width exch def
+	gsave
+		width 0 gt {
+			[] 0 setdash
+			text stringwidth pop width exch sub text length div 0 text ashow
+		} if
+	grestore
+} def
+
+/boxprim {				% xcorner ycorner xsize ysize
+		4 2 roll
+		moveto
+		2 copy
+		exch 0 rlineto
+		0 exch rlineto
+		pop neg 0 rlineto
+		closepath
+} bind def
+
+/ellipse_path {
+	/ry exch def
+	/rx exch def
+	/y exch def
+	/x exch def
+	matrix currentmatrix
+	newpath
+	x y translate
+	rx ry scale
+	0 0 1 0 360 arc
+	setmatrix
+} bind def
+
+/endpage { showpage } bind def
+/showpage { } def
+
+/layercolorseq
+	[	% layer color sequence - darkest to lightest
+		[0 0 0]
+		[.2 .8 .8]
+		[.4 .8 .8]
+		[.6 .8 .8]
+		[.8 .8 .8]
+	]
+def
+
+/layerlen layercolorseq length def
+
+/setlayer {/maxlayer exch def /curlayer exch def
+	layercolorseq curlayer 1 sub layerlen mod get
+	aload pop sethsbcolor
+	/nodecolor {nopcolor} def
+	/edgecolor {nopcolor} def
+	/graphcolor {nopcolor} def
+} bind def
+
+/onlayer { curlayer ne {invis} if } def
+
+/onlayers {
+	/myupper exch def
+	/mylower exch def
+	curlayer mylower lt
+	curlayer myupper gt
+	or
+	{invis} if
+} def
+
+/curlayer 0 def
+
+%%EndResource
+%%EndProlog
+%%BeginSetup
+14 default-font-family set_font
+1 setmiterlimit
+% /arrowlength 10 def
+% /arrowwidth 5 def
+
+% make sure pdfmark is harmless for PS-interpreters other than Distiller
+/pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse
+% make '<<' and '>>' safe on PS Level 1 devices
+/languagelevel where {pop languagelevel}{1} ifelse
+2 lt {
+    userdict (<<) cvn ([) cvn load put
+    userdict (>>) cvn ([) cvn load put
+} if
+
+%%EndSetup
+setupLatin1
+%%Page: 1 1
+%%PageBoundingBox: 36 36 122 152
+%%PageOrientation: Portrait
+0 0 1 beginpage
+gsave
+36 36 86 116 boxprim clip newpath
+1 1 set_scale 0 rotate 40 40 translate
+% GRAS
+gsave
+[ /Rect [ 12 72 66 108 ]
+  /Border [ 0 0 0 ]
+  /Action << /Subtype /URI /URI (bookvol10.3.pdf#nameddest=GRAS) >>
+  /Subtype /Link
+/ANN pdfmark
+0.273 0.733 1.000 nodecolor
+newpath 66 108 moveto
+12 108 lineto
+12 72 lineto
+66 72 lineto
+closepath fill
+1 setlinewidth
+filled
+0.273 0.733 1.000 nodecolor
+newpath 66 108 moveto
+12 108 lineto
+12 72 lineto
+66 72 lineto
+closepath stroke
+0.000 0.000 0.000 nodecolor
+14 /Times-Roman set_font
+19.5 85.9 moveto 39 (GRAS) alignedtext
+grestore
+% IVECTOR
+gsave
+[ /Rect [ 0 0 78 36 ]
+  /Border [ 0 0 0 ]
+  /Action << /Subtype /URI /URI (bookvol10.3.pdf#nameddest=IVECTOR) >>
+  /Subtype /Link
+/ANN pdfmark
+0.273 0.733 1.000 nodecolor
+newpath 78 36 moveto
+0 36 lineto
+0 0 lineto
+78 0 lineto
+closepath fill
+1 setlinewidth
+filled
+0.273 0.733 1.000 nodecolor
+newpath 78 36 moveto
+0 36 lineto
+0 0 lineto
+78 0 lineto
+closepath stroke
+0.000 0.000 0.000 nodecolor
+14 /Times-Roman set_font
+7.5 13.9 moveto 63 (IVECTOR) alignedtext
+grestore
+% GRAS->IVECTOR
+gsave
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 39 72 moveto
+39 64 39 55 39 46 curveto
+stroke
+0.000 0.000 0.000 edgecolor
+newpath 42.5 46 moveto
+39 36 lineto
+35.5 46 lineto
+closepath fill
+1 setlinewidth
+solid
+0.000 0.000 0.000 edgecolor
+newpath 42.5 46 moveto
+39 36 lineto
+35.5 46 lineto
+closepath stroke
+grestore
+endpage
+showpage
+grestore
+%%PageTrailer
+%%EndPage: 1
+%%Trailer
+%%Pages: 1
+%%BoundingBox: 36 36 122 152
+end
+restore
+%%EOF
diff --git a/changelog b/changelog
index 7b33517..a8ca671 100644
--- a/changelog
+++ b/changelog
@@ -1,3 +1,11 @@
+20091209 tpd src/axiom-website/patches.html 20091209.01.myb.patch
+20091209 tpd src/algebra/exposed.lsp expose GrassmannAlgebra
+20091209 tpd src/algebra/Makefile add GrassmannAlgebra help, regress
+20091209 tpd books/bookvol2 add instructions for adding algebra
+20091209 myb books/bookvol10.3 add GrassmanAlgebra
+20091209 tpd books/bookvol5 add Martin Baker to credits
+20091209 tpd readme add Martin Baker to credits
+20091209 myb Martin Baker <gg87346@martinb.com>
 20091207 tpd src/axiom-website/patches.html 20091207.01.fxm.patch
 20091207 tpd src/share/algebra/users.daase/index.kaf update daasefor vsbasis
 20091207 tpd src/share/algebra/operation.daase update databases for vsbasis
diff --git a/readme b/readme
index f734e4a..66011d2 100644
--- a/readme
+++ b/readme
@@ -190,13 +190,13 @@ at the axiom command prompt will prettyprint the list.
 "An alphabetical listing of contributors to AXIOM:"
 "Cyril Alberga          Roy Adler              Christian Aistleitner"
 "Richard Anderson       George Andrews         S.J. Atkins"
-"Henry Baker            Stephen Balzac         Yurij Baransky"
-"David R. Barton        Gerald Baumgartner     Gilbert Baumslag"
-"Michael Becker         Jay Belanger           David Bindel"
-"Fred Blair             Vladimir Bondarenko    Mark Botch"
-"Alexandre Bouyer       Peter A. Broadbery     Martin Brock"
-"Manuel Bronstein       Stephen Buchwald       Florian Bundschuh"
-"Luanne Burns           William Burge"
+"Henry Baker            Martin Baker           Stephen Balzac"
+"Yurij Baransky         David R. Barton        Gerald Baumgartner"
+"Gilbert Baumslag       Michael Becker         Jay Belanger"
+"David Bindel           Fred Blair             Vladimir Bondarenko"
+"Mark Botch             Alexandre Bouyer       Peter A. Broadbery"
+"Martin Brock           Manuel Bronstein       Stephen Buchwald"
+"Florian Bundschuh      Luanne Burns           William Burge"
 "Quentin Carpent        Robert Caviness        Bruce Char"
 "Ondrej Certik          Cheekai Chin           David V. Chudnovsky"
 "Gregory V. Chudnovsky  Josh Cohen             Christophe Conil"
diff --git a/src/algebra/Makefile.pamphlet b/src/algebra/Makefile.pamphlet
index f645f3d..28bbbaf 100644
--- a/src/algebra/Makefile.pamphlet
+++ b/src/algebra/Makefile.pamphlet
@@ -4486,7 +4486,8 @@ LAYER10=\
   ${OUT}/COORDSYS.o ${OUT}/DBASE.o    ${OUT}/DHMATRIX.o ${OUT}/DIOSP.o   \
   ${OUT}/DIRPCAT.o  ${OUT}/DIRPCAT-.o ${OUT}/D02BBFA.o  ${OUT}/D02BHFA.o \
   ${OUT}/D02CJFA.o  ${OUT}/FAXF.o     ${OUT}/FAXF-.o    ${OUT}/FFPOLY2.o \
-  ${OUT}/FNLA.o     ${OUT}/GRAY.o     ${OUT}/HB.o       ${OUT}/INBFF.o   \
+  ${OUT}/FNLA.o     ${OUT}/GRAS.o \
+  ${OUT}/GRAY.o     ${OUT}/HB.o       ${OUT}/INBFF.o   \
   ${OUT}/IRSN.o     ${OUT}/MCALCFN.o  ${OUT}/MHROWRED.o ${OUT}/NUMODE.o  \
   ${OUT}/NUMQUAD.o  ${OUT}/ODESYS.o   ${OUT}/ODETOOLS.o ${OUT}/ORDFUNS.o \
   ${OUT}/PERMAN.o   ${OUT}/PFECAT.o   ${OUT}/PFECAT-.o  ${OUT}/POINT.o   \
@@ -4769,6 +4770,25 @@ LAYER10=\
 "FNLA" -> "IVECTOR"
 /*"FNLA" -> {"IARRAY1"; "LIST"; "ILIST"; "LSAGG-"; "STAGG-"; "PI"; "NNI"}*/
 
+"GRAS" [color="#88FF44",href="bookvol10.3.pdf#nameddest=GRAS"]
+/*"GRAS" -> {"RING"; "RNG"; "ABELGRP"; "CABMON"; "ABELMON"; "ABELSG"} */
+/*"GRAS" -> {"SETCAT"; "BASTYPE"; "KOERCE"; "SGROUP"; "MONOID"} */
+/*"GRAS" -> {"LMODULE"; "ALGEBRA"; "MODULE"; "BMODULE"; "RMODULE"} */
+/*"GRAS" -> {"FIELD"; "EUCDOM"; "PID"; "GCDDOM"; "INTDOM"; "COMRING"} */
+/*"GRAS" -> {"ENTIRER"; "UFD"; "DIVRING"; "PI"; "NNI"; "INT"; "MONOID-"} */
+/*"GRAS" -> {"ABELSG-"; "SGROUP-"; "SINT"; "PRIMARR"; "BOOLEAN"; "A1AGG"} */
+/*"GRAS" -> {"FLAGG"; "LNAGG"; "IXAGG"; "HOAGG"; "AGG"; "TYPE"; "EVALAB"} */
+/*"GRAS" -> {"IEVALAB"; "ELTAGG"; "ELTAB"; "CLAGG"; "KONVERT"; "ORDSET"} */
+/*"GRAS" -> {"EUCDOM-"; "UFD-"; "GCDDOM-"; "INTDOM-"; "ALGEBRA-"} */
+/*"GRAS" -> {"DIFRING-"; "ORDRING-"; "MODULE-"; "RING-"; "ABELGRP-"} */
+/*"GRAS" -> {"ABELMON-"; "ORDSET-"; "LOGIC-"; "SETCAT-"; "RETRACT-"} */
+/*"GRAS" -> {"BASTYPE-"; "VECTOR"} */
+"GRAS" -> "IVECTOR"
+/*"GRAS" -> {"IARRAY1"; "LSAGG"} */
+/*"GRAS" -> {"STAGG"; "URAGG"; "RCAGG"; "ELAGG"; "OM"; "LIST"; "ILIST"} */
+/*"GRAS" -> {"LSAGG-"; "STAGG-"; "ELAGG-"; "FLAGG-"; "URAGG-"; "LNAGG-"} */
+/*"GRAS" -> {"RCAGG-"; "IXAGG-"; "VECTCAT"; "VECTCAT-"; "A1AGG-"} */
+
 "GRAY" [color="#FF4488",href="bookvol10.4.pdf#nameddest=GRAY"]
 /*"GRAY" -> {"INT"; "VECTOR"}*/
 "GRAY" -> "IVECTOR"
@@ -16499,6 +16519,7 @@ SPADHELP=\
  ${HELP}/FullPartialFractionExpansion.help \
  ${HELP}/GeneralDistributedMultivariatePolynomial.help \
  ${HELP}/GeneralSparseTable.help \
+ ${HELP}/GrassmannAlgebra.help \
  ${HELP}/GroebnerFactorizationPackage.help \
  ${HELP}/GroebnerPackage.help \
  ${HELP}/Heap.help \
@@ -16649,6 +16670,7 @@ REGRESS= \
  FullPartialFractionExpansion.regress \
  GeneralDistributedMultivariatePolynomial.regress \
  GeneralSparseTable.regress \
+ GrassmannAlgebra.regress \
  GroebnerFactorizationPackage.regress \
  GroebnerPackage.regress \
  Heap.regress \
@@ -17146,6 +17168,16 @@ ${HELP}/GeneralSparseTable.help: ${BOOKS}/bookvol10.3.pamphlet
             >${INPUT}/GeneralSparseTable.input
 	@echo "GeneralSparseTable (GSTBL)" >>${HELPFILE}
 
+${HELP}/GrassmannAlgebra.help: ${BOOKS}/bookvol10.3.pamphlet
+	@echo 8215 create GrassmannAlgebra.help from \
+           ${BOOKS}/bookvol10.3.pamphlet
+	@${TANGLE} -R"GrassmannAlgebra.help" ${BOOKS}/bookvol10.3.pamphlet \
+           >${HELP}/GrassmannAlgebra.help
+	@cp ${HELP}/GrassmannAlgebra.help ${HELP}/GRAS.help
+	@${TANGLE} -R"GrassmannAlgebra.input" ${BOOKS}/bookvol10.3.pamphlet \
+            >${INPUT}/GrassmannAlgebra.input
+	@echo "GrassmannAlgebra (GRAS)" >>${HELPFILE}
+
 ${HELP}/GroebnerFactorizationPackage.help: ${BOOKS}/bookvol10.4.pamphlet
 	@echo 7370 create GroebnerFactorizationPackage.help \
             from ${BOOKS}/bookvol10.4.pamphlet
diff --git a/src/algebra/exposed.lsp.pamphlet b/src/algebra/exposed.lsp.pamphlet
index 695b338..e7301be 100644
--- a/src/algebra/exposed.lsp.pamphlet
+++ b/src/algebra/exposed.lsp.pamphlet
@@ -164,6 +164,7 @@
   (|GeneralUnivariatePowerSeries| . GSERIES)
   (|GenerateUnivariatePowerSeries| . GENUPS)
   (|GraphicsDefaults| . GRDEF)
+  (|GrassmannAlgebra| . GRAS)
   (|GroebnerPackage| . GB)
   (|GroebnerFactorizationPackage| . GBF)
   (|Guess| . GUESS)
diff --git a/src/axiom-website/patches.html b/src/axiom-website/patches.html
index 50c392c..643a443 100644
--- a/src/axiom-website/patches.html
+++ b/src/axiom-website/patches.html
@@ -2310,5 +2310,7 @@ src/axiom-website/download.html add fedora10 nov2009 build <br/>
 books/bookvol10.2 latex cleanup<br/>
 <a href="patches/20091207.01.fxm.patch">20091207.01.fxm.patch</a>
 books/bookvol10.3 add VectorSpaceBasis from Francois Maltey<br/>
+<a href="patches/20091209.01.myb.patch">20091209.01.myb.patch</a>
+books/bookvol10.3 add GrassmannAlgebra from Martin Baker<br/>
  </body>
 </html>
