Skip to content

Commit

Permalink
Few more docstring edits
Browse files Browse the repository at this point in the history
  • Loading branch information
gmou3 committed May 24, 2024
1 parent d55b922 commit 50d6354
Showing 1 changed file with 35 additions and 36 deletions.
71 changes: 35 additions & 36 deletions src/sage/ext/fast_callable.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ overhead from the evaluation, but all of the individual arithmetic
operations are done using standard Sage arithmetic. This is still a
huge win over :mod:`sage.calculus`, which evidently has a lot of overhead.
Compare the cost of evaluating Wilkinson's polynomial (in unexpanded
form) at x=30::
form) at `x = 30`::
sage: # needs sage.symbolic
sage: wilk = prod((x-i) for i in [1 .. 20]); wilk
(x - 1)*(x - 2)*(x - 3)*(x - 4)*(x - 5)*(x - 6)*(x - 7)*(x - 8)*(x - 9)*(x - 10)*(x - 11)*(x - 12)*(x - 13)*(x - 14)*(x - 15)*(x - 16)*(x - 17)*(x - 18)*(x - 19)*(x - 20)
sage: timeit('wilk.subs(x=30)') # random # long time
sage: timeit('wilk.subs(x=30)') # random, long time
625 loops, best of 3: 1.43 ms per loop
sage: fc_wilk = fast_callable(wilk, vars=[x])
sage: timeit('fc_wilk(30)') # random # long time
sage: timeit('fc_wilk(30)') # random, long time
625 loops, best of 3: 9.72 us per loop
You can specify a particular domain for the evaluation using
Expand All @@ -58,9 +58,9 @@ To mitigate the costs, we check whether the value already has
the correct parent before we call ``D``.
We don't yet have a special interpreter with domain ``ZZ``, so we can see
how that compares to the generic fc_wilk example above::
how that compares to the generic ``fc_wilk`` example above::
sage: timeit('fc_wilk_zz(30)') # random # long time # needs sage.symbolic
sage: timeit('fc_wilk_zz(30)') # random, long time # needs sage.symbolic
625 loops, best of 3: 15.4 us per loop
However, for other types, using ``domain=D`` will get a large speedup,
Expand All @@ -71,7 +71,7 @@ floating-point operations directly and skip all the Python object
creations that you would get from actually using ``RDF`` objects::
sage: fc_wilk_rdf = fast_callable(wilk, vars=[x], domain=RDF) # needs sage.symbolic
sage: timeit('fc_wilk_rdf(30.0)') # random # long time # needs sage.symbolic
sage: timeit('fc_wilk_rdf(30.0)') # random, long time # needs sage.symbolic
625 loops, best of 3: 7 us per loop
The domain does not need to be a Sage type; for instance, ``domain=float``
Expand All @@ -81,32 +81,31 @@ the return value is an ``RDF`` element, and when ``domain=float`` is used,
the return value is a Python :class:`float`.) ::
sage: fc_wilk_float = fast_callable(wilk, vars=[x], domain=float) # needs sage.symbolic
sage: timeit('fc_wilk_float(30.0)') # random # long time # needs sage.symbolic
sage: timeit('fc_wilk_float(30.0)') # random, long time # needs sage.symbolic
625 loops, best of 3: 5.04 us per loop
We also have support for ``RR``::
sage: fc_wilk_rr = fast_callable(wilk, vars=[x], domain=RR) # needs sage.symbolic
sage: timeit('fc_wilk_rr(30.0)') # random # long time # needs sage.symbolic
sage: timeit('fc_wilk_rr(30.0)') # random, long time # needs sage.symbolic
625 loops, best of 3: 13 us per loop
For ``CC``::
sage: fc_wilk_cc = fast_callable(wilk, vars=[x], domain=CC) # needs sage.symbolic
sage: timeit('fc_wilk_cc(30.0)') # random # long time # needs sage.symbolic
sage: timeit('fc_wilk_cc(30.0)') # random, long time # needs sage.symbolic
625 loops, best of 3: 23 us per loop
And support for ``CDF``::
sage: fc_wilk_cdf = fast_callable(wilk, vars=[x], domain=CDF) # needs sage.symbolic
sage: timeit('fc_wilk_cdf(30.0)') # random # long time # needs sage.symbolic
sage: timeit('fc_wilk_cdf(30.0)') # random, long time # needs sage.symbolic
625 loops, best of 3: 10.2 us per loop
Currently, :func:`fast_callable` can accept two kinds of objects:
polynomials (univariate and multivariate) and symbolic expressions
(elements of the Symbolic Ring). (This list is likely to grow
significantly in the near future.) For polynomials, you can omit the
'vars' argument; the variables will default to the ring generators (in
(elements of the Symbolic Ring). For polynomials, you can omit the
``vars`` argument; the variables will default to the ring generators (in
the order used when creating the ring). ::
sage: K.<x,y,z> = QQ[]
Expand Down Expand Up @@ -215,12 +214,12 @@ EXAMPLES::
sage: f.op_list() # needs sage.symbolic
[('load_arg', 0), ('ipow', 7), ('load_const', 1.0), 'add', 'sqrt', 'return']
To interpret that last line, we load argument 0 ('x' in this case) onto
the stack, push the constant 7.0 onto the stack, call the pow function
(which takes 2 arguments from the stack), push the constant 1.0, add the
top two arguments of the stack, and then call sqrt.
To interpret that last line, we load argument 0 (``x`` in this case) onto
the stack, push the constant `7.0` onto the stack, call the :func:`pow`
functionn(which takes 2 arguments from the stack), push the constant `1.0`,
add the top two arguments of the stack, and then call :func:`sqrt`.
Here we take sin of the first argument and add it to f::
Here we take :func:`sin` of the first argument and add it to ``f``::
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
sage: etb = ExpressionTreeBuilder('x')
Expand Down Expand Up @@ -330,11 +329,11 @@ def fast_callable(x, domain=None, vars=None,
would evaluate it -- addition maps to ``PyNumber_Add``, etc. However,
you can specify ``domain=D`` where ``D`` is some Sage parent or Python
type; in this case, all arithmetic is done in that domain. If we
have a special-purpose interpreter for that parent (like ``RDF`` or :class:`float`),
``domain=...`` will trigger the use of that interpreter.
have a special-purpose interpreter for that parent (like ``RDF`` or
:class:`float`), ``domain=...`` will trigger the use of that interpreter.
If ``vars`` is ``None`` and ``x`` is a polynomial, then we will use the
generators of parent(x) as the variables; otherwise, ``vars`` must be
generators of ``parent(x)`` as the variables; otherwise, ``vars`` must be
specified (unless ``x`` is a symbolic expression with only one variable,
and ``expect_one_var`` is ``True``, in which case we will use that variable).
Expand Down Expand Up @@ -413,8 +412,8 @@ def fast_callable(x, domain=None, vars=None,
sage: fc(5, 7)
0.5514266812416906
Check that :func:`fast_callable` also works for symbolic functions with evaluation
functions::
Check that :func:`fast_callable` also works for symbolic functions with
evaluation functions::
sage: # needs sage.symbolic
sage: def evalf_func(self, x, y, parent):
Expand Down Expand Up @@ -575,8 +574,8 @@ def function_name(fn):
Given a function, return a string giving a name for the function.
For functions we recognize, we use our standard opcode name for the
function (so :func:`operator.add` becomes ``'add'``, and :func:`sage.functions.trig.sin`
becomes ``'sin'``).
function (so :func:`operator.add` becomes ``'add'``, and
:func:`sage.functions.trig.sin` becomes ``'sin'``).
For functions we don't recognize, we try to come up with a name,
but the name will be wrapped in braces; this is a signal that
Expand Down Expand Up @@ -633,9 +632,9 @@ cdef class ExpressionTreeBuilder:
Initialize an instance of :class:`ExpressionTreeBuilder`.
Takes a list or tuple of variable names to use, and also an optional
``domain``. If a ``domain`` is given, then creating an :class:`ExpressionConstant`
node with the :meth:`__call__`, make, or constant methods will convert
the value into the given domain.
``domain``. If a ``domain`` is given, then creating an
:class:`ExpressionConstant` node with the :meth:`__call__`, make, or
constant methods will convert the value into the given domain.
Note that this is the only effect of the domain parameter. It
is quite possible to use different domains for
Expand Down Expand Up @@ -668,9 +667,9 @@ cdef class ExpressionTreeBuilder:
r"""
Try to convert the given value to an :class:`Expression`.
If it is already an Expression, just return it. If it has a :meth:`_fast_callable_`
method, then call the method with ``self`` as an argument. Otherwise,
use ``self.constant()`` to turn it into a constant.
If it is already an Expression, just return it. If it has a
:meth:`_fast_callable_` method, then call the method with ``self`` as
an argument. Otherwise, use ``self.constant()`` to turn it into a constant.
EXAMPLES::
Expand Down Expand Up @@ -795,8 +794,8 @@ cdef class ExpressionTreeBuilder:
The arguments will be converted to Expressions using
:meth:`ExpressionTreeBuilder.__call__`.
As a special case, notices if the function is :func:`operator.pow` and
the second argument is integral, and constructs an :class:`ExpressionIPow`
As a special case, notice if the function is :func:`operator.pow` and
the second argument is integral, and construct an :class:`ExpressionIPow`
instead.
EXAMPLES::
Expand Down Expand Up @@ -2351,9 +2350,9 @@ cdef class InterpreterMetadata():
(instruction name, :class:`CompilerInstrSpec`) pairs, and a range of exponents
for which the ``'ipow'`` instruction can be used. This range can be
``False`` (if the ``'ipow'`` instruction should never be used), a pair of
two integers ``(a, b)``, if ``'ipow'`` should be used for a<=n<=b, or ``True``,
if ``'ipow'`` should always be used. When ``'ipow'`` cannot be used, then
we fall back on calling :class:`IntegerPowerFunction`.
two integers `(a, b)`, if ``'ipow'`` should be used for `a \le n \le b`, or
``True``, if ``'ipow'`` should always be used. When ``'ipow'`` cannot be
used, then we fall back on calling :class:`IntegerPowerFunction`.
See the class docstring for :class:`CompilerInstrSpec` for more information.
Expand Down

0 comments on commit 50d6354

Please sign in to comment.