1 """ Provides CommutativeRing class.
2 """
3
4 __docformat__ = "restructuredtext"
5 __all__ = ['CommutativeRing']
6
7 from .algebra import Algebra
8
10 """ Base class to commutative rings.
11
12 Derived classes may redefine the following methods::
13
14 Symbol(cls, obj)
15 Number(cls, obj)
16 Add(cls, *seq)
17 Mul(cls, *seq),
18 Pow(cls, base, exponent)
19 Terms(cls, *seq)
20 Factors(cls, *seq)
21 as_Add_args(self)
22 as_Mul_args(self)
23 as_Pow_args(self),
24 as_Terms_args(self)
25 as_Factors_args(self)
26 """
27 __slots__ = ['_symbols']
28 _symbols = None
29
30 @classmethod
32 """ Compute sum over seq containing algebra elements.
33 """
34 raise NotImplementedError('%s must define classmethod Add'
35 % (cls.__name__))
36
37 @classmethod
39 """ Compute ``seq[0] - Add(*seq[0])``.
40 """
41 if seq:
42 return seq[0] - cls.Add(*seq[1:])
43 return cls.zero
44
45 @classmethod
47 """ Compute product over seq containing algebra elements.
48 """
49 raise NotImplementedError('%s must define classmethod Mul'
50 % (cls.__name__))
51
52 @classmethod
54 """ Compute ``seq[0] / Mul(*seq[0])``.
55 """
56 if seq:
57 return seq[0] / cls.Mul(*seq[1:])
58 return cls.one
59
60 @classmethod
61 - def Pow(cls, base, exponent):
62 """ Compute power from base and exponent.
63
64 Argument base must be an algebra element and exponent must be
65 an element of exponent algebra.
66 """
67 raise NotImplementedError('%s must define classmethod Pow'
68 % (cls.__name__))
69
70 @classmethod
71 - def Log(cls, arg, base=None):
72 """ Compute logarithm of arg in base.
73
74 Argument arg must be an element of exponent algebra and base
75 is an element of an algebra.
76 """
77 raise NotImplementedError('%s must define classmethod Pow'
78 % (cls.__name__))
79
80 @classmethod
82 """ Compute sum over seq containing pairs ``(element, coefficient)``.
83
84 ``element``-s must belong to algebra, ``coefficient``-s must
85 belong to the coefficient algebra.
86 """
87 raise NotImplementedError('%s must define classmethod Terms'
88 % (cls.__name__))
89
90 @classmethod
92 """ Compute product over seq containing pairs ``(element, exponent)``.
93
94 ``element``-s must belong to algebra, ``exponent``-s must belong
95 to the exponent algebra.
96 """
97 raise NotImplementedError('%s must define classmethod Factors'
98 % (self.__class__.__name__))
99
101 """ Return a sequence such that ``Add(*self.as_Add_args()) == self``
102 """
103 raise NotImplementedError('%s must define method as_Add_args'
104 % (self.__class__.__name__))
105
107 """ Return a sequence such that ``Mul(*self.as_Mul_args()) == self``
108 """
109 raise NotImplementedError('%s must define method as_Mul_args'
110 % (self.__class__.__name__))
111
113 """ Return a 2-tuple such that ``Pow(*self.as_Pow_args()) == self``
114 """
115 raise NotImplementedError('%s must define method as_Pow_args'
116 % (self.__class__.__name__))
117
119 """ Return a 2-tuple such that ``Log(*self.as_Log_args()) == self``
120 """
121 raise NotImplementedError('%s must define method as_Log_args'
122 % (self.__class__.__name__))
123
125 """ Return a sequence such that ``Terms(*self.as_Terms_args()) == self``
126 """
127 raise NotImplementedError('%s must define method as_Terms_args'
128 % (self.__class__.__name__))
129
131 """ Return a sequence such that ``Factors(*self.as_Factors_args()) == self``
132 """
133 raise NotImplementedError('%s must define method as_Factors_args'
134 % (self.__class__.__name__))
135
138
141
143 other = self.convert(other, False)
144 if other is NotImplemented:
145 return NotImplemented
146 return self.Add(self, other)
147
149 other = self.convert(other, False)
150 if other is NotImplemented:
151 return NotImplemented
152 return self.Add(other, self)
153
155 other = self.convert(other, False)
156 if other is NotImplemented:
157 return NotImplemented
158 return self + (-other)
159
161 other = self.convert(other, False)
162 if other is NotImplemented:
163 return NotImplemented
164 return other + (-self)
165
167 other = self.convert(other, False)
168 if other is NotImplemented:
169 return NotImplemented
170 return self.Mul(self, other)
171
173 other = self.convert(other, False)
174 if other is NotImplemented:
175 return NotImplemented
176 return self.Mul(other, self)
177
179 other = self.convert(other, False)
180 if other is NotImplemented:
181 return NotImplemented
182 if isinstance(other, (int, long)):
183 other = self.Number(other)
184 return self * other ** (-1)
185
187 other = self.convert(other, False)
188 if other is NotImplemented:
189 return NotImplemented
190 return other * self ** (-1)
191
193 other = self.convert(other, False)
194 if other is NotImplemented:
195 return NotImplemented
196 return self * other ** (-1)
197
199 other = self.convert(other, False)
200 if other is NotImplemented:
201 return NotImplemented
202 return other * self ** (-1)
203
205 other = self.convert_exponent(other, False)
206 if other is NotImplemented:
207 return NotImplemented
208 return self.Pow(self, other)
209
211 other = self.convert(other, False)
212 if other is NotImplemented:
213 return NotImplemented
214 return self.Pow(other, self.convert_exponent(self))
215
216 - def _matches(pattern, expr, repl_dict, wild_info):
217 pfunc = pattern.func
218 efunc = expr.func
219 Add = pattern.Add
220 Mul = pattern.Mul
221 if pfunc==Add:
222 wild_part = []
223 exact_part = []
224 for a in pattern.args:
225 if a.symbols.intersection(wild_info[0]):
226 if a.head is SYMBOL:
227 wild_part.append(a)
228 else:
229 wild_part.insert(0, a)
230 else:
231 exact_part.append(a)
232 if exact_part:
233 expr = expr - Add(*exact_part)
234 if len(wild_part)==1:
235 return wild_part[0].matches(expr, repl_dict, wild_info)
236 expr_args = expr.as_Add_args() + [pattern.zero]
237 for i in range(len(wild_part)):
238 w = wild_part[i]
239 w_rest = Add(*(wild_part[:i]+wild_part[i+1:]))
240 for e in expr_args:
241 r = w.matches(e, repl_dict, wild_info)
242 if r is not None:
243 r1 = w_rest.subs(r.items()).matches(expr-e, r, wild_info)
244 if r1 is not None:
245 return r1
246 elif pfunc==Mul:
247 wild_part = []
248 exact_part = []
249 for a in pattern.args:
250 if a.symbols.intersection(wild_info[0]):
251 if a.head is SYMBOL:
252 wild_part.append(a)
253 else:
254 wild_part.insert(0, a)
255 else:
256 exact_part.append(a)
257 if exact_part:
258 expr = expr / Mul(*exact_part)
259 if len(wild_part)==1:
260 return wild_part[0].matches(expr, repl_dict, wild_info)
261 expr_args = expr.as_Mul_args() + [pattern.one]
262 for i in range(len(wild_part)):
263 w = wild_part[i]
264 w_rest = Mul(*(wild_part[:i]+wild_part[i+1:]))
265 for e in expr_args:
266 r = w.matches(e, repl_dict, wild_info)
267 if r is not None:
268 r1 = w_rest.subs(r.items()).matches(expr/e, r, wild_info)
269 if r1 is not None:
270 return r1
271 elif pfunc == efunc:
272 return pattern._matches_seq(pattern.args, expr.args, repl_dict, wild_info)
273 return
274
275 from ..utils import NUMBER, SYMBOL
276