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']) -