symgeoalg

symbolic geometric algebra calculations
git clone git://git.rr3.xyz/symgeoalg
Log | Files | Refs | README | LICENSE

commit a6c66052d01a7925848f6de02bd5b9e74a772179
parent ab38267ed2c9b057de5be6780c0e9184be28dd0b
Author: Robert Russell <robertrussell.72001@gmail.com>
Date:   Sat, 27 Jul 2024 00:41:12 -0700

Organize and simplify geometric algebra mul

Currently there is a bug in mul for GeometricAlgebra.

Also, ToString for GeometricAlgebra orders terms weirdly.

Diffstat:
MMain.lean | 168++++++++++++++++++++++++++++++-------------------------------------------------
1 file changed, 63 insertions(+), 105 deletions(-)

diff --git a/Main.lean b/Main.lean @@ -1,7 +1,7 @@ import Batteries.Data.Rat -------------------------------------------------------------------------------- --- Util +-- Fin util def finSum (i : Fin (m + n)) : Sum (Fin m) (Fin n) := -- Commute m and n in i's type to please Fin.subNat. @@ -33,6 +33,19 @@ def finProd (i : Fin (m * n)) : Prod (Fin m) (Fin n) := (q, r) -------------------------------------------------------------------------------- +-- BitVec util + +def bitVecFoldl (f : α -> Bool -> α) (bv : BitVec n) (init : α) : α := + Fin.foldl n (fun acc i => f acc (bv.getLsb i)) init + +def bitVecEnuml (n : Nat) (f : α -> BitVec n -> α) (init : α) : α := + let loop acc i := f acc (BitVec.ofFin i) + Fin.foldl (2^n) loop init + +def bitVecPopCount (bv : BitVec n) : Nat := + bitVecFoldl (fun acc bit => acc + bit.toNat) bv 0 + +-------------------------------------------------------------------------------- -- Notation instance : HPow Type Nat Type where @@ -240,52 +253,9 @@ instance [Field F] : Algebra F F where -- TODO: More Algebra instances - - - -def bitVecFoldl (f : α -> Bool -> α) (bv : BitVec n) (init : α) : α := - sorry - -def bitVecEnuml (n : Nat) (f : α -> BitVec n -> α) (init : α) : α := - let loop acc i := f acc (BitVec.ofFin i) - Fin.foldl (2^n) loop init - - -structure BasisBlade (n : Nat) : Type where - bits : BitVec n - --- TODO: ? -def BasisBlade.empty : BasisBlade n -> Bool := sorry - -def BasisBlade.has (bld : BasisBlade n) (i : Fin n) : Bool := - bld.bits.getLsb i - --- TODO: delete --- def BasisBlade.cons (bit : Bool) (bld : BasisBlade i) : BasisBlade (i + 1) := --- ⟨BitVec.cons bit bld.bits⟩ --- def BasisBlade.enum (n : Nat) : List (BasisBlade n) := --- let enum (i : Fin n) (b : List (BasisBlade i.val)) : List (BasisBlade (i.val + 1)) := --- (BasisBlade.cons false <$> b) ++ (BasisBlade.cons true <$> b) --- Fin.hIterate (List ∘ BasisBlade) [⟨BitVec.nil⟩] enum - -def BasisBlade.mulScalar [Field F] [AddGroup V] [VectorSpace F V] {b : FiniteBasis V n} - (q : OrthoQuadraticForm b) (bld0 bld1 : BasisBlade n) : F := - bitVecFoldl x (bld0 &&& bld1) 0 - -def BasisBlade.foldl (n : Nat) (f : α -> BasisBlade n -> α) (init : α) : α := - let loop acc i := f acc ⟨BitVec.ofFin i⟩ - Fin.foldl (2^n) loop init - -instance : ToString (BasisBlade n) where - toString bld := - let indexToString i acc := if bld.has i then toString i :: acc else acc - let indexStrings := Fin.foldr n indexToString [] - let sep := if n > 9 then "," else "" - "{" ++ String.intercalate sep indexStrings ++ "}" - - - - +-------------------------------------------------------------------------------- +-- Geometric algebra generation from vector spaces with a quadratic form and +-- an orthogonal finite basis structure GeometricAlgebra [Field F] [AddGroup V] [VectorSpace F V] {b : FiniteBasis V n} (q : OrthoQuadraticForm b) : Type where @@ -341,77 +311,65 @@ instance [Field F] [AddGroup V] [VectorSpace F V] {b : FiniteBasis V n} -- Now, if we want the component of v * w corresponding to blade bld = 010, we -- consider the following pairs of vbld and wbld: -- vbld wbld --- 010 000 --- 011 001 -- 000 010 -- 001 011 --- 110 100 --- 111 101 +-- 010 000 +-- 011 001 -- 100 110 -- 101 111 --- (These are just all 2^3 3-bit numbers, but with one column (vbld in this +-- 110 100 +-- 111 101 +-- (These are just all 2^3 3-bit numbers, but with one column (wbld in this -- case) XORed with bld.) Then we multiply the coefficients corresponding to --- each row and sum the results. We call each row a "term". We build up each --- row (i.e., (vbld, wbld) pair) incrementally, bit-by-bit, so an - --- When vbld and wbld share a bit, it "cancels" --- and gets replaced by a scalar in accordance with the quadratic form. Also, - - --- The type --- PartialTerm F i represents part of such a term, specifically the first i bits of l and r --- and an associated scalar a. We also keep track of the parity of the l bits seen so far, so --- that we know if we should flip the sign of a when we get the next r bit. This type should --- be local to the multiplication function, but I don't think structures can be local in Lean --- (ughh!). --- structure PartialTerm (F : Type) [Field F] (i : Nat) where --- a : F --- lParity : F --- l : BitVec i --- r : BitVec i --- def PartialTerm.cons [Field F] (a : F) (l r : Bool) (pt : PartialTerm F i) : PartialTerm F (i + 1) := --- let a' := a * pt.a * if r then pt.lParity else 1 --- let lParity' := pt.lParity * if l then -1 else 1 --- ⟨a', lParity', BitVec.cons l pt.l, BitVec.cons r pt.r⟩ --- def PartialTerm.eval [Field F] {q : QuadraticForm F n} (u v : GeometricAlgebra F n q) (pt : PartialTerm F n) : F := --- pt.a * u.fn ⟨pt.l⟩ * v.fn ⟨pt.r⟩ +-- each row and sum the results. Additionally, we must calculate a sign from +-- vbld and wbld (in accordance with the equation ei * ej = - ej * ei for all +-- basis vectors ei != ej), and we must calculuate a scalar by multiplying the +-- "squares" of each basis vector shared by vbld and wbld, where "square" means +-- apply the quadratic form. instance [Field F] [AddGroup V] [VectorSpace F V] {b : FiniteBasis V n} {q : OrthoQuadraticForm b} : MulMonoid (GeometricAlgebra q) where - one := ⟨fun b => if b.bits = 0 then 1 else 0⟩ + one := ⟨fun bld => if bld = 0 then 1 else 0⟩ mul v w := - let coords (bld : BasisBlade n) : F := - let addTerm (acc : F) (vbld : BasisBlade n) : F := - let wbld : BasisBlade n := ⟨vbld.bits ^^^ bld.bits⟩ - let bldScalar : F := - let vCoeff : F := v.coords vbld - let wCoeff : F := w.coords wbld - acc + v.coords vbld * w.coords wbld * vbld.mul wbld - BasisBlade.foldl n addTerm 0 + let sign (x y : BitVec n) : F := + let addSwaps (acc : Nat) (i : Fin n) : Nat := + acc + bitVecPopCount (x &&& (y >>> (i.val + 1))) + let nSwaps := Fin.foldl n addSwaps 0 + if nSwaps % 2 = 0 then 1 else -1 + + let scalar (x y : BitVec n) : F := + let z := x &&& y + let mulSquares (acc : F) (i : Fin n) : F := + if z.getLsb i then acc * q.evalBasis i else acc + Fin.foldl n mulSquares 1 + + let coords (bld : BitVec n) : F := + let addTerm (acc : F) (vbld : BitVec n) : F := + let wbld : BitVec n := vbld ^^^ bld + acc + sign vbld wbld * scalar vbld wbld * v.coords vbld * w.coords wbld + bitVecEnuml n addTerm 0 ⟨coords⟩ - --mul v w := - -- let terms (b : Blade n) (i : Fin n) (acc : List (PartialTerm F i.val)) : List (PartialTerm F (i.val + 1)) := - -- if b.has i then - -- (PartialTerm.cons 1 false true <$> acc) ++ (PartialTerm.cons 1 true false <$> acc) - -- else - -- (PartialTerm.cons 1 false false <$> acc) ++ (PartialTerm.cons (q i) true true <$> acc) - -- let coords (b : BasisBlade n) : F := - -- let ts := Fin.hIterate (List ∘ PartialTerm F) [⟨1, 1, BitVec.nil, BitVec.nil⟩] (terms b) - -- let x := PartialTerm.eval u v <$> ts - -- List.foldl AddSemigroup.add 0 x - -- ⟨coords⟩ --------------------------------------------------------------------------------- +instance [Field F] [AddGroup V] [VectorSpace F V] {b : FiniteBasis V n} + {q : OrthoQuadraticForm b} : Algebra F (GeometricAlgebra q) where -------------------------------------------------------------------------------- +-- Main -def main : IO Unit := +def main : IO Unit := do let F : Type := Rat - let n : Nat := 3 - let q : QuadraticForm F 3 := fun - | 0 => 1 - | 1 => 1 - | 2 => 1 - let u : GeometricAlgebra F n q := ⟨fun _ => 1⟩ - let w : GeometricAlgebra F n q := u * u + let V : Type := F ^ 3 + let b : FiniteBasis V 3 := FiniteBasis.pow (FiniteBasis.field F) 3 + let q : OrthoQuadraticForm b := ⟨ + fun + | 0 => 1 + | 1 => 1 + | 2 => 1 + ⟩ + let G : Type := GeometricAlgebra q + + let v : G := ⟨fun _ => 1⟩ + let w : G := v * v + + IO.println v IO.println w