_eval_apply() converted to canonize()
[sympy.git] / sympy / functions / elementary / complexes.py
blobdf7dc7c8c52ce0597393dde0a21cdc06a70c7714
2 from sympy.core.basic import Basic, S, cache_it, cache_it_immutable
3 from sympy.core.function import SingleValuedFunction
5 ###############################################################################
6 ######################### REAL and IMAGINARY PARTS ############################
7 ###############################################################################
9 class re(SingleValuedFunction):
10 """Returns real part of expression. This function performs only
11 elementary analysis and so it will fail to decompose properly
12 more complicated expressions. If completely simplified result
13 is needed then use Basic.as_real_imag() or perform complex
14 expansion on instance of this function.
16 >>> from sympy import *
18 >>> x, y = symbols('x', 'y')
20 >>> re(2*E)
21 2*E
23 >>> re(2*I + 17)
26 >>> re(2*I)
29 >>> re(im(x) + x*I + 2)
32 """
34 nofargs = 1
36 is_real = True
38 @classmethod
39 def _eval_apply_subs(self, *args):
40 return
42 @classmethod
43 def canonize(cls, arg):
44 arg = Basic.sympify(arg)
46 if isinstance(arg, Basic.NaN):
47 return S.NaN
48 elif arg.is_real:
49 return arg
50 else:
51 if not isinstance(arg, Basic.Add):
52 arg = [arg]
54 included, reverted, excluded = [], [], []
56 for term in arg:
57 coeff = term.as_coefficient(S.ImaginaryUnit)
59 if coeff is not None:
60 if not coeff.is_real:
61 reverted.append(coeff)
62 elif not term.has(S.ImaginaryUnit) and term.is_real:
63 excluded.append(term)
64 else:
65 included.append(term)
67 if len(arg[:]) != len(included):
68 a, b, c = map(lambda xs: Basic.Add(*xs),
69 [included, reverted, excluded])
71 return cls(a) - im(b) + c
73 def _eval_conjugate(self):
74 return self
76 def _eval_is_real(self):
77 return True
79 def _eval_expand_complex(self, *args):
80 return self.func(self[0].as_real_imag()[0])
82 class im(SingleValuedFunction):
83 """Returns imaginary part of expression. This function performs
84 only elementary analysis and so it will fail to decompose
85 properly more complicated expressions. If completely simplified
86 result is needed then use Basic.as_real_imag() or perform complex
87 expansion on instance of this function.
89 >>> from sympy import *
91 >>> x, y = symbols('x', 'y')
93 >>> im(2*E)
96 >>> re(2*I + 17)
99 >>> im(x*I)
100 re(x)
102 >>> im(re(x) + y)
103 im(y)
107 nofargs = 1
109 is_real = True
111 @classmethod
112 def _eval_apply_subs(self, *args):
113 return
115 @classmethod
116 def canonize(cls, arg):
117 arg = Basic.sympify(arg)
119 if isinstance(arg, Basic.NaN):
120 return S.NaN
121 elif arg.is_real:
122 return S.Zero
123 else:
124 if not isinstance(arg, Basic.Add):
125 arg = [arg]
127 included, reverted, excluded = [], [], []
129 for term in arg:
130 coeff = term.as_coefficient(S.ImaginaryUnit)
132 if coeff is not None:
133 if not coeff.is_real:
134 reverted.append(coeff)
135 else:
136 excluded.append(coeff)
137 elif term.has(S.ImaginaryUnit) or not term.is_real:
138 included.append(term)
140 if len(arg[:]) != len(included):
141 a, b, c = map(lambda xs: Basic.Add(*xs),
142 [included, reverted, excluded])
144 return cls(a) + re(b) + c
146 def _eval_conjugate(self):
147 return self
149 def _eval_is_real(self):
150 return True
152 def _eval_expand_complex(self, *args):
153 return self.func(self[0].as_real_imag()[1])
155 ###############################################################################
156 ############### SIGN, ABSOLUTE VALUE, ARGUMENT and CONJUGATION ################
157 ###############################################################################
159 class sign(SingleValuedFunction):
161 nofargs = 1
163 @classmethod
164 def canonize(cls, arg):
165 if isinstance(arg, Basic.NaN):
166 return S.NaN
167 if isinstance(arg, Basic.Zero): return S.One
168 if arg.is_positive: return S.One
169 if arg.is_negative: return S.NegativeOne
170 if isinstance(arg, Basic.Mul):
171 coeff, terms = arg.as_coeff_terms()
172 if not isinstance(coeff, Basic.One):
173 return cls(coeff) * cls(Basic.Mul(*terms))
175 is_bounded = True
177 def _eval_conjugate(self):
178 return self
180 def _eval_is_zero(self):
181 return isinstance(self[0], Basic.Zero)
183 class abs(SingleValuedFunction):
185 nofargs = 1
187 def fdiff(self, argindex=1):
188 if argindex == 1:
189 return sign(self[0])
190 else:
191 raise ArgumentIndexError(self, argindex)
193 @classmethod
194 def _eval_apply_subs(self, *args):
195 return
197 @classmethod
198 def canonize(cls, arg):
199 if isinstance(arg, Basic.NaN):
200 return S.NaN
201 if arg.is_positive: return arg
202 if arg.is_negative: return -arg
203 coeff, terms = arg.as_coeff_terms()
204 if not isinstance(coeff, Basic.One):
205 return cls(coeff) * cls(Basic.Mul(*terms))
206 if arg.is_real is False:
207 return Basic.sqrt( (arg * arg.conjugate()).expand() )
208 return
210 @classmethod
211 def _eval_apply_evalf(cls, arg):
212 # XXX this is weird!!!
213 # XXX remove me when 'abs -> abs_' is done
214 arg = arg.evalf()
216 if isinstance(arg, Basic.Number):
217 import operator
218 return operator.abs(float(arg))
220 def _eval_is_zero(self):
221 return isinstance(self[0], Basic.Zero)
223 def _eval_conjugate(self):
224 return self
226 class arg(SingleValuedFunction):
228 nofargs = 1
230 is_real = True
232 def _eval_conjugate(self):
233 return self
235 def _eval_is_real(self):
236 return True
238 class conjugate(SingleValuedFunction):
240 nofargs = 1
242 @classmethod
243 def canonize(cls, arg):
244 obj = arg._eval_conjugate()
245 if obj is not None:
246 return obj
248 def _eval_conjugate(self):
249 return self[0]