88from itertools import combinations
99import functools
1010from functools import reduce
11- from typing import Tuple , TypeVar , Callable
11+ from typing import Tuple , TypeVar , Callable , Mapping
1212
1313from sympy import (
1414 diff , Rational , Symbol , S , Mul , Add ,
@@ -137,7 +137,7 @@ def nc_subs(expr, base_keys, base_values=None):
137137
138138
139139_T = TypeVar ('T' )
140- _U = TypeVar ('T ' )
140+ _U = TypeVar ('U ' )
141141
142142
143143class GradedTuple (Tuple [Tuple [_T , ...], ...]):
@@ -170,6 +170,20 @@ def _map(self, func: Callable[[_T], _U]) -> 'GradedTuple[_U]':
170170 )
171171
172172
173+ class OrderedBiMap (OrderedDict , Mapping ):
174+ """ A dict with an ``.inverse`` attribute mapping in the other direction """
175+ def __init__ (self , items ):
176+ # set up the inverse mapping, bypassing our __init__
177+ self .inverse = OrderedBiMap .__new__ (type (self ))
178+
179+ # populate both
180+ OrderedDict .__init__ (self , items )
181+ OrderedDict .__init__ (self .inverse , [(v , k ) for k , v in items ])
182+
183+ # and complete the inverse loop
184+ self .inverse .inverse = self
185+
186+
173187class Ga (metric .Metric ):
174188 r"""
175189 The vector space (basis, metric, derivatives of basis vectors) is
@@ -245,21 +259,17 @@ class Ga(metric.Metric):
245259 Linear combination of coordinates and basis vectors. For
246260 example in orthogonal 3D :math:`x*e_x+y*e_y+z*e_z`.
247261
248- .. attribute:: blades_to_indexes_dict
249-
250- Map basis blades to index tuples (dictionary).
251-
252262 .. attribute:: indexes_to_blades_dict
253263
254- Map index tuples to basis blades (dictionary).
255-
256- .. attribute:: bases_to_indexes_dict
264+ Bidirectional map from index tuples (:attr:`indices`) to basis blades (:attr:`blades`)
257265
258- Map basis bases to index tuples (dictionary).
266+ :type: OrderedBiMap[Tuple[int, ...], sympy.Symbol]
259267
260268 .. attribute:: indexes_to_bases_dict
261269
262- Map index tuples to basis bases (dictionary).
270+ Bidirectional map from index tuples (:attr:`indices`) to basis bases (:attr:`bases`)
271+
272+ :type: OrderedBiMap[Tuple[int, ...], sympy.Symbol]
263273
264274 .. rubric:: Multiplication tables data structures
265275
@@ -830,13 +840,7 @@ def _build_bases(self):
830840 self .blades = self .indexes ._map (
831841 lambda index : self ._build_basis_blade_symbol (index ))
832842
833- self .blades_to_indexes = []
834- self .indexes_to_blades = []
835- for index , blade in zip (self .indexes .flat , self .blades .flat ):
836- self .blades_to_indexes .append ((blade , index ))
837- self .indexes_to_blades .append ((index , blade ))
838- self .blades_to_indexes_dict = OrderedDict (self .blades_to_indexes )
839- self .indexes_to_blades_dict = OrderedDict (self .indexes_to_blades )
843+ self .indexes_to_blades_dict = OrderedBiMap (list (zip (self .indexes .flat , self .blades .flat )))
840844
841845 self .blades_to_grades_dict = {
842846 blade : igrade
@@ -848,13 +852,7 @@ def _build_bases(self):
848852 self .bases = self .indexes ._map (
849853 lambda index : self ._build_basis_base_symbol (index ))
850854
851- self .bases_to_indexes = []
852- self .indexes_to_bases = []
853- for index , base in zip (self .indexes .flat , self .bases .flat ):
854- self .bases_to_indexes .append ((base , index ))
855- self .indexes_to_bases .append ((index , base ))
856- self .bases_to_indexes_dict = OrderedDict (self .bases_to_indexes )
857- self .indexes_to_bases_dict = OrderedDict (self .indexes_to_bases )
855+ self .indexes_to_bases_dict = OrderedBiMap (list (zip (self .indexes .flat , self .bases .flat )))
858856
859857 self .bases_to_grades_dict = {
860858 base : igrade
@@ -879,13 +877,11 @@ def _build_bases(self):
879877 if self .debug :
880878 printer .oprint ('indexes' , self .indexes , 'list(indexes)' , self .indexes .flat ,
881879 'blades' , self .blades , 'list(blades)' , self .blades .flat ,
882- 'blades_to_indexes_dict' , self .blades_to_indexes_dict ,
883880 'indexes_to_blades_dict' , self .indexes_to_blades_dict ,
884881 'blades_to_grades_dict' , self .blades_to_grades_dict ,
885882 'blade_super_scripts' , self .blade_super_scripts )
886883 if not self .is_ortho :
887884 printer .oprint ('bases' , self .bases , 'list(bases)' , self .bases .flat ,
888- 'bases_to_indexes_dict' , self .bases_to_indexes_dict ,
889885 'indexes_to_bases_dict' , self .indexes_to_bases_dict ,
890886 'bases_to_grades_dict' , self .bases_to_grades_dict )
891887
@@ -897,6 +893,54 @@ def _build_bases(self):
897893 for obj in self .basis
898894 )
899895
896+ @property
897+ def indexes_to_bases (self ):
898+ # galgebra 0.5.0
899+ warnings .warn (
900+ "`ga.indexes_to_bases` is deprecated, use `ga.indexes_to_bases_dict.items()`" ,
901+ DeprecationWarning , stacklevel = 2 )
902+ return self .indexes_to_bases_dict .items ()
903+
904+ @property
905+ def indexes_to_blades (self ):
906+ # galgebra 0.5.0
907+ warnings .warn (
908+ "`ga.indexes_to_blades` is deprecated, use `ga.indexes_to_blades_dict.items()`" ,
909+ DeprecationWarning , stacklevel = 2 )
910+ return self .indexes_to_blades_dict .items ()
911+
912+ @property
913+ def bases_to_indexes (self ):
914+ # galgebra 0.5.0
915+ warnings .warn (
916+ "`ga.bases_to_indexes` is deprecated, use `ga.indexes_to_bases_dict.inverse.items()`" ,
917+ DeprecationWarning , stacklevel = 2 )
918+ return self .indexes_to_bases_dict .inverse .items ()
919+
920+ @property
921+ def blades_to_indexes (self ):
922+ # galgebra 0.5.0
923+ warnings .warn (
924+ "`ga.blades_to_indexes` is deprecated, use `ga.indexes_to_blades_dict.inverse.items()`" ,
925+ DeprecationWarning , stacklevel = 2 )
926+ return self .indexes_to_blades_dict .inverse .items ()
927+
928+ @property
929+ def bases_to_indexes_dict (self ):
930+ # galgebra 0.5.0
931+ warnings .warn (
932+ "`ga.bases_to_indexes_dict` is deprecated, use `ga.indexes_to_bases_dict.inverse.`" ,
933+ DeprecationWarning , stacklevel = 2 )
934+ return self .indexes_to_bases_dict .inverse
935+
936+ @property
937+ def blades_to_indexes_dict (self ):
938+ # galgebra 0.5.0
939+ warnings .warn (
940+ "`ga.blades_to_indexes_dict` is deprecated, use `ga.indexes_to_blades_dict.inverse`" ,
941+ DeprecationWarning , stacklevel = 2 )
942+ return self .indexes_to_blades_dict .inverse
943+
900944 def _build_basis_product_tables (self ):
901945 """
902946 For the different products of geometric algebra bases/blade
@@ -954,8 +998,8 @@ def geometric_product_basis_blades(self, blade12):
954998 # geometric (*) product for orthogonal basis
955999 if self .is_ortho :
9561000 blade1 , blade2 = blade12
957- index1 = self .blades_to_indexes_dict [blade1 ]
958- index2 = self .blades_to_indexes_dict [blade2 ]
1001+ index1 = self .indexes_to_blades_dict . inverse [blade1 ]
1002+ index2 = self .indexes_to_blades_dict . inverse [blade2 ]
9591003 blade_index = list (index1 + index2 )
9601004 repeats = []
9611005 sgn = 1
@@ -1137,8 +1181,8 @@ def wedge_product_basis_blades(self, blade12): # blade12 = blade1*blade2
11371181 # outer (^) product of basis blades
11381182 # this method works for both orthogonal and non-orthogonal basis
11391183 blade1 , blade2 = blade12
1140- index1 = self .blades_to_indexes_dict [blade1 ]
1141- index2 = self .blades_to_indexes_dict [blade2 ]
1184+ index1 = self .indexes_to_blades_dict . inverse [blade1 ]
1185+ index2 = self .indexes_to_blades_dict . inverse [blade2 ]
11421186 index12 = list (index1 + index2 )
11431187
11441188 if len (index12 ) > self .n :
@@ -1177,8 +1221,8 @@ def dot_product_basis_blades(self, blade12, mode):
11771221 # dot (|), left (<), and right (>) products
11781222 # dot product for orthogonal basis
11791223 blade1 , blade2 = blade12
1180- index1 = self .blades_to_indexes_dict [blade1 ]
1181- index2 = self .blades_to_indexes_dict [blade2 ]
1224+ index1 = self .indexes_to_blades_dict . inverse [blade1 ]
1225+ index2 = self .indexes_to_blades_dict . inverse [blade2 ]
11821226 index = list (index1 + index2 )
11831227
11841228 grade = self ._dot_product_grade (len (index1 ), len (index2 ), mode = mode )
@@ -1265,7 +1309,7 @@ def _build_non_orthogonal_mul_table(self):
12651309 def non_orthogonal_bases_products (self , base12 ): # base12 = (base1, base2)
12661310 # geometric product of bases for non-orthogonal basis vectors
12671311 base1 , base2 = base12
1268- index = self .bases_to_indexes_dict [base1 ] + self .bases_to_indexes_dict [base2 ]
1312+ index = self .indexes_to_bases_dict . inverse [base1 ] + self .indexes_to_bases_dict . inverse [base2 ]
12691313
12701314 coefs , indexes = self .reduce_basis (index )
12711315
@@ -1281,7 +1325,7 @@ def _build_base_blade_conversions(self):
12811325
12821326 # expand blade basis in terms of base basis
12831327 for blade in self .blades .flat :
1284- index = self .blades_to_indexes_dict [blade ]
1328+ index = self .indexes_to_blades_dict . inverse [blade ]
12851329 grade = len (index )
12861330 if grade <= 1 :
12871331 blade_expansion .append (blade )
@@ -1766,7 +1810,7 @@ def blade_derivation(self, blade, ib):
17661810 if key in self ._dbases :
17671811 return self ._dbases [key ]
17681812
1769- index = self .blades_to_indexes_dict [blade ]
1813+ index = self .indexes_to_blades_dict . inverse [blade ]
17701814 grade = len (index )
17711815 if grade == 1 :
17721816 db = self .de [ib ][index [0 ]]
0 commit comments