diff --git a/.gitignore b/.gitignore
index af2f5375..3161f0e5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@ __pycache__/
# Distribution / packaging
.Python
+env/
build/
develop-eggs/
dist/
@@ -43,7 +44,7 @@ htmlcov/
.cache
nosetests.xml
coverage.xml
-*.cover
+*.covercover
.hypothesis/
# Translations
@@ -102,3 +103,9 @@ venv.bak/
# mypy
.mypy_cache/
+
+# py.test cache
+.pytest_cache
+
+# backup files from 2to3
+**/*.bak
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..f4b1cd71
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,28 @@
+
+sudo: false
+
+language: python
+
+matrix:
+ include:
+ - os: linux
+ python: '2.7'
+ env: CONDA=true
+ # Remove too many targets for now to speed up a build
+ # - os: linux
+ # python: '3.5'
+ # env: CONDA=true
+ - os: linux
+ python: '3.6'
+ env: CONDA=true
+
+
+before_install:
+ - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then lsb_release -a ; fi
+
+install:
+ - python setup.py install
+
+script:
+ - py.test galgebra/test_test.py
+ - py.test galgebra/test_mv.py
diff --git a/galgebra/ga.py b/galgebra/ga.py
index 2afb045f..1b4a3277 100755
--- a/galgebra/ga.py
+++ b/galgebra/ga.py
@@ -1,5 +1,9 @@
# ga.py
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
import operator
import copy
from sympy import diff, Rational, Symbol, S, Mul, Pow, Add, \
@@ -9,10 +13,11 @@
from collections import OrderedDict
#from sympy.core.compatibility import combinations
from itertools import combinations
-import printer
-import metric
-import mv
-import lt
+from . import printer
+from . import metric
+from . import mv
+from . import lt
+from functools import reduce
half = Rational(1, 2)
one = S(1)
@@ -104,7 +109,7 @@ def nc_subs(expr, base_keys, base_values=None):
keys for long lists of keys.
"""
if base_values is None:
- [base_keys, base_values] = zip(*base_keys)
+ [base_keys, base_values] = list(zip(*base_keys))
if expr.is_commutative:
return expr
@@ -129,7 +134,7 @@ def nc_subs(expr, base_keys, base_values=None):
class Ga(metric.Metric):
- """
+ r"""
The vector space (basis, metric, derivatives of basis vectors) is
defined by the base class 'Metric'.
@@ -299,7 +304,7 @@ def preset(setting, root='e', debug=False):
return Ga(*kargs, **kwargs)
def __eq__(self, ga):
- if self.name == self.ga:
+ if self.name == ga.name:
return True
return False
@@ -356,7 +361,7 @@ def __init__(self, bases, **kwargs):
if self.e_sq.is_number:
if self.e_sq == S(0):
self.sing_flg = True
- print '!!!!If I**2 = 0, I cannot be normalized!!!!'
+ print('!!!!If I**2 = 0, I cannot be normalized!!!!')
#raise ValueError('!!!!If I**2 = 0, I cannot be normalized!!!!')
if self.e_sq > S(0):
self.i = self.e/sqrt(self.e_sq)
@@ -379,7 +384,7 @@ def __init__(self, bases, **kwargs):
self.grads()
if self.debug:
- print 'Exit Ga.__init__()'
+ print('Exit Ga.__init__()')
self.a = [] # List of dummy vectors for Mlt calculations
self.agrads = {} # Gradient operator with respect to vector a
@@ -393,7 +398,7 @@ def make_grad(self, a, cmpflg=False): # make gradient operator with respect to
self.make_grad(ai)
return
- if a in self.agrads.keys():
+ if a in list(self.agrads.keys()):
return self.agrads[a]
if isinstance(a, mv.Mv):
@@ -467,7 +472,7 @@ def mv(self, root=None, *kargs, **kwargs):
return mv.Mv(root, *kargs, **kwargs)
def mvr(self,norm=True):
- """
+ r"""
Returns tumple of reciprocal basis vectors. If norm=True or
basis vectors are orthogonal the reciprocal basis is normalized
in the sense that
@@ -765,7 +770,7 @@ def basis_product_tables(self):
self.dot_mode = '|'
if self.debug:
- print 'Exit basis_product_tables.\n'
+ print('Exit basis_product_tables.\n')
return
def build_connection(self):
@@ -1056,7 +1061,7 @@ def non_orthogonal_mul_table(self):
self.basic_mul_table_dict = OrderedDict(mul_table)
if self.debug:
- print 'basic_mul_table =\n', self.basic_mul_table
+ print('basic_mul_table =\n', self.basic_mul_table)
return
def non_orthogonal_bases_products(self, base12): # base12 = (base1,base2)
@@ -1103,10 +1108,10 @@ def base_blade_conversions(self):
blade_expansion.append(expand(a_W_A))
self.blade_expansion = blade_expansion
- self.blade_expansion_dict = OrderedDict(zip(self.blades_lst, blade_expansion))
+ self.blade_expansion_dict = OrderedDict(list(zip(self.blades_lst, blade_expansion)))
if self.debug:
- print 'blade_expansion_dict =', self.blade_expansion_dict
+ print('blade_expansion_dict =', self.blade_expansion_dict)
# expand base basis in terms of blade basis
@@ -1126,7 +1131,7 @@ def base_blade_conversions(self):
self.base_expansion_dict = OrderedDict(base_expand)
if self.debug:
- print 'base_expansion_dict =', self.base_expansion_dict
+ print('base_expansion_dict =', self.base_expansion_dict)
return
@@ -1236,7 +1241,7 @@ def grade_decomposition(self, A):
grade_dict = {}
for (coef,blade) in zip(coefs,blades):
if blade == one:
- if 0 in grade_dict.keys():
+ if 0 in list(grade_dict.keys()):
grade_dict[0] += coef
else:
grade_dict[0] = coef
@@ -1247,7 +1252,7 @@ def grade_decomposition(self, A):
else:
grade_dict[grade] = coef * blade
if isinstance(A, mv.Mv):
- for grade in grade_dict.keys():
+ for grade in list(grade_dict.keys()):
grade_dict[grade] = self.mv(grade_dict[grade])
return grade_dict
@@ -1422,7 +1427,7 @@ def even_odd(self, A, even=True): # Return even or odd part of A
##################### Multivector derivatives ######################
def build_reciprocal_basis(self,gsym):
- """
+ r"""
Calculate reciprocal basis vectors e^{j} where
e^{j}\cdot e_{k} = \delta_{k}^{j}
and \delta_{k}^{j} is the kronecker delta. We use the formula
@@ -1439,7 +1444,7 @@ def build_reciprocal_basis(self,gsym):
"""
if self.debug:
- print 'Enter build_reciprocal_basis.\n'
+ print('Enter build_reciprocal_basis.\n')
if self.is_ortho:
self.r_basis = [self.basis[i] / self.g[i, i] for i in self.n_range]
@@ -1462,7 +1467,7 @@ def build_reciprocal_basis(self,gsym):
else:
self.e_sq = simplify((self.e * self.e).obj)
if self.debug:
- print 'E**2 =', self.e_sq
+ print('E**2 =', self.e_sq)
duals = list(self.blades_lst[-(self.n + 1):-1])
duals.reverse()
@@ -1477,14 +1482,14 @@ def build_reciprocal_basis(self,gsym):
if self.debug:
printer.oprint('E', self.iobj, 'E**2', self.e_sq, 'unnormalized reciprocal basis =\n', self.r_basis)
self.dot_mode = '|'
- print 'reciprocal basis test ='
+ print('reciprocal basis test =')
for ei in self.basis:
for ej in self.r_basis:
ei_dot_ej = self.dot(ei, ej)
if ei_dot_ej == zero:
- print 'e_{i}|e_{j} = ' + str(ei_dot_ej)
+ print('e_{i}|e_{j} = ' + str(ei_dot_ej))
else:
- print 'e_{i}|e_{j} = ' + str(expand(ei_dot_ej / self.e_sq))
+ print('e_{i}|e_{j} = ' + str(expand(ei_dot_ej / self.e_sq)))
self.e_obj = self.blades_lst[-1]
@@ -1527,7 +1532,7 @@ def build_reciprocal_basis(self,gsym):
self.g_inv = g_inv
if self.debug:
- print 'reciprocal basis dictionary =\n', self.r_basis_dict
+ print('reciprocal basis dictionary =\n', self.r_basis_dict)
# True is for left derivative and False is for right derivative
self.deriv = {('*', True): [], ('^', True): [], ('|', True): [],
@@ -1663,9 +1668,9 @@ def grad_sqr(self, A, grad_sqr_mode, mode, left):
mode = *_{2} = *, ^, or |.
"""
(Sop, Bop) = Ga.DopFop[(grad_sqr_mode, mode)]
- print '(Sop, Bop) =', Sop, Bop
+ print('(Sop, Bop) =', Sop, Bop)
- print 'grad_sqr:A =', A
+ print('grad_sqr:A =', A)
self.dot_mode == '|'
s = zero
@@ -1677,7 +1682,7 @@ def grad_sqr(self, A, grad_sqr_mode, mode, left):
for coord_i in self.coords:
dA_i.append(self.pDiff(A, coord_i))
- print 'dA_i =', dA_i
+ print('dA_i =', dA_i)
if Sop:
for i in self.n_range:
@@ -1692,8 +1697,8 @@ def grad_sqr(self, A, grad_sqr_mode, mode, left):
if Bop and self.connect_flg:
for i in self.n_range:
coord_i = self.coords[i]
- print 'mode =', mode
- print 'dA_i[i] =', dA_i[i]
+ print('mode =', mode)
+ print('dA_i[i] =', dA_i[i])
if left:
if mode == '|':
s += self.dot(self.grad_sq_mv_connect[coord_i], dA_i[i])
@@ -1882,11 +1887,11 @@ def __init__(self, *kargs, **kwargs):
#print 'dxdu =', dxdu
- sub_pairs = zip(ga.coords, u)
+ sub_pairs = list(zip(ga.coords, u))
#Construct metric tensor form coordinate maps
g = eye(n_sub) #Zero n_sub x n_sub sympy matrix
- n_range = range(n_sub)
+ n_range = list(range(n_sub))
for i in n_range:
for j in n_range:
s = zero
@@ -1912,7 +1917,7 @@ def __init__(self, *kargs, **kwargs):
self.u = u
if debug:
- print 'Exit Sm.__init__()'
+ print('Exit Sm.__init__()')
def vpds(self):
if not self.is_ortho:
diff --git a/galgebra/lt.py b/galgebra/lt.py
index 5a4c2b6a..9b4b0d9f 100755
--- a/galgebra/lt.py
+++ b/galgebra/lt.py
@@ -1,21 +1,24 @@
#linear_transformations
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
import sys
import inspect
import types
import itertools
from sympy import collect, expand, symbols, Matrix, Transpose, zeros, Symbol, Function, S, Add
from copy import copy
-import printer
-import metric
-import mv
-import lt
+from . import printer
+from . import metric
+from . import mv
+from functools import reduce
def aprint(a):
out = ''
for ai in a:
out += str(ai)+','
- print '['+out[:-1]+']'
+ print('['+out[:-1]+']')
return
def Symbolic_Matrix(root,coords=None,mode='g',f=False,sub=True):
@@ -25,7 +28,7 @@ def Symbolic_Matrix(root,coords=None,mode='g',f=False,sub=True):
pos = '__'
if isinstance(coords,(list,tuple)):
n = len(coords)
- n_range = xrange(n)
+ n_range = range(n)
mat = zeros(n)
if mode == 'g': # General symbolic matrix
for row in n_range:
@@ -83,7 +86,7 @@ def Matrix_to_dictionary(mat_rep,basis):
n = len(basis)
if mat_rep.rows != n or mat_rep.cols != n:
raise ValueError('Matrix and Basis dimensions not equal for Matrix = ' + str(mat))
- n_range = range(n)
+ n_range = list(range(n))
for row in n_range:
dict_rep[basis[row]] = S(0)
for col in n_range:
@@ -92,9 +95,9 @@ def Matrix_to_dictionary(mat_rep,basis):
def Dictionary_to_Matrix(dict_rep, ga):
# Convert dictionary representation of linear transformation to matrix
- basis = dict_rep.keys()
+ basis = list(dict_rep.keys())
n = len(basis)
- n_range = range(n)
+ n_range = list(range(n))
lst_mat = [] # list representation of sympy matrix
for row in n_range:
e_row = ga.basis[row]
@@ -277,7 +280,7 @@ def __add__(self, LT):
raise ValueError("Attempting addition of Lt's from different geometric algebras")
self_add_LT = copy(self.lt_dict)
- for key in LT.lt_dict.keys():
+ for key in list(LT.lt_dict.keys()):
if key in self_add_LT:
self_add_LT[key] = collect(self_add_LT[key] + LT.lt_dict[key], self.Ga.basis)
else:
@@ -290,7 +293,7 @@ def __sub__(self, LT):
raise ValueError("Attempting subtraction of Lt's from different geometric algebras")
self_add_LT = copy(self.lt_dict)
- for key in LT.lt_dict.keys():
+ for key in list(LT.lt_dict.keys()):
if key in self_add_LT:
self_add_LT[key] = collect(self_add_LT[key] - LT.lt_dict[key], self.Ga.basis)
else:
@@ -388,16 +391,18 @@ def Lt_latex_str(self):
if self.spinor:
s = '\\left \\{ \\begin{array}{ll} '
for base in self.Ga.basis:
- s += 'L \\left ( ' + str(base) + '\\right ) =& ' + str(self.R * mv.Mv(base, ga=self.Ga) * self.Rrev) + ' \\\\ '
+ str_base = printer.latex(base)
+ s += 'L \\left ( ' + str_base + '\\right ) =& ' + printer.latex(self.R * mv.Mv(base, ga=self.Ga) * self.Rrev) + ' \\\\ '
s = s[:-3] + ' \\end{array} \\right \\} \n'
return s
else:
s = '\\left \\{ \\begin{array}{ll} '
for base in self.Ga.basis:
+ str_base = printer.latex(base)
if base in self.lt_dict:
- s += 'L \\left ( ' + str(base) + '\\right ) =& ' + str(mv.Mv(self.lt_dict[base], ga=self.Ga)) + ' \\\\ '
+ s += 'L \\left ( ' + str_base + '\\right ) =& ' + printer.latex(mv.Mv(self.lt_dict[base], ga=self.Ga)) + ' \\\\ '
else:
- s += 'L \\left ( ' + str(base) + '\\right ) =& 0 \\\\ '
+ s += 'L \\left ( ' + str_base + '\\right ) =& 0 \\\\ '
s = s[:-3] + ' \\end{array} \\right \\} \n'
return s
@@ -408,7 +413,7 @@ def Fmt(self, fmt=1, title=None):
latex_str = printer.GaLatexPrinter.latex(self)
- """
+ r"""
if printer.GaLatexPrinter.ipy:
if title is None:
if r'\begin{align*}' not in latex_str:
@@ -514,7 +519,7 @@ def subs(Ga, anew):
i = 0
for a in anew:
acoefs = a.get_coefs(1)
- sub_lst += zip(Ga.pdiffs[i], acoefs)
+ sub_lst += list(zip(Ga.pdiffs[i], acoefs))
i += 1
return sub_lst
@@ -624,9 +629,9 @@ def Fmt(self, lcnt=1, title=None):
display(Math(latex_str))
else:
if title is not None:
- print title + ' = ' + latex_str
+ print(title + ' = ' + latex_str)
else:
- print latex_str
+ print(latex_str)
return
@staticmethod
@@ -684,7 +689,7 @@ def __init__(self, f, Ga, args, fct=False):
self.nargs = nargs
self.fvalue = f
self.f = None
- elif isinstance(f, lt.Lt): # f is linear transformation T = a1 | f(a2)
+ elif isinstance(f, Lt): # f is linear transformation T = a1 | f(a2)
if self.nargs != 2:
raise ValueError('For mlt nargs != 2 for linear transformation!\n')
Ga.make_grad(self.args)
@@ -700,8 +705,8 @@ def __init__(self, f, Ga, args, fct=False):
self.nargs = 1
if self.nargs > 1: # General tensor of rank > 1
t_indexes = self.nargs * [Mlt.extact_basis_indexes(self.Ga)]
- print t_indexes
- print self.Ga.Pdiffs
+ print(t_indexes)
+ print(self.Ga.Pdiffs)
self.fvalue = 0
for (t_index,a_prod) in zip(itertools.product(*t_indexes),
itertools.product(*self.Ga.Pdiffs)):
@@ -819,7 +824,7 @@ def remove_slot(mv, slot, nargs, ga):
if slot == nargs:
return mv
for islot in range(slot, nargs):
- mv = mv.subs(zip(ga.pdiffs[islot], ga.pdiffs[islot - 1]))
+ mv = mv.subs(list(zip(ga.pdiffs[islot], ga.pdiffs[islot - 1])))
return mv
def contract(self, slot1, slot2):
@@ -857,12 +862,12 @@ def comps(self):
basis = self.Ga.mv()
rank = self.nargs
ndim = len(basis)
- i_indexes = rank*[range(ndim)]
+ i_indexes = rank*[list(range(ndim))]
indexes = rank*[basis]
i = 1
output = ''
for (e,i_index) in zip(itertools.product(*indexes),itertools.product(*i_indexes)):
- if i_index[-1] % ndim == 0: print ''
+ if i_index[-1] % ndim == 0: print('')
output += str(i)+':'+str(i_index)+':'+str(self(*e)) + '\n'
i += 1
return output
diff --git a/galgebra/metric.py b/galgebra/metric.py
index ad0ac9ce..8f18ee49 100755
--- a/galgebra/metric.py
+++ b/galgebra/metric.py
@@ -1,5 +1,8 @@
#metric.py
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
import sys
import copy
import itertools
@@ -8,7 +11,7 @@
Add, simplify, together, ratsimp, Expr, latex, \
numbers, Function
-import printer
+from . import printer
half = Rational(1, 2)
@@ -84,7 +87,7 @@ def linear_expand(expr, mode=True):
if mode:
return (coefs, bases)
else:
- return zip(coefs, bases)
+ return list(zip(coefs, bases))
def square_root_of_expr(expr):
@@ -165,9 +168,9 @@ def test_init_slots(init_slots, **kwargs):
for slot in kwargs:
if slot not in init_slots:
- print 'Allowed keyed input arguments'
+ print('Allowed keyed input arguments')
for key in init_slots:
- print key + ': ' + init_slots[key][1]
+ print(key + ': ' + init_slots[key][1])
raise ValueError('"' + slot + ' = " not in allowed values.')
for slot in init_slots:
if slot in kwargs:
@@ -303,7 +306,7 @@ def metric_symbols_list(self, s=None): # input metric tensor as string
s = self.n * (s[:-1] + ',')
s = s[:-1]
- if isinstance(s, basestring):
+ if isinstance(s, str):
rows = s.split(',')
n_rows = len(rows)
@@ -345,7 +348,7 @@ def metric_symbols_list(self, s=None): # input metric tensor as string
if n != self.n:
raise ValueError('Input metric "' + s + '" has' +
' different rank than bases "' + str(self.basis) + '"')
- n_range = range(n)
+ n_range = list(range(n))
for (row, i1) in zip(m_lst, n_range):
row_symbols = []
for (s, i2) in zip(row, n_range):
@@ -392,7 +395,7 @@ def derivatives_of_basis(self): # Derivatives of basis vectors from Christ-Awfu
self.de = None
return
- n_range = range(len(self.basis))
+ n_range = list(range(len(self.basis)))
de = [] # de[i][j] = \partial_{x_{i}}e^{x_{j}}
@@ -460,7 +463,7 @@ def Christoffel_symbols(self,mode=1):
self.de = None
return
- n_range = range(len(self.basis))
+ n_range = list(range(len(self.basis)))
dG = [] # dG[i][j][k] = half * (dg[j][k][i] + dg[i][k][j] - dg[i][j][k])
@@ -524,7 +527,7 @@ def normalize_metric(self):
if self.debug:
for x_i in self.n_range:
for jb in self.n_range:
- print '\partial_{' + str(self.coords[x_i]) + '}\hat{e}_{' + str(self.coords[jb]) + '} =', self.de[x_i][jb]
+ print(r'\partial_{' + str(self.coords[x_i]) + r'}\hat{e}_{' + str(self.coords[jb]) + '} =', self.de[x_i][jb])
# Normalize metric tensor
@@ -580,7 +583,7 @@ def __init__(self, basis, **kwargs):
self.name = 'GA' + str(Metric.count)
Metric.count += 1
- if not isinstance(basis, basestring):
+ if not isinstance(basis, str):
raise TypeError('"' + str(basis) + '" must be string')
X = kwargs['X'] # Vector manifold
@@ -628,7 +631,7 @@ def __init__(self, basis, **kwargs):
if self.debug:
printer.oprint('e_{i}', self.basis, 'e^{i}', self.r_symbols)
self.n = len(self.basis)
- self.n_range = range(self.n)
+ self.n_range = list(range(self.n))
# Generate metric as list of lists of symbols, rationals, or functions of coordinates
@@ -655,7 +658,7 @@ def __init__(self, basis, **kwargs):
printer.oprint('X_{i}', X, 'D_{i}X_{j}', dX)
else: # metric is symbolic or list of lists of functions of coordinates
- if isinstance(g, basestring): # metric elements are symbols or constants
+ if isinstance(g, str): # metric elements are symbols or constants
if g == 'g': # general symbolic metric tensor (g_ij functions of position)
g_lst = []
g_inv_lst = []
@@ -735,7 +738,7 @@ def __init__(self, basis, **kwargs):
self.e_sq_sgn = '-'
if self.debug:
- print 'signature =', self.sig
+ print('signature =', self.sig)
if __name__ == "__main__":
diff --git a/galgebra/mv.py b/galgebra/mv.py
index 09b773fb..866a6779 100755
--- a/galgebra/mv.py
+++ b/galgebra/mv.py
@@ -1,10 +1,15 @@
#mv.py
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
import itertools
import copy
import numbers
import operator
-from compiler.ast import flatten
+# from compiler.ast import flatten
+# https://stackoverflow.com/questions/16176742/python-3-replacement-for-deprecated-compiler-ast-flatten-function
+from .utils import flatten
from operator import itemgetter, mul, add
from itertools import combinations
from sympy import Symbol, Function, S, expand, Add, Mul, Pow, Basic, \
@@ -12,13 +17,14 @@
simplify, diff, Rational, Expr, Abs, collect, combsimp
from sympy import exp as sympy_exp
from sympy import N as Nsympy
-import printer
-import metric
-import ga
+from . import printer
+from . import metric
import sys
+from functools import reduce, cmp_to_key
ONE = S(1)
ZERO = S(0)
+HALF = Rational(1, 2)
half = Rational(1, 2)
@@ -346,7 +352,7 @@ def reflect_in_blade(self, blade): # Reflect mv in blade
grade_dict = self.Ga.grade_decomposition(self)
blade_grade = blade.i_grade
reflect = Mv(0,'scalar',ga=self.Ga)
- for grade in grade_dict.keys():
+ for grade in list(grade_dict.keys()):
if (grade * (blade_grade + 1)) % 2 == 0:
reflect += blade * grade_dict[grade] * blade_inv
else:
@@ -627,7 +633,7 @@ def Mv_str(self):
grade0 += c
if grade0 != S(0):
terms[-1] = (grade0, S(1), -1)
- terms = terms.items()
+ terms = list(terms.items())
sorted_terms = sorted(terms, key=itemgetter(0)) # sort via base indexes
s = str(sorted_terms[0][1][0] * sorted_terms[0][1][1])
@@ -711,7 +717,7 @@ def append_plus(c_str):
grade0 += c
if grade0 != S(0):
terms[-1] = (grade0, S(1), 0)
- terms = terms.items()
+ terms = list(terms.items())
sorted_terms = sorted(terms, key=itemgetter(0)) # sort via base indexes
@@ -899,12 +905,12 @@ def collect(self,deep=False):
coefs, bases = metric.linear_expand(self.obj)
obj_dict = {}
for (coef, base) in zip(coefs, bases):
- if base in obj_dict.keys():
+ if base in list(obj_dict.keys()):
obj_dict[base] += coef
else:
obj_dict[base] = coef
obj = 0
- for base in obj_dict.keys():
+ for base in list(obj_dict.keys()):
if deep:
obj += collect(obj_dict[base])*base
else:
@@ -988,7 +994,7 @@ def get_grade(self, r):
def components(self):
(coefs, bases) = metric.linear_expand(self.obj)
bases_lst = self.Ga.blades_lst
- cb = zip(coefs, bases)
+ cb = list(zip(coefs, bases))
cb = sorted(cb, key=lambda x: self.Ga.blades_lst0.index(x[1]))
terms = []
for (coef, base) in cb:
@@ -998,9 +1004,9 @@ def components(self):
def get_coefs(self, grade):
(coefs, bases) = metric.linear_expand(self.obj)
bases_lst = self.Ga.blades_lst
- cb = zip(coefs, bases)
+ cb = list(zip(coefs, bases))
cb = sorted(cb, key=lambda x: self.Ga.blades[grade].index(x[1]))
- (coefs, bases) = zip(*cb)
+ (coefs, bases) = list(zip(*cb))
return coefs
def blade_coefs(self, blade_lst=None):
@@ -1401,13 +1407,13 @@ def compare(A,B):
return 0
if Bcoefs[0] != 0 and Abases[0] == Bbases[0]:
c = simplify(Acoefs[0]/Bcoefs[0])
- print 'c =',c
+ print('c =',c)
else:
return 0
for acoef,abase,bcoef,bbase in zip(Acoefs[1:],Abases[1:],Bcoefs[1:],Bbases[1:]):
- print acoef,'\n',abase,'\n',bcoef,'\n',bbase
+ print(acoef,'\n',abase,'\n',bcoef,'\n',bbase)
if bcoef != 0 and abase == bbase:
- print 'c-a/b =',simplify(c-(acoef/bcoef))
+ print('c-a/b =',simplify(c-(acoef/bcoef)))
if simplify(acoef/bcoef) != c:
return 0
else:
@@ -1468,7 +1474,7 @@ def consolidate_coefs(sdop):
else:
new_coefs.append(coef)
new_pdiffs.append(pd)
- new_terms = zip(new_coefs, new_pdiffs)
+ new_terms = list(zip(new_coefs, new_pdiffs))
if isinstance(sdop, Sdop):
return Sdop(new_terms, ga=sdop.Ga)
@@ -1476,15 +1482,16 @@ def consolidate_coefs(sdop):
return new_terms
def simplify(self, modes=simplify):
- coefs, pdiffs = zip(*self.terms)
+ coefs, pdiffs = list(zip(*self.terms))
new_coefs = []
for coef in coefs:
new_coefs.append(metric.apply_function_list(modes,coef))
- self.terms = zip(new_coefs,pdiffs)
+ self.terms = list(zip(new_coefs,pdiffs))
return self
def sort_terms(self):
- self.terms.sort(key=operator.itemgetter(1), cmp=Pdop.compare)
+ # self.terms.sort(key=operator.itemgetter(1))
+ self.terms.sort(key=cmp_to_key(Pdop.compare))
return
def Sdop_str(self):
@@ -1494,7 +1501,8 @@ def Sdop_str(self):
self.sort_terms()
s = ''
for (coef, pdop) in self.terms:
- pd_str = str(pdop)
+ coef_str = printer.latex(coef)
+ pd_str = printer.latex(pdop)
if coef == S(1):
s += pd_str
@@ -1502,9 +1510,9 @@ def Sdop_str(self):
s += '-' + pd_str
else:
if isinstance(coef, Add):
- s += '(' + str(coef) + ')*' + pd_str
+ s += '(' + coef_str + ')*' + pd_str
else:
- s += str(coef) + '*' + pd_str
+ s += coef_str + '*' + pd_str
s += ' + '
s = s.replace('+ -','- ')
@@ -1522,7 +1530,8 @@ def Sdop_latex_str(self):
s = ''
for (coef, pdop) in self.terms:
- pd_str = str(pdop)
+ coef_str = printer.latex(coef)
+ pd_str = printer.latex(pdop)
if coef == S(1):
if pd_str == '':
s += '1'
@@ -1535,9 +1544,9 @@ def Sdop_latex_str(self):
s += '-' + pd_str
else:
if isinstance(coef, Add):
- s += r'\left ( ' + str(coef) + r'\right ) ' + pd_str
+ s += r'\left ( ' + coef_str + r'\right ) ' + pd_str
else:
- s += str(coef) + ' ' + pd_str
+ s += coef_str + ' ' + pd_str
s += ' + '
s = s.replace('+ -','- ')
@@ -1616,8 +1625,8 @@ def Add(sdop1, sdop2):
if isinstance(sdop1, Sdop) and isinstance(sdop1, Sdop):
if sdop1.Ga != sdop2.Ga:
raise ValueError('In Sdop.Add sdop1.Ga != sdop2.Ga.')
- coefs1, pdiffs1 = zip(*sdop1.terms)
- coefs2, pdiffs2 = zip(*sdop2.terms)
+ coefs1, pdiffs1 = list(zip(*sdop1.terms))
+ coefs2, pdiffs2 = list(zip(*sdop2.terms))
pdiffs1 = list(pdiffs1)
pdiffs2 = list(pdiffs2)
@@ -1637,7 +1646,7 @@ def Add(sdop1, sdop2):
sdop_sum = Sdop(coefs, pdiffs, ga=sdop1.Ga)
elif isinstance(sdop1, Sdop):
- coefs, pdiffs = zip(*sdop1.terms)
+ coefs, pdiffs = list(zip(*sdop1.terms))
if sdop1.Ga.Pdop_identity in pdiffs:
index = pdiffs.index(sdop1.Ga.Pdop_identity)
coef[index] += sdop2
@@ -1646,7 +1655,7 @@ def Add(sdop1, sdop2):
pdiff.append(sdop1.Ga.Pdop_identity)
return Sdop(coefs, pdiffs, ga=sdop1.Ga)
else:
- coefs, pdiffs = zip(*sdop2.terms)
+ coefs, pdiffs = list(zip(*sdop2.terms))
if sdop2.Ga.Pdop_identity in pdiffs:
index = pdiffs.index(sdop2.Ga.Pdop_identity)
coef[index] += sdop1
@@ -1682,7 +1691,7 @@ def __add_ab__(self, sdop):
if self.Ga != sdop.Ga:
raise ValueError('In Sdop.__add_ab__ self.Ga != sdop.Ga.')
- coefs, pdiffs = zip(*self.terms)
+ coefs, pdiffs = list(zip(*self.terms))
pdiffs = list(pdiffs)
coefs = list(coefs)
@@ -1693,7 +1702,7 @@ def __add_ab__(self, sdop):
else:
pdiffs.append(pdiff)
coefs.append(coef)
- self.term = zip(coefs, pdiffs)
+ self.term = list(zip(coefs, pdiffs))
self = Sdop.consolidate_coefs(self)
return
@@ -1739,7 +1748,7 @@ def __rmul__(self,sdop):
#################### Partial Derivative Operator Class #################
class Pdop(object):
- """
+ r"""
Partial derivative class for multivectors. The partial derivatives
are of the form
@@ -1770,8 +1779,8 @@ def compare(pdop1, pdop2): # compare two Pdops
if pdop1.order < pdop2.order:
return -1
- keys1 = pdop1.pdiffs.keys()
- keys2 = pdop2.pdiffs.keys()
+ keys1 = list(pdop1.pdiffs.keys())
+ keys2 = list(pdop2.pdiffs.keys())
lkeys1 = len(keys1)
lkeys2 = len(keys2)
@@ -1830,7 +1839,7 @@ def __init__(self, *kargs, **kwargs):
else:
raise ValueError('In pdop kargs = ', str(kargs))
- for x in self.pdiffs.keys(): # self.order is total number of differentiations
+ for x in list(self.pdiffs.keys()): # self.order is total number of differentiations
self.order += self.pdiffs[x]
def factor(self):
@@ -1845,7 +1854,7 @@ def factor(self):
if self.order == 1:
return S(0), self
else:
- x = self.pdiffs.keys()[0]
+ x = list(self.pdiffs.keys())[0]
self.order -= 1
n = self.pdiffs[x]
if n == 1:
@@ -1941,15 +1950,15 @@ def Pdop_latex_str(self):
return ''
s = r'\frac{\partial'
if self.order > 1:
- s += '^{' + str(self.order) + '}'
+ s += '^{' + printer.latex(self.order) + '}'
s += '}{'
- keys = self.pdiffs.keys()
+ keys = list(self.pdiffs.keys())
keys.sort(key=(self.Ga.coords + keys).index)
for key in keys:
i = self.pdiffs[key]
- s += r'\partial ' + str(key)
+ s += r'\partial ' + printer.latex(key)
if i > 1:
- s += '^{' + str(i) + '}'
+ s += '^{' + printer.latex(i) + '}'
s += '}'
return s
@@ -1970,7 +1979,7 @@ def __repr__(self):
################# Multivector Differential Operator Class ##############
class Dop(object):
- """
+ r"""
Differential operator class for multivectors. The operators are of
the form
@@ -2047,7 +2056,7 @@ def __init__(self, *kargs, **kwargs):
if len(kargs) == 2:
if len(kargs[0]) != len(kargs[1]):
raise ValueError('In Dop.__init__ coefficent list and Pdop list must be same length.')
- self.terms = zip(kargs[0],kargs[1])
+ self.terms = list(zip(kargs[0],kargs[1]))
elif len(kargs) == 1:
if isinstance(kargs[0][0][0], Mv): # Mv expansion [(Mv, Pdop)]
self.terms = kargs[0]
@@ -2062,7 +2071,7 @@ def __init__(self, *kargs, **kwargs):
else:
pdiffs.append(pdiff)
coefs.append(coef * mv)
- self.terms = zip(coefs, pdiffs)
+ self.terms = list(zip(coefs, pdiffs))
else:
raise ValueError('In Dop.__init__ kargs[0] form not allowed. kargs = ' + str(kargs))
else:
@@ -2079,7 +2088,7 @@ def simplify(self, modes=simplify):
tmp = coef.simplify(modes=modes)
new_coefs.append(tmp)
new_pd.append(pd)
- self.terms = zip(new_coefs, new_pd)
+ self.terms = list(zip(new_coefs, new_pd))
return Dop(new_coefs, new_pd, ga=self.Ga, cmpflg=self.cmpflg)
def consolidate_coefs(self):
@@ -2099,7 +2108,7 @@ def consolidate_coefs(self):
new_coefs.append(coef)
new_pdiffs.append(pd)
- self.terms = zip(new_coefs, new_pdiffs)
+ self.terms = list(zip(new_coefs, new_pdiffs))
return Dop(new_coefs, new_pdiffs, ga=self.Ga, cmpflg=self.cmpflg)
@@ -2123,8 +2132,8 @@ def Add(dop1, dop2):
if dop1.cmpflg != dop2.cmpflg:
raise ValueError('In Dop.Add complement flags have different values.')
- coefs1, pdiffs1 = zip(*dop1.terms)
- coefs2, pdiffs2 = zip(*dop2.terms)
+ coefs1, pdiffs1 = list(zip(*dop1.terms))
+ coefs2, pdiffs2 = list(zip(*dop2.terms))
pdiffs1 = list(pdiffs1)
pdiffs2 = list(pdiffs2)
@@ -2162,7 +2171,7 @@ def __radd__(self, dop):
def __neg__(self):
- coefs, pdiffs = zip(*self.terms)
+ coefs, pdiffs = list(zip(*self.terms))
coefs = [-x for x in coefs]
@@ -2329,7 +2338,7 @@ def components(self):
new_pdiffs.append(pdiff)
new_coefs.append(coef * base)
new_coefs = [Mv(x, ga=self.Ga) for x in new_coefs]
- terms = zip(new_coefs, new_pdiffs)
+ terms = list(zip(new_coefs, new_pdiffs))
dop_lst.append(Dop(terms, ga=self.Ga))
return tuple(dop_lst)
@@ -2362,7 +2371,7 @@ def Dop_mv_expand(self, modes=None):
if modes is not None:
for i in range(len(coefs)):
coefs[i] = coefs[i].simplify(modes)
- terms = zip(coefs, bases)
+ terms = list(zip(coefs, bases))
return sorted(terms, key=lambda x: self.Ga.blades_lst0.index(x[1]))
def Dop_str(self):
@@ -2373,26 +2382,27 @@ def Dop_str(self):
s = ''
for (sdop, base) in mv_terms:
- str_sdop = str(sdop)
+ str_base = printer.latex(base)
+ str_sdop = printer.latex(sdop)
if base == S(1):
s += str_sdop
else:
if len(sdop.terms) > 1:
if self.cmpflg:
- s += '(' + str_sdop + ')*' + str(base)
+ s += '(' + str_sdop + ')*' + str_base
else:
- s += str(base) + '*(' + str_sdop + ')'
+ s += str_base + '*(' + str_sdop + ')'
else:
if str_sdop[0] == '-' and not isinstance(sdop.terms[0][0], Add):
if self.cmpflg:
- s += str_sdop + '*' + str(base)
+ s += str_sdop + '*' + str_base
else:
- s += '-' + str(base) + '*' + str_sdop[1:]
+ s += '-' + str_base + '*' + str_sdop[1:]
else:
if self.cmpflg:
- s += str_dop + '*' + str(base)
+ s += str_dop + '*' + str_base
else:
- s += str(base) + '*' + str_sdop
+ s += str_base + '*' + str_sdop
s += ' + '
s = s.replace('+ -','-')
@@ -2408,33 +2418,34 @@ def Dop_latex_str(self):
s = ''
for (sdop, base) in mv_terms:
- str_sdop = str(sdop)
+ str_base = printer.latex(base)
+ str_sdop = printer.latex(sdop)
if base == S(1):
s += str_sdop
else:
if str_sdop == '1':
- s += str(base)
+ s += str_base
if str_sdop == '-1':
- s += '-' + str(base)
+ s += '-' + str_base
if str_sdop[1:] != '1':
s += ' ' + str_sdop[1:]
else:
if len(sdop.terms) > 1:
if self.cmpflg:
- s += r'\left ( ' + str_sdop + r'\right ) ' + str(base)
+ s += r'\left ( ' + str_sdop + r'\right ) ' + str_base
else:
- s += str(base) + ' ' + r'\left ( ' + str_sdop + r'\right ) '
+ s += str_base + ' ' + r'\left ( ' + str_sdop + r'\right ) '
else:
if str_sdop[0] == '-' and not isinstance(sdop.terms[0][0], Add):
if self.cmpflg:
- s += str_sdop + str(base)
+ s += str_sdop + str_base
else:
- s += '-' + str(base) + ' ' + str_sdop[1:]
+ s += '-' + str_base + ' ' + str_sdop[1:]
else:
if self.cmpflg:
- s += str_sdop + ' ' + str(base)
+ s += str_sdop + ' ' + str_base
else:
- s += str(base) + ' ' + str_sdop
+ s += str_base + ' ' + str_sdop
s += ' + '
s = s.replace('+ -','-')
@@ -2503,7 +2514,7 @@ def Nga(x, prec=5):
def printeigen(M): # Print eigenvalues, multiplicities, eigenvectors of M.
evects = M.eigenvects()
for i in range(len(evects)): # i iterates over eigenvalues
- print('Eigenvalue =', evects[i][0], ' Multiplicity =', evects[i][1], ' Eigenvectors:')
+ print(('Eigenvalue =', evects[i][0], ' Multiplicity =', evects[i][1], ' Eigenvectors:'))
for j in range(len(evects[i][2])): # j iterates over eigenvectors of a given eigenvalue
result = '['
for k in range(len(evects[i][2][j])): # k iterates over coordinates of an eigenvector
@@ -2697,7 +2708,7 @@ def __init__(self, base, mvtype, fct=False, blade_rep=True):
Mv.__init__(self, base, mvtype, f=fct, ga=MV.GA)
def Fmt(self, fmt=1, title=None):
- print Mv.Fmt(self, fmt=fmt, title=title)
+ print(Mv.Fmt(self, fmt=fmt, title=title))
return
def ReciprocalFrame(basis, mode='norm'):
diff --git a/galgebra/printer.py b/galgebra/printer.py
index 7473878c..4829b7db 100755
--- a/galgebra/printer.py
+++ b/galgebra/printer.py
@@ -1,8 +1,12 @@
#printer.py
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
import os
import sys
-import StringIO
+import io
import re
from sympy import Matrix, Basic, S, Symbol, Function, Derivative, Pow
from itertools import islice
@@ -26,7 +30,7 @@
Format_cnt = 0
ip_cmds = \
-"""
+r"""
$\\DeclareMathOperator{\Tr}{Tr}
\\DeclareMathOperator{\Adj}{Adj}
\\newcommand{\\bfrac}[2]{\\displaystyle\\frac{#1}{#2}}
@@ -136,7 +140,7 @@ def ostr_rec(obj, dict_mode):
elif isinstance(obj, dict):
if dict_mode:
ostr_s += '\n'
- for key in obj.keys():
+ for key in list(obj.keys()):
ostr_rec(key, dict_mode)
if ostr_s[-1] == ',':
ostr_s = ostr_s[:-1]
@@ -147,7 +151,7 @@ def ostr_rec(obj, dict_mode):
ostr_s += '\n'
else:
ostr_s += '{'
- for key in obj.keys():
+ for key in list(obj.keys()):
ostr_rec(key, dict_mode)
if ostr_s[-1] == ',':
ostr_s = ostr_s[:-1]
@@ -227,16 +231,16 @@ def oprint(*args, **kwargs):
for (title, obj) in zip(titles, objs):
if obj is None:
- print title
+ print(title)
else:
npad = n - len(title)
if isinstance(obj, dict):
- print title + ':' + ostr(obj, dict_mode)
+ print(title + ':' + ostr(obj, dict_mode))
else:
- print title + npad * ' ' + ' = ' + ostr(obj, dict_mode)
+ print(title + npad * ' ' + ' = ' + ostr(obj, dict_mode))
else:
for arg in args:
- print ostr(arg, dict_mode)
+ print(ostr(arg, dict_mode))
return
@@ -252,7 +256,7 @@ class Eprint:
'dark gray': '1;30', 'bright yellow': '1;33',
'normal': '0'}
- InvColorCode = dict(zip(ColorCode.values(), ColorCode.keys()))
+ InvColorCode = dict(list(zip(list(ColorCode.values()), list(ColorCode.keys()))))
normal = ''
base = ''
@@ -285,10 +289,10 @@ def __init__(self, base=None, fct=None, deriv=None, on=True, debug=False):
Eprint.normal = '\033[0m'
if debug:
- print 'Enhanced Printing is on:'
- print 'Base/Blade color is ' + Eprint.InvColorCode[Eprint.base]
- print 'Function color is ' + Eprint.InvColorCode[Eprint.fct]
- print 'Derivative color is ' + Eprint.InvColorCode[Eprint.deriv] + '\n'
+ print('Enhanced Printing is on:')
+ print('Base/Blade color is ' + Eprint.InvColorCode[Eprint.base])
+ print('Function color is ' + Eprint.InvColorCode[Eprint.fct])
+ print('Derivative color is ' + Eprint.InvColorCode[Eprint.deriv] + '\n')
Eprint.base = '\033[' + Eprint.base + 'm'
Eprint.fct = '\033[' + Eprint.fct + 'm'
@@ -338,23 +342,27 @@ def _print_Function(self, expr):
return Eprint.Fct("%s" % (name,))
def _print_Derivative(self, expr):
- diff_args = map(self._print, expr.args)
+ # Break the following to support both py 2 & 3
+ # function, *diff_args = expr.args
+ function = expr.args[0]
+ diff_args = expr.args[1:]
+
xi = []
ni = []
- for x in diff_args[1:]:
+ for x, n in diff_args:
if x in xi:
i = xi.index(x)
- ni[i] += 1
+ ni[i] += n
else:
- xi.append(x)
- ni.append(1)
+ xi.append(self._print(x))
+ ni.append(n)
s = 'D'
- for (x, n) in zip(xi, ni):
+ for x, n in zip(xi, ni):
s += '{' + str(x) + '}'
if n > 1:
s += '^' + str(n)
- s += str(diff_args[0])
+ s += str(self._print(function))
return Eprint.Deriv(s)
def _print_Matrix(self, expr):
@@ -392,7 +400,7 @@ def enhance_print():
return
class GaLatexPrinter(LatexPrinter):
- """
+ r"""
The latex printer is turned on with the function (in ga.py) -
Format(Fmode=True,Dmode=True,ipy=False)
@@ -463,7 +471,7 @@ class GaLatexPrinter(LatexPrinter):
inv_trig_style = None
preamble = \
-"""
+r"""
\\pagestyle{empty}
\\usepackage[latin1]{inputenc}
\\usepackage{amsmath}
@@ -620,7 +628,7 @@ def redirect():
pass
else:
GaLatexPrinter.stdout = sys.stdout
- sys.stdout = StringIO.StringIO()
+ sys.stdout = io.StringIO()
return
@staticmethod
@@ -737,10 +745,10 @@ def translate(s):
name = '\\boldsymbol{' + name +'}'
if supers != []:
- supers = map(translate, supers)
+ supers = list(map(translate, supers))
if subs != []:
- subs = map(translate, subs)
+ subs = list(map(translate, subs))
# glue all items together:
if len(supers) > 0:
@@ -781,6 +789,7 @@ def _print_Function(self, expr, exp=None):
return getattr(self, '_print_' + func)(expr, exp)
else:
args = [str(self._print(arg)) for arg in expr.args]
+
# How inverse trig functions should be displayed, formats are:
# abbreviated: asin, full: arcsin, power: sin^-1
#inv_trig_style = self._settings['inv_trig_style']
@@ -955,7 +964,7 @@ def latex(expr, **settings):
def print_latex(expr, **settings):
"""Prints LaTeX representation of the given expression."""
- print latex(expr, **settings)
+ print(latex(expr, **settings))
def Format(Fmode=True, Dmode=True, dop=1, inverse='full'):
@@ -1022,7 +1031,7 @@ def xpdf(filename=None, paper=(14, 11), crop=False, png=False, prog=False, debug
latex_str = GaLatexPrinter.latex_str + sys.stdout.getvalue()
GaLatexPrinter.latex_str = ''
GaLatexPrinter.restore()
- """
+ r"""
Each line in the latex_str is interpreted to be an equation or align
environment. If the line does not begin with '\begin{align*}' then
'begin{equation*}' will be added to the beginning of the line and
@@ -1107,7 +1116,7 @@ def xpdf(filename=None, paper=(14, 11), crop=False, png=False, prog=False, debug
latex_str = prog_str + latex_str
if debug:
- print latex_str
+ print(latex_str)
if paper == 'letter':
paper_size = \
@@ -1134,7 +1143,7 @@ def xpdf(filename=None, paper=(14, 11), crop=False, png=False, prog=False, debug
rootfilename = pyfilename.replace('.py', '')
filename = rootfilename + '.tex'
- print 'latex file =', filename
+ print('latex file =', filename)
latex_file = open(filename, 'w')
latex_file.write(latex_str)
@@ -1144,7 +1153,7 @@ def xpdf(filename=None, paper=(14, 11), crop=False, png=False, prog=False, debug
pdflatex = find_executable('pdflatex')
- print 'pdflatex path =', pdflatex
+ print('pdflatex path =', pdflatex)
if pdflatex is not None:
latex_str = 'pdflatex'
@@ -1158,10 +1167,10 @@ def xpdf(filename=None, paper=(14, 11), crop=False, png=False, prog=False, debug
os.system(latex_str + ' ' + filename[:-4] + sys_cmd['null'])
print_cmd = sys_cmd['evince'] + ' ' + filename[:-4] + '.pdf ' + sys_cmd['&']
- print print_cmd
+ print(print_cmd)
os.system(print_cmd)
- raw_input('!!!!Return to continue!!!!\n')
+ eval(input('!!!!Return to continue!!!!\n'))
if debug:
os.system(sys_cmd['rm'] + ' ' + filename[:-4] + '.aux ' + filename[:-4] + '.log')
@@ -1212,16 +1221,16 @@ def Print_Function():
fct_name = fct_name.replace('_', ' ')
if GaLatexPrinter.latex_flg:
#print '#Code for '+fct_name
- print '##\\begin{lstlisting}[language=Python,showspaces=false,' + \
- 'showstringspaces=false,backgroundcolor=\color{gray},frame=single]'
- print tmp_str
- print '##\\end{lstlisting}'
- print '#Code Output:'
+ print(r'##\\begin{lstlisting}[language=Python,showspaces=false,' + \
+ r'showstringspaces=false,backgroundcolor=\color{gray},frame=single]')
+ print(tmp_str)
+ print('##\\end{lstlisting}')
+ print('#Code Output:')
else:
- print '\n' + 80 * '*'
+ print('\n' + 80 * '*')
#print '\nCode for '+fct_name
- print tmp_str
- print 'Code output:\n'
+ print(tmp_str)
+ print('Code output:\n')
return
@@ -1409,11 +1418,11 @@ def GAeval(s, pstr=False):
seval = parse_line(s)
if pstr:
- print s
- print seval
+ print(s)
+ print(seval)
return eval(seval, global_dict)
-"""
+r"""
\begin{array}{c}
\left ( \begin{array}{c} F,\\ \end{array} \right . \\
\begin{array}{c} F, \\ \end{array} \\
diff --git a/galgebra/setgapth.py b/galgebra/setgapth.py
index 5de02332..e73a3000 100755
--- a/galgebra/setgapth.py
+++ b/galgebra/setgapth.py
@@ -1,6 +1,10 @@
#!/usr/bin/python
#setgapth.py
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
Completion_Message = \
"""
Python pth file Ga.pth for all modules of galgebra has been created and
@@ -29,11 +33,11 @@
pth_file.write('#Path of Ga module\n'+cur_dir)
pth_file.close()
-print 'os name:',os.name
-print 'site-packages directory:',pth_name
-print 'Ga.pth:'
-print os.system('more ' + pth_name)
+print('os name:',os.name)
+print('site-packages directory:',pth_name)
+print('Ga.pth:')
+print(os.system('more ' + pth_name))
-print Completion_Message
+print(Completion_Message)
diff --git a/galgebra/test_mv.py b/galgebra/test_mv.py
index 3c6b76c0..033ee7cc 100644
--- a/galgebra/test_mv.py
+++ b/galgebra/test_mv.py
@@ -1,8 +1,10 @@
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
import unittest
-
from sympy import Symbol
-from ga import Ga
+from galgebra.ga import Ga
class TestMv(unittest.TestCase):
diff --git a/galgebra/test_test.py b/galgebra/test_test.py
index ca90c813..ec310f63 100755
--- a/galgebra/test_test.py
+++ b/galgebra/test_test.py
@@ -1,390 +1,450 @@
#!/usr/bin/python
-import sys
-from sympy import symbols,sin,cos,Rational,expand,collect,Symbol
-from ga import simplify,Ga
-from mv import MV,Nga,ONE,ZERO
-from printer import GaPrinter
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
-HALF = Rational(1,2)
+import sys
+import unittest
+from sympy import symbols, sin, cos, Rational, expand, collect, simplify, Symbol
+from galgebra.printer import Format, Eprint, Get_Program, latex, GaPrinter
+from galgebra.ga import Ga, one, zero
+from galgebra.mv import Mv, Nga
+# for backward compatibility
+from galgebra.mv import MV, ONE, ZERO, HALF
+from galgebra import ga
def F(x):
- global n,nbar
- Fx = HALF*((x*x)*n+2*x-nbar)
+ global n, nbar
+ Fx = HALF * ((x * x) * n + 2 * x - nbar)
return(Fx)
-def make_vector(a,n = 3):
+def make_vector(a, n=3, ga=None):
if isinstance(a,str):
- sym_str = ''
+ v = zero
for i in range(n):
- sym_str += a+str(i+1)+' '
- sym_lst = list(symbols(sym_str))
- sym_lst.append(ZERO)
- sym_lst.append(ZERO)
- a = MV(sym_lst,'vector')
- return(F(a))
+ a_i = Symbol(a+str(i+1))
+ v += a_i*ga.basis[i]
+ v = ga.mv(v)
+ return(F(v))
+ else:
+ return(F(a))
+
+class TestTest(unittest.TestCase):
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ def test_basic_multivector_operations(self):
+
+ g3d = Ga('e*x|y|z')
+ (ex,ey,ez) = g3d.mv()
+
+ A = g3d.mv('A','mv')
+
+ assert str(A) == 'A + A__x*e_x + A__y*e_y + A__z*e_z + A__xy*e_x^e_y + A__xz*e_x^e_z + A__yz*e_y^e_z + A__xyz*e_x^e_y^e_z'
+ assert str(A) == 'A + A__x*e_x + A__y*e_y + A__z*e_z + A__xy*e_x^e_y + A__xz*e_x^e_z + A__yz*e_y^e_z + A__xyz*e_x^e_y^e_z'
+ assert str(A) == 'A + A__x*e_x + A__y*e_y + A__z*e_z + A__xy*e_x^e_y + A__xz*e_x^e_z + A__yz*e_y^e_z + A__xyz*e_x^e_y^e_z'
+
+ X = g3d.mv('X','vector')
+ Y = g3d.mv('Y','vector')
+
+ assert str(X) == 'X__x*e_x + X__y*e_y + X__z*e_z'
+ assert str(Y) == 'Y__x*e_x + Y__y*e_y + Y__z*e_z'
+
+ assert str((X*Y)) == '(e_x.e_x)*X__x*Y__x + (e_x.e_y)*X__x*Y__y + (e_x.e_y)*X__y*Y__x + (e_x.e_z)*X__x*Y__z + (e_x.e_z)*X__z*Y__x + (e_y.e_y)*X__y*Y__y + (e_y.e_z)*X__y*Y__z + (e_y.e_z)*X__z*Y__y + (e_z.e_z)*X__z*Y__z + (X__x*Y__y - X__y*Y__x)*e_x^e_y + (X__x*Y__z - X__z*Y__x)*e_x^e_z + (X__y*Y__z - X__z*Y__y)*e_y^e_z'
+ assert str((X^Y)) == '(X__x*Y__y - X__y*Y__x)*e_x^e_y + (X__x*Y__z - X__z*Y__x)*e_x^e_z + (X__y*Y__z - X__z*Y__y)*e_y^e_z'
+ assert str((X|Y)) == '(e_x.e_x)*X__x*Y__x + (e_x.e_y)*X__x*Y__y + (e_x.e_y)*X__y*Y__x + (e_x.e_z)*X__x*Y__z + (e_x.e_z)*X__z*Y__x + (e_y.e_y)*X__y*Y__y + (e_y.e_z)*X__y*Y__z + (e_y.e_z)*X__z*Y__y + (e_z.e_z)*X__z*Y__z'
+
+
+ g2d = Ga('e*x|y')
+ (ex,ey) = g2d.mv()
+
+ X = g2d.mv('X','vector')
+ A = g2d.mv('A','spinor')
+
+ assert str(X) == 'X__x*e_x + X__y*e_y'
+ assert str(A) == 'A + A__xy*e_x^e_y'
+
+ assert str((X|A)) == '-A__xy*((e_x.e_y)*X__x + (e_y.e_y)*X__y)*e_x + A__xy*((e_x.e_x)*X__x + (e_x.e_y)*X__y)*e_y'
+ assert str((XX)) == 'A__xy*((e_x.e_y)*X__x + (e_y.e_y)*X__y)*e_x - A__xy*((e_x.e_x)*X__x + (e_x.e_y)*X__y)*e_y'
+
+
+ o2d = Ga('e*x|y', g=[1, 1])
+ (ex, ey) = o2d.mv()
+
+ X = o2d.mv('X', 'vector')
+ A = o2d.mv('A', 'spinor')
+
+ assert str(X) == 'X__x*e_x + X__y*e_y'
+ assert str(A) == 'A + A__xy*e_x^e_y'
+
+ assert str((X*A)) == '(A*X__x - A__xy*X__y)*e_x + (A*X__y + A__xy*X__x)*e_y'
+ assert str((X|A)) == '-A__xy*X__y*e_x + A__xy*X__x*e_y'
+ assert str((XA)) == 'A*X__x*e_x + A*X__y*e_y'
+
+ assert str((A*X)) == '(A*X__x + A__xy*X__y)*e_x + (A*X__y - A__xy*X__x)*e_y'
+ assert str((A|X)) == 'A__xy*X__y*e_x - A__xy*X__x*e_y'
+ assert str((AX)) == 'A__xy*X__y*e_x - A__xy*X__x*e_y'
+
+ return
+
+ def test_check_generalized_BAC_CAB_formulas(self):
+
+ (a,b,c,d,e) = Ga('a b c d e').mv()
+
+ assert str(a|(b*c)) == '-(a.c)*b + (a.b)*c'
+ assert str(a|(b^c)) == '-(a.c)*b + (a.b)*c'
+ assert str(a|(b^c^d)) == '(a.d)*b^c - (a.c)*b^d + (a.b)*c^d'
+
+ expr = (a|(b^c))+(c|(a^b))+(b|(c^a)) # = (a.b)*c - (b.c)*a - ((a.b)*c - (b.c)*a)
+ assert str(expr.simplify()) == '0'
+
+ assert str(a*(b^c)-b*(a^c)+c*(a^b)) == '3*a^b^c'
+ assert str(a*(b^c^d)-b*(a^c^d)+c*(a^b^d)-d*(a^b^c)) == '4*a^b^c^d'
+ assert str((a^b)|(c^d)) == '-(a.c)*(b.d) + (a.d)*(b.c)'
+ assert str(((a^b)|c)|d) == '-(a.c)*(b.d) + (a.d)*(b.c)'
+ assert str(Ga.com(a^b,c^d)) == '-(b.d)*a^c + (b.c)*a^d + (a.d)*b^c - (a.c)*b^d'
+ assert str((a|(b^c))|(d^e)) == '(-(a.b)*(c.e) + (a.c)*(b.e))*d + ((a.b)*(c.d) - (a.c)*(b.d))*e'
+
+ return
+
+ def test_derivatives_in_rectangular_coordinates(self):
+
+ X = (x, y, z) = symbols('x y z')
+ o3d = Ga('e_x e_y e_z', g=[1, 1, 1], coords=X)
+ (ex, ey, ez) = o3d.mv()
+ grad = o3d.grad
+
+ f = o3d.mv('f', 'scalar', f=True)
+ A = o3d.mv('A', 'vector', f=True)
+ B = o3d.mv('B', 'bivector', f=True)
+ C = o3d.mv('C', 'mv', f=True)
+
+ assert str(f) == 'f'
+ assert str(A) == 'A__x*e_x + A__y*e_y + A__z*e_z'
+ assert str(B) == 'B__xy*e_x^e_y + B__xz*e_x^e_z + B__yz*e_y^e_z'
+ assert str(C) == 'C + C__x*e_x + C__y*e_y + C__z*e_z + C__xy*e_x^e_y + C__xz*e_x^e_z + C__yz*e_y^e_z + C__xyz*e_x^e_y^e_z'
+
+ assert str(grad*f) == 'D{x}f*e_x + D{y}f*e_y + D{z}f*e_z'
+ assert str(grad|A) == 'D{x}A__x + D{y}A__y + D{z}A__z'
+ assert str(grad*A) == 'D{x}A__x + D{y}A__y + D{z}A__z + (-D{y}A__x + D{x}A__y)*e_x^e_y + (-D{z}A__x + D{x}A__z)*e_x^e_z + (-D{z}A__y + D{y}A__z)*e_y^e_z'
+
+ assert str(-o3d.I()*(grad^A)) == '(-D{z}A__y + D{y}A__z)*e_x + (D{z}A__x - D{x}A__z)*e_y + (-D{y}A__x + D{x}A__y)*e_z'
+ assert str(grad*B) == '(-D{y}B__xy - D{z}B__xz)*e_x + (D{x}B__xy - D{z}B__yz)*e_y + (D{x}B__xz + D{y}B__yz)*e_z + (D{z}B__xy - D{y}B__xz + D{x}B__yz)*e_x^e_y^e_z'
+ assert str(grad^B) == '(D{z}B__xy - D{y}B__xz + D{x}B__yz)*e_x^e_y^e_z'
+ assert str(grad|B) == '(-D{y}B__xy - D{z}B__xz)*e_x + (D{x}B__xy - D{z}B__yz)*e_y + (D{x}B__xz + D{y}B__yz)*e_z'
+
+ assert str(gradA) == 'D{x}A__x + D{y}A__y + D{z}A__z'
+ assert str(gradB) == '0'
+ assert str(gradC) == 'D{x}C__x + D{y}C__y + D{z}C__z + D{x}C*e_x + D{y}C*e_y + D{z}C*e_z'
+
+ return
+
+ def test_derivatives_in_spherical_coordinates(self):
+
+ X = (r, th, phi) = symbols('r theta phi')
+ s3d = Ga('e_r e_theta e_phi', g=[1, r ** 2, r ** 2 * sin(th) ** 2], coords=X, norm=True)
+ (er, eth, ephi) = s3d.mv()
+ grad = s3d.grad
+
+ f = s3d.mv('f', 'scalar', f=True)
+ A = s3d.mv('A', 'vector', f=True)
+ B = s3d.mv('B', 'bivector', f=True)
+
+ assert str(f) == 'f'
+ assert str(A) == 'A__r*e_r + A__theta*e_theta + A__phi*e_phi'
+ assert str(B) == 'B__rtheta*e_r^e_theta + B__rphi*e_r^e_phi + B__thetaphi*e_theta^e_phi'
+
+ assert str(grad*f) == 'D{r}f*e_r + D{theta}f*e_theta/r + D{phi}f*e_phi/(r*sin(theta))'
+ assert str((grad|A).simplify()) == '(r*D{r}A__r + 2*A__r + A__theta/tan(theta) + D{theta}A__theta + D{phi}A__phi/sin(theta))/r'
+ assert str(-s3d.I()*(grad^A)) == '(A__phi/tan(theta) + D{theta}A__phi - D{phi}A__theta/sin(theta))*e_r/r + (-r*D{r}A__phi - A__phi + D{phi}A__r/sin(theta))*e_theta/r + (r*D{r}A__theta + A__theta - D{theta}A__r)*e_phi/r'
+
+ assert latex(grad) == r'\boldsymbol{e}_{r} \frac{\partial}{\partial r} + \boldsymbol{e}_{\theta } \frac{1}{r} \frac{\partial}{\partial \theta } + \boldsymbol{e}_{\phi } \frac{1}{r \sin{\left (\theta \right )}} \frac{\partial}{\partial \phi }'
+ assert latex(B|(eth^ephi)) == r'- B^{\theta \phi } {\left (r,\theta ,\phi \right )}'
+
+ assert str(grad^B) == '(r*D{r}B__thetaphi - B__rphi/tan(theta) + 2*B__thetaphi - D{theta}B__rphi + D{phi}B__rtheta/sin(theta))*e_r^e_theta^e_phi/r'
+
+ return
+
+ def test_rounding_numerical_components(self):
+
+ o3d = Ga('e_x e_y e_z', g=[1, 1, 1])
+ (ex, ey, ez) = o3d.mv()
+
+ X = 1.2*ex+2.34*ey+0.555*ez
+ Y = 0.333*ex+4*ey+5.3*ez
+
+ assert str(X) == '1.2*e_x + 2.34*e_y + 0.555*e_z'
+ assert str(Nga(X,2)) == '1.2*e_x + 2.3*e_y + 0.55*e_z'
+ assert str(X*Y) == '12.7011000000000 + 4.02078*e_x^e_y + 6.175185*e_x^e_z + 10.182*e_y^e_z'
+ assert str(Nga(X*Y,2)) == '13. + 4.0*e_x^e_y + 6.2*e_x^e_z + 10.0*e_y^e_z'
+
+ return
+
+ def test_noneuclidian_distance_calculation(self):
+ from sympy import solve,sqrt
+
+ g = '0 # #,# 0 #,# # 1'
+ necl = Ga('X Y e',g=g)
+ (X,Y,e) = necl.mv()
+
+ assert str((X^Y)*(X^Y)) == '(X.Y)**2'
+
+ L = X^Y^e
+ B = (L*e).expand().blade_rep() # D&L 10.152
+ assert str(B) == 'X^Y - (Y.e)*X^e + (X.e)*Y^e'
+ Bsq = B*B
+ assert str(Bsq) == '(X.Y)*((X.Y) - 2*(X.e)*(Y.e))'
+ Bsq = Bsq.scalar()
+ assert str(B) == 'X^Y - (Y.e)*X^e + (X.e)*Y^e'
+
+ BeBr = B*e*B.rev()
+ assert str(BeBr) == '(X.Y)*(-(X.Y) + 2*(X.e)*(Y.e))*e'
+ assert str(B*B) == '(X.Y)*((X.Y) - 2*(X.e)*(Y.e))'
+ assert str(L*L) == '(X.Y)**2 - 2*(X.Y)*(X.e)*(Y.e)' # D&L 10.153
+
+ (s,c,Binv,M,S,C,alpha) = symbols('s c (1/B) M S C alpha')
+
+ XdotY = necl.g[0,1]
+ Xdote = necl.g[0,2]
+ Ydote = necl.g[1,2]
+
+ Bhat = Binv*B # D&L 10.154
+ R = c+s*Bhat # Rotor R = exp(alpha*Bhat/2)
+ assert str(R) == 'c + (1/B)*s*X^Y - (1/B)*(Y.e)*s*X^e + (1/B)*(X.e)*s*Y^e'
+
+ Z = R*X*R.rev() # D&L 10.155
+ Z.obj = expand(Z.obj)
+ Z.obj = Z.obj.collect([Binv,s,c,XdotY])
+ assert str(Z) == '((1/B)**2*(X.Y)**2*s**2 - 2*(1/B)**2*(X.Y)*(X.e)*(Y.e)*s**2 + 2*(1/B)*(X.Y)*c*s - 2*(1/B)*(X.e)*(Y.e)*c*s + c**2)*X + 2*(1/B)*(X.e)**2*c*s*Y + 2*(1/B)*(X.Y)*(X.e)*s*(-(1/B)*(X.Y)*s + 2*(1/B)*(X.e)*(Y.e)*s - c)*e'
+ W = Z|Y
+ # From this point forward all calculations are with sympy scalars
+ W = W.scalar()
+ assert str(W) == '(1/B)**2*(X.Y)**3*s**2 - 4*(1/B)**2*(X.Y)**2*(X.e)*(Y.e)*s**2 + 4*(1/B)**2*(X.Y)*(X.e)**2*(Y.e)**2*s**2 + 2*(1/B)*(X.Y)**2*c*s - 4*(1/B)*(X.Y)*(X.e)*(Y.e)*c*s + (X.Y)*c**2'
+ W = expand(W)
+ W = simplify(W)
+ W = W.collect([s*Binv])
+
+ M = 1/Bsq
+ W = W.subs(Binv**2,M)
+ W = simplify(W)
+ Bmag = sqrt(XdotY**2-2*XdotY*Xdote*Ydote)
+ W = W.collect([Binv*c*s,XdotY])
+
+ #Double angle substitutions
+
+ W = W.subs(2*XdotY**2-4*XdotY*Xdote*Ydote,2/(Binv**2))
+ W = W.subs(2*c*s,S)
+ W = W.subs(c**2,(C+1)/2)
+ W = W.subs(s**2,(C-1)/2)
+ W = simplify(W)
+ W = W.subs(Binv,1/Bmag)
+ W = expand(W)
+
+ assert str(W.simplify()) == '(X.Y)*C - (X.e)*(Y.e)*C + (X.e)*(Y.e) + S*sqrt((X.Y)*((X.Y) - 2*(X.e)*(Y.e)))'
+
+ Wd = collect(W,[C,S],exact=True,evaluate=False)
+
+ Wd_1 = Wd[one]
+ Wd_C = Wd[C]
+ Wd_S = Wd[S]
+
+ assert str(Wd_1) == '(X.e)*(Y.e)'
+ assert str(Wd_C) == '(X.Y) - (X.e)*(Y.e)'
+
+ assert str(Wd_S) == 'sqrt((X.Y)**2 - 2*(X.Y)*(X.e)*(Y.e))'
+ assert str(Bmag) == 'sqrt((X.Y)**2 - 2*(X.Y)*(X.e)*(Y.e))'
+
+ Wd_1 = Wd_1.subs(Binv,1/Bmag)
+ Wd_C = Wd_C.subs(Binv,1/Bmag)
+ Wd_S = Wd_S.subs(Binv,1/Bmag)
+
+ lhs = Wd_1+Wd_C*C
+ rhs = -Wd_S*S
+ lhs = lhs**2
+ rhs = rhs**2
+ W = expand(lhs-rhs)
+ W = expand(W.subs(1/Binv**2,Bmag**2))
+ W = expand(W.subs(S**2,C**2-1))
+ W = W.collect([C,C**2],evaluate=False)
+
+ a = simplify(W[C**2])
+ b = simplify(W[C])
+ c = simplify(W[one])
+
+ assert str(a) == '(X.e)**2*(Y.e)**2'
+ assert str(b) == '2*(X.e)*(Y.e)*((X.Y) - (X.e)*(Y.e))'
+ assert str(c) == '(X.Y)**2 - 2*(X.Y)*(X.e)*(Y.e) + (X.e)**2*(Y.e)**2'
+
+ x = Symbol('x')
+ C = solve(a*x**2+b*x+c,x)[0]
+ assert str(expand(simplify(expand(C)))) == '-(X.Y)/((X.e)*(Y.e)) + 1'
+
+ return
+
+ def test_conformal_representations_of_circles_lines_spheres_and_planes(self):
+ global n,nbar
+
+ g = '1 0 0 0 0,0 1 0 0 0,0 0 1 0 0,0 0 0 0 2,0 0 0 2 0'
+
+ cnfml3d = Ga('e_1 e_2 e_3 n nbar',g=g)
+
+ (e1,e2,e3,n,nbar) = cnfml3d.mv()
+
+ e = n+nbar
+
+ #conformal representation of points
+
+ A = make_vector(e1,ga=cnfml3d) # point a = (1,0,0) A = F(a)
+ B = make_vector(e2,ga=cnfml3d) # point b = (0,1,0) B = F(b)
+ C = make_vector(-e1,ga=cnfml3d) # point c = (-1,0,0) C = F(c)
+ D = make_vector(e3,ga=cnfml3d) # point d = (0,0,1) D = F(d)
+ X = make_vector('x',3,ga=cnfml3d)
+
+ assert str(A) == 'e_1 + n/2 - nbar/2'
+ assert str(B) == 'e_2 + n/2 - nbar/2'
+ assert str(C) == '-e_1 + n/2 - nbar/2'
+ assert str(D) == 'e_3 + n/2 - nbar/2'
+ assert str(X) == 'x1*e_1 + x2*e_2 + x3*e_3 + (x1**2/2 + x2**2/2 + x3**2/2)*n - nbar/2'
+
+ assert str((A^B^C^X)) == '-x3*e_1^e_2^e_3^n + x3*e_1^e_2^e_3^nbar + (x1**2/2 + x2**2/2 + x3**2/2 - 1/2)*e_1^e_2^n^nbar'
+ assert str((A^B^n^X)) == '-x3*e_1^e_2^e_3^n + (x1/2 + x2/2 - 1/2)*e_1^e_2^n^nbar + x3*e_1^e_3^n^nbar/2 - x3*e_2^e_3^n^nbar/2'
+ assert str((((A^B)^C)^D)^X) == '(-x1**2/2 - x2**2/2 - x3**2/2 + 1/2)*e_1^e_2^e_3^n^nbar'
+ assert str((A^B^n^D^X)) == '(-x1/2 - x2/2 - x3/2 + 1/2)*e_1^e_2^e_3^n^nbar'
+
+ L = (A^B^e)^X
+
+ assert str(L) == '-x3*e_1^e_2^e_3^n - x3*e_1^e_2^e_3^nbar + (-x1**2/2 + x1 - x2**2/2 + x2 - x3**2/2 - 1/2)*e_1^e_2^n^nbar + x3*e_1^e_3^n^nbar - x3*e_2^e_3^n^nbar'
+
+ return
+
+ def test_properties_of_geometric_objects(self):
+
+ global n, nbar
-def test_basic_multivector_operations():
- (ex,ey,ez) = MV.setup('e*x|y|z')
+ g = '# # # 0 0,'+ \
+ '# # # 0 0,'+ \
+ '# # # 0 0,'+ \
+ '0 0 0 0 2,'+ \
+ '0 0 0 2 0'
- A = MV('A','mv')
+ c3d = Ga('p1 p2 p3 n nbar',g=g)
- assert str(A) == 'A + A__x*e_x + A__y*e_y + A__z*e_z + A__xy*e_x^e_y + A__xz*e_x^e_z + A__yz*e_y^e_z + A__xyz*e_x^e_y^e_z'
- assert str(A) == 'A + A__x*e_x + A__y*e_y + A__z*e_z + A__xy*e_x^e_y + A__xz*e_x^e_z + A__yz*e_y^e_z + A__xyz*e_x^e_y^e_z'
- assert str(A) == 'A + A__x*e_x + A__y*e_y + A__z*e_z + A__xy*e_x^e_y + A__xz*e_x^e_z + A__yz*e_y^e_z + A__xyz*e_x^e_y^e_z'
+ (p1,p2,p3,n,nbar) = c3d.mv()
- X = MV('X','vector')
- Y = MV('Y','vector')
+ P1 = F(p1)
+ P2 = F(p2)
+ P3 = F(p3)
+ L = P1^P2^n
+ delta = (L|n)|nbar
+ assert str(delta) == '2*p1 - 2*p2'
- assert str(X) == 'X__x*e_x + X__y*e_y + X__z*e_z'
- assert str(Y) == 'Y__x*e_x + Y__y*e_y + Y__z*e_z'
+ C = P1^P2^P3
+ delta = ((C^n)|n)|nbar
+ assert str(delta) == '2*p1^p2 - 2*p1^p3 + 2*p2^p3'
+ assert str((p2-p1)^(p3-p1)) == 'p1^p2 - p1^p3 + p2^p3'
- assert str((X*Y)) == '(e_x.e_x)*X__x*Y__x + (e_x.e_y)*X__x*Y__y + (e_x.e_y)*X__y*Y__x + (e_x.e_z)*X__x*Y__z + (e_x.e_z)*X__z*Y__x + (e_y.e_y)*X__y*Y__y + (e_y.e_z)*X__y*Y__z + (e_y.e_z)*X__z*Y__y + (e_z.e_z)*X__z*Y__z + (X__x*Y__y - X__y*Y__x)*e_x^e_y + (X__x*Y__z - X__z*Y__x)*e_x^e_z + (X__y*Y__z - X__z*Y__y)*e_y^e_z'
- assert str((X^Y)) == '(X__x*Y__y - X__y*Y__x)*e_x^e_y + (X__x*Y__z - X__z*Y__x)*e_x^e_z + (X__y*Y__z - X__z*Y__y)*e_y^e_z'
- assert str((X|Y)) == '(e_x.e_x)*X__x*Y__x + (e_x.e_y)*X__x*Y__y + (e_x.e_y)*X__y*Y__x + (e_x.e_z)*X__x*Y__z + (e_x.e_z)*X__z*Y__x + (e_y.e_y)*X__y*Y__y + (e_y.e_z)*X__y*Y__z + (e_y.e_z)*X__z*Y__y + (e_z.e_z)*X__z*Y__z'
+ return
- (ex,ey) = MV.setup('e*x|y')
+ def test_extracting_vectors_from_conformal_2_blade(self):
+ g = '0 -1 #,'+ \
+ '-1 0 #,'+ \
+ '# # #'
- X = MV('X','vector')
- A = MV('A','spinor')
+ e2b = Ga('P1 P2 a',g=g)
- assert str(X) == 'X__x*e_x + X__y*e_y'
- assert str(A) == 'A + A__xy*e_x^e_y'
+ (P1,P2,a) = e2b.mv()
- assert str((X|A)) == '-A__xy*((e_x.e_y)*X__x + (e_y.e_y)*X__y)*e_x + A__xy*((e_x.e_x)*X__x + (e_x.e_y)*X__y)*e_y'
- assert str((XX)) == 'A__xy*((e_x.e_y)*X__x + (e_y.e_y)*X__y)*e_x - A__xy*((e_x.e_x)*X__x + (e_x.e_y)*X__y)*e_y'
+ B = P1^P2
+ Bsq = B*B
+ assert str(Bsq) == '1'
+ ap = a-(a^B)*B
+ assert str(ap) == '-(P2.a)*P1 - (P1.a)*P2'
- (ex,ey) = MV.setup('e*x|y',metric='[1,1]')
+ Ap = ap+ap*B
+ Am = ap-ap*B
+ assert str(Ap) == '-2*(P2.a)*P1'
+ assert str(Am) == '-2*(P1.a)*P2'
- X = MV('X','vector')
- A = MV('A','spinor')
+ assert str(Ap*Ap) == '0'
+ assert str(Am*Am) == '0'
- assert str(X) == 'X__x*e_x + X__y*e_y'
- assert str(A) == 'A + A__xy*e_x^e_y'
+ aB = a|B
+ assert str(aB) == '-(P2.a)*P1 + (P1.a)*P2'
- assert str((X*A)) == '(A*X__x - A__xy*X__y)*e_x + (A*X__y + A__xy*X__x)*e_y'
- assert str((X|A)) == '-A__xy*X__y*e_x + A__xy*X__x*e_y'
- assert str((XA)) == 'A*X__x*e_x + A*X__y*e_y'
+ return
- assert str((A*X)) == '(A*X__x + A__xy*X__y)*e_x + (A*X__y - A__xy*X__x)*e_y'
- assert str((A|X)) == 'A__xy*X__y*e_x - A__xy*X__x*e_y'
- assert str((AX)) == 'A__xy*X__y*e_x - A__xy*X__x*e_y'
- return
-
-def test_check_generalized_BAC_CAB_formulas():
- (a,b,c,d,e) = MV.setup('a b c d e')
+ def test_reciprocal_frame_test(self):
- assert str(a|(b*c)) == '-(a.c)*b + (a.b)*c'
- assert str(a|(b^c)) == '-(a.c)*b + (a.b)*c'
- assert str(a|(b^c^d)) == '(a.d)*b^c - (a.c)*b^d + (a.b)*c^d'
- #assert str( (a|(b^c))+(c|(a^b))+(b|(c^a)) ) == '0'
- assert str(a*(b^c)-b*(a^c)+c*(a^b)) == '3*a^b^c'
- assert str(a*(b^c^d)-b*(a^c^d)+c*(a^b^d)-d*(a^b^c)) == '4*a^b^c^d'
- assert str((a^b)|(c^d)) == '-(a.c)*(b.d) + (a.d)*(b.c)'
- assert str(((a^b)|c)|d) == '-(a.c)*(b.d) + (a.d)*(b.c)'
- assert str(Ga.com(a^b,c^d)) == '-(b.d)*a^c + (b.c)*a^d + (a.d)*b^c - (a.c)*b^d'
- assert str((a|(b^c))|(d^e)) == '(-(a.b)*(c.e) + (a.c)*(b.e))*d + ((a.b)*(c.d) - (a.c)*(b.d))*e'
- return
-
-def test_derivatives_in_rectangular_coordinates():
- X = (x,y,z) = symbols('x y z')
- (ex,ey,ez,grad) = MV.setup('e_x e_y e_z',metric='[1,1,1]',coords=X)
-
- f = MV('f','scalar',fct=True)
- A = MV('A','vector',fct=True)
- B = MV('B','grade2',fct=True)
- C = MV('C','mv',fct=True)
-
- assert str(f) == 'f'
- assert str(A) == 'A__x*e_x + A__y*e_y + A__z*e_z'
- assert str(B) == 'B__xy*e_x^e_y + B__xz*e_x^e_z + B__yz*e_y^e_z'
- assert str(C) == 'C + C__x*e_x + C__y*e_y + C__z*e_z + C__xy*e_x^e_y + C__xz*e_x^e_z + C__yz*e_y^e_z + C__xyz*e_x^e_y^e_z'
-
- assert str(grad*f) == 'D{x}f*e_x + D{y}f*e_y + D{z}f*e_z'
- assert str(grad|A) == 'D{x}A__x + D{y}A__y + D{z}A__z'
- assert str(grad*A) == 'D{x}A__x + D{y}A__y + D{z}A__z + (-D{y}A__x + D{x}A__y)*e_x^e_y + (-D{z}A__x + D{x}A__z)*e_x^e_z + (-D{z}A__y + D{y}A__z)*e_y^e_z'
-
- assert str(-MV.I*(grad^A)) == '(-D{z}A__y + D{y}A__z)*e_x + (D{z}A__x - D{x}A__z)*e_y + (-D{y}A__x + D{x}A__y)*e_z'
-
- assert str(grad*B) == '(-D{y}B__xy - D{z}B__xz)*e_x + (D{x}B__xy - D{z}B__yz)*e_y + (D{x}B__xz + D{y}B__yz)*e_z + (D{z}B__xy - D{y}B__xz + D{x}B__yz)*e_x^e_y^e_z'
- assert str(grad^B) == '(D{z}B__xy - D{y}B__xz + D{x}B__yz)*e_x^e_y^e_z'
- assert str(grad|B) == '(-D{y}B__xy - D{z}B__xz)*e_x + (D{x}B__xy - D{z}B__yz)*e_y + (D{x}B__xz + D{y}B__yz)*e_z'
-
- assert str(gradA) == 'D{x}A__x + D{y}A__y + D{z}A__z'
- assert str(gradB) == '0'
- assert str(gradC) == 'D{x}C__x + D{y}C__y + D{z}C__z + D{x}C*e_x + D{y}C*e_y + D{z}C*e_z'
- return
-
-def test_derivatives_in_spherical_coordinates():
- X = (r,th,phi) = symbols('r theta phi')
- curv = [[r*cos(phi)*sin(th),r*sin(phi)*sin(th),r*cos(th)],[1,r,r*sin(th)]]
- (er,eth,ephi,grad) = MV.setup('e_r e_theta e_phi',metric='[1,1,1]',coords=X,curv=curv)
-
- f = MV('f','scalar',fct=True)
- A = MV('A','vector',fct=True)
- B = MV('B','grade2',fct=True)
-
- assert str(f) == 'f'
- assert str(A) == 'A__r*e_r + A__theta*e_theta + A__phi*e_phi'
- assert str(B) == 'B__rtheta*e_r^e_theta + B__rphi*e_r^e_phi + B__thetaphi*e_theta^e_phi'
-
- assert str(grad*f) == 'D{r}f*e_r + D{theta}f/r*e_theta + D{phi}f/(r*sin(theta))*e_phi'
- assert str(grad|A) == 'D{r}A__r + 2*A__r/r + A__theta*cos(theta)/(r*sin(theta)) + D{theta}A__theta/r + D{phi}A__phi/(r*sin(theta))'
- assert str(-MV.I*(grad^A)) == '((A__phi*cos(theta)/sin(theta) + D{theta}A__phi - D{phi}A__theta/sin(theta))/r)*e_r + (-D{r}A__phi - A__phi/r + D{phi}A__r/(r*sin(theta)))*e_theta + (D{r}A__theta + A__theta/r - D{theta}A__r/r)*e_phi'
- assert str(grad^B) == '(D{r}B__thetaphi - B__rphi*cos(theta)/(r*sin(theta)) + 2*B__thetaphi/r - D{theta}B__rphi/r + D{phi}B__rtheta/(r*sin(theta)))*e_r^e_theta^e_phi'
- return
-
-def test_rounding_numerical_components():
- (ex,ey,ez) = MV.setup('e_x e_y e_z',metric='[1,1,1]')
-
- X = 1.2*ex+2.34*ey+0.555*ez
- Y = 0.333*ex+4*ey+5.3*ez
-
- #assert str(X) == '1.20000000000000*e_x + 2.34000000000000*e_y + 0.555000000000000*e_z'
- assert str(Nga(X,2)) == '1.2*e_x + 2.3*e_y + 0.55*e_z'
- #assert str(X*Y) == '12.7011000000000 + 4.02078000000000*e_x^e_y + 6.17518500000000*e_x^e_z + 10.1820000000000*e_y^e_z'
- assert str(Nga(X*Y,2)) == '13. + 4.0*e_x^e_y + 6.2*e_x^e_z + 10.*e_y^e_z'
- return
-
-def test_noneuclidian_distance_calculation():
- from sympy import solve,sqrt
- metric = '0 # #,# 0 #,# # 1'
- (X,Y,e) = MV.setup('X Y e',metric)
-
- assert str((X^Y)*(X^Y)) == '(X.Y)**2'
-
- L = X^Y^e
- B = L*e
- assert str(B) == 'X^Y - (Y.e)*X^e + (X.e)*Y^e'
- Bsq = B*B
- assert str(Bsq) == '(X.Y)*((X.Y) - 2*(X.e)*(Y.e))'
- Bsq = Bsq.scalar()
- assert str(B) == 'X^Y - (Y.e)*X^e + (X.e)*Y^e'
-
- BeBr =B*e*B.rev()
- assert str(BeBr) == '((X.Y)*(-(X.Y) + 2*(X.e)*(Y.e)))*e'
- assert str(B*B) == '(X.Y)*((X.Y) - 2*(X.e)*(Y.e))'
- assert str(L*L) == '(X.Y)*((X.Y) - 2*(X.e)*(Y.e))'
- (s,c,Binv,M,S,C,alpha,XdotY,Xdote,Ydote) = symbols('s c (1/B) M S C alpha (X.Y) (X.e) (Y.e)')
-
- Bhat = Binv*B
- R = c+s*Bhat
- assert str(R) == 'c + (1/B)*s*X^Y - (1/B)*(Y.e)*s*X^e + (1/B)*(X.e)*s*Y^e'
-
- Z = R*X*R.rev()
- Z.obj = expand(Z.obj)
- Z.obj = Z.obj.collect([Binv,s,c,XdotY])
- assert str(Z) == '((1/B)**2*(X.Y)**2*s**2 - 2*(1/B)**2*(X.Y)*(X.e)*(Y.e)*s**2 + 2*(1/B)*(X.Y)*c*s - 2*(1/B)*(X.e)*(Y.e)*c*s + c**2)*X + 2*(1/B)*(X.e)**2*c*s*Y + (2*(1/B)*(X.Y)*(X.e)*s*(-(1/B)*(X.Y)*s + 2*(1/B)*(X.e)*(Y.e)*s - c))*e'
- W = Z|Y
- # From this point forward all calculations are with sympy scalars
- W = W.scalar()
- assert str(W) == '(1/B)**2*(X.Y)**3*s**2 - 4*(1/B)**2*(X.Y)**2*(X.e)*(Y.e)*s**2 + 4*(1/B)**2*(X.Y)*(X.e)**2*(Y.e)**2*s**2 + 2*(1/B)*(X.Y)**2*c*s - 4*(1/B)*(X.Y)*(X.e)*(Y.e)*c*s + (X.Y)*c**2'
- W = expand(W)
- W = simplify(W)
- W = W.collect([s*Binv])
-
- M = 1/Bsq
- W = W.subs(Binv**2,M)
- W = simplify(W)
- Bmag = sqrt(XdotY**2-2*XdotY*Xdote*Ydote)
- W = W.collect([Binv*c*s,XdotY])
-
- #Double angle substitutions
-
- W = W.subs(2*XdotY**2-4*XdotY*Xdote*Ydote,2/(Binv**2))
- W = W.subs(2*c*s,S)
- W = W.subs(c**2,(C+1)/2)
- W = W.subs(s**2,(C-1)/2)
- W = simplify(W)
- W = W.subs(1/Binv,Bmag)
- W = expand(W)
-
-
- assert str(W) == '(X.Y)*C - (X.e)*(Y.e)*C + (X.e)*(Y.e) + S*sqrt((X.Y)**2 - 2*(X.Y)*(X.e)*(Y.e))'
-
- Wd = collect(W,[C,S],exact=True,evaluate=False)
-
- Wd_1 = Wd[ONE]
- Wd_C = Wd[C]
- Wd_S = Wd[S]
-
- assert str(Wd_1) == '(X.e)*(Y.e)'
- assert str(Wd_C) == '(X.Y) - (X.e)*(Y.e)'
- assert str(Wd_S) == 'sqrt((X.Y)**2 - 2*(X.Y)*(X.e)*(Y.e))'
-
- assert str(Bmag) == 'sqrt((X.Y)**2 - 2*(X.Y)*(X.e)*(Y.e))'
- Wd_1 = Wd_1.subs(Bmag,1/Binv)
- Wd_C = Wd_C.subs(Bmag,1/Binv)
- Wd_S = Wd_S.subs(Bmag,1/Binv)
-
- lhs = Wd_1+Wd_C*C
- rhs = -Wd_S*S
- lhs = lhs**2
- rhs = rhs**2
- W = expand(lhs-rhs)
- W = expand(W.subs(1/Binv**2,Bmag**2))
- W = expand(W.subs(S**2,C**2-1))
- W = W.collect([C,C**2],evaluate=False)
-
- a = simplify(W[C**2])
- b = simplify(W[C])
- c = simplify(W[ONE])
-
-
- assert str(a) == '(X.e)**2*(Y.e)**2'
- assert str(b) == '2*(X.e)*(Y.e)*((X.Y) - (X.e)*(Y.e))'
- assert str(c) == '(X.Y)**2 - 2*(X.Y)*(X.e)*(Y.e) + (X.e)**2*(Y.e)**2'
-
- x = Symbol('x')
- C = solve(a*x**2+b*x+c,x)[0]
- assert str(expand(simplify(expand(C)))) == '-(X.Y)/((X.e)*(Y.e)) + 1'
- return
-
-def test_conformal_representations_of_circles_lines_spheres_and_planes():
- global n,nbar
-
- metric = '1 0 0 0 0,0 1 0 0 0,0 0 1 0 0,0 0 0 0 2,0 0 0 2 0'
-
- (e1,e2,e3,n,nbar) = MV.setup('e_1 e_2 e_3 n nbar',metric)
-
- e = n+nbar
- #conformal representation of points
-
- A = make_vector(e1)
- B = make_vector(e2)
- C = make_vector(-e1)
- D = make_vector(e3)
- X = make_vector('x',3)
-
- assert str(A) == 'e_1 + 1/2*n - 1/2*nbar'
- assert str(B) == 'e_2 + 1/2*n - 1/2*nbar'
- assert str(C) == '-e_1 + 1/2*n - 1/2*nbar'
- assert str(D) == 'e_3 + 1/2*n - 1/2*nbar'
- assert str(X) == 'x1*e_1 + x2*e_2 + x3*e_3 + ((x1**2 + x2**2 + x3**2)/2)*n - 1/2*nbar'
-
- assert str((A^B^C^X)) == '-x3*e_1^e_2^e_3^n + x3*e_1^e_2^e_3^nbar + ((x1**2 + x2**2 + x3**2 - 1)/2)*e_1^e_2^n^nbar'
- assert str((A^B^n^X)) == '-x3*e_1^e_2^e_3^n + ((x1 + x2 - 1)/2)*e_1^e_2^n^nbar + x3/2*e_1^e_3^n^nbar - x3/2*e_2^e_3^n^nbar'
- assert str((((A^B)^C)^D)^X) == '((-x1**2 - x2**2 - x3**2 + 1)/2)*e_1^e_2^e_3^n^nbar'
- assert str((A^B^n^D^X)) == '((-x1 - x2 - x3 + 1)/2)*e_1^e_2^e_3^n^nbar'
-
- L = (A^B^e)^X
-
- assert str(L) == '-x3*e_1^e_2^e_3^n - x3*e_1^e_2^e_3^nbar + (-x1**2/2 + x1 - x2**2/2 + x2 - x3**2/2 - 1/2)*e_1^e_2^n^nbar + x3*e_1^e_3^n^nbar - x3*e_2^e_3^n^nbar'
- return
-
-def test_properties_of_geometric_objects():
- metric = '# # # 0 0,'+ \
- '# # # 0 0,'+ \
- '# # # 0 0,'+ \
- '0 0 0 0 2,'+ \
- '0 0 0 2 0'
-
- (p1,p2,p3,n,nbar) = MV.setup('p1 p2 p3 n nbar',metric)
+ g = '1 # #,'+ \
+ '# 1 #,'+ \
+ '# # 1'
- P1 = F(p1)
- P2 = F(p2)
- P3 = F(p3)
+ g3dn = Ga('e1 e2 e3',g=g)
- L = P1^P2^n
- delta = (L|n)|nbar
- assert str(delta) == '2*p1 - 2*p2'
+ (e1,e2,e3) = g3dn.mv()
- C = P1^P2^P3
- delta = ((C^n)|n)|nbar
- assert str(delta) == '2*p1^p2 - 2*p1^p3 + 2*p2^p3'
- assert str((p2-p1)^(p3-p1)) == 'p1^p2 - p1^p3 + p2^p3'
- return
+ E = e1^e2^e3
+ Esq = (E*E).scalar()
+ assert str(E) == 'e1^e2^e3'
+ assert str(Esq) == '(e1.e2)**2 - 2*(e1.e2)*(e1.e3)*(e2.e3) + (e1.e3)**2 + (e2.e3)**2 - 1'
+ Esq_inv = 1/Esq
-def test_extracting_vectors_from_conformal_2_blade():
- metric = ' 0 -1 #,'+ \
- '-1 0 #,'+ \
- ' # # #,'
+ E1 = (e2^e3)*E
+ E2 = (-1)*(e1^e3)*E
+ E3 = (e1^e2)*E
- (P1,P2,a) = MV.setup('P1 P2 a',metric)
+ assert str(E1) == '((e2.e3)**2 - 1)*e1 + ((e1.e2) - (e1.e3)*(e2.e3))*e2 + (-(e1.e2)*(e2.e3) + (e1.e3))*e3'
+ assert str(E2) == '((e1.e2) - (e1.e3)*(e2.e3))*e1 + ((e1.e3)**2 - 1)*e2 + (-(e1.e2)*(e1.e3) + (e2.e3))*e3'
+ assert str(E3) == '(-(e1.e2)*(e2.e3) + (e1.e3))*e1 + (-(e1.e2)*(e1.e3) + (e2.e3))*e2 + ((e1.e2)**2 - 1)*e3'
- B = P1^P2
- Bsq = B*B
- assert str(Bsq) == '1'
- ap = a-(a^B)*B
- assert str(ap) == '-(P2.a)*P1 - (P1.a)*P2'
-
- Ap = ap+ap*B
- Am = ap-ap*B
-
- assert str(Ap) == '-2*(P2.a)*P1'
- assert str(Am) == '-2*(P1.a)*P2'
-
- assert str(Ap*Ap) == '0'
- assert str(Am*Am) == '0'
+ w = (E1|e2)
+ w = w.expand()
+ assert str(w) == '0'
- aB = a|B
- assert str(aB) == '-(P2.a)*P1 + (P1.a)*P2'
- return
+ w = (E1|e3)
+ w = w.expand()
+ assert str(w) == '0'
-def test_reciprocal_frame_test():
- metric = '1 # #,'+ \
- '# 1 #,'+ \
- '# # 1,'
+ w = (E2|e1)
+ w = w.expand()
+ assert str(w) == '0'
- (e1,e2,e3) = MV.setup('e1 e2 e3',metric)
+ w = (E2|e3)
+ w = w.expand()
+ assert str(w) == '0'
- E = e1^e2^e3
- Esq = (E*E).scalar()
- assert str(E) == 'e1^e2^e3'
- assert str(Esq) == '(e1.e2)**2 - 2*(e1.e2)*(e1.e3)*(e2.e3) + (e1.e3)**2 + (e2.e3)**2 - 1'
- Esq_inv = 1/Esq
+ w = (E3|e1)
+ w = w.expand()
+ assert str(w) == '0'
- E1 = (e2^e3)*E
- E2 = (-1)*(e1^e3)*E
- E3 = (e1^e2)*E
+ w = (E3|e2)
+ w = w.expand()
+ assert str(w) == '0'
- assert str(E1) == '((e2.e3)**2 - 1)*e1 + ((e1.e2) - (e1.e3)*(e2.e3))*e2 + (-(e1.e2)*(e2.e3) + (e1.e3))*e3'
- assert str(E2) == '((e1.e2) - (e1.e3)*(e2.e3))*e1 + ((e1.e3)**2 - 1)*e2 + (-(e1.e2)*(e1.e3) + (e2.e3))*e3'
- assert str(E3) == '(-(e1.e2)*(e2.e3) + (e1.e3))*e1 + (-(e1.e2)*(e1.e3) + (e2.e3))*e2 + ((e1.e2)**2 - 1)*e3'
+ w = (E1|e1)
+ w = (w.expand()).scalar()
+ Esq = expand(Esq)
+ assert str(simplify(w/Esq)) == '1'
- w = (E1|e2)
- w = w.expand()
- assert str(w) == '0'
-
- w = (E1|e3)
- w = w.expand()
- assert str(w) == '0'
-
- w = (E2|e1)
- w = w.expand()
- assert str(w) == '0'
-
- w = (E2|e3)
- w = w.expand()
- assert str(w) == '0'
-
- w = (E3|e1)
- w = w.expand()
- assert str(w) == '0'
+ w = (E2|e2)
+ w = (w.expand()).scalar()
+ assert str(simplify(w/Esq)) == '1'
- w = (E3|e2)
- w = w.expand()
- assert str(w) == '0'
+ w = (E3|e3)
+ w = (w.expand()).scalar()
+ assert str(simplify(w/Esq)) == '1'
- w = (E1|e1)
- w = (w.expand()).scalar()
- Esq = expand(Esq)
- assert str(simplify(w/Esq)) == '1'
-
- w = (E2|e2)
- w = (w.expand()).scalar()
- assert str(simplify(w/Esq)) == '1'
-
- w = (E3|e3)
- w = (w.expand()).scalar()
- assert str(simplify(w/Esq)) == '1'
- return
+ return
diff --git a/galgebra/utils.py b/galgebra/utils.py
new file mode 100644
index 00000000..00d38bf8
--- /dev/null
+++ b/galgebra/utils.py
@@ -0,0 +1,18 @@
+# utils.py
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import collections
+
+# https://stackoverflow.com/questions/16176742/python-3-replacement-for-deprecated-compiler-ast-flatten-function
+def flatten(x):
+ result = []
+
+ for el in x:
+ if isinstance(x, collections.Iterable) and not isinstance(el, str):
+ result.extend(flatten(el))
+ else:
+ result.append(el)
+ return result
\ No newline at end of file
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 00000000..6ecd4e23
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,2 @@
+[test]
+test_suite = tests
diff --git a/setup.py b/setup.py
index 7c7c3159..04f430fc 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,6 @@
from setuptools import setup, find_packages
from distutils.core import Extension
-
VERSION = '0.4.1.1'
LONG_DESCRIPTION = """
A symbolic geometric algebra module for python. BSD License.
@@ -13,7 +12,7 @@
description='Symbolic Geometric Algebra/Calculus modules for sympy',
author='Alan Bromborsky',
author_email='hadfield.hugo@gmail.com',
- url='https://github.com/hugohadfield/galgebra',
+ url='https://github.com/pygae/galgebra',
license='BSD',
packages=find_packages(),
package_dir={'galgebra':'galgebra'},
@@ -31,4 +30,3 @@
'Programming Language :: Python :: 2.7',
'Topic :: Scientific/Engineering :: Mathematics',
'Topic :: Scientific/Engineering :: Physics'])
-