# HG changeset patch
# User Carl Witty <cwitty@newtonlabs.com>
# Date 1237434511 25200
# Node ID d90665b8ed8a4f4653e177d9b2d1766dfb9cbf84
# Parent a97f9d176f07425f7dc6c9965a931152469b7bdf
Remove features from the API that are likely to change, so I don't have to worry about deprecation later
diff -r a97f9d176f07 -r d90665b8ed8a sage/ext/fast_callable.pyx
a
|
b
|
|
16 | 16 | quickly. |
17 | 17 | |
18 | 18 | sage: f = sin(x) + 3*x^2 |
19 | | sage: ff = fast_callable(f) |
| 19 | sage: ff = fast_callable(f, vars=[x]) |
20 | 20 | sage: ff(3.5) |
21 | 21 | 36.3992167723104 |
22 | 22 | sage: ff(RIF(3.5)) |
… |
… |
|
33 | 33 | (x - 20)*(x - 19)*(x - 18)*(x - 17)*(x - 16)*(x - 15)*(x - 14)*(x - 13)*(x - 12)*(x - 11)*(x - 10)*(x - 9)*(x - 8)*(x - 7)*(x - 6)*(x - 5)*(x - 4)*(x - 3)*(x - 2)*(x - 1) |
34 | 34 | sage: timeit('wilk.subs(x=30)') # random, long time |
35 | 35 | 625 loops, best of 3: 1.43 ms per loop |
36 | | sage: fc_wilk = fast_callable(wilk) |
| 36 | sage: fc_wilk = fast_callable(wilk, vars=[x]) |
37 | 37 | sage: timeit('fc_wilk(30)') # random, long time |
38 | 38 | 625 loops, best of 3: 9.72 us per loop |
39 | 39 | |
40 | 40 | You can specify a particular domain for the evaluation using |
41 | 41 | \code{domain=}: |
42 | 42 | |
43 | | sage: fc_wilk_zz = fast_callable(wilk, domain=ZZ) |
| 43 | sage: fc_wilk_zz = fast_callable(wilk, vars=[x], domain=ZZ) |
44 | 44 | |
45 | 45 | The meaning of domain=D is that each intermediate and final result |
46 | 46 | is converted to type D. For instance, the previous example of |
… |
… |
|
68 | 68 | floating-point operations directly and skip all the Python object |
69 | 69 | creations that you would get from actually using RDF objects. |
70 | 70 | |
71 | | sage: fc_wilk_rdf = fast_callable(wilk, domain=RDF) |
| 71 | sage: fc_wilk_rdf = fast_callable(wilk, vars=[x], domain=RDF) |
72 | 72 | sage: timeit('fc_wilk_rdf(30.0)') # random, long time |
73 | 73 | 625 loops, best of 3: 7 us per loop |
74 | 74 | |
… |
… |
|
78 | 78 | the return value is an RDF element, and when domain=float is used, |
79 | 79 | the return value is a Python float.) |
80 | 80 | |
81 | | sage: fc_wilk_float = fast_callable(wilk, domain=float) |
| 81 | sage: fc_wilk_float = fast_callable(wilk, vars=[x], domain=float) |
82 | 82 | sage: timeit('fc_wilk_float(30.0)') # random, long time |
83 | 83 | 625 loops, best of 3: 5.04 us per loop |
84 | 84 | |
85 | 85 | We also have support for RR: |
86 | 86 | |
87 | | sage: fc_wilk_rr = fast_callable(wilk, domain=RR) |
| 87 | sage: fc_wilk_rr = fast_callable(wilk, vars=[x], domain=RR) |
88 | 88 | sage: timeit('fc_wilk_rr(30.0)') # random, long time |
89 | 89 | 625 loops, best of 3: 13 us per loop |
90 | 90 | |
91 | | By default, \function{fast_callable} uses the same variable names in the |
92 | | same order that the \method{__call__} method on its argument would use; |
93 | | for instance, on symbolic expressions, the variables are used in alphabetical |
94 | | order. |
| 91 | Currently, \function{fast_callable} can accept two kinds of objects: |
| 92 | polynomials (univariate and multivariate) and symbolic expressions |
| 93 | (elements of the Symbolic Ring). (This list is likely to grow |
| 94 | significantly in the near future.) For polynomials, you can omit the |
| 95 | 'vars' argument; the variables will default to the ring generators (in |
| 96 | the order used when creating the ring). |
| 97 | |
| 98 | sage: K.<x,y,z> = QQ[] |
| 99 | sage: p = 10*y + 100*z + x |
| 100 | sage: fp = fast_callable(p) |
| 101 | sage: fp(1,2,3) |
| 102 | 321 |
| 103 | |
| 104 | But you can also specify the variable names to override the default |
| 105 | ordering (you can include extra variable names here, too). |
| 106 | |
| 107 | sage: fp = fast_callable(p, vars=('x','w','z','y')) |
| 108 | |
| 109 | For symbolic expressions, you need to specify the variable names, so |
| 110 | that \function{fast_callable} knows what order to use. |
95 | 111 | |
96 | 112 | sage: var('y,z,x') |
97 | 113 | (y, z, x) |
98 | 114 | sage: f = 10*y + 100*z + x |
99 | | sage: f(1,2,3) |
100 | | 321 |
101 | | sage: ff = fast_callable(f) |
| 115 | sage: ff = fast_callable(f, vars=(x,y,z)) |
102 | 116 | sage: ff(1,2,3) |
103 | 117 | 321 |
104 | 118 | |
105 | | However, this can be overridden with \code{vars=}: |
| 119 | You can also specify extra variable names: |
106 | 120 | |
107 | 121 | sage: ff = fast_callable(f, vars=('x','w','z','y')) |
108 | 122 | sage: ff(1,2,3,4) |
… |
… |
|
175 | 189 | EXAMPLES: |
176 | 190 | sage: var('x') |
177 | 191 | x |
178 | | sage: f = fast_callable(sqrt(x^7+1), domain=float) |
| 192 | sage: f = fast_callable(sqrt(x^7+1), vars=[x], domain=float) |
179 | 193 | |
180 | 194 | sage: f(1) |
181 | 195 | 1.4142135623730951 |
… |
… |
|
280 | 294 | |
281 | 295 | include "stdsage.pxi" |
282 | 296 | |
283 | | def fast_callable(x, domain=None, vars=None): |
| 297 | def fast_callable(x, domain=None, vars=None, |
| 298 | _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality=False): |
284 | 299 | r""" |
285 | 300 | Given an expression x, compiles it into a form that can be quickly |
286 | 301 | evaluated, given values for the variables in x. |
287 | 302 | |
288 | | x can be an expression object, or anything that has a .variables() |
289 | | method and a ._fast_callable_() method (this includes SR, univariate |
290 | | polynomials, and multivariate polynomials). |
| 303 | Currently, x can be an expression object, an element of SR, or a |
| 304 | (univariate or multivariate) polynomial; this list will probably |
| 305 | be extended soon. |
291 | 306 | |
292 | 307 | By default, x is evaluated the same way that a Python function |
293 | 308 | would evaluate it -- addition maps to PyNumber_Add, etc. However, |
… |
… |
|
296 | 311 | have a special-purpose interpreter for that parent (like RDF or float), |
297 | 312 | domain=... will trigger the use of that interpreter. |
298 | 313 | |
299 | | If vars is None, then we will attempt to determine the set of |
300 | | variables from x; otherwise, we will use the given set. |
| 314 | If vars is None and x is a polynomial, then we will use the |
| 315 | generators of parent(x) as the variables; otherwise, vars must be |
| 316 | specified. |
301 | 317 | |
302 | 318 | EXAMPLES: |
303 | 319 | sage: var('x') |
304 | 320 | x |
305 | 321 | sage: expr = sin(x) + 3*x^2 |
306 | | sage: f = fast_callable(expr) |
| 322 | sage: f = fast_callable(expr, vars=[x]) |
307 | 323 | sage: f(2) |
308 | 324 | sin(2) + 12 |
309 | 325 | sage: f(2.0) |
… |
… |
|
315 | 331 | the RDF interpreter; elements of RDF just don't display all |
316 | 332 | their digits. |
317 | 333 | |
318 | | sage: f_float = fast_callable(expr, domain=float) |
| 334 | sage: f_float = fast_callable(expr, vars=[x], domain=float) |
319 | 335 | sage: f_float(2) |
320 | 336 | 12.909297426825681 |
321 | | sage: f_rdf = fast_callable(expr, domain=RDF) |
| 337 | sage: f_rdf = fast_callable(expr, vars=[x], domain=RDF) |
322 | 338 | sage: f_rdf(2) |
323 | 339 | 12.9092974268 |
324 | 340 | sage: f = fast_callable(expr, vars=('z','x','y')) |
… |
… |
|
361 | 377 | vars = et._etb._vars |
362 | 378 | else: |
363 | 379 | if vars is None or len(vars) == 0: |
| 380 | from sage.calculus.calculus import SR |
| 381 | if x.parent() is SR and not _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality: |
| 382 | raise ValueError, "List of variables must be specified for symbolic expressions" |
364 | 383 | vars = x.variables() |
365 | 384 | # XXX This is pretty gross... there should be a "callable_variables" |
366 | 385 | # method that does all this. |
367 | | from sage.calculus.calculus import SR |
368 | 386 | from sage.rings.all import is_PolynomialRing, is_MPolynomialRing |
369 | 387 | if x.parent() is SR and x.number_of_arguments() > len(vars): |
370 | 388 | vars = list(vars) + ['EXTRA_VAR%d' % n for n in range(len(vars), x.number_of_arguments())] |
… |
… |
|
1531 | 1549 | TESTS: |
1532 | 1550 | sage: def my_sin(x): return sin(x) |
1533 | 1551 | sage: def my_norm(x, y): return x*x + y*y |
1534 | | sage: def my_sqrt(x): return sqrt(x, extend=False) |
| 1552 | sage: def my_sqrt(x): |
| 1553 | ... if x < 0: raise ValueError, "sqrt of negative number" |
| 1554 | ... return sqrt(x, extend=False) |
1535 | 1555 | sage: fc = fast_callable(expr, domain=RealField(130)) |
1536 | 1556 | sage: fc(0) |
1537 | 1557 | 3.1415926535897932384626433832795028842 |
… |
… |
|
1570 | 1590 | sage: fc(-3) |
1571 | 1591 | Traceback (most recent call last): |
1572 | 1592 | ... |
1573 | | ValueError: math domain error |
| 1593 | ValueError: sqrt of negative number |
1574 | 1594 | sage: fc = fast_callable(etb.call(my_sqrt, x), domain=RR) |
1575 | 1595 | sage: fc(3) |
1576 | 1596 | 1.73205080756888 |
1577 | 1597 | sage: fc(-3) |
1578 | 1598 | Traceback (most recent call last): |
1579 | 1599 | ... |
1580 | | ValueError: negative number -3.00000000000000 does not have a square root in the real field |
| 1600 | ValueError: sqrt of negative number |
1581 | 1601 | sage: etb2 = ExpressionTreeBuilder(('y','z')) |
1582 | 1602 | sage: y = etb2.var('y') |
1583 | 1603 | sage: z = etb2.var('z') |
… |
… |
|
2157 | 2177 | (Probably only useful when writing doctests.) |
2158 | 2178 | |
2159 | 2179 | EXAMPLES: |
2160 | | sage: fast_callable(sin(x)/x, domain=RDF).get_orig_args() |
| 2180 | sage: fast_callable(sin(x)/x, vars=[x], domain=RDF).get_orig_args() |
2161 | 2181 | {'domain': Real Double Field, 'code': [0, 0, 16, 0, 0, 7, 2], 'py_constants': [], 'args': 1, 'stack': 2, 'constants': []} |
2162 | 2182 | """ |
2163 | 2183 | return self._orig_args |
… |
… |
|
2167 | 2187 | Return the list of instructions in this wrapper. |
2168 | 2188 | |
2169 | 2189 | EXAMPLES: |
2170 | | sage: fast_callable(cos(x)*x, domain=RDF).op_list() |
| 2190 | sage: fast_callable(cos(x)*x, vars=[x], domain=RDF).op_list() |
2171 | 2191 | [('load_arg', 0), 'cos', ('load_arg', 0), 'mul', 'return'] |
2172 | 2192 | """ |
2173 | 2193 | return op_list(self._orig_args, self._metadata) |
… |
… |
|
2182 | 2202 | this up by adding a new instruction to the interpreter.) |
2183 | 2203 | |
2184 | 2204 | EXAMPLES: |
2185 | | sage: fast_callable(abs(sin(x)), domain=RDF).python_calls() |
| 2205 | sage: fast_callable(abs(sin(x)), vars=[x], domain=RDF).python_calls() |
2186 | 2206 | [] |
2187 | | sage: fast_callable(abs(sin(factorial(x)))).python_calls() |
| 2207 | sage: fast_callable(abs(sin(factorial(x))), vars=[x]).python_calls() |
2188 | 2208 | [factorial, sin] |
2189 | 2209 | """ |
2190 | 2210 | ops = self.op_list() |
diff -r a97f9d176f07 -r d90665b8ed8a sage/ext/fast_eval.pyx
a
|
b
|
|
1347 | 1347 | if old: |
1348 | 1348 | return f._fast_float_(*vars) |
1349 | 1349 | else: |
1350 | | return fast_callable(f, vars=vars, domain=float) |
| 1350 | return fast_callable(f, vars=vars, domain=float, _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality=True) |
1351 | 1351 | except AttributeError: |
1352 | 1352 | pass |
1353 | 1353 | |