Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Features from meuns/galgebra: GA4CS examples, PGA, code-generation, and more #68

Open
wants to merge 87 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 82 commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
2f925ff
remove and ignore pyc files
meuns Mar 6, 2016
c67ac34
leo dorst book chapter 2 drills
meuns Mar 6, 2016
5fded26
ignore eclipe project files
meuns Mar 10, 2016
216731c
leo dorst book chapter 2 exercices (in progress)
meuns Mar 10, 2016
cf9c50f
fix and test Mv.blade_coefs method
meuns Mar 11, 2016
50509ff
leo dorst book chapter 2 exercices (in progress)
meuns Mar 17, 2016
dc779f2
remove and ignore pyc files
meuns Mar 6, 2016
d6ec574
leo dorst book chapter 2 drills
meuns Mar 6, 2016
0b9b78f
ignore eclipe project files
meuns Mar 10, 2016
8cd317b
leo dorst book chapter 2 exercices (in progress)
meuns Mar 10, 2016
d9f0d7b
leo dorst book chapter 2 exercices (in progress)
meuns Mar 17, 2016
3af9f1e
merge after rebasing on brombo
meuns Mar 17, 2016
1b1672a
leo dorst book chapter 2 exercices (in progress)
meuns Mar 23, 2016
2f4aa45
cleanup path hack
meuns Mar 27, 2016
539ef47
leo dorst book chapter 3 exercices (in progress)
meuns Mar 27, 2016
4791c4d
remove and ignore pyc files
meuns Mar 6, 2016
053cead
leo dorst book chapter 2 drills
meuns Mar 6, 2016
c10a4c9
ignore eclipe project files
meuns Mar 10, 2016
f908814
leo dorst book chapter 2 exercices (in progress)
meuns Mar 10, 2016
93b9a83
fix and test Mv.blade_coefs method
meuns Mar 11, 2016
ff08a83
leo dorst book chapter 2 exercices (in progress)
meuns Mar 17, 2016
a9341b4
leo dorst book chapter 2 exercices (in progress)
meuns Mar 10, 2016
e46619f
leo dorst book chapter 2 exercices (in progress)
meuns Mar 23, 2016
96b43a1
cleanup path hack
meuns Mar 27, 2016
7923202
leo dorst book chapter 3 exercices (in progress)
meuns Mar 27, 2016
dd79887
merge branch 'master' of https://github.com/meuns/galgebra after reba…
meuns Apr 9, 2016
47564c4
add I_inv method to Ga class
meuns Apr 9, 2016
569a40c
remove Abs from Mv.norm2 method
meuns Apr 9, 2016
5edaa64
leo dorst book chapter 3 exercices (in progress)
meuns Apr 9, 2016
53f7af8
leo dorst book chapter 3 exercices (in progress)
meuns Apr 11, 2016
0c33701
cleanup chapter 3 exercices
meuns Apr 12, 2016
99e20e9
leo dorst book chapter 3 exercices (in progress)
meuns Apr 12, 2016
dcd1d45
leo dorst book chapter 3 exercices (in progress)
meuns Apr 15, 2016
7803817
leo dorst book chapter 3 exercices (in progress)
meuns Apr 17, 2016
ca9c388
leo dorst book chapter 2 exercices (in progress)
meuns Sep 29, 2019
d5028e1
leo dorst book chapter 2 exercices (in progress)
meuns Sep 30, 2019
0afad0b
compute grades using grade_decomposition instead of pure_grade, leo d…
meuns Oct 3, 2019
cef764f
leo dorst book chapter 3 exercices (in progress)
meuns Oct 3, 2019
5d637bb
more about cross product
meuns Oct 4, 2019
ff8d2e8
leo dorst book chapter 3 exercices (in progress)
meuns Oct 4, 2019
7b077f9
fix Mv.__mul__(A) when A is a scalar and self isn't
meuns Oct 4, 2019
e6d4291
leo dorst book chapter 6 exercices (in progress)
meuns Oct 4, 2019
9d1b6d0
leo dorst book chapter 6 exercices (in progress)
meuns Oct 4, 2019
c1eb831
leo dorst book chapter 6 exercices (in progress)
meuns Oct 6, 2019
99583d0
fix inv, norm2 and norm, enhance inverse test3_5_2
meuns Oct 6, 2019
941a780
Mv.__init__ can make k-blades using the 'blade' factory, fix Mv.__xor…
meuns Oct 7, 2019
a233877
leo dorst book chapter 6 exercices (in progress)
meuns Oct 7, 2019
b6ee442
leo dorst book chapter 7 exercices (in progress)
meuns Oct 7, 2019
5b124d9
Small fixes, cleanup and use don't use grade_decomposition if we alre…
meuns Oct 7, 2019
a94289b
Fix add missing parenthesis
meuns Oct 9, 2019
7a7617f
leo dorst book chapter 10 exercises (in progress)
meuns Oct 11, 2019
c2634e8
Rename a file
meuns Oct 11, 2019
080f6c0
Rename a file
meuns Oct 11, 2019
ff08cb6
leo dorst book chapter 11 exercises (in progress)
meuns Oct 12, 2019
2f26ea4
leo dorst book chapter 11 exercises (in progress)
meuns Oct 13, 2019
cc0bb70
Revert mistake about inv, norm and norm2
meuns Oct 22, 2019
1b41f89
A test about associativity of the outer product and calculating deter…
meuns Oct 22, 2019
f25281b
Generate some flat geometric algebra (like ganja.js)
meuns Oct 22, 2019
7905e50
leo dorst book chapter 13 exercises (in progress)
meuns Oct 23, 2019
fd88288
first pga version
meuns Oct 25, 2019
e9a8d80
More pga tests
meuns Oct 27, 2019
188aeb1
Generate flat pga
meuns Oct 27, 2019
9697689
Change norm computation for pga tests
meuns Oct 28, 2019
f5d4d87
More pga tests and squared norm
meuns Oct 29, 2019
1e2cda9
Cleanup, rotors and translators (work in progress)
meuns Oct 31, 2019
229bd4e
implement custom basis (like enki) and add more tests
meuns Oct 31, 2019
2fb10bb
implement custom basis (like enki) and add more tests
meuns Oct 31, 2019
41dbbef
Merge remote-tracking branch 'origin/master'
meuns Oct 31, 2019
d59b69b
leo dorst book chapter 8 exercises (in progress)
meuns Nov 1, 2019
9d4c5aa
Merge all brombo's commits until ae32af960f0525f42eff5b99f695b8e1a970…
meuns Nov 22, 2019
43e0f66
Merge commits until Run included
meuns Nov 22, 2019
b07e3ff
Quick and easy fixes after migrating to python 3
meuns Nov 22, 2019
c358afe
Merge all utensil commits in 2018 21ed56db65fc57cf720cab5f3425a06469e…
meuns Nov 22, 2019
634a4b0
Quick and easy fixes after merging utensil commits
meuns Nov 22, 2019
685455c
Merge all release_0_4_4 commits
meuns Nov 23, 2019
36df07f
Merge all pygae/master commits
meuns Nov 23, 2019
06682cb
Fix test2_12_1_4
meuns Nov 23, 2019
3722052
Refactor assertEquals, assertNotEquals and assertProjEquals and fix a…
meuns Nov 25, 2019
7c2069e
Symbols are real
meuns Nov 25, 2019
4fce49f
Fix PEP8
meuns Nov 25, 2019
1043951
Use assertEqual, assertNotEqual and assertProjEqual
meuns Nov 25, 2019
e376c59
Move all tests to test
meuns Nov 25, 2019
4689050
Merge pygae/master until commit 09ecbd1a4ad489fb3c579319faa2fd5ccfe77…
meuns Dec 1, 2019
c4693c8
Refactor chapter 13
meuns Dec 6, 2019
3c4a5b8
chapter 13 exercises (in progress)
meuns Dec 6, 2019
5fc94d2
Fix assertEqual for difficult expressions
meuns Dec 7, 2019
3fea69f
chapter 13 exercises (in progress)
meuns Dec 7, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions galgebra/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.pyc
111 changes: 88 additions & 23 deletions galgebra/ga.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ def __init__(self, bases, **kwargs):
metric.Metric.__init__(self, bases, **kwargs)

self.par_coords = None
self.build_bases()
self.build_bases(kwargs.get('sign_and_indexes', None))
self.dot_mode = '|'
self.basis_product_tables()

Expand Down Expand Up @@ -513,6 +513,9 @@ def E(self): # Unnoromalized pseudo-scalar
def I(self): # Noromalized pseudo-scalar
return self.i

def I_inv(self):
return self.i_inv

def X(self):
return self.mv(sum([coord*base for (coord, base) in zip(self.coords, self.basis)]))

Expand Down Expand Up @@ -660,7 +663,54 @@ def parametric(self, coords):
def basis_vectors(self):
return tuple(self.basis)

def build_bases(self):
def build_cobases(self, coindexes=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xref #215.

I think I understand the rough intent here, although it's not clear to me why a separate set of indices or signs are needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a "canonical" way for building cobases (see John Browne's book) and PGA uses some kind of "tricky" way for building it (J and Jinv stuff). My implementation is probably not the best we can do.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@enkimute, is "cobase" consistent with the terminology you'd use?

Copy link
Contributor Author

@meuns meuns Jan 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sign is for using the orthogonal wedge implementation provided by galgebra which needs a canonical basis. PGA basis isn't canonical too.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you say the PGA basis isn't canonical, do you mean that the default is not to use lexicographically-order basis blades? Eg, e132 is considered a "base" blade in that algebra, rather than e123?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeap

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This forum post captures the issue I assume?

https://discourse.bivector.net/t/dual-operator-disambiguation/59/45

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeap

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another way to handle this might just be in the printing only

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be very nice if you are able to run test_pga.py without adding the custom indexes and signs. I don't see how we can achieve this.

"""
Cobases for building Poincare duality, this is useful for defining wedge and vee without using I nor any metric.
"""
# TODO: check this can be used with another GA than 3D PGA...
if coindexes is None:
basis_indexes = tuple(self.n_range)
self.coindexes = []
self.coindexes_lst = []
for i in reversed(basis_indexes):
base_tuple = tuple(reversed(tuple(combinations(basis_indexes, i + 1))))
self.coindexes.append(base_tuple)
self.coindexes_lst += list(base_tuple)
self.coindexes.append(())
self.coindexes = tuple(self.coindexes)
else:
self.coindexes = coindexes
self.coindexes_lst = [index for cograde_index in coindexes for index in cograde_index]

def format_symbol_name(symbol_index):
return (''.join([str(self.basis[i]) + '^' for i in symbol_index]))[:-1]

n = self.n

self.coblades_lst = []
for cograde_index in self.coindexes:
k = len(cograde_index[0]) if len(cograde_index) > 0 else 0
for cobase_index in cograde_index:
coblade_sign = -1 if k == n - 1 and k % 2 == 1 else 1
coblade = coblade_sign * Symbol(format_symbol_name(cobase_index), commutative=False)
self.coblades_lst.append(coblade)
self.coblades_lst0 = self.coblades_lst + [S(1),]

self.coblades_inv_lst = []
for grade_index in self.indexes:
k = len(grade_index[0]) if len(grade_index) > 0 else 0
for base_index in grade_index:
coblade_inv_sign = -1 if k == 1 and k % 2 == 1 else 1
coblade_inv = coblade_inv_sign * Symbol(format_symbol_name(base_index), commutative=False)
self.coblades_inv_lst.append(coblade_inv)
self.coblades_inv_lst = list(reversed(self.coblades_inv_lst))
self.coblades_inv_lst0 = self.coblades_inv_lst + [S(1),]

self.mv_blades_lst0 = []
for obj in self.blades_lst0:
self.mv_blades_lst0.append(self.mv(obj))

def build_bases(self, sign_and_indexes=None):
r"""
The bases for the multivector (geometric) algebra are formed from
all combinations of the bases of the vector space and the scalars.
Expand Down Expand Up @@ -696,14 +746,18 @@ def build_bases(self):
"""

# index list for multivector bases and blades by grade
basis_indexes = tuple(self.n_range)
self.indexes = [()]
self.indexes_lst = []
for i in basis_indexes:
base_tuple = tuple(combinations(basis_indexes, i + 1))
self.indexes.append(base_tuple)
self.indexes_lst += list(base_tuple)
self.indexes = tuple(self.indexes)
if sign_and_indexes is None:
basis_indexes = tuple(self.n_range)
self.indexes = [()]
self.indexes_lst = []
for i in basis_indexes:
base_tuple = tuple(combinations(basis_indexes, i + 1))
self.indexes.append(base_tuple)
self.indexes_lst += list(base_tuple)
self.indexes = tuple(self.indexes)
else:
self.indexes = sign_and_indexes[1]
self.indexes_lst = [index for grade_index in self.indexes for index in grade_index]

# list of non-commutative symbols for multivector bases and blades
# by grade and as a flattened list
Expand Down Expand Up @@ -742,9 +796,20 @@ def build_bases(self):

self.blades_to_indexes = []
self.indexes_to_blades = []
for (index, blade) in zip(self.indexes_lst, self.blades_lst):
self.blades_to_indexes.append((blade, index))
self.indexes_to_blades.append((index, blade))
if sign_and_indexes is None:
for (index, blade) in zip(self.indexes_lst, self.blades_lst):
self.blades_to_indexes.append((blade, (1, index)))
self.indexes_to_blades.append((index, blade))
else:
basis_indexes = tuple(self.n_range)
default_indexes_lst = []
for i in basis_indexes:
base_tuple = tuple(combinations(basis_indexes, i + 1))
default_indexes_lst += list(base_tuple)
signs_lst = [sign for grade_sign in sign_and_indexes[0] for sign in grade_sign]
for (default_index, sign, blade) in zip(default_indexes_lst, signs_lst, self.blades_lst):
self.blades_to_indexes.append((blade, (sign, default_index)))
self.indexes_to_blades.append((default_index, sign * blade))
self.blades_to_indexes_dict = OrderedDict(self.blades_to_indexes)
self.indexes_to_blades_dict = OrderedDict(self.indexes_to_blades)

Expand Down Expand Up @@ -885,11 +950,11 @@ def geometric_product_basis_blades(self, blade12):
# geometric (*) product for orthogonal basis
if self.is_ortho:
(blade1, blade2) = blade12
index1 = self.blades_to_indexes_dict[blade1]
index2 = self.blades_to_indexes_dict[blade2]
sign1, index1 = self.blades_to_indexes_dict[blade1]
sign2, index2 = self.blades_to_indexes_dict[blade2]
blade_index = list(index1 + index2)
repeats = []
sgn = 1
sgn = sign1 * sign2
for i in range(1, len(blade_index)):
save = blade_index[i]
j = i
Expand Down Expand Up @@ -1030,15 +1095,15 @@ def wedge_product_basis_blades(self, blade12): # blade12 = blade1*blade2
# outer (^) product of basis blades
# this method works for both orthogonal and non-orthogonal basis
(blade1, blade2) = blade12
index1 = self.blades_to_indexes_dict[blade1]
index2 = self.blades_to_indexes_dict[blade2]
sign1, index1 = self.blades_to_indexes_dict[blade1]
sign2, index2 = self.blades_to_indexes_dict[blade2]
index12 = list(index1 + index2)

if len(index12) > self.n:
return 0
(sgn, wedge12) = Ga.blade_reduce(index12)
if sgn != 0:
return(sgn * self.indexes_to_blades_dict[tuple(wedge12)])
return(sgn * sign1 * sign2 * self.indexes_to_blades_dict[tuple(wedge12)])
else:
return 0

Expand All @@ -1048,8 +1113,8 @@ def dot_product_basis_blades(self, blade12, mode):
# dot (|), left (<), and right (>) products
# dot product for orthogonal basis
(blade1, blade2) = blade12
index1 = self.blades_to_indexes_dict[blade1]
index2 = self.blades_to_indexes_dict[blade2]
sign1, index1 = self.blades_to_indexes_dict[blade1]
sign2, index2 = self.blades_to_indexes_dict[blade2]
index = list(index1 + index2)
grade1 = len(index1)
grade2 = len(index2)
Expand All @@ -1065,7 +1130,7 @@ def dot_product_basis_blades(self, blade12, mode):
if grade < 0:
return 0
n = len(index)
sgn = 1
sgn = sign1 * sign2
result = 1
ordered = False
while n > grade:
Expand Down Expand Up @@ -1185,7 +1250,7 @@ def base_blade_conversions(self):

# expand blade basis in terms of base basis
for blade in self.blades_lst:
index = self.blades_to_indexes_dict[blade]
sign, index = self.blades_to_indexes_dict[blade]
grade = len(index)
if grade == 1:
blade_expansion.append(blade)
Expand Down
122 changes: 122 additions & 0 deletions galgebra/generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# -*- coding: utf-8 -*-

from sympy import Symbol

from .ga import Ga
from .mv import J, Jinv


def create_multivector(GA, name):
blades = [1] + GA.blades_lst
mv = GA.mv(0, 'scalar')
for blade_index, blade in enumerate(blades):
mv += Symbol('{name}[{i}]'.format(name=name, i=blade_index)) * blade
return mv


_CLASS_TEMPLATE = '''# -*- coding: utf-8 -*-


class FlatMv(object):
def __init__(self, coefs):
assert len(coefs) == {class_blade_count}
self.coefs = coefs

def __getitem__(self, index):
return self.coefs[index]
'''

_BINARY_OPERATOR_TEMPLATE = '''
def __{op_name}__(self, other):
x = self.coefs
y = other.coefs
return FlatMv([
{op_list}
])
'''

_UNARY_METHOD_TEMPLATE = '''
def {method_name}(self):
x = self.coefs
return FlatMv([
{method_list}
])
'''

_BINARY_METHOD_TEMPLATE = '''
def {method_name}(self, other):
x = self.coefs
y = other.coefs
return FlatMv([
{method_list}
])
'''


def format_class(class_blade_count):
return _CLASS_TEMPLATE.format(class_blade_count=class_blade_count)


def format_op_name(name):
return name


def format_op_list(mv):
return ',\n '.join(str(blade_coef) for blade_coef in mv.blade_coefs())


def format_binary_operator(name, mv):
return _BINARY_OPERATOR_TEMPLATE.format(op_name=format_op_name(name), op_list=format_op_list(mv))


def format_method_name(name):
return name


def format_method_list(mv):
return ',\n '.join(str(blade_coef) for blade_coef in mv.blade_coefs())


def format_unary_method(name, mv):
return _UNARY_METHOD_TEMPLATE.format(method_name=format_method_name(name), method_list=format_method_list(mv))


def format_binary_method(name, mv):
return _BINARY_METHOD_TEMPLATE.format(method_name=format_method_name(name), method_list=format_method_list(mv))


def format_geometric_algebra(GA):

X = create_multivector(GA, 'x')
Y = create_multivector(GA, 'y')

flat_geometric_algebra = format_class(len(GA.blades_lst0))
flat_geometric_algebra += format_binary_operator('add', X + Y)
flat_geometric_algebra += format_binary_operator('sub', X - Y)
flat_geometric_algebra += format_binary_operator('mul', X * Y)
flat_geometric_algebra += format_binary_operator('and', Jinv(J(X) ^ J(Y)))
flat_geometric_algebra += format_binary_operator('xor', X ^ Y)
flat_geometric_algebra += format_binary_operator('lshift', X << Y)
flat_geometric_algebra += format_binary_operator('rshift', X >> Y)
flat_geometric_algebra += format_binary_method('meet', Jinv(J(X) ^ J(Y)))
flat_geometric_algebra += format_binary_method('join', X ^ Y)
flat_geometric_algebra += format_unary_method('rev', X.rev())

return flat_geometric_algebra


def flatten(flat_ga_module, mv):
return flat_ga_module.FlatMv([blade_coef for blade_coef in mv.blade_coefs()])


def expand(GA, flat_mv):
assert len(flat_mv.coefs) == len(GA.blades_lst0)
mv = GA.mv(0, 'scalar')
for blade_coef, blade in zip(flat_mv.coefs, GA.blades_lst0):
mv += blade_coef * blade
return mv


if __name__ == "__main__":
GA = Ga('e*1|2|3', g=[1, 1, 1])
print(format_geometric_algebra(GA))
3 changes: 2 additions & 1 deletion galgebra/metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,8 @@ class Metric(object):
'gsym': (None, 'String s to use "det("+s+")" function in reciprocal basis'),
'sig': ('e', 'Signature of metric, default is (n,0) a Euclidean metric'),
'Isq': ('-', "Sign of square of pseudo-scalar, default is '-'"),
'wedge': (True, 'Use ^ symbol to print basis blades')}
'wedge': (True, 'Use ^ symbol to print basis blades'),
'sign_and_indexes': (None, 'bases indexes')}

@staticmethod
def dot_orthogonal(V1, V2, g=None):
Expand Down
Loading