Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Few more docstring edits #42

Merged
merged 2 commits into from
May 24, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
gmou3 marked this conversation as resolved.
Show resolved Hide resolved
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
Loading