Just now, 2011 July 28, I suspect the code below is wrong. Perhaps alpha is wrong.

Here is a beefed up version of the Clifford engine. Use definitions for Do and grc4 for a pseudo random number generator.

(define (G f)
(apply (lambda (rp / tr bar alpha sg zer zer? one + - * rls basis) (list
 (lambda (x) (rp (car x))) ; The real part
 (lambda (x) (let* ((a (car x))(b (cdr x))(ai (/ a))) ; inverse
    (if ai (let* ((aib (* ai b))(c (/ (+ a (* b (alpha aib)))))
        (d (- (* aib (alpha c))))) (cons c d))
    (let ((bi (/ b)))
       (if bi (let* ((bia (* bi a))(d (- (/ (+ (* (alpha a) bia) (alpha b)))))
         (c (alpha (- (* bia d))))) (cons c d))
  (lambda (x) (cons (tr (car x)) (bar (cdr x)))) ; tr
  (lambda (x) (cons (bar (car x)) (- (tr (cdr x))))) ; bar
  (lambda (x) (cons (alpha (car x)) (- (alpha (cdr x))))) ; alpha
  (lambda () (cons (sg) (sg))) ; sg
  (cons zer zer) ; zer
  (lambda (a) (and (zer? (car a)) (zer? (cdr a)))) ; zer?
  (cons one zer) ; one
  (lambda (a b) (cons (+ (car a)(car b))(+ (cdr a)(cdr b)))) ; +
  (lambda (a) (cons (-(car a))(-(cdr a)))) ; - (negation)
  (lambda (a b) (cons (+ (* (car a)(car b))(-(* (cdr a)(alpha (cdr b))))) ; *
                     (+ (* (car a)(cdr b))(* (cdr a)(alpha (car b))))))
  (lambda (x)(cons (rls x) zer)) ; rls
  (cons (cons zer one) (map (lambda (x) (cons x zer)) basis)) ; basis
  )) f))

(define rr (let ((ig (grc4 "vjoe"))) (lambda ()(/ (ig 1)(+ 1 (ig 1))))))
(define reals (let ((i (lambda (x) x))) (list i
 (lambda (x) (if (zero? x) #f (/ x)))
 i i i rr 0 zero? 1 + - * i '())))
(define Px (G (G (G (G reals)))))
(define rp (car Px))
(define P (cdr Px))
(define C/ (car P)) ; multiplicative inverse
(define tr (cadr P)) ; transpose
(define bar (caddr P)) ; conjugate (bar)
(define Ha (cadddr P)) ; main involution
(define p (cddddr P)) ; rest
(define Cr (car p)) ; sample generator
(define C0 (cadr p)) ; 0
(define C0? (caddr p)) ; 0 predicate
(define q (cdddr p)) ; rest of tools
(define H1 (car q)) ; multiplicative identity
(define C+ (cadr q)) ; addition
(define C- (lambda (x y) (C+ x ((caddr q) y)))) ; subtraction
(define C* (cadddr q)) ; multiplication
(define r (cddddr q)) ; rest of tools
(define Hrls (car r)) ; returns Clifford number corresponding to real.
(define basis (cadr r)) ; list of basis vectors of V as Clifford numbers.
; Define.
(define (even a)(C* (Hrls 1/2)(C+ a (Ha a)))) ; even part of Clifford number
(define (odd a)(C* (Hrls 1/2)(C- a (Ha a)))) ; odd part of Clifford number
(define (Vr) (let Vr ((x basis)) (if (null? x) C0
   (C+ (C* (Hrls (rr)) (car x)) (Vr (cdr x)))))) ; a random vector generator

(define g3 (car basis)) ; individual Clifford number basis elements for V in C.
(define g2 (cadr basis))
(define g1 (caddr basis))
(define g0 (cadddr basis))
; sp below is a bilinear form for the Clifford algebra.
(define (sp a b) (rp (C* (tr a) b)))

(let* ((a (Cr))(b (Cr))(c (Cr))(y (rr))(x (Hrls y))) (list
  (- (sp (C+ a b) c) (+ (sp a c) (sp b c)))
  (- (sp c (C+ a b)) (+ (sp c a) (sp c b)))
  (- (* y (sp a b))(sp a (C* x b)))
  (- (* y (sp a b))(sp (C* a x) b)))) ; => (0 0 0 0) thus sp is bilinear.
; It is the bilinear form of the quadratic form of V. (map (lambda (x) (map (lambda (y) (sp x y)) basis)) basis) ; => ((-1 0 0 0) (0 -1 0 0) (0 0 -1 0) (0 0 0 -1)) ; Thus for v in V, (sp v v) is the norm squared of v:
(define (mag c)(if (number? c) (* c c) (+ (mag (car c)) (mag (cdr c)))))

(let ((v (Vr))) (+ (mag v) (sp v v))) ; => 0
(let ((a (Cr)))(+ (mag a)(sp a a)))
; but for other Clifford numbers it is not the obvious bilinear form. The quadratic form (sp x x) is neither positive definite nor negative definite and thus cannot yield a norm.

Program note: routine mag above assumes that there are numbers at the bottom—numbers that Scheme will recognize with the number? predicate. This is so if we start from reals but these functions will fail for surrogate numbers.

(let ((g01 (C* g0 g1))) (list (sp H1 H1) (sp g0 g0) (sp g01 g01))) ; => (1 -1 1)
Nonetheless using this quadratic form blindly in the Gram-Schmidt process we seem to extract the vector part of a Clifford number:
(define (gs x) (Ha (let sm ((s C0)(bs basis)) (if (null? bs) s
    (sm (C+ s (C* (Hrls (sp x (car bs))) (car bs))) (cdr bs))))))

(let ((x (Cr))) (list x (gs x)))
Note that (gs x) has the same components as x for those basis elements that are in V and 0 otherwise. A test for a Clifford value being in V is thus:
(define (V? x) (C0? (C- x (gs x))))
Now we can provide the predicate for belonging to the Clifford Group. It takes a special equivalence predicate if we want to test both exact and floating point Clifford numbers.
(define (turn v x) (C* x (C* v (Ha (C/ x)))))

(define (Cg? x) (and (not (zero? (sp x x))) (V? (turn (Vr) x))))
Note that (turn x v) = xvα(x−1) preserves the norm Q(v).

A few factoids are relevant here:

(Cg? (Cr)) ; => #f (I should hope so!)
(Cg? H1) ; => #t (the identity)
(Cg? (Vr)) ; => #t (reflection about some 3-space in V)
(Cg? (C* g1 g2)) ; => #t (a rotation)
(Cg? (C+ g1 g2)) ; => #t (a reflection)
(Cg? (C+ (C* g1 g2) g3)) ; => #f
Bulletin: We interrupt this program to anounce that we have just found out first zero divisor! Indeed
(let ((a (C+ (C* g1 g2) g3))(b (C+ (C* g2 g1) g3))) (list
  (C0? a) (C0? b) (C0? (C* a b)))) ; => (#f #f #t)
These two factors have no inverse and thus do not belong to the Clifford group. I thought that (sp x x)=0 was a test for such zero divisors but see below.

I don’t understand why (Cg? (C+ g2 (C* (Hrls 2)(C* g1 (C* g2 g3))))) yields #t but (Cg? (C+ g0 (C* (Hrls 2)(C* g1 (C* g2 g3))))) yields #f

(define e '((((0 . 1) 2 . 0) (3 . 0) 0 . 4) ((0 . 5) 6 . 0) (7 . 0) 0 . 8))
(Cg? (cons (car e)(car C0))) ; => #t
(Cg? (cons (car C0)(cdr e))) ; => #t
; but
(Cg? e) ; => #f

We have a crisis in multiplicative inverses. g = (C+ g0 (C* g1 (C* g2 g3))) has no inverse by my code. Inverting the rotation of g, and rotating back indicates that g indeed lacks an inverse despite (sp g g) => –2. We have two more zero divisors: (γ3 + γ0γ1γ2)(γ1 + γ0γ2γ3) = 0
So much for the conjecture that pure all even or odd Clifford numbers have inverses.

(define (nrm cn) (sp cn cn))

(let ((a (C+ g1 (C* g0 (C* g2 g3))))(b (C+ g3 (C* g2 (C* g0 g1))))) (cons
  (list (C0? a) (C0? b) (C0? (C* a b)))
  (list (nrm a) (nrm b) (nrm (C* a b)))
)) ; => ((#f #f #t) . (-2 -2 0))

Getting the Real Rotation

To compute the orthogonal matrix for a given Clifford group member we record the action of that number on each of the elements of basis.
(define (Om cn) (let ((cni (Ha (C/ cn)))) (map (lambda (be)
   (map (lambda (x) (sp x (C* cn (C* (Ha be) cni)))) basis)) basis)))

(Om H1) ; => ((1 0 0 0) (0 1 0 0) (0 0 1 0) (0 0 0 1)) ; OK
(Om g0) ; => ((1 0 0 0) (0 1 0 0) (0 0 1 0) (0 0 0 -1)) ; OK
(Om (C* g1 g3)) ; => ((-1 0 0 0) (0 1 0 0) (0 0 -1 0) (0 0 0 1)) ; good
(Om (C+ g1 g3)) ; => ((0 0 -1 0) (0 1 0 0) (-1 0 0 0) (0 0 0 1)) ; good, reflection off of 45 degree plane
(Om (C+ (C* (Hrls 3/5) H1) (C* (Hrls 4/5) g1))) ; => ((1 0 0 0) (0 1 0 0) (0 0 -7/25 0) (0 0 0 1))
We have work to do. Note that:
(Cg? (C+ (C* (Hrls 3/5) H1) (C* (Hrls 4/5) g1))) ; => #f
My error was that you can never add an even cn to an odd cn and expect to stay in the Clifford group. While there are small rotations that dont move any vector much, there are no small reflections. A small rotation is near the identity whose cn is H1. Thus the cn of a small rotation is near H1. Here is the cn for a small rotation:
(define sr (C+ (C* (Hrls (cos 0.1)) H1) (C* (Hrls (sin 0.1)) (C* g0 g2))))

sr ; => ((((0.9950041652780258 . 0) 0 . 0) (0.09983341664682815 . 0) 0 . 0) ((0 . 0) 0 . 0) (0 . 0) 0 . 0)

(Cg? sr) ; => #t

(Om sr) ; => ((1.0 0 0 0) (0 0.9800665778412416 0 -0.19866933079506122) (0 0 1.0 0) (0 0.19866933079506122 0 0.9800665778412416))
We were lucky with (Cg? sr) that floating point calculations rounded just right to give exact 0.


In summary the Clifford group is the set of Clifford numbers that denote rotations and reflections of the base vector space. Clifford multiplication is the operator for this group. They are all even or odd. Among even and odd clifford numbers, some lack inverses, and are thus not in the Clifford group. Some odd Clifford numbers with inverses fail to leave V invariant and are thus not in the group. Scalar non zero multiples of a cn in the group are in the group and denote the same orientation. −cn denotes the same orientation as cn but denotes the opposite maneuver. I don’t know whether there are other cases where two cns denote the same orientation. Cg? above tests for membership in the Clifford group. Om above computes the orthogonal matrix corresponding to a given Clifford number.

Quoting Baez

To see how this works, first let Pin(n) be the group sitting inside Cliff(n) that consists of all products of unit vectors in ℝn. This group is a double cover of the orthogonal group O(n), where given any unit vector v∊ℝn, we map both ±v∊Pin(n) to the element of O(n) that reflects across the hyperplane perpendicular to v. Since every element of O(n) is a product of reflections, this homomorphism is indeed onto.
There are clues here. Can it be that among all of the cns of the group that denote the same orientation, there is just one, or two that are a product of ‘unit vectors’? No, the dimensions are wrong.

My code suggests that products of members of V are indeed in the clifford group.

(Cg? (Vr)) ; => #t
(Cg? (C* (Vr) (Vr))) ; => #t
(Cg? (C* (C* (Vr) (Vr)) (Vr))) ; => #t
(Cg? (C* (C* (Vr) (Vr)) (C* (Vr) (Vr)))) ; => #t
The question remains, is every element of the Clifford group the product of vectors in V? (or must one do some adding?)

I think any polynomial in a product of vectors is in the group. The terms of a polynomial commute and sums of commuting group members are members.

(define a (let ((a (C* (Vr)(Vr))))(C+ (C+ (sm .7 C1)(sm -.5 a))(sm .3 (C* a a)))))
seems to be a member of the group. Sums of products of vectors, when the products don’t commute, are not generally in the group.


The Clifford scalar product, here sp, is a bilinear form. It is multiplicative:
(let ((x (Cr))(y (Cr))(a (Cr))) (cons
  (- (sp (C* a x) y) (sp x (C* (tr a) y)))
  (- (sp (C* x a) y) (sp x (C* y (tr a)))))) ; => (0 . 0)


lstr below turns a cons tree into a leaf list.
(lstr '((1 . 2) . (3 . (4 . 5)))) => (1 2 3 4 5)
(define (lstr x) (let ls ((x x)(k '())) (if (pair? x) (ls (car x) (ls (cdr x) k))
  (cons x k))))