Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" Pynac interface """
#***************************************************************************** # Copyright (C) 2008 William Stein <wstein@gmail.com> # Copyright (C) 2008 Burcin Erocal <burcin@erocal.org> # Copyright (C) 2017 Jeroen Demeyer <jdemeyer@cage.ugent.be> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import absolute_import, division, print_function
from cpython cimport * from libc cimport math
from sage.ext.stdsage cimport PY_NEW from sage.libs.gmp.all cimport * from sage.libs.gsl.types cimport * from sage.libs.gsl.complex cimport * from sage.libs.gsl.gamma cimport gsl_sf_lngamma_complex_e from sage.libs.mpmath import utils as mpmath_utils from sage.libs.pari.all import pari
from sage.cpython.string cimport str_to_bytes, char_to_str
from sage.arith.all import gcd, lcm, is_prime, factorial, bernoulli
from sage.structure.element cimport Element, parent, coercion_model from sage.structure.sage_object import loads, dumps
from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer, smallInteger from sage.rings.rational cimport Rational from sage.rings.real_mpfr import RR, RealField from sage.rings.rational cimport rational_power_parts from sage.rings.real_double cimport RealDoubleElement from sage.rings.all import CC
from sage.symbolic.expression cimport Expression, new_Expression_from_GEx from sage.symbolic.function import get_sfunction_from_serial from sage.symbolic.function cimport Function from sage.symbolic.substitution_map cimport new_SubstitutionMap_from_GExMap from sage.symbolic import ring
from .constant cimport PynacConstant
################################################################# # Symbolic function helpers #################################################################
cdef ex_to_pyExpression(GEx juice): """ Convert given GiNaC::ex object to a python Expression instance.
Used to pass parameters to custom power and series functions. """ cdef Expression nex
cdef exprseq_to_PyTuple(GEx seq): """ Convert an exprseq to a Python tuple.
Used while converting arguments of symbolic functions to Python objects.
EXAMPLES::
sage: from sage.symbolic.function import BuiltinFunction sage: class TFunc(BuiltinFunction): ....: def __init__(self): ....: BuiltinFunction.__init__(self, 'tfunc', nargs=0) ....: ....: def _eval_(self, *args): ....: print("len(args): %s, types: %s"%(len(args), str(list(map(type, args))))) ....: for i, a in enumerate(args): ....: if isinstance(a, tuple): ....: print("argument %s is a tuple, with types %s"%(str(i), str(list(map(type, a))))) ....: sage: tfunc = TFunc() sage: u = SR._force_pyobject((1, x+1, 2)) sage: tfunc(u, x, SR._force_pyobject((3.0, 2^x))) len(args): 3, types: [<... 'tuple'>, <type 'sage.symbolic.expression.Expression'>, <... 'tuple'>] argument 0 is a tuple, with types [<type 'sage.rings.integer.Integer'>, <type 'sage.symbolic.expression.Expression'>, <type 'sage.rings.integer.Integer'>] argument 2 is a tuple, with types [<type 'sage.rings.real_mpfr.RealLiteral'>, <type 'sage.symbolic.expression.Expression'>] tfunc((1, x + 1, 2), x, (3.00000000000000, 2^x)) """ else:
def unpack_operands(Expression ex): """ EXAMPLES::
sage: from sage.libs.pynac.pynac import unpack_operands sage: t = SR._force_pyobject((1, 2, x, x+1, x+2)) sage: unpack_operands(t) (1, 2, x, x + 1, x + 2) sage: type(unpack_operands(t)) <... 'tuple'> sage: list(map(type, unpack_operands(t))) [<type 'sage.rings.integer.Integer'>, <type 'sage.rings.integer.Integer'>, <type 'sage.symbolic.expression.Expression'>, <type 'sage.symbolic.expression.Expression'>, <type 'sage.symbolic.expression.Expression'>] sage: u = SR._force_pyobject((t, x^2)) sage: unpack_operands(u) ((1, 2, x, x + 1, x + 2), x^2) sage: type(unpack_operands(u)[0]) <... 'tuple'> """
cdef exvector_to_PyTuple(GExVector seq): """ Converts arguments list given to a function to a PyTuple.
Used to pass arguments to python methods assigned to custom evaluation, derivative, etc. functions of symbolic functions.
We convert Python objects wrapped in symbolic expressions back to regular Python objects.
EXAMPLES::
sage: from sage.symbolic.function import BuiltinFunction sage: class TFunc(BuiltinFunction): ....: def __init__(self): ....: BuiltinFunction.__init__(self, 'tfunc', nargs=0) ....: ....: def _eval_(self, *args): ....: print("len(args): %s, types: %s"%(len(args), str(list(map(type, args))))) sage: tfunc = TFunc() sage: u = SR._force_pyobject((1, x+1, 2)) sage: tfunc(u, x, 3.0, 5.0r) len(args): 4, types: [<... 'tuple'>, <type 'sage.symbolic.expression.Expression'>, <type 'sage.rings.real_mpfr.RealLiteral'>, <... 'float'>] tfunc((1, x + 1, 2), x, 3.00000000000000, 5.0)
TESTS:
Check if symbolic functions in the arguments are preserved::
sage: tfunc(sin(x), tfunc(1, x^2)) len(args): 2, types: [<type 'sage.rings.integer.Integer'>, <type 'sage.symbolic.expression.Expression'>] len(args): 2, types: [<type 'sage.symbolic.expression.Expression'>, <type 'sage.symbolic.expression.Expression'>] tfunc(sin(x), tfunc(1, x^2))
""" else:
cdef GEx pyExpression_to_ex(res) except *: """ Converts an Expression object to a GiNaC::ex.
Used to pass return values of custom python evaluation, derivation functions back to C++ level. """ raise TypeError("function returned None, expected return value of type sage.symbolic.expression.Expression")
cdef paramset_to_PyTuple(const_paramset_ref s): """ Converts a std::multiset<unsigned> to a PyTuple.
Used to pass a list of parameter numbers with respect to which a function is differentiated to the printing functions py_print_fderivative and py_latex_fderivative. """
def paramset_from_Expression(Expression e): """ EXAMPLES::
sage: from sage.libs.pynac.pynac import paramset_from_Expression sage: f = function('f') sage: paramset_from_Expression(f(x).diff(x)) [0L] # 32-bit [0] # 64-bit """
cdef int GINAC_FN_SERIAL = 0
cdef set_ginac_fn_serial(): """ Initialize the GINAC_FN_SERIAL variable to the number of functions defined by GiNaC. This allows us to prevent collisions with C++ level special functions when a user asks to construct a symbolic function with the same name. """ global GINAC_FN_SERIAL GINAC_FN_SERIAL = g_registered_functions().size()
cdef int py_get_ginac_serial(): """ Returns the number of C++ level functions defined by GiNaC.
EXAMPLES::
sage: from sage.libs.pynac.pynac import get_ginac_serial sage: get_ginac_serial() >= 35 True """ global GINAC_FN_SERIAL
def get_ginac_serial(): """ Number of C++ level functions defined by GiNaC. (Defined mainly for testing.)
EXAMPLES::
sage: sage.libs.pynac.pynac.get_ginac_serial() >= 35 True """
cdef get_fn_serial_c(): """ Return overall size of Pynac function registry. """
def get_fn_serial(): """ Return the overall size of the Pynac function registry which corresponds to the last serial value plus one.
EXAMPLES::
sage: from sage.libs.pynac.pynac import get_fn_serial sage: from sage.symbolic.function import get_sfunction_from_serial sage: get_fn_serial() > 125 True sage: print(get_sfunction_from_serial(get_fn_serial())) None sage: get_sfunction_from_serial(get_fn_serial() - 1) is not None True """
cdef subs_args_to_PyTuple(const GExMap& map, unsigned options, const GExVector& seq): """ Convert arguments from ``GiNaC::subs()`` to a PyTuple.
EXAMPLES::
sage: from sage.symbolic.function import BuiltinFunction sage: class TFunc(BuiltinFunction): ....: def __init__(self): ....: BuiltinFunction.__init__(self, 'tfunc', nargs=0) ....: ....: def _subs_(self, *args): ....: print("len(args): %s, types: %s"%(len(args), str(list(map(type, args))))) ....: return args[-1] sage: tfunc = TFunc() sage: tfunc(x).subs(x=1) len(args): 3, types: [<type 'sage.symbolic.substitution_map.SubstitutionMap'>, <type 'int'>, # 64-bit <type 'long'>, # 32-bit <type 'sage.symbolic.expression.Expression'>] x """
################################################################# # Printing helpers #################################################################
########################################################################## # Pynac's precedence levels, as extracted from the raw source code on # 2009-05-15. If this changes in Pynac it could cause a bug in # printing. But it's hardcoded in Pynac now, so there's not much to # be done (at present). # Container: 10 # Expairseq: 10 # Relational: 20 # Numeric: 30 # Pseries: 38 # Addition: 40 # Integral: 45 # Multiplication: 50 # Noncummative mult: 50 # Index: 55 # Power: 60 # Clifford: 65 # Function: 70 # Structure: 70 ##########################################################################
cdef stdstring* py_repr(o, int level): """ Return string representation of o. If level > 0, possibly put parentheses around the string. """ # s may need parens (e.g., is in an exponent), so decide if we # have to put parentheses around s: # A regexp might seem better, but I don't think it's really faster. # It would be more readable. Python does the below (with in) very quickly. else: # Python complexes are always printed with parentheses # we try to avoid double parentheses
cdef stdstring* py_latex(o, int level): """ Return latex string representation of o. If level > 0, possibly put parentheses around the string. """
cdef stdstring* string_from_pystr(py_str) except NULL: """ Creates a C++ string with the same contents as the given python string.
Used when passing string output to Pynac for printing, since we don't want to mess with reference counts of the python objects and we cannot guarantee they won't be garbage collected before the output is printed. """ cdef bytes s elif isinstance(py_str, str): # Note: This should only by the case on Python 3 since on Python 2 # bytes is str s = str_to_bytes(py_str) else: s = b"(INVALID)" # Avoid segfaults for invalid input
cdef stdstring* py_latex_variable(var_name): """ Returns a c++ string containing the latex representation of the given variable name.
Real work is done by the function sage.misc.latex.latex_variable_name.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_latex_variable_for_doctests sage: py_latex_variable = py_latex_variable_for_doctests
sage: py_latex_variable('a') a sage: py_latex_variable('abc') \mathit{abc} sage: py_latex_variable('a_00') a_{00} sage: py_latex_variable('sigma_k') \sigma_{k} sage: py_latex_variable('sigma389') \sigma_{389} sage: py_latex_variable('beta_00') \beta_{00} """
def py_latex_variable_for_doctests(x): """ Internal function used so we can doctest a certain cdef'd method.
EXAMPLES::
sage: sage.libs.pynac.pynac.py_latex_variable_for_doctests('x') x sage: sage.libs.pynac.pynac.py_latex_variable_for_doctests('sigma') \sigma """
def py_print_function_pystring(id, args, fname_paren=False): """ Return a string with the representation of the symbolic function specified by the given id applied to args.
INPUT:
- id -- serial number of the corresponding symbolic function - params -- Set of parameter numbers with respect to which to take the derivative. - args -- arguments of the function.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_print_function_pystring, get_ginac_serial, get_fn_serial sage: from sage.symbolic.function import get_sfunction_from_serial sage: var('x,y,z') (x, y, z) sage: foo = function('foo', nargs=2) sage: for i in range(get_ginac_serial(), get_fn_serial()): ....: if get_sfunction_from_serial(i) == foo: break
sage: get_sfunction_from_serial(i) == foo True sage: py_print_function_pystring(i, (x,y)) 'foo(x, y)' sage: py_print_function_pystring(i, (x,y), True) '(foo)(x, y)' sage: def my_print(self, *args): return "my args are: " + ', '.join(map(repr, args)) sage: foo = function('foo', nargs=2, print_func=my_print) sage: for i in range(get_ginac_serial(), get_fn_serial()): ....: if get_sfunction_from_serial(i) == foo: break
sage: get_sfunction_from_serial(i) == foo True sage: py_print_function_pystring(i, (x,y)) 'my args are: x, y' """ # This function is called from two places, from function::print in Pynac # and from py_print_fderivative. function::print checks if the serial # belongs to a function defined at the C++ level. There are no C++ level # functions that return an instance of fderivative when derivated. Hence, # func will never be None.
# if function has a custom print function call it # make sure the output is a string return "" return str(res)
# otherwise use default output else:
cdef stdstring* py_print_function(unsigned id, args):
def py_latex_function_pystring(id, args, fname_paren=False): r""" Return a string with the latex representation of the symbolic function specified by the given id applied to args.
See documentation of py_print_function_pystring for more information.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_latex_function_pystring, get_ginac_serial, get_fn_serial sage: from sage.symbolic.function import get_sfunction_from_serial sage: var('x,y,z') (x, y, z) sage: foo = function('foo', nargs=2) sage: for i in range(get_ginac_serial(), get_fn_serial()): ....: if get_sfunction_from_serial(i) == foo: break
sage: get_sfunction_from_serial(i) == foo True sage: py_latex_function_pystring(i, (x,y^z)) '{\\rm foo}\\left(x, y^{z}\\right)' sage: py_latex_function_pystring(i, (x,y^z), True) '\\left({\\rm foo}\\right)\\left(x, y^{z}\\right)' sage: py_latex_function_pystring(i, (int(0),x)) '{\\rm foo}\\left(0, x\\right)'
Test latex_name::
sage: foo = function('foo', nargs=2, latex_name=r'\mathrm{bar}') sage: for i in range(get_ginac_serial(), get_fn_serial()): ....: if get_sfunction_from_serial(i) == foo: break
sage: get_sfunction_from_serial(i) == foo True sage: py_latex_function_pystring(i, (x,y^z)) '\\mathrm{bar}\\left(x, y^{z}\\right)'
Test custom func::
sage: def my_print(self, *args): return "my args are: " + ', '.join(map(repr, args)) sage: foo = function('foo', nargs=2, print_latex_func=my_print) sage: for i in range(get_ginac_serial(), get_fn_serial()): ....: if get_sfunction_from_serial(i) == foo: break
sage: get_sfunction_from_serial(i) == foo True sage: py_latex_function_pystring(i, (x,y^z)) 'my args are: x, y^z'
""" # This function is called from two places, from function::print in Pynac # and from py_latex_fderivative. function::print checks if the serial # belongs to a function defined at the C++ level. There are no C++ level # functions that return an instance of fderivative when derivated. Hence, # func will never be None.
# if function has a custom print method call it # make sure the output is a string return str(res)
# otherwise, use the latex name if defined else: # if latex_name is not defined, then call # latex_variable_name with "is_fname=True" flag else: # print the arguments r'\right)'] )
cdef stdstring* py_latex_function(unsigned id, args):
def tolerant_is_symbol(a): """ Utility function to test if something is a symbol.
Returns False for arguments that do not have an is_symbol attribute. Returns the result of calling the is_symbol method otherwise.
EXAMPLES::
sage: from sage.libs.pynac.pynac import tolerant_is_symbol sage: tolerant_is_symbol(var("x")) True sage: tolerant_is_symbol(None) False sage: None.is_symbol() Traceback (most recent call last): ... AttributeError: 'NoneType' object has no attribute 'is_symbol' """
cdef stdstring* py_print_fderivative(unsigned id, params, args): """ Return a string with the representation of the derivative of the symbolic function specified by the given id, lists of params and args.
INPUT:
- id -- serial number of the corresponding symbolic function - params -- Set of parameter numbers with respect to which to take the derivative. - args -- arguments of the function. """ else:
def py_print_fderivative_for_doctests(id, params, args): """ Used for testing a cdef'd function.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_print_fderivative_for_doctests as py_print_fderivative, get_ginac_serial, get_fn_serial sage: var('x,y,z') (x, y, z) sage: from sage.symbolic.function import get_sfunction_from_serial sage: foo = function('foo', nargs=2) sage: for i in range(get_ginac_serial(), get_fn_serial()): ....: if get_sfunction_from_serial(i) == foo: break
sage: get_sfunction_from_serial(i) == foo True sage: py_print_fderivative(i, (0, 1, 0, 1), (x, y^z)) D[0, 1, 0, 1](foo)(x, y^z)
Test custom print function::
sage: def my_print(self, *args): return "func_with_args(" + ', '.join(map(repr, args)) +')' sage: foo = function('foo', nargs=2, print_func=my_print) sage: for i in range(get_ginac_serial(), get_fn_serial()): ....: if get_sfunction_from_serial(i) == foo: break
sage: get_sfunction_from_serial(i) == foo True sage: py_print_fderivative(i, (0, 1, 0, 1), (x, y^z)) D[0, 1, 0, 1]func_with_args(x, y^z)
"""
cdef stdstring* py_latex_fderivative(unsigned id, params, args): """ Return a string with the latex representation of the derivative of the symbolic function specified by the given id, lists of params and args.
See documentation of py_print_fderivative for more information.
""" else: else: else: else: else:
def py_latex_fderivative_for_doctests(id, params, args): r""" Used internally for writing doctests for certain cdef'd functions.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_latex_fderivative_for_doctests as py_latex_fderivative, get_ginac_serial, get_fn_serial
sage: var('x,y,z') (x, y, z) sage: from sage.symbolic.function import get_sfunction_from_serial sage: foo = function('foo', nargs=2) sage: for i in range(get_ginac_serial(), get_fn_serial()): ....: if get_sfunction_from_serial(i) == foo: break
sage: get_sfunction_from_serial(i) == foo True sage: py_latex_fderivative(i, (0, 1, 0, 1), (x, y^z)) \mathrm{D}_{0, 1, 0, 1}\left({\rm foo}\right)\left(x, y^{z}\right)
Test latex_name::
sage: foo = function('foo', nargs=2, latex_name=r'\mathrm{bar}') sage: for i in range(get_ginac_serial(), get_fn_serial()): ....: if get_sfunction_from_serial(i) == foo: break
sage: get_sfunction_from_serial(i) == foo True sage: py_latex_fderivative(i, (0, 1, 0, 1), (x, y^z)) \mathrm{D}_{0, 1, 0, 1}\left(\mathrm{bar}\right)\left(x, y^{z}\right)
Test custom func::
sage: def my_print(self, *args): return "func_with_args(" + ', '.join(map(repr, args)) +')' sage: foo = function('foo', nargs=2, print_latex_func=my_print) sage: for i in range(get_ginac_serial(), get_fn_serial()): ....: if get_sfunction_from_serial(i) == foo: break
sage: get_sfunction_from_serial(i) == foo True sage: py_latex_fderivative(i, (0, 1, 0, 1), (x, y^z)) \mathrm{D}_{0, 1, 0, 1}func_with_args(x, y^z) """
################################################################# # Archive helpers #################################################################
cdef stdstring* py_dumps(o): # pynac archive format terminates atoms with zeroes. # since pickle output can break the archive format # we use the base64 data encoding
cdef py_loads(s):
cdef py_get_sfunction_from_serial(unsigned s): """ Return the Python object associated with a serial. """
cdef unsigned py_get_serial_from_sfunction(f): """ Given a Function object return its serial.
Python's unpickling mechanism is used to unarchive a symbolic function with custom methods (evaluation, differentiation, etc.). Pynac extracts a string representation from the archive, calls loads() to recreate the stored function. This allows us to extract the serial from the Python object to set the corresponding member variable of the C++ object representing this function. """
cdef unsigned py_get_serial_for_new_sfunction(stdstring &s, unsigned nargs): """ Return a symbolic function with the given name and number of arguments.
When unarchiving a user defined symbolic function, Pynac goes through the registry of existing functions. If there is no function already defined with the archived name and number of arguments, this method is called to create one and set up the function tables properly. """ from sage.symbolic.function_factory import function_factory cdef Function fn = function_factory(s.c_str(), nargs) return fn._serial
################################################################# # Modular helpers #################################################################
cdef int py_get_parent_char(o) except -1: """ TESTS:
:trac:`24072` fixes the workaround provided in :trac:`21187`::
sage: p = next_prime(2^100) sage: R.<y> = FiniteField(p)[] sage: y = SR(y) Traceback (most recent call last): ... TypeError: positive characteristic not allowed in symbolic computations """ return 0
# Pynac only differentiates between # - characteristic 0 # - characteristic 2 # - characteristic > 0 but not 2 # # To avoid integer overflow in the last case, we just return 3 # instead of the actual characteristic. elif c == 2: return 2 else: return 3
################################################################# # power helpers #################################################################
cdef py_rational_power_parts(base, exp): if type(base) is not Rational: base = Rational(base) if type(exp) is not Rational: exp = Rational(exp) res= rational_power_parts(base, exp) return res + (bool(res[0] == 1),)
################################################################# # Binomial Coefficients #################################################################
cdef py_binomial_int(int n, unsigned int k): cdef bint sign if n < 0: n = -n + (k-1) sign = k%2 else: sign = 0 cdef Integer ans = PY_NEW(Integer) # Compute the binomial coefficient using GMP. mpz_bin_uiui(ans.value, n, k) # Return the answer or the negative of it (only if k is odd and n is negative). if sign: return -ans else: return ans
cdef py_binomial(n, k): # Keep track of the sign we should use. cdef bint sign else: # Convert n and k to unsigned ints. # Compute the binomial coefficient using GMP. # Return the answer or the negative of it (only if k is odd and n is negative). else:
def test_binomial(n, k): """ The Binomial coefficients. It computes the binomial coefficients. For integer n and k and positive n this is the number of ways of choosing k objects from n distinct objects. If n is negative, the formula binomial(n,k) == (-1)^k*binomial(k-n-1,k) is used to compute the result.
INPUT:
- n, k -- integers, with k >= 0.
OUTPUT:
integer
EXAMPLES::
sage: import sage.libs.pynac.pynac sage: sage.libs.pynac.pynac.test_binomial(5,2) 10 sage: sage.libs.pynac.pynac.test_binomial(-5,3) -35 sage: -sage.libs.pynac.pynac.test_binomial(3-(-5)-1, 3) -35 """
################################################################# # GCD ################################################################# cdef py_gcd(n, k): if mpz_cmp_si((<Integer>n).value,1) == 0: return n elif mpz_cmp_si((<Integer>k).value,1) == 0: return k return n.gcd(k)
return n.content(k) # some strange meaning in case of weird things with no usual lcm.
################################################################# # LCM ################################################################# cdef py_lcm(n, k): if isinstance(n, Integer) and isinstance(k, Integer): if mpz_cmp_si((<Integer>n).value,1) == 0: return k elif mpz_cmp_si((<Integer>k).value,1) == 0: return n return n.lcm(k) try: return lcm(n,k) except (TypeError, ValueError, AttributeError): # some strange meaning in case of weird things with no usual lcm, e.g., # elements of finite fields. return 1
################################################################# # Real Part ################################################################# cdef py_real(x): """ Returns the real part of x.
TESTS::
sage: from sage.libs.pynac.pynac import py_real_for_doctests as py_real sage: py_real(I) 0 sage: py_real(CC(1,5)) 1.00000000000000 sage: py_real(CC(1)) 1.00000000000000 sage: py_real(RR(1)) 1.00000000000000
sage: py_real(Mod(2,7)) 2
sage: py_real(QQ['x'].gen()) x sage: py_real(float(2)) 2.0 sage: py_real(complex(2,2)) 2.0 """
pass pass
def py_real_for_doctests(x): """ Used for doctesting py_real.
TESTS::
sage: from sage.libs.pynac.pynac import py_real_for_doctests sage: py_real_for_doctests(I) 0 """
################################################################# # Imaginary Part ################################################################# cdef py_imag(x): """ Return the imaginary part of x.
TESTS::
sage: from sage.libs.pynac.pynac import py_imag_for_doctests as py_imag sage: py_imag(I) 1 sage: py_imag(CC(1,5)) 5.00000000000000 sage: py_imag(CC(1)) 0.000000000000000 sage: py_imag(RR(1)) 0 sage: py_imag(Mod(2,7)) 0
sage: py_imag(QQ['x'].gen()) 0 sage: py_imag(float(2)) 0.0 sage: py_imag(complex(2,2)) 2.0 """ pass pass
def py_imag_for_doctests(x): """ Used for doctesting py_imag.
TESTS::
sage: from sage.libs.pynac.pynac import py_imag_for_doctests sage: py_imag_for_doctests(I) 1 """
################################################################# # Conjugate ################################################################# cdef py_conjugate(x): try: return x.conjugate() except AttributeError: return x # assume is real since it doesn't have an imag attribute.
cdef bint py_is_rational(x):
cdef bint py_is_equal(x, y): """ Return True precisely if x and y are equal. """
cdef bint py_is_integer(x): r""" Returns True if pynac should treat this object as an integer.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_is_integer_for_doctests sage: py_is_integer = py_is_integer_for_doctests
sage: py_is_integer(1r) True sage: py_is_integer(long(1)) True sage: py_is_integer(3^57) True sage: py_is_integer(SR(5)) True sage: py_is_integer(4/2) True sage: py_is_integer(QQbar(sqrt(2))^2) True sage: py_is_integer(3.0) False sage: py_is_integer(3.0r) False """
def py_is_integer_for_doctests(x): """ Used internally for doctesting purposes.
TESTS::
sage: sage.libs.pynac.pynac.py_is_integer_for_doctests(1r) True sage: sage.libs.pynac.pynac.py_is_integer_for_doctests(1/3) False sage: sage.libs.pynac.pynac.py_is_integer_for_doctests(2) True """
cdef bint py_is_even(x): except Exception: pass return 0
cdef bint py_is_crational(x): else:
def py_is_crational_for_doctest(x): """ Returns True if pynac should treat this object as an element of `\QQ(i)`.
TESTS::
sage: from sage.libs.pynac.pynac import py_is_crational_for_doctest sage: py_is_crational_for_doctest(1) True sage: py_is_crational_for_doctest(-2r) True sage: py_is_crational_for_doctest(1.5) False sage: py_is_crational_for_doctest(I.pyobject()) True sage: py_is_crational_for_doctest(I.pyobject()+1/2) True """
cdef bint py_is_real(a): return False pass
cdef bint py_is_prime(n): try: return n.is_prime() except Exception: # yes, I'm doing this on purpose. pass try: return is_prime(n) except Exception: pass return False
cdef bint py_is_exact(x):
cdef py_numer(n): """ Return the numerator of the given object. This is called for typesetting coefficients.
TESTS::
sage: from sage.libs.pynac.pynac import py_numer_for_doctests as py_numer sage: py_numer(2r) 2 sage: py_numer(3) 3 sage: py_numer(2/3) 2 sage: C.<i> = NumberField(x^2+1) sage: py_numer(2/3*i) 2*i sage: class no_numer: ....: def denominator(self): ....: return 5 ....: def __mul__(left, right): ....: return 42 ... sage: py_numer(no_numer()) 42 """
def py_numer_for_doctests(n): """ This function is used to test py_numer().
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_numer_for_doctests sage: py_numer_for_doctests(2/3) 2 """
cdef py_denom(n): """ Return the denominator of the given object. This is called for typesetting coefficients.
TESTS::
sage: from sage.libs.pynac.pynac import py_denom_for_doctests as py_denom sage: py_denom(5) 1 sage: py_denom(2/3) 3 sage: C.<i> = NumberField(x^2+1) sage: py_denom(2/3*i) 3 """
def py_denom_for_doctests(n): """ This function is used to test py_denom().
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_denom_for_doctests sage: py_denom_for_doctests(2/3) 3 """
cdef bint py_is_cinteger(x):
def py_is_cinteger_for_doctest(x): """ Returns True if pynac should treat this object as an element of `\ZZ(i)`.
TESTS::
sage: from sage.libs.pynac.pynac import py_is_cinteger_for_doctest sage: py_is_cinteger_for_doctest(1) True sage: py_is_cinteger_for_doctest(long(-3)) True sage: py_is_cinteger_for_doctest(I.pyobject()) True sage: py_is_cinteger_for_doctest(I.pyobject() - 3) True sage: py_is_cinteger_for_doctest(I.pyobject() + 1/2) False """
cdef py_float(n, PyObject* kwds): """ Evaluate pynac numeric objects numerically.
TESTS::
sage: from sage.libs.pynac.pynac import py_float_for_doctests as py_float sage: py_float(I, {'parent':ComplexField(10)}) 1.0*I sage: py_float(pi, {'parent':RealField(100)}) 3.1415926535897932384626433833 sage: py_float(10, {'parent':CDF}) 10.0 sage: type(py_float(10, {'parent':CDF})) <type 'sage.rings.complex_double.ComplexDoubleElement'> sage: py_float(1/2, {'parent':CC}) 0.500000000000000 sage: type(py_float(1/2, {'parent':CC})) <type 'sage.rings.complex_number.ComplexNumber'> """ else: else: try: return RR(n) except TypeError: return CC(n)
def py_float_for_doctests(n, kwds): """ This function is for testing py_float.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_float_for_doctests sage: py_float_for_doctests(pi, {'parent':RealField(80)}) 3.1415926535897932384626 sage: py_float_for_doctests(I, {'parent':RealField(80)}) 1.0000000000000000000000*I sage: py_float_for_doctests(I, {'parent':float}) 1j sage: py_float_for_doctests(pi, {'parent':complex}) (3.141592653589793+0j) """
cdef py_RDF_from_double(double x): cdef RealDoubleElement r = RealDoubleElement.__new__(RealDoubleElement) r._value = x return r
################################################################# # SPECIAL FUNCTIONS ################################################################# cdef py_tgamma(x): """ The gamma function exported to pynac.
TESTS::
sage: from sage.libs.pynac.pynac import py_tgamma_for_doctests as py_tgamma sage: py_tgamma(4) 6 sage: py_tgamma(1/2) 1.77245385090552 """ x = float(x) return math.tgamma(PyFloat_AS_DOUBLE(x))
# try / except blocks are faster than # if hasattr(x, 'gamma') except AttributeError: return CC(x).gamma()
# the result should be numeric, however the gamma method of rationals may # return symbolic expressions. for example (1/2).gamma() -> sqrt(pi). except ValueError: return CC(res)
def py_tgamma_for_doctests(x): """ This function is for testing py_tgamma().
TESTS::
sage: from sage.libs.pynac.pynac import py_tgamma_for_doctests sage: py_tgamma_for_doctests(3) 2 """
cdef py_factorial(x): """ The factorial function exported to pynac.
TESTS::
sage: from sage.libs.pynac.pynac import py_factorial_py as py_factorial sage: py_factorial(4) 24 sage: py_factorial(-2/3) 2.67893853470775 """ # factorial(x) is only defined for non-negative integers x # so we first test if x can be coerced into ZZ and is non-negative. # If this is not the case then we return the symbolic expression gamma(x+1) # This fixes Trac 9240
else:
def py_factorial_py(x): """ This function is a python wrapper around py_factorial(). This wrapper is needed when we override the eval() method for GiNaC's factorial function in sage.functions.other.Function_factorial.
TESTS::
sage: from sage.libs.pynac.pynac import py_factorial_py sage: py_factorial_py(3) 6 """
cdef py_doublefactorial(x): raise ValueError("argument must be >= -1")
def doublefactorial(n): """ The double factorial combinatorial function:
n!! == n * (n-2) * (n-4) * ... * ({1|2}) with 0!! == (-1)!! == 1.
INPUT:
- n -- an integer > = 1
EXAMPLES::
sage: from sage.libs.pynac.pynac import doublefactorial sage: doublefactorial(-1) 1 sage: doublefactorial(0) 1 sage: doublefactorial(1) 1 sage: doublefactorial(5) 15 sage: doublefactorial(20) 3715891200 sage: prod( [20,18,..,2] ) 3715891200 """
cdef py_fibonacci(n): return Integer(pari(n).fibonacci())
cdef py_step(n): """ Return step function of n. """ if n < 0: return ZERO elif n > 0: return ONE return ONE_HALF
cdef py_bernoulli(x):
cdef py_sin(x): """ TESTS::
sage: sin(float(2)) #indirect doctest 0.9092974268256817 sage: sin(2.) 0.909297426825682 sage: sin(2.*I) 3.62686040784702*I sage: sin(QQbar(I)) # known bug I*sinh(1) """ pass except (TypeError, ValueError): return CC(x).sin()
cdef py_cos(x): """ TESTS::
sage: cos(float(2)) #indirect doctest -0.4161468365471424 sage: cos(2.) -0.416146836547142 sage: cos(2.*I) 3.76219569108363 sage: cos(QQbar(I)) # known bug cosh(1) """ pass except (TypeError, ValueError): return CC(x).cos()
cdef py_stieltjes(x): """ Return the Stieltjes constant of the given index.
The value is expected to be a non-negative integer.
TESTS::
sage: from sage.libs.pynac.pynac import py_stieltjes_for_doctests as py_stieltjes sage: py_stieltjes(0) 0.577215664901533 sage: py_stieltjes(1.0) -0.0728158454836767 sage: py_stieltjes(RealField(100)(5)) 0.00079332381730106270175333487744 sage: py_stieltjes(-1) Traceback (most recent call last): ... ValueError: Stieltjes constant of negative index """ else:
def py_stieltjes_for_doctests(x): """ This function is for testing py_stieltjes().
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_stieltjes_for_doctests sage: py_stieltjes_for_doctests(0.0) 0.577215664901533 """
cdef py_zeta(x): """ Return the value of the zeta function at the given value.
The value is expected to be a numerical object, in RR, CC, RDF or CDF, different from 1.
TESTS::
sage: from sage.libs.pynac.pynac import py_zeta_for_doctests as py_zeta sage: py_zeta(CC.0) 0.00330022368532410 - 0.418155449141322*I sage: py_zeta(CDF(5)) 1.03692775514337 sage: py_zeta(RealField(100)(5)) 1.0369277551433699263313654865 """
def py_zeta_for_doctests(x): """ This function is for testing py_zeta().
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_zeta_for_doctests sage: py_zeta_for_doctests(CC.0) 0.00330022368532410 - 0.418155449141322*I """
cdef py_exp(x): """ Return the value of the exp function at the given value.
The value is expected to be a numerical object, in RR, CC, RDF or CDF.
TESTS::
sage: from sage.libs.pynac.pynac import py_exp_for_doctests as py_exp sage: py_exp(CC(1)) 2.71828182845905 sage: py_exp(CC(.5*I)) 0.877582561890373 + 0.479425538604203*I sage: py_exp(float(1)) 2.718281828459045... sage: py_exp(QQbar(I)) 0.540302305868140 + 0.841470984807897*I """ pass
def py_exp_for_doctests(x): """ This function tests py_exp.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_exp_for_doctests sage: py_exp_for_doctests(CC(2)) 7.38905609893065 """
cdef py_log(x): """ Return the value of the log function at the given value.
The value is expected to be a numerical object, in RR, CC, RDF or CDF.
TESTS::
sage: from sage.libs.pynac.pynac import py_log_for_doctests as py_log sage: py_log(CC(e)) 1.00000000000000 sage: py_log(CC.0) 1.57079632679490*I sage: py_log(float(e)) 1.0 sage: py_log(float(0)) -inf sage: py_log(float(-1)) 3.141592653589793j sage: py_log(int(1)) 0.0 sage: py_log(long(1)) 0.0 sage: py_log(int(0)) -inf sage: py_log(long(0)) -inf sage: py_log(complex(0)) -inf sage: py_log(2) 0.693147180559945 """ cdef gsl_complex res cdef double real, imag else: res = gsl_complex_log(gsl_complex_rect(real, imag)) return PyComplex_FromDoubles(res.dat[0], res.dat[1]) try: return RR(x).log() except (TypeError, ValueError): return CC(x).log()
def py_log_for_doctests(x): """ This function tests py_log.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_log_for_doctests sage: py_log_for_doctests(CC(e)) 1.00000000000000 """
cdef py_tan(x): pass except TypeError: return CC(x).tan()
cdef py_asin(x): try: return x.arcsin() except AttributeError: return RR(x).arcsin()
cdef py_acos(x): try: return x.arccos() except AttributeError: return RR(x).arccos()
cdef py_atan(x):
cdef py_atan2(x, y): """ Return the value of the two argument arctan function at the given values.
The values are expected to be numerical objects, for example in RR, CC, RDF or CDF.
Note that the usual call signature of this function has the arguments reversed.
TESTS::
sage: from sage.libs.pynac.pynac import py_atan2_for_doctests as py_atan2 sage: py_atan2(0, 1) 1.57079632679490 sage: py_atan2(0.r, 1.r) 1.5707963267948966 sage: CC100 = ComplexField(100) sage: py_atan2(CC100(0), CC100(1)) 1.5707963267948966192313216916 sage: RR100 = RealField(100) sage: py_atan2(RR100(0), RR100(1)) 1.5707963267948966192313216916
Check that :trac:`21428` is fixed::
sage: plot(real(sqrt(x - 1.*I)), (x,0,1)) Graphics object consisting of 1 graphics primitive
Check that :trac:`22553` is fixed::
sage: arctan2(1.5, -1.300000000000001) 2.284887025407... sage: atan2(2.1000000000000000000000000000000000000, -1.20000000000000000000000000000000) 2.089942441041419571002776071...
Check that :trac:`22877` is fixed::
sage: atan2(CC(I), CC(I+1)) 0.553574358897045 + 0.402359478108525*I sage: atan2(CBF(I), CBF(I+1)) [0.55357435889705 +/- 5.58e-15] + [0.402359478108525 +/- 7.11e-16]*I
Check that :trac:`23776` is fixed and RDF input gives real output::
sage: atan2(RDF(-3), RDF(-1)) -1.8925468811915387 """ else: else: else: return P(pi) else:
def py_atan2_for_doctests(x, y): """ Wrapper function to test py_atan2.
TESTS::
sage: from sage.libs.pynac.pynac import py_atan2_for_doctests sage: py_atan2_for_doctests(0., 1.) 1.57079632679490 """
cdef py_sinh(x):
cdef py_cosh(x): except AttributeError: return RR(x).cosh()
cdef py_tanh(x):
cdef py_asinh(x): try: return x.arcsinh() except AttributeError: pass try: return RR(x).arcsinh() except TypeError: return CC(x).arcsinh()
cdef py_acosh(x): try: return x.arccosh() except AttributeError: pass try: return RR(x).arccosh() except TypeError: return CC(x).arccosh()
cdef py_atanh(x): try: return x.arctanh() except AttributeError: pass try: return RR(x).arctanh() except TypeError: return CC(x).arctanh()
cdef py_lgamma(x): """ Return the value of the principal branch of the log gamma function at the given value.
The value is expected to be a numerical object, in RR, CC, RDF or CDF, or of the Python ``float`` or ``complex`` type.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_lgamma_for_doctests as py_lgamma sage: py_lgamma(4) 1.79175946922805 sage: py_lgamma(4.r) # abs tol 2e-14 1.79175946922805 sage: py_lgamma(4r) # abs tol 2e-14 1.79175946922805 sage: py_lgamma(CC.0) -0.650923199301856 - 1.87243664726243*I sage: py_lgamma(ComplexField(100).0) -0.65092319930185633888521683150 - 1.8724366472624298171188533494*I """
pass
def py_lgamma_for_doctests(x): """ This function tests py_lgamma.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_lgamma_for_doctests sage: py_lgamma_for_doctests(CC(I)) -0.650923199301856 - 1.87243664726243*I """
cdef py_isqrt(x): return Integer(x).isqrt()
cdef py_sqrt(x): # WORRY: What if Integer's sqrt calls symbolic one and we go in circle? except AttributeError as msg: return math.sqrt(float(x))
cdef py_abs(x): return abs(x)
cdef py_mod(x, n): """ Return x mod n. Both x and n are assumed to be integers.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_mod_for_doctests as py_mod sage: py_mod(I.parent(5), 4) 1 sage: py_mod(3, -2) -1 sage: py_mod(3/2, 2) Traceback (most recent call last): ... TypeError: no conversion of this rational to integer
Note: The original code for this function in GiNaC checks if the arguments are integers, and returns 0 otherwise. We omit this check, since all the calls to py_mod are preceded by an integer check. We also raise an error if converting the arguments to integers fails, since silently returning 0 would hide possible misuses of this function.
Regarding the sign of the return value, the CLN reference manual says:
If x and y are both >= 0, mod(x,y) = rem(x,y) >= 0. In general, mod(x,y) has the sign of y or is zero, and rem(x,y) has the sign of x or is zero.
This matches the behavior of the % operator for integers in Sage. """
def py_mod_for_doctests(x, n): """ This function is a python wrapper so py_mod can be tested. The real tests are in the docstring for py_mod.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_mod_for_doctests sage: py_mod_for_doctests(5, 2) 1 """
cdef py_smod(a, b): # Modulus (in symmetric representation). # Equivalent to Maple's mods. # returns a mod b in the range [-iquo(abs(b)-1,2), iquo(abs(b),2)] a = Integer(a); b = Integer(b) b = abs(b) c = a % b if c > b//2: c -= b return c
cdef py_irem(x, n): return Integer(x) % Integer(n)
cdef py_iquo(x, n): return Integer(x)//Integer(n)
cdef py_iquo2(x, n): x = Integer(x); n = Integer(n) try: q = x//n r = x - q*n return q, r except (TypeError, ValueError): return 0, 0
cdef int py_int_length(x) except -1: # Size in binary notation. For integers, this is the smallest n >= 0 such # that -2^n <= x < 2^n. If x > 0, this is the unique n > 0 such that # 2^(n-1) <= x < 2^n. This returns 0 if x is not an integer. return Integer(x).nbits()
cdef py_li(x, n, parent): """ Returns a numerical approximation of polylog(n, x) with precision given by the ``parent`` argument.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_li_for_doctests as py_li sage: py_li(0,2,RR) 0.000000000000000 sage: py_li(-1,2,RR) -0.822467033424113 sage: py_li(0, 1, float) 0.000000000000000 """
def py_li_for_doctests(x, n, parent): """ This function is a python wrapper so py_li can be tested. The real tests are in the docstring for py_li.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_li_for_doctests sage: py_li_for_doctests(0,2,float) 0.000000000000000 """
cdef py_psi(x): """ EXAMPLES::
sage: from sage.libs.pynac.pynac import py_psi_for_doctests as py_psi sage: py_psi(0) Traceback (most recent call last): ... ValueError: polygamma pole sage: py_psi(1) -0.577215664901533 sage: euler_gamma.n() 0.577215664901533 """ prec = (<Element>x)._parent.prec() else:
def py_psi_for_doctests(x): """ This function is a python wrapper so py_psi can be tested. The real tests are in the docstring for py_psi.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_psi_for_doctests sage: py_psi_for_doctests(2) 0.422784335098467 """
cdef py_psi2(n, x): """ EXAMPLES::
sage: from sage.libs.pynac.pynac import py_psi2_for_doctests as py_psi2 sage: py_psi2(2, 1) -2.40411380631919 """ else:
def py_psi2_for_doctests(n, x): """ This function is a python wrapper so py_psi2 can be tested. The real tests are in the docstring for py_psi2.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_psi2_for_doctests sage: py_psi2_for_doctests(1, 2) 0.644934066848226 """
cdef py_li2(x): """ EXAMPLES::
sage: from sage.libs.pynac.pynac import py_li2_for_doctests as py_li2 sage: py_li2(-1.1) -0.890838090262283 """ else: prec = 53
def py_li2_for_doctests(x): """ This function is a python wrapper so py_psi2 can be tested. The real tests are in the docstring for py_psi2.
EXAMPLES::
sage: from sage.libs.pynac.pynac import py_li2_for_doctests sage: py_li2_for_doctests(-1.1) -0.890838090262283 """
################################################################## # Constants ##################################################################
cdef GConstant py_get_constant(const char* name): """ Returns a constant given its name. This is called by constant::unarchive in constant.cpp in Pynac and is used for pickling. """ cdef PynacConstant pc raise RuntimeError else:
cdef py_eval_constant(unsigned serial, kwds):
cdef py_eval_unsigned_infinity(): """ Returns unsigned_infinity. """
def py_eval_unsigned_infinity_for_doctests(): """ This function tests py_eval_unsigned_infinity.
TESTS::
sage: from sage.libs.pynac.pynac import py_eval_unsigned_infinity_for_doctests as py_eval_unsigned_infinity sage: py_eval_unsigned_infinity() Infinity """
cdef py_eval_infinity(): """ Returns positive infinity, i.e., oo. """
def py_eval_infinity_for_doctests(): """ This function tests py_eval_infinity.
TESTS::
sage: from sage.libs.pynac.pynac import py_eval_infinity_for_doctests as py_eval_infinity sage: py_eval_infinity() +Infinity """
cdef py_eval_neg_infinity(): """ Returns minus_infinity. """
def py_eval_neg_infinity_for_doctests(): """ This function tests py_eval_neg_infinity.
TESTS::
sage: from sage.libs.pynac.pynac import py_eval_neg_infinity_for_doctests as py_eval_neg_infinity sage: py_eval_neg_infinity() -Infinity """
################################################################## # Constructors ##################################################################
cdef py_integer_from_long(long x):
cdef py_integer_from_python_obj(x): return Integer(x)
cdef py_integer_from_mpz(mpz_t bigint):
cdef py_rational_from_mpq(mpq_t bigrat):
cdef bint py_is_Integer(x):
cdef bint py_is_Rational(x):
cdef mpz_ptr py_mpz_from_integer(x):
cdef mpq_ptr py_mpq_from_rational(x):
ZERO = ring.SR(0) ONE = ring.SR(1) ONE_HALF = ring.SR(Rational((1,2)))
symbol_table = {'functions':{}} def register_symbol(obj, conversions): """ Add an object to the symbol table, along with how to convert it to other systems such as Maxima, Mathematica, etc. This table is used to convert *from* other systems back to Sage.
INPUT:
- `obj` -- a symbolic object or function.
- `conversions` -- a dictionary of conversions, where the keys are the names of interfaces (e.g., 'maxima'), and the values are the string representation of obj in that system.
EXAMPLES::
sage: sage.libs.pynac.pynac.register_symbol(SR(5),{'maxima':'five'}) sage: SR(maxima_calculus('five')) 5 """ pass symbol_table[system] = system_table = {}
import sage.rings.integer ginac_pyinit_Integer(sage.rings.integer.Integer)
import sage.rings.real_double ginac_pyinit_Float(sage.rings.real_double.RDF)
cdef Element pynac_I I = None
def init_pynac_I(): """ Initialize the numeric I object in pynac. We use the generator of QQ(i).
EXAMPLES::
sage: I I sage: I^2 -1
Note that conversions to real fields will give TypeErrors::
sage: float(I) Traceback (most recent call last): ... TypeError: unable to simplify to float approximation sage: gp(I) I sage: RR(I) Traceback (most recent call last): ... TypeError: unable to convert '1.00000000000000*I' to a real number
We can convert to complex fields::
sage: C = ComplexField(200); C Complex Field with 200 bits of precision sage: C(I) 1.0000000000000000000000000000000000000000000000000000000000*I sage: I._complex_mpfr_field_(ComplexField(53)) 1.00000000000000*I
sage: I._complex_double_(CDF) 1.0*I sage: CDF(I) 1.0*I
sage: z = I + I; z 2*I sage: C(z) 2.0000000000000000000000000000000000000000000000000000000000*I sage: 1e8*I 1.00000000000000e8*I
sage: complex(I) 1j
sage: QQbar(I) I
sage: abs(I) 1
sage: I.minpoly() x^2 + 1 sage: maxima(2*I) 2*%i
TESTS:
sage: repr(I) 'I' sage: latex(I) i
sage: sage.libs.pynac.pynac.init_pynac_I() sage: type(sage.libs.pynac.pynac.I) <type 'sage.symbolic.expression.Expression'> sage: type(sage.libs.pynac.pynac.I.pyobject()) <type 'sage.rings.number_field.number_field_element_quadratic.NumberFieldElement_quadratic'>
Check that :trac:`10064` is fixed::
sage: y = I*I*x / x # so y is the expression -1 sage: y.is_positive() False sage: z = -x / x sage: z.is_positive() False sage: bool(z == y) True """ global pynac_I, I
def init_function_table(): """ Initializes the function pointer table in Pynac. This must be called before Pynac is used; otherwise, there will be segfaults. """
py_funcs.py_gcd = &py_gcd py_funcs.py_lcm = &py_lcm py_funcs.py_real = &py_real py_funcs.py_imag = &py_imag py_funcs.py_numer = &py_numer py_funcs.py_denom = &py_denom
py_funcs.py_is_rational = &py_is_rational py_funcs.py_is_real = &py_is_real py_funcs.py_is_integer = &py_is_integer py_funcs.py_is_equal = &py_is_equal py_funcs.py_is_even = &py_is_even py_funcs.py_is_prime = &py_is_prime py_funcs.py_is_exact = &py_is_exact
py_funcs.py_integer_from_mpz = &py_integer_from_mpz py_funcs.py_rational_from_mpq = &py_rational_from_mpq py_funcs.py_integer_from_long = &py_integer_from_long py_funcs.py_integer_from_python_obj = &py_integer_from_python_obj py_funcs.py_is_Integer = &py_is_Integer py_funcs.py_is_Rational = &py_is_Rational py_funcs.py_mpz_from_integer = &py_mpz_from_integer py_funcs.py_mpq_from_rational = &py_mpq_from_rational
py_funcs.py_float = &py_float
py_funcs.py_factorial = &py_factorial py_funcs.py_doublefactorial = &py_doublefactorial py_funcs.py_fibonacci = &py_fibonacci py_funcs.py_step = &py_step py_funcs.py_bernoulli = &py_bernoulli py_funcs.py_sin = &py_sin py_funcs.py_cos = &py_cos py_funcs.py_stieltjes = &py_stieltjes py_funcs.py_zeta = &py_zeta py_funcs.py_exp = &py_exp py_funcs.py_log = &py_log py_funcs.py_tan = &py_tan py_funcs.py_asin = &py_asin py_funcs.py_acos = &py_acos py_funcs.py_atan = &py_atan py_funcs.py_atan2 = &py_atan2 py_funcs.py_sinh = &py_sinh py_funcs.py_cosh = &py_cosh py_funcs.py_tanh = &py_tanh py_funcs.py_asinh = &py_asinh py_funcs.py_acosh = &py_acosh py_funcs.py_atanh = &py_atanh py_funcs.py_isqrt = &py_isqrt py_funcs.py_sqrt = &py_sqrt py_funcs.py_mod = &py_mod py_funcs.py_smod = &py_smod py_funcs.py_irem = &py_irem py_funcs.py_psi = &py_psi py_funcs.py_psi2 = &py_psi2
py_funcs.py_eval_constant = &py_eval_constant py_funcs.py_eval_unsigned_infinity = &py_eval_unsigned_infinity py_funcs.py_eval_infinity = &py_eval_infinity py_funcs.py_eval_neg_infinity = &py_eval_neg_infinity
py_funcs.py_get_parent_char = &py_get_parent_char
py_funcs.py_latex = &py_latex py_funcs.py_repr = &py_repr
py_funcs.py_dumps = &py_dumps py_funcs.py_loads = &py_loads
py_funcs.exvector_to_PyTuple = &exvector_to_PyTuple py_funcs.pyExpression_to_ex = &pyExpression_to_ex py_funcs.ex_to_pyExpression = &ex_to_pyExpression py_funcs.subs_args_to_PyTuple = &subs_args_to_PyTuple py_funcs.py_print_function = &py_print_function py_funcs.py_latex_function = &py_latex_function py_funcs.py_get_ginac_serial = &py_get_ginac_serial py_funcs.py_get_sfunction_from_serial = &py_get_sfunction_from_serial py_funcs.py_get_serial_from_sfunction = &py_get_serial_from_sfunction py_funcs.py_get_serial_for_new_sfunction = &py_get_serial_for_new_sfunction
py_funcs.py_get_constant = &py_get_constant py_funcs.py_print_fderivative = &py_print_fderivative py_funcs.py_latex_fderivative = &py_latex_fderivative py_funcs.paramset_to_PyTuple = ¶mset_to_PyTuple
init_function_table() init_pynac_I()
set_ginac_fn_serial() |