# HG changeset patch
# User Ondrej Certik <ondrej@certik.cz>
# Date 1196036139 28800
# Node ID d902e2401fc6b05795605a4c98f38c36c80a4d1d
# Parent 59c0c1153bbe0cd5172cdc45e8ffb07d902d12f4
SymPy and SAGE objects can now be mixed
diff -r 59c0c1153bbe -r d902e2401fc6 sage/calculus/calculus.py
|
a
|
b
|
|
| 363 | 363 | sage: x.subs(x=y0/y1) |
| 364 | 364 | y0/y1 |
| 365 | 365 | """ |
| | 366 | import sympy |
| 366 | 367 | if isinstance(x, CallableSymbolicExpression): |
| 367 | 368 | return x._expr |
| 368 | 369 | elif isinstance(x, SymbolicExpression): |
| 369 | 370 | return x |
| 370 | 371 | elif isinstance(x, MaximaElement): |
| 371 | 372 | return symbolic_expression_from_maxima_element(x) |
| | 373 | elif isinstance(x, sympy.Basic): |
| | 374 | #elif hasattr(x, "_sage_"): |
| | 375 | # if "x" implements the _sage_() method, let's use it to convert |
| | 376 | # the expression to a SAGE expression (for example SymPy provides |
| | 377 | # _sage_() methods, some other libraries can too) |
| | 378 | # |
| | 379 | # unfortunately, the hasattr() above doesn't work (infinite |
| | 380 | # recursion), so we check for SymPy directly. |
| | 381 | |
| | 382 | return self(x._sage_()) |
| 372 | 383 | elif is_Polynomial(x) or is_MPolynomial(x): |
| 373 | 384 | if x.base_ring() != self: # would want coercion to go the other way |
| 374 | 385 | return SymbolicPolynomial(x) |
| … |
… |
|
| 3271 | 3282 | infixops[self._operator], |
| 3272 | 3283 | ops[1]._maxima_init_()) |
| 3273 | 3284 | |
| | 3285 | def _sympy_(self): |
| | 3286 | """Converts any expression to SymPy.""" |
| | 3287 | |
| | 3288 | # Current implementation is fragile - it first converts the expression |
| | 3289 | # to string, then preparses it, then gets rid of "Integer" and then |
| | 3290 | # sympifies this string. |
| | 3291 | |
| | 3292 | # In order to make this robust, one would have to implement _sympy_ |
| | 3293 | # recursively in all expressions. But we want something now, instead of |
| | 3294 | # tomorrow, so the following one-liner does the job for now. |
| | 3295 | # Also all ugly things are concentrated in this line, everything else |
| | 3296 | # (sympy.sympify, sage.all.SR, ...) is clean and robust. |
| | 3297 | import sympy |
| | 3298 | from sage.all import preparse |
| | 3299 | s = sympy.sympify(preparse(repr(self)).replace("Integer","")) |
| | 3300 | return s |
| | 3301 | |
| 3274 | 3302 | def _sys_init_(self, system): |
| 3275 | 3303 | ops = self._operands |
| 3276 | 3304 | if self._operator is operator.neg: |
diff -r 59c0c1153bbe -r d902e2401fc6 sage/calculus/test_sympy.py
|
a
|
b
|
|
| 123 | 123 | sage: f._sage_() |
| 124 | 124 | 8651*x^8/13440 + 241*x^6/240 + 11*x^4/8 + 3*x^2/2 + 1 |
| 125 | 125 | |
| | 126 | |
| | 127 | |
| | 128 | Mixing SymPy with SAGE: |
| | 129 | sage: import sympy |
| | 130 | sage: sympy.sympify(var("y"))+sympy.Symbol("x") |
| | 131 | x + y |
| | 132 | sage: o = var("omega") |
| | 133 | sage: s = sympy.Symbol("x") |
| | 134 | sage: t1 = s + o |
| | 135 | sage: t2 = o + s |
| | 136 | sage: print type(t1) |
| | 137 | <class 'sympy.core.add.Add'> |
| | 138 | sage: print type(t2) |
| | 139 | <class 'sage.calculus.calculus.SymbolicArithmetic'> |
| | 140 | sage: print t1, t2 |
| | 141 | omega + x x + omega |
| | 142 | sage: e=sympy.sin(var("y"))+sage.all.cos(Symbol("x")) |
| | 143 | sage: print type(e) |
| | 144 | <class 'sympy.core.add.Add'> |
| | 145 | sage: print e |
| | 146 | cos(x) + sin(y) |
| | 147 | sage: e=e._sage_() |
| | 148 | sage: print type(e) |
| | 149 | <class 'sage.calculus.calculus.SymbolicArithmetic'> |
| | 150 | sage: print e |
| | 151 | sin(y) + cos(x) |
| | 152 | sage: e = sage.all.cos(var("y")**3)**4+var("x")**2 |
| | 153 | sage: e = e._sympy_() |
| | 154 | sage: print e |
| | 155 | x**2 + cos(y**3)**4 |
| 126 | 156 | """ |
diff -r 59c0c1153bbe -r d902e2401fc6 sage/structure/coerce.pyx
|
a
|
b
|
|
| 327 | 327 | return x, y |
| 328 | 328 | return _verify_canonical_coercion_c(x,y) |
| 329 | 329 | |
| | 330 | if PY_TYPE_CHECK(xp, type) or PY_TYPE_CHECK(yp, type): |
| | 331 | if hasattr(x, "_sage_") and hasattr(y, "_sage_"): |
| | 332 | x = x._sage_() |
| | 333 | y = y._sage_() |
| | 334 | try: |
| | 335 | return _verify_canonical_coercion_c(x,y) |
| | 336 | except RuntimeError: |
| | 337 | # well, the coercion failed or there is some other error, |
| | 338 | # and we should leave it as is (errors should never pass |
| | 339 | # silently, unless explicitly silenced), but SAGE needs to |
| | 340 | # return a TypeError, raised below, so we silence it... |
| | 341 | pass |
| | 342 | |
| 330 | 343 | raise TypeError, "no common canonical parent for objects with parents: '%s' and '%s'"%(xp, yp) |
| 331 | 344 | |
| 332 | 345 | |