Package sympycore :: Package basealgebra :: Module algebra
[hide private]
[frames] | no frames]

Source Code for Module sympycore.basealgebra.algebra

  1  """ Provides BasicAlgebra class. 
  2  """ 
  3   
  4  __docformat__ = "restructuredtext" 
  5   
  6  from ..core import Basic, classes 
  7   
8 -class BasicAlgebra(Basic):
9 """ Represents an element of an algebraic structure. 10 11 This class collects implementation specific methods of algebra 12 classes. 13 14 For implemented algebras, see: 15 16 PrimitiveAlgebra 17 CommutativeRingWithPairs 18 19 New algebras may need to redefine the following methods:: 20 21 __new__(cls, ...) 22 convert(cls, obj, typeerror=True) 23 convert_coefficient(cls, obj, typeerror=True) 24 convert_exponent(cls, obj, typeerror=True) 25 as_primitive(self) 26 as_algebra(self, cls) 27 28 and the following properties:: 29 30 args(self) 31 func(self) 32 33 """ 34 __slots__ = ['_str_value'] 35 36 _str_value = None 37
38 - def __str__(self):
39 s = self._str_value 40 if s is None: 41 s = self._str_value = str(self.as_primitive()) 42 return s
43
44 - def __repr__(self):
45 return '%s(%r)' % (self.__class__.__name__, str(self))
46
47 - def as_tree(self, tab='', level=0):
48 return self.as_primitive().as_tree(tab,level)
49 50 @classmethod
51 - def convert(cls, obj, typeerror=True):
52 """ Convert obj to algebra element. 53 54 Set typeerror=False when calling from operation methods like __add__, 55 __mul__, etc. 56 """ 57 # check if obj is already algebra element: 58 if isinstance(obj, cls): 59 return obj 60 61 # parse algebra expression from string: 62 if isinstance(obj, (str, unicode, PrimitiveAlgebra)): 63 return PrimitiveAlgebra(obj).as_algebra(cls) 64 65 # check if obj belongs to coefficient algebra 66 r = cls.convert_coefficient(obj, typeerror=False) 67 if r is not NotImplemented: 68 return cls.Number(r) 69 70 # as a last resort, convert from another algebra: 71 if isinstance(obj, BasicAlgebra): 72 return obj.as_algebra(cls) 73 74 if typeerror: 75 raise TypeError('%s.convert: failed to convert %s instance'\ 76 ' to algebra'\ 77 % (cls.__name__, obj.__class__.__name__)) 78 else: 79 return NotImplemented
80 81 @classmethod
82 - def convert_exponent(cls, obj, typeerror=True):
83 """ Convert obj to exponent algebra. 84 """ 85 if isinstance(obj, (int, long, cls)): 86 return obj 87 if typeerror: 88 raise TypeError('%s.convert_exponent: failed to convert %s instance'\ 89 ' to exponent algebra, expected int|long object'\ 90 % (cls.__name__, obj.__class__.__name__)) 91 else: 92 return NotImplemented
93 94 @classmethod
95 - def convert_coefficient(cls, obj, typeerror=True):
96 """ Convert obj to coefficient algebra. 97 """ 98 if isinstance(obj, (int, long)): 99 return obj 100 if typeerror: 101 raise TypeError('%s.convert_coefficient: failed to convert %s instance'\ 102 ' to coefficient algebra, expected int|long object'\ 103 % (cls.__name__, obj.__class__.__name__)) 104 else: 105 return NotImplemented
106
107 - def as_primitve(self):
108 raise NotImplementedError('%s must define as_primitive method' #pragma NO COVER 109 % (self.__class__.__name__)) #pragma NO COVER
110
111 - def as_algebra(self, cls):
112 """ Convert algebra to another algebra. 113 114 This method uses default conversation via primitive algebra that 115 might not be the most efficient. For efficiency, algebras should 116 redefine this method to implement direct conversation. 117 """ 118 # todo: cache primitive algebras 119 if cls is classes.PrimitiveAlgebra: 120 return self.as_primitive() 121 return self.as_primitive().as_algebra(cls)
122 123 @classmethod
124 - def get_predefined_symbols(cls, name):
125 return
126 127 @property
128 - def func(self):
129 """ Returns a callable such that ``self.func(*self.args) == self``. 130 """ 131 raise NotImplementedError('%s must define property func' #pragma NO COVER 132 % (cls.__name__)) #pragma NO COVER
133 134 @property
135 - def args(self):
136 """ Returns a sequence such that ``self.func(*self.args) == self``. 137 """ 138 raise NotImplementedError('%s must define property args' #pragma NO COVER 139 % (cls.__name__)) #pragma NO COVER
140 141 @classmethod
142 - def Symbol(cls, obj):
143 """ Construct algebra symbol directly from obj. 144 """ 145 raise NotImplementedError('%s must define classmethod Symbol' #pragma NO COVER 146 % (cls.__name__)) #pragma NO COVER
147 148 @classmethod
149 - def Number(cls, num, denom=None):
150 """ Construct algebra number directly from obj. 151 """ 152 raise NotImplementedError('%s must define classmethod Number' #pragma NO COVER 153 % (cls.__name__)) #pragma NO COVER
154 155 @property
156 - def symbols(self):
157 """ Return a set of atomic subexpressions in a symbolic object. 158 """ 159 symbols = self._symbols 160 if symbols is None: 161 args = self.args 162 if args: 163 symbols = set() 164 for arg in args: 165 symbols |= arg.symbols 166 else: 167 symbols = set([self]) 168 self._symbols = symbols 169 return symbols
170
171 - def has(self, obj):
172 """ Return True if self contains atomic expression obj. 173 """ 174 convert = self.convert 175 return convert(obj) in self.symbols
176
177 - def match(self, pattern, *wildcards):
178 """ 179 Pattern matching. 180 181 Return None when expression (self) does not match with 182 pattern. Otherwise return a dictionary such that 183 184 :: 185 186 pattern.subs_dict(self.match(pattern, *wildcards)) == self 187 188 Don't redefine this method, redefine ``matches(..)`` method instead. 189 190 :See: 191 http://wiki.sympy.org/wiki/Generic_interface#Pattern_matching 192 """ 193 pattern = self.convert(pattern) 194 wild_expressions = [] 195 wild_predicates = [] 196 for w in wildcards: 197 if type(w) in [list, tuple]: 198 assert len(w)==2,`w` 199 s, func = w 200 else: 201 s, func = w, True 202 s = self.convert(s) 203 wild_expressions.append(s) 204 wild_predicates.append(func) 205 if wild_expressions: 206 wild_info = (wild_expressions, wild_predicates) 207 else: 208 wild_info = None 209 return pattern.matches(self, {}, wild_info)
210
211 - def matches(pattern, expr, repl_dict={}, wild_info=None):
212 # check if pattern has a match and return it provided that 213 # the match matches with expr: 214 v = repl_dict.get(pattern) 215 if v is not None: 216 if v==expr: 217 return repl_dict 218 return 219 # check if pattern matches with expr: 220 if pattern==expr: 221 if wild_info and expr in wild_info[0]: 222 return 223 return repl_dict 224 if wild_info: 225 wild_expressions, wild_predicates = wild_info 226 # check if pattern is a wild expression 227 if pattern in wild_expressions: 228 if expr in wild_expressions: 229 # wilds do not match other wilds 230 return 231 # wild pattern matches with expr only if predicate(expr) returns True 232 predicate = wild_predicates[wild_expressions.index(pattern)] 233 if (isinstance(predicate, bool) and predicate) or predicate(expr): 234 repl_dict = repl_dict.copy() 235 repl_dict[pattern] = expr 236 return repl_dict 237 pattern_symbols = pattern.symbols 238 for w in wild_expressions: 239 if w in pattern_symbols: 240 # _matches implements implementation specific matches, 241 # pattern should contain wild symbols, otherwise 242 # _matches would always return None 243 return pattern._matches(expr, repl_dict, wild_info) 244 return
245 246 @classmethod
247 - def _matches_seq(cls, pattern_seq, expr_seq, repl_dict, wild_info):
248 n = len(pattern_seq) 249 m = len(expr_seq) 250 if n!=m: 251 return 252 elif n==0: 253 return repl_dict 254 elif n==1: 255 p = pattern_seq[0] 256 if isinstance(p, cls): 257 return p.matches(expr_seq[0], repl_dict, wild_info) 258 if p==expr_seq[0]: 259 return repl_dict 260 return 261 def matches(pattern, expr): 262 if isinstance(pattern, cls): 263 return pattern.matches(expr, repl_dict, wild_info) 264 if pattern==expr: 265 return repl_dict 266 return
267 def subs(expr, l): 268 if isinstance(expr, cls): 269 return expr.subs(l) 270 return expr
271 for i in xrange(n): 272 p = pattern_seq[i] 273 e = expr_seq[i] 274 r = matches(p, e) 275 if r is not None: 276 new_pattern_seq = [subs(pattern_seq[j],r.items()) for j in xrange(n) if j!=i] 277 new_expr_seq = [expr_seq[j] for j in xrange(n) if j!=i] 278 r1 = cls._matches_seq(new_pattern_seq, new_expr_seq, r, wild_info) 279 if r1 is not None: 280 return r1 281 return 282
283 - def _matches(pattern, expr, repl_dict, wild_info):
284 if pattern.func == expr.func: 285 return pattern._matches_seq(pattern.args, expr.args, repl_dict, wild_info) 286 return
287
288 - def subs(self, subexpr, newexpr=None):
289 """ Substitute a sub-expression with new expression. 290 291 There are two usage forms:: 292 293 obj.subs(subexpr, newexpr) 294 obj.subs([(subexpr1, newexpr1), (subexpr2, newexpr2), ..]) 295 296 """ 297 convert = self.convert 298 if newexpr is None: 299 r = self 300 for s,n in subexpr: 301 r = r._subs(convert(s), convert(n)) 302 return r 303 return self._subs(convert(subexpr), convert(newexpr))
304
305 - def _subs(self, subexpr, newexpr):
306 raise NotImplementedError('%s must define _subs method' #pragma NO COVER 307 % (self.__class__.__name__)) #pragma NO COVER
308 309 310 from .primitive import PrimitiveAlgebra 311