diff --git a/doc/geometric-algebra.rst b/doc/geometric-algebra.rst index 53e3d5fafc8d48d4b5c96a0037f00925d8b22cc3..e9c5458f83f9ffbd9df42b4efad2b9a97779636b 100644 --- a/doc/geometric-algebra.rst +++ b/doc/geometric-algebra.rst @@ -35,6 +35,7 @@ Multivectors .. automethod:: rev .. automethod:: invol .. automethod:: dual + .. automethod:: __inv__ .. automethod:: norm_squared .. automethod:: __abs__ .. autoattribute:: I diff --git a/pymbolic/geometric_algebra.py b/pymbolic/geometric_algebra.py index d7957f21e326b868e1cb62ad4e63caaf0da91f85..967deefaa12366c55653b4cb3a26ff2490eae708 100644 --- a/pymbolic/geometric_algebra.py +++ b/pymbolic/geometric_algebra.py @@ -421,7 +421,7 @@ class MultiVector(object): def __getinitargs__(self): return (self.data, self.space) - mapper_method = "map_multi_vector" + mapper_method = "map_multivector" # {{{ stringification @@ -438,8 +438,8 @@ class MultiVector(object): except AttributeError: coeff_str = str(coeff) else: - from pymbolic.mapper.stringifier import PREC_TIMES - coeff_str = strifier(coeff, PREC_TIMES) + from pymbolic.mapper.stringifier import PREC_PRODUCT + coeff_str = strifier()(coeff, PREC_PRODUCT) blade_str = self.space.blade_bits_to_str(bits) if not blade_str: @@ -688,11 +688,15 @@ class MultiVector(object): def dual(self): r"""Return the dual of *self*, see (1.2.26) in [HS]. - Often written :math:`\widetilde A`. + Written :math:`\widetilde A` by [HS] and :math:`A^\ast` by [DFW]. """ return self | self.I.rev() + def __inv__(self): + """Return the dual of *self*, see :meth:`dual`.""" + return self.dual() + def norm_squared(self): return self.rev().scalar_product(self) @@ -709,6 +713,14 @@ class MultiVector(object): # {{{ comparisons + @memoize_method + def __hash__(self): + result = hash(self.space) + for bits, coeff in self.data.iteritems(): + result ^= hash(bits) ^ hash(coeff) + + return result + def __nonzero__(self): return bool(self.data) @@ -863,4 +875,17 @@ class MultiVector(object): # }}} + +def componentwise(f, expr): + """Apply function *f* componentwise to object arrays and + :class:`MultiVector` instances. *expr* is also allowed to + be a scalar. + """ + + if isinstance(expr, MultiVector): + return expr.map(f) + + from pytools.obj_array import with_object_array_or_scalar + return with_object_array_or_scalar(f, expr) + # vim: foldmethod=marker diff --git a/pymbolic/mapper/__init__.py b/pymbolic/mapper/__init__.py index cd56ad807b59c50a5339c9bac9b9a22cb2ac7024..bf3e628655e491c65f84a8e703b8d08bf4bb67d8 100644 --- a/pymbolic/mapper/__init__.py +++ b/pymbolic/mapper/__init__.py @@ -216,6 +216,9 @@ class CombineMapper(RecursiveMapper): def map_numpy_array(self, expr, *args): return self.combine(self.rec(el) for el in expr.flat) + def map_multivector(self, expr, *args): + return self.combine(self.rec(coeff) for bits, coeff in expr.data.iteritems()) + def map_common_subexpression(self, expr, *args): return self.rec(expr.child, *args) @@ -338,6 +341,9 @@ class IdentityMapper(Mapper): result[i] = self.rec(expr[i]) return result + def map_multivector(self, expr, *args): + return expr.map(lambda ch: self.rec(ch, *args)) + def map_common_subexpression(self, expr, *args, **kwargs): from pymbolic.primitives import is_zero result = self.rec(expr.child, *args, **kwargs) diff --git a/pymbolic/mapper/evaluator.py b/pymbolic/mapper/evaluator.py index c4ef3f64f8c3e3a401239e08db188c020b6ecaa5..ec6f93e955da8b5736028f362fd9803aa5746017 100644 --- a/pymbolic/mapper/evaluator.py +++ b/pymbolic/mapper/evaluator.py @@ -147,6 +147,9 @@ class EvaluationMapper(RecursiveMapper): result[i] = self.rec(expr[i]) return result + def map_multivector(self, expr, *args): + return expr.map(lambda ch: self.rec(ch, *args)) + def map_common_subexpression(self, expr): try: return self.common_subexp_cache[expr.child]