Пример #1
0
    def length_rational_fraction(self, var='b'):
        r"""
        Return the generating series for the number of lengths with the given boundaries
        """
        from sage.symbolic.ring import SR

        F = SR.one()

        for dart in range(self._total_darts):
            if not self._active_darts[dart]:
                continue
            i = self._dart_to_edge_index[dart]
            j1, j2 = self._edge_cycles[i]
            if j1 == dart:
                continue
            else:
                assert j2 == dart

            f1 = self._dart_to_face_index[j1]
            f2 = self._dart_to_face_index[j2]

            b1 = SR.var('%s%d' %(var, f1))
            b2 = SR.var('%s%d' %(var, f2))

            F *= b1*b2 / (1 - b1*b2)

        return F
Пример #2
0
    def __call__(self, a, b, z, **kwargs):
        """
        Return symbolic hypergeometric function expression.
         
        INPUT:
    
        - ``a`` -- a list or tuple of parameters
        - ``b`` -- a list or tuple of parameters
        - ``z`` -- a number or symbolic expression
    
        EXAMPLES::

            sage: hypergeometric([], [], 1)
            hypergeometric((), (), 1)
            sage: hypergeometric([], [1], 1)
            hypergeometric((), (1,), 1)
            sage: hypergeometric([2, 3], [1], 1)
            hypergeometric((2, 3), (1,), 1)
            sage: hypergeometric([], [], x)
            hypergeometric((), (), x)
            sage: hypergeometric([x], [], x^2)
            hypergeometric((x,), (), x^2)
    
        The only simplification that is done automatically is returning 1
        if ``z`` is 0. For other simplifications use the
        ``simplify_hypergeometric`` method.
        """
        return BuiltinFunction.__call__(self,
                                        SR._force_pyobject(a),
                                        SR._force_pyobject(b),
                                        z, **kwargs)
Пример #3
0
        def fourier_series_sine_coefficient(cls, self, parameters, variable, n,
                                            L):
            r"""
            Returns the n-th Fourier series coefficient of
            `\sin(n\pi x/L)`, `b_n`.

            INPUT:


            -  ``self`` - the function f(x), defined over -L x L

            -  ``n`` - an integer n0

            -  ``L`` - (the period)/2


            OUTPUT:
            `b_n = \frac{1}{L}\int_{-L}^L f(x)\sin(n\pi x/L)dx`

            EXAMPLES::

                sage: f(x) = x^2
                sage: f = piecewise([[(-1,1),f]])
                sage: f.fourier_series_sine_coefficient(2,1)  # L=1, n=2
                0
            """
            from sage.all import sin, pi
            x = SR.var('x')
            result = 0
            for domain, f in parameters:
                for interval in domain:
                    a = interval.lower()
                    b = interval.upper()
                    result += (f * sin(pi * x * n / L) / L).integrate(x, a, b)
            return SR(result).simplify_trig()
Пример #4
0
def mma_free_integrator(expression, v, a=None, b=None):
    """
        sage: from sage.symbolic.integration.external import mma_free_integrator
        sage: mma_free_integrator(sin(x), x) # optional - internet
        -cos(x)
    """
    import urllib, re
    # We need to integrate against x
    vars = [str(x) for x in expression.variables()]
    if any(len(x)>1 for x in vars):
        raise NotImplementedError("Mathematica online integrator can only handle single letter variables.")
    x = SR.var('x')
    if repr(v) != 'x':
        for i in range(ord('a'), ord('z')+1):
            if chr(i) not in vars:
                shadow_x = SR.var(chr(i))
                break
        expression = expression.subs({x:shadow_x}).subs({dvar: x})
    params = urllib.urlencode({'expr': expression._mathematica_init_(), 'random': 'false'})
    page = urllib.urlopen("http://integrals.wolfram.com/index.jsp", params).read()
    page = page[page.index('"inputForm"'):page.index('"outputForm"')]
    page = re.sub("\s", "", page)
    mexpr = re.match(r".*Integrate.*==</em><br/>(.*)</p>", page).groups()[0]
    try:
        ans = SR(mexpr.lower().replace('[', '(').replace(']', ')'))
        if repr(v) != 'x':
            ans = ans.subs({x:v}).subs({shadow_x:x})
        return ans
    except TypeError:
        raise ValueError("Unable to parse: %s" % mexpr)
Пример #5
0
    def _eval_(self, a, z):
        """
        EXAMPLES::

            sage: struve_H(0,0)
            0
            sage: struve_H(pi,0)
            0
            sage: struve_H(-1/2,x)
            sqrt(2)*sqrt(1/(pi*x))*sin(x)
            sage: struve_H(1/2,-1)
            -sqrt(2)*sqrt(-1/pi)*(cos(1) - 1)
            sage: struve_H(1/2,pi)
            2*sqrt(2)/pi
            sage: struve_H(2,x)
            struve_H(2, x)
            sage: struve_H(-3/2,x)
            -bessel_J(3/2, x)
        """
        from sage.symbolic.ring import SR
        if z.is_zero() \
                and (SR(a).is_numeric() or SR(a).is_constant()) \
                and a.real() >= -1:
                return ZZ(0)
        if a == -Integer(1)/2:
            from sage.functions.trig import sin
            return sqrt(2/(pi*z)) * sin(z)
        if a == Integer(1)/2:
            from sage.functions.trig import cos
            return sqrt(2/(pi*z)) * (1-cos(z))
        if a < 0 and not SR(a).is_integer() and SR(2*a).is_integer():
            from sage.rings.rational_field import QQ
            n = (a*(-2) - 1)/2
            return Integer(-1)**n * bessel_J(n+QQ(1)/2, z)
Пример #6
0
def mma_free_integrator(expression, v, a=None, b=None):
    """
        sage: from sage.symbolic.integration.external import mma_free_integrator
        sage: mma_free_integrator(sin(x), x) # optional - internet
        -cos(x)
    """
    import urllib, re
    # We need to integrate against x
    vars = [str(x) for x in expression.variables()]
    if any(len(x) > 1 for x in vars):
        raise NotImplementedError, "Mathematica online integrator can only handle single letter variables."
    x = SR.var('x')
    if repr(v) != 'x':
        for i in range(ord('a'), ord('z') + 1):
            if chr(i) not in vars:
                shadow_x = SR.var(chr(i))
                break
        expression = expression.subs({x: shadow_x}).subs({dvar: x})
    params = urllib.urlencode({
        'expr': expression._mathematica_init_(),
        'random': 'false'
    })
    page = urllib.urlopen("http://integrals.wolfram.com/index.jsp",
                          params).read()
    page = page[page.index('"inputForm"'):page.index('"outputForm"')]
    page = re.sub("\s", "", page)
    mexpr = re.match(r".*Integrate.*==</em><br/>(.*)</p>", page).groups()[0]
    try:
        ans = SR(mexpr.lower().replace('[', '(').replace(']', ')'))
        if repr(v) != 'x':
            ans = ans.subs({x: v}).subs({shadow_x: x})
        return ans
    except TypeError:
        raise ValueError, "Unable to parse: %s" % mexpr
Пример #7
0
    def __call__(self, a, b, z, **kwargs):
        """
        Return symbolic hypergeometric function expression.
         
        INPUT:
    
        - ``a`` -- a list or tuple of parameters
        - ``b`` -- a list or tuple of parameters
        - ``z`` -- a number or symbolic expression
    
        EXAMPLES::

            sage: hypergeometric([], [], 1)
            hypergeometric((), (), 1)
            sage: hypergeometric([], [1], 1)
            hypergeometric((), (1,), 1)
            sage: hypergeometric([2, 3], [1], 1)
            hypergeometric((2, 3), (1,), 1)
            sage: hypergeometric([], [], x)
            hypergeometric((), (), x)
            sage: hypergeometric([x], [], x^2)
            hypergeometric((x,), (), x^2)
    
        The only simplification that is done automatically is returning 1
        if ``z`` is 0. For other simplifications use the
        ``simplify_hypergeometric`` method.
        """
        return BuiltinFunction.__call__(self, SR._force_pyobject(a),
                                        SR._force_pyobject(b), z, **kwargs)
Пример #8
0
    def length_rational_fraction(self, var='b'):
        r"""
        Return the generating series for the number of lengths with the given boundaries
        """
        from sage.symbolic.ring import SR

        F = SR.one()

        for dart in range(self._total_darts):
            if not self._active_darts[dart]:
                continue
            i = self._dart_to_edge_index[dart]
            j1, j2 = self._edge_cycles[i]
            if j1 == dart:
                continue
            else:
                assert j2 == dart

            f1 = self._dart_to_face_index[j1]
            f2 = self._dart_to_face_index[j2]

            b1 = SR.var('%s%d' %(var, f1))
            b2 = SR.var('%s%d' %(var, f2))

            F *= b1*b2 / (1 - b1*b2)

        return F
Пример #9
0
    def _eval_(self, a, z):
        """
        EXAMPLES::

            sage: struve_L(-2,0)
            struve_L(-2, 0)
            sage: struve_L(-1,0)
            0
            sage: struve_L(pi,0)
            0
            sage: struve_L(-1/2,x)
            sqrt(2)*sqrt(1/(pi*x))*sinh(x)
            sage: struve_L(1/2,1)
            sqrt(2)*(cosh(1) - 1)/sqrt(pi)
            sage: struve_L(2,x)
            struve_L(2, x)
            sage: struve_L(-3/2,x)
            -bessel_I(3/2, x)
        """
        from sage.symbolic.ring import SR
        if z.is_zero() \
                and (SR(a).is_numeric() or SR(a).is_constant()) \
                and a.real() >= -1:
                return ZZ(0)
        if a == -Integer(1)/2:
            from sage.functions.hyperbolic import sinh
            return sqrt(2/(pi*z)) * sinh(z)
        if a == Integer(1)/2:
            from sage.functions.hyperbolic import cosh
            return sqrt(2/(pi*z)) * (cosh(z)-1)
        if a < 0 and not SR(a).is_integer() and SR(2*a).is_integer():
            from sage.rings.rational_field import QQ
            n = (a*(-2) - 1)/2
            return Integer(-1)**n * bessel_I(n+QQ(1)/2, z)
Пример #10
0
def max_to_sr(expr):
    r"""
    Convert a Maxima object into a symbolic expression.

    INPUT:

    - ``expr`` - ECL object

    OUTPUT: symbolic expression

    EXAMPLES::

        sage: from sage.interfaces.maxima_lib import maxima_lib, max_to_sr
        sage: f = maxima_lib('f(x)')
        sage: f.ecl()
        <ECL: (($F SIMP) $X)>
        sage: max_to_sr(f.ecl())
        f(x)

    TESTS::

        sage: from sage.interfaces.maxima_lib import sr_to_max, max_to_sr
        sage: f = function('f',x).diff()
        sage: bool(max_to_sr(sr_to_max(f)) == f)
        True
    """
    if expr.consp():
        op_max=caar(expr)
        if op_max in special_max_to_sage:
            return special_max_to_sage[op_max](expr)
        if not(op_max in max_op_dict):
            op_max_str=maxprint(op_max).python()[1:-1]
            if op_max_str in max_to_pynac_table:
                op = max_to_pynac_table[op_max_str]
            else:
                # This could be unsafe if the conversion to SR
                # changes the structure of expr
                sage_expr=SR(maxima(expr))
                op=sage_expr.operator()
            if op in sage_op_dict:
                raise RuntimeError("Encountered operator mismatch in maxima-to-sr translation")
            max_op_dict[op_max]=op
            sage_op_dict[op]=op_max
        else:
            op=max_op_dict[op_max]
        max_args=cdr(expr)
        args=[max_to_sr(a) for a in max_args]
        return op(*args)
    elif expr.symbolp():
        if not(expr in max_sym_dict):
            sage_symbol=SR(maxima(expr))
            sage_sym_dict[sage_symbol]=expr
            max_sym_dict[expr]=sage_symbol
        return max_sym_dict[expr]
    else:
        e=expr.python()
        if isinstance(e,float):
            return sage.rings.real_double.RealDoubleElement(e)
        return e
Пример #11
0
 def test_issue_4023():
     from sage.symbolic.ring import SR
     from sage.functions.all import log
     from sympy import integrate, simplify
     a, x = SR.var("a x")
     i = integrate(log(x) / a, (x, a, a + 1))
     i2 = simplify(i)
     s = SR(i2)
     assert s == (a * log(1 + a) - a * log(a) + log(1 + a) - 1) / a
Пример #12
0
def fricas_integrator(expression, v, a=None, b=None, noPole=True):
    """
    Integration using FriCAS

    EXAMPLES::

        sage: from sage.symbolic.integration.external import fricas_integrator  # optional - fricas
        sage: fricas_integrator(sin(x), x)                                      # optional - fricas
        -cos(x)
        sage: fricas_integrator(cos(x), x)                                      # optional - fricas
        sin(x)
        sage: fricas_integrator(1/(x^2-2), x, 0, 1)                             # optional - fricas
        1/4*sqrt(2)*(log(3*sqrt(2) - 4) - log(sqrt(2)))
        sage: fricas_integrator(1/(x^2+6), x, -oo, oo)                          # optional - fricas
        1/6*sqrt(6)*pi

    TESTS:

    Check that :trac:`25220` is fixed::

        sage: integral(sqrt(1-cos(x)), x, 0, 2*pi, algorithm="fricas")          # optional - fricas
        4*sqrt(2)

    Check that in case of failure one gets unevaluated integral::

        sage: integral(cos(ln(cos(x))), x, 0, pi/8, algorithm='fricas')   # optional - fricas
        integrate(cos(log(cos(x))), x, 0, 1/8*pi)
        sage: integral(cos(ln(cos(x))), x, algorithm='fricas')   # optional - fricas
        integral(cos(log(cos(x))), x)
    """
    if not isinstance(expression, Expression):
        expression = SR(expression)

    from sage.interfaces.fricas import fricas
    ex = fricas(expression)

    if a is None:
        result = ex.integrate(v)
    else:
        seg = fricas.equation(v, fricas.segment(a, b))

        if noPole:
            result = ex.integrate(seg, '"noPole"')
        else:
            result = ex.integrate(seg)

    result = result.sage()

    if result == "failed":
        return expression.integrate(v, a, b, hold=True)

    if result == "potentialPole":
        raise ValueError("The integrand has a potential pole"
                         " in the integration interval")

    return result
Пример #13
0
        def laplace(cls, self, parameters, variable, x='x', s='t'):
            r"""
            Returns the Laplace transform of self with respect to the variable
            var.

            INPUT:

            -  ``x`` - variable of self

            -  ``s`` - variable of Laplace transform.

            We assume that a piecewise function is 0 outside of its domain and
            that the left-most endpoint of the domain is 0.

            EXAMPLES::

                sage: x, s, w = var('x, s, w')
                sage: f = piecewise([[(0,1),1],[[1,2], 1-x]])
                sage: f.laplace(x, s)
                -e^(-s)/s + (s + 1)*e^(-2*s)/s^2 + 1/s - e^(-s)/s^2
                sage: f.laplace(x, w)
                -e^(-w)/w + (w + 1)*e^(-2*w)/w^2 + 1/w - e^(-w)/w^2

            ::

                sage: y, t = var('y, t')
                sage: f = piecewise([[[1,2], 1-y]])
                sage: f.laplace(y, t)
                (t + 1)*e^(-2*t)/t^2 - e^(-t)/t^2

            ::

                sage: s = var('s')
                sage: t = var('t')
                sage: f1(t) = -t
                sage: f2(t) = 2
                sage: f = piecewise([[[0,1],f1],[(1,infinity),f2]])
                sage: f.laplace(t,s)
                (s + 1)*e^(-s)/s^2 + 2*e^(-s)/s - 1/s^2
            """
            from sage.all import assume, exp, forget
            x = SR.var(x)
            s = SR.var(s)
            assume(s>0)
            result = 0
            for domain, f in parameters:
                for interval in domain:
                    a = interval.lower()
                    b = interval.upper()
                    result += (SR(f)*exp(-s*x)).integral(x,a,b)
            forget(s>0)
            return result
Пример #14
0
def _step_upper_bound_low_mem(r, m, q, generating_function):
    r"""
    Low memory implementation of :func:`_step_upper_bound_internal`.

    Significantly slower, but the memory footprint does not significantly
    increase even if the series coefficients need to be computed to very high
    degree terms.
    """
    L = LieAlgebra(ZZ, ['X_%d' % k for k in range(r)]).Lyndon()
    dim_fm = L.graded_dimension(m)

    PR = PolynomialRing(ZZ, 't')
    t = PR.gen()
    a = (1 - dim_fm * (1 - t**q)) * t**m
    b = PR.one()
    for k in range(1, m):
        b *= (1 - t**k)**L.graded_dimension(k)

    # extract initial coefficients from a symbolic series expansion
    bd = b.degree()
    id = max(a.degree() + 1, bd)
    offset = id - bd
    quot = SR(a / b)
    sym_t = SR(t)
    qs = quot.series(sym_t, id)

    # check if partial sum is positive already within series expansion
    # store the last offset...id terms to start the linear recurrence
    coeffs = deque()
    cumul = ZZ.zero()
    for s in range(id):
        c = ZZ(qs.coefficient(sym_t, s))
        cumul += c
        if s >= offset:
            coeffs.append(c)
        if cumul > 0:
            if generating_function:
                return s, quot
            return s

    # the rest of the coefficients are defined by a recurrence relation
    multipliers = [-b.monomial_coefficient(t**(bd - k)) for k in range(bd)]
    while cumul <= 0:
        c_next = sum(c * m for c, m in zip(coeffs, multipliers))
        cumul += c_next
        s += 1
        coeffs.append(c_next)
        coeffs.popleft()

    if generating_function:
        return s, quot
    return s
Пример #15
0
        def laplace(cls, self, parameters, variable, x='x', s='t'):
            r"""
            Returns the Laplace transform of self with respect to the variable
            var.

            INPUT:

            -  ``x`` - variable of self

            -  ``s`` - variable of Laplace transform.

            We assume that a piecewise function is 0 outside of its domain and
            that the left-most endpoint of the domain is 0.

            EXAMPLES::

                sage: x, s, w = var('x, s, w')
                sage: f = piecewise([[(0,1),1],[[1,2], 1-x]])
                sage: f.laplace(x, s)
                -e^(-s)/s + (s + 1)*e^(-2*s)/s^2 + 1/s - e^(-s)/s^2
                sage: f.laplace(x, w)
                -e^(-w)/w + (w + 1)*e^(-2*w)/w^2 + 1/w - e^(-w)/w^2

            ::

                sage: y, t = var('y, t')
                sage: f = piecewise([[[1,2], 1-y]])
                sage: f.laplace(y, t)
                (t + 1)*e^(-2*t)/t^2 - e^(-t)/t^2

            ::

                sage: s = var('s')
                sage: t = var('t')
                sage: f1(t) = -t
                sage: f2(t) = 2
                sage: f = piecewise([[[0,1],f1],[(1,infinity),f2]])
                sage: f.laplace(t,s)
                (s + 1)*e^(-s)/s^2 + 2*e^(-s)/s - 1/s^2
            """
            from sage.all import assume, exp, forget
            x = SR.var(x)
            s = SR.var(s)
            assume(s > 0)
            result = 0
            for domain, f in parameters:
                for interval in domain:
                    a = interval.lower()
                    b = interval.upper()
                    result += (SR(f) * exp(-s * x)).integral(x, a, b)
            forget(s > 0)
            return result
Пример #16
0
def simplify_abs_trig(expr):
    r"""
    Simplify abs(sin(...)) in symbolic expressions
    """
    from sage.symbolic.ring import SR
    from sage.symbolic.constants import pi
    sexpr = str(expr)
    if 'abs(sin(' not in sexpr:  # nothing to simplify
        return expr
    tp = []
    val = []
    for pos in range(len(sexpr)):
        if sexpr[pos:pos + 8] == 'abs(sin(':
            # finding the end of abs argument:
            scan = pos + 4  # start of abs
            parenth = 1
            while parenth != 0:
                if sexpr[scan] == '(': parenth += 1
                if sexpr[scan] == ')': parenth -= 1
                scan += 1
            pos_abs_end = scan
            # finding the end of sin argument:
            scan = pos + 8  # start of sin
            parenth = 1
            while parenth != 0:
                if sexpr[scan] == '(': parenth += 1
                if sexpr[scan] == ')': parenth -= 1
                scan += 1
            pos_sin_end = scan
            # if the abs contains only the sinus, the simplification can be tried:
            if pos_sin_end == pos_abs_end - 1:
                tp.append(pos)
                val.append(sexpr[pos:pos_abs_end])
    simp = []
    for v in val:
        # argument of the sinus:
        sx = v[8:-2]
        x = SR(sx)
        if x >= 0 and x <= pi:
            simp.append('sin(' + sx + ')')
        elif x >= -pi and x <= 0:
            simp.append('(-sin(' + sx + '))')
        else:
            simp.append(v)  # no simplification is applicable
    nexpr = ""
    pos0 = 0
    for i, pos in enumerate(tp):
        nexpr += sexpr[pos0:pos] + simp[i]
        pos0 = pos + len(val[i])
    nexpr += sexpr[pos0:]
    return SR(nexpr)
Пример #17
0
def max_to_sr(expr):
    r"""
    Convert a Maxima object into a symbolic expression.

    INPUT:

    - ``expr`` - ECL object

    OUTPUT: symbolic expression

    EXAMPLES::

        sage: from sage.interfaces.maxima_lib import maxima_lib, max_to_sr
        sage: f = maxima_lib('f(x)')
        sage: f.ecl()
        <ECL: (($F SIMP) $X)>
        sage: max_to_sr(f.ecl())
        f(x)

    TESTS::

        sage: from sage.interfaces.maxima_lib import sr_to_max, max_to_sr
        sage: f = function('f',x).diff()
        sage: bool(max_to_sr(sr_to_max(f)) == f)
        True
    """
    if expr.consp():
        op_max=caar(expr)
        if op_max in special_max_to_sage:
            return special_max_to_sage[op_max](expr)
        if not(op_max in max_op_dict):
            # This could be unsafe if the conversion to SR
            # changes the structure of expr
            sage_expr=SR(maxima(expr))
            max_op_dict[op_max]=sage_expr.operator()
            sage_op_dict[sage_expr.operator()]=op_max
        op=max_op_dict[op_max]
        max_args=cdr(expr)
        args=[max_to_sr(a) for a in max_args]
        return op(*args)
    elif expr.symbolp():
        if not(expr in max_sym_dict):
            sage_symbol=SR(maxima(expr))
            sage_sym_dict[sage_symbol]=expr
            max_sym_dict[expr]=sage_symbol
        return max_sym_dict[expr]
    else:
        e=expr.python()
        if isinstance(e,float):
            return sage.rings.real_double.RealDoubleElement(e)
        return e
Пример #18
0
def simplify_sqrt_real(expr):
    r"""
    Simplify sqrt in symbolic expressions in the real domain.
    
    EXAMPLES:
    
    Simplifications of basic expressions::
    
        sage: assume(x<0)      
        sage: simplify_sqrt_real( sqrt(x^2) )
        -x
        sage: simplify_sqrt_real( sqrt(x^2-2*x+1) )
        -x + 1
        sage: simplify_sqrt_real( sqrt(x^2) + sqrt(x^2-2*x+1) )
        -2*x + 1

    """
    from sage.symbolic.ring import SR
    from sage.calculus.calculus import maxima
    # 1/ Search for the sqrt's in expr
    sexpr = str(expr)
    if 'sqrt(' not in sexpr:  # no sqrt to simplify
        return expr
    pos_sqrts = []  # positions of the sqrt's in sexpr
    the_sqrts = []  # the sqrt sub-expressions in sexpr
    for pos in range(len(sexpr)):
        if sexpr[pos:pos + 5] == 'sqrt(':
            pos_sqrts.append(pos)
            parenth = 1
            scan = pos + 5
            while parenth != 0:
                if sexpr[scan] == '(': parenth += 1
                if sexpr[scan] == ')': parenth -= 1
                scan += 1
            the_sqrts.append(sexpr[pos:scan])
    # 2/ Simplifications of the sqrt's
    new_expr = ""  # will contain the result
    pos0 = 0
    for i, pos in enumerate(pos_sqrts):
        # radcan is called on each sqrt:
        x = SR(the_sqrts[i])
        simpl = SR(x._maxima_().radcan())
        # the absolute value of radcan's output is taken, the call to simplify()
        # taking into account possible assumptions regarding the sign of simpl:
        new_expr += sexpr[pos0:pos] + '(' + str(abs(simpl).simplify()) + ')'
        pos0 = pos + len(the_sqrts[i])
    new_expr += sexpr[pos0:]
    return SR(new_expr)
    def weight_integrand(self, simplify_factor=True):
        """
        Weight integrand as a rational function.

        The Jacobian determinant of some coordinate transformation.
        """
        def arg(x, y):
            return arctan(y / x)  # up to a constant, but it doesn't matter

        def phi(x, y, a, b):
            z = (a + I * b - x - I * y) * (a - I * b - x - I * y)
            w = z.real()
            q = z.imag()
            return arg(w, q).full_simplify()

        n = len(self.internal_vertices())
        coordinates = lambda v: SR.var(chr(97+2*(v-1)) + ',' + chr(97+2*(v-1)+1)) \
                                if v in self.internal_vertices() else \
                                [(0,0), (1,0)][self.ground_vertices().index(v)]
        internal_coordinates = sum(
            (list(coordinates(v)) for v in sorted(self.internal_vertices())),
            [])
        U = CoordinatePatch(internal_coordinates)
        F = DifferentialForms(U)
        psi = 0
        two_forms = []
        for v in self.internal_vertices():
            x, y = coordinates(v)
            outgoing_edges = self.outgoing_edges([v])
            left_target = filter(lambda (x, y, z): z == 'L',
                                 outgoing_edges)[0][1]
            right_target = filter(lambda (x, y, z): z == 'R',
                                  outgoing_edges)[0][1]
            one_forms = []
            for target in [left_target, right_target]:
                a, b = coordinates(target)
                one_form = DifferentialForm(F, 1)
                for v in internal_coordinates:
                    index = internal_coordinates.index(v)
                    one_form[index] = phi(x, y, a, b).diff(v)
                    if simplify_factor:
                        one_form[index] = SR(one_form[index]).full_simplify()
                one_forms.append(one_form)
            two_form = one_forms[0] * one_forms[1]
            two_forms.append(two_form)
        import operator
        two_n_form = reduce(operator.mul, two_forms, 1)
        return two_n_form[range(0, 2 * n)]
Пример #20
0
def simplify_sqrt_real(expr):
    r"""
    Simplify sqrt in symbolic expressions in the real domain.
    
    EXAMPLES:
    
    Simplifications of basic expressions::
    
        sage: assume(x<0)      
        sage: simplify_sqrt_real( sqrt(x^2) )
        -x
        sage: simplify_sqrt_real( sqrt(x^2-2*x+1) )
        -x + 1
        sage: simplify_sqrt_real( sqrt(x^2) + sqrt(x^2-2*x+1) )
        -2*x + 1

    """
    from sage.symbolic.ring import SR
    from sage.calculus.calculus import maxima
    # 1/ Search for the sqrt's in expr
    sexpr = str(expr)
    if 'sqrt(' not in sexpr:  # no sqrt to simplify
        return expr
    pos_sqrts = []   # positions of the sqrt's in sexpr
    the_sqrts = []   # the sqrt sub-expressions in sexpr
    for pos in range(len(sexpr)):
        if sexpr[pos:pos+5] == 'sqrt(':
            pos_sqrts.append(pos)
            parenth = 1
            scan = pos+5
            while parenth != 0:
                if sexpr[scan] == '(': parenth += 1
                if sexpr[scan] == ')': parenth -= 1
                scan += 1 
            the_sqrts.append( sexpr[pos:scan] )
    # 2/ Simplifications of the sqrt's
    new_expr = ""    # will contain the result
    pos0 = 0
    for i, pos in enumerate(pos_sqrts):
        # radcan is called on each sqrt:
        x = SR(the_sqrts[i])
        simpl = SR(x._maxima_().radcan())
        # the absolute value of radcan's output is taken, the call to simplify() 
        # taking into account possible assumptions regarding the sign of simpl:
        new_expr += sexpr[pos0:pos] + '(' + str(abs(simpl).simplify()) + ')'
        pos0 = pos + len(the_sqrts[i])
    new_expr += sexpr[pos0:]
    return SR(new_expr)
Пример #21
0
def _sympysage_symbol(self):
    """
    EXAMPLES::

        sage: from sympy import Symbol
        sage: assert x._sympy_() == Symbol('x')
        sage: assert x == Symbol('x')._sage_()
    """
    from sage.symbolic.ring import SR
    try:
        return SR.var(self.name)
    except ValueError:
        # sympy sometimes returns dummy variables
        # with name = 'None', str rep = '_None'
        # in particular in inverse Laplace and inverse Mellin transforms
        return SR.var(str(self))
Пример #22
0
        def fourier_series_sine_coefficient(cls, self, parameters, variable, n, L):
            r"""
            Returns the n-th Fourier series coefficient of
            `\sin(n\pi x/L)`, `b_n`.

            INPUT:


            -  ``self`` - the function f(x), defined over -L x L

            -  ``n`` - an integer n0

            -  ``L`` - (the period)/2


            OUTPUT:
            `b_n = \frac{1}{L}\int_{-L}^L f(x)\sin(n\pi x/L)dx`

            EXAMPLES::

                sage: f(x) = x^2
                sage: f = piecewise([[(-1,1),f]])
                sage: f.fourier_series_sine_coefficient(2,1)  # L=1, n=2
                0
            """
            from sage.all import sin, pi
            x = SR.var('x')
            result = 0
            for domain, f in parameters:
                for interval in domain:
                    a = interval.lower()
                    b = interval.upper()
                    result += (f*sin(pi*x*n/L)/L).integrate(x, a, b)
            return SR(result).simplify_trig()
Пример #23
0
 def __init__(self,
              ambient_manifold,
              n,
              coordinates,
              chart_name,
              embedding_functions,
              name=None,
              latex_name=None,
              ambient_chart=None,
              start_index=0):
     from sage.symbolic.ring import SR
     Manifold.__init__(self, n, name, latex_name, start_index)
     if not isinstance(ambient_manifold, Manifold):
         raise TypeError(
             "The argument ambient_manifold must be a manifold.")
     self.ambient_manifold = ambient_manifold
     Chart(self, coordinates, chart_name)
     if ambient_chart is None:
         ambient_chart = ambient_manifold.def_chart.name
     n_amb = ambient_manifold.dim
     if len(embedding_functions) != n_amb:
         raise ValueError(
             str(n_amb) + " coordinate functions must be provided.")
     embedding_expressions = [
         SR(embedding_functions[i]) for i in range(n_amb)
     ]
     self.embedding = DiffMapping(self, ambient_manifold,
                                  embedding_expressions, chart_name,
                                  ambient_chart)
Пример #24
0
    def show(self, show_hyperboloid=True, **graphics_options):
        r"""
        Plot ``self``.

        EXAMPLES::

            sage: from sage.geometry.hyperbolic_space.hyperbolic_geodesic import *
            sage: g = HyperbolicPlane().HM().random_geodesic()
            sage: g.show()
            Graphics3d Object
        """
        x = SR.var('x')
        opts = self.graphics_options()
        opts.update(graphics_options)
        v1, u2 = [vector(k.coordinates()) for k in self.endpoints()]
        # Lorentzian Gram Shmidt.  The original vectors will be
        # u1, u2 and the orthogonal ones will be v1, v2.  Except
        # v1 = u1, and I don't want to declare another variable,
        # hence the odd naming convention above.
        # We need the Lorentz dot product of v1 and u2.
        v1_ldot_u2 = u2[0]*v1[0] + u2[1]*v1[1] - u2[2]*v1[2]
        v2 = u2 + v1_ldot_u2 * v1
        v2_norm = sqrt(v2[0]**2 + v2[1]**2 - v2[2]**2)
        v2 = v2 / v2_norm
        v2_ldot_u2 = u2[0]*v2[0] + u2[1]*v2[1] - u2[2]*v2[2]
        # Now v1 and v2 are Lorentz orthogonal, and |v1| = -1, |v2|=1
        # That is, v1 is unit timelike and v2 is unit spacelike.
        # This means that cosh(x)*v1 + sinh(x)*v2 is unit timelike.
        hyperbola = cosh(x)*v1 + sinh(x)*v2
        endtime = arcsinh(v2_ldot_u2)
        from sage.plot.plot3d.all import parametric_plot3d
        pic = parametric_plot3d(hyperbola, (x, 0, endtime), **graphics_options)
        if show_hyperboloid:
            pic += self._model.get_background_graphic()
        return pic
Пример #25
0
    def show(self, show_hyperboloid=True, **graphics_options):
        r"""
        Plot ``self``.

        EXAMPLES::

            sage: from sage.geometry.hyperbolic_space.hyperbolic_geodesic import *
            sage: g = HyperbolicPlane().HM().random_geodesic()
            sage: g.show()
            Graphics3d Object
        """
        x = SR.var('x')
        opts = self.graphics_options()
        opts.update(graphics_options)
        v1, u2 = [vector(k.coordinates()) for k in self.endpoints()]
        # Lorentzian Gram Shmidt.  The original vectors will be
        # u1, u2 and the orthogonal ones will be v1, v2.  Except
        # v1 = u1, and I don't want to declare another variable,
        # hence the odd naming convention above.
        # We need the Lorentz dot product of v1 and u2.
        v1_ldot_u2 = u2[0] * v1[0] + u2[1] * v1[1] - u2[2] * v1[2]
        v2 = u2 + v1_ldot_u2 * v1
        v2_norm = sqrt(v2[0]**2 + v2[1]**2 - v2[2]**2)
        v2 = v2 / v2_norm
        v2_ldot_u2 = u2[0] * v2[0] + u2[1] * v2[1] - u2[2] * v2[2]
        # Now v1 and v2 are Lorentz orthogonal, and |v1| = -1, |v2|=1
        # That is, v1 is unit timelike and v2 is unit spacelike.
        # This means that cosh(x)*v1 + sinh(x)*v2 is unit timelike.
        hyperbola = cosh(x) * v1 + sinh(x) * v2
        endtime = arcsinh(v2_ldot_u2)
        from sage.plot.plot3d.all import parametric_plot3d
        pic = parametric_plot3d(hyperbola, (x, 0, endtime), **graphics_options)
        if show_hyperboloid:
            pic += self._model.get_background_graphic()
        return pic
Пример #26
0
def random_expr(size,
                nvars=1,
                ncoeffs=None,
                var_frac=0.5,
                internal=full_internal,
                nullary=full_nullary,
                nullary_frac=0.2,
                coeff_generator=QQ.random_element,
                verbose=False):
    r"""
    Produce a random symbolic expression of the given size.  By
    default, the expression involves (at most) one variable, an arbitrary
    number of coefficients, and all of the symbolic functions and constants
    (from the probability lists full_internal and full_nullary).  It is
    possible to adjust the ratio of leaves between symbolic constants,
    variables, and coefficients (var_frac gives the fraction of variables,
    and nullary_frac the fraction of symbolic constants; the remaining
    leaves are coefficients).

    The actual mix of symbolic constants and internal nodes can be modified
    by specifying different probability lists.

    To use a different type for coefficients, you can specify
    coeff_generator, which should be a function that will return
    a random coefficient every time it is called.

    This function will often raise an error because it tries to create
    an erroneous expression (such as a division by zero).

    EXAMPLES::

        sage: from sage.symbolic.random_tests import *
        sage: some_functions = [arcsinh, arctan, arctan2, arctanh,
        ....: arg, beta, binomial, ceil, conjugate, cos, cosh, cot, coth,
        ....: elliptic_pi, erf, exp, factorial, floor, heaviside, imag_part,
        ....: sech, sgn, sin, sinh, tan, tanh, unit_step, zeta, zetaderiv]
        sage: my_internal = [(0.6, full_binary, 2), (0.2, full_unary, 1),
        ....: (0.2, [(1.0,f,f.number_of_arguments()) for f in some_functions])]
        sage: set_random_seed(1)
        sage: random_expr(50, nvars=3, internal=my_internal,
        ....:   coeff_generator=CDF.random_element)  # not tested  # known bug
        (v1^(0.9713408427702117 + 0.195868299334218*I)/cot(-pi + v1^2 + v3) + tan(arctan(v2 + arctan2(-0.35859061674557324 + 0.9407509502498164*I, v3) - 0.8419115504372718 + 0.30375717982404615*I) + arctan2((0.2275357305882964 - 0.8258002386106038*I)/factorial(v2), -v3 - 0.7604559947718565 - 0.5543672548552057*I) + ceil(1/arctan2(v1, v1))))/v2
        sage: random_expr(5, verbose=True)  # not tested  # known bug
        About to apply <built-in function inv> to [31]
        About to apply sgn to [v1]
        About to apply <built-in function add> to [1/31, sgn(v1)]
        sgn(v1) + 1/31

    """
    vars = [(1.0, SR.var('v%d' % (n + 1))) for n in range(nvars)]
    if ncoeffs is None:
        ncoeffs = size
    coeffs = [(1.0, coeff_generator()) for _ in range(ncoeffs)]
    leaves = [(var_frac, vars), (1.0 - var_frac - nullary_frac, coeffs),
              (nullary_frac, nullary)]
    leaves = normalize_prob_list(leaves)

    internal = normalize_prob_list(internal)

    return random_expr_helper(size, internal, leaves, verbose)
    def __setitem__(self, subscript, fun):
        r"""
        Modify a given component of the differential form.

        INPUT:

        - ``subscript``: subscript of the component.  Must be an integer or a list of integers.

        EXAMPLES::

            sage: F = DifferentialForms(); F
            Algebra of differential forms in the variables x, y, z
            sage: f = DifferentialForm(F, 2)
            sage: f[1, 2] = x; f
            x*dy/\dz
        """

        if isinstance(subscript, (Integer, int)):
            subscript = (subscript, )
        else:
            subscript = tuple(subscript)

        dim = self.parent().base_space().dim()
        if any([s >= dim for s in subscript]):
            raise ValueError("Index out of bounds.")

        if len(subscript) != self._degree:
            raise TypeError("%s is not a subscript of degree %s" %\
                (subscript, self._degree))

        sign, subscript = sort_subscript(subscript)
        self._components[subscript] = sign * SR(fun)
Пример #28
0
        def fourier_series_partial_sum(cls, self, parameters, variable, N, L):
            r"""
            Returns the partial sum

            .. math::

               f(x) \sim \frac{a_0}{2} + \sum_{n=1}^N [a_n\cos(\frac{n\pi x}{L}) + b_n\sin(\frac{n\pi x}{L})],

            as a string.

            EXAMPLE::

                sage: f(x) = x^2
                sage: f = piecewise([[(-1,1),f]])
                sage: f.fourier_series_partial_sum(3,1)
                cos(2*pi*x)/pi^2 - 4*cos(pi*x)/pi^2 + 1/3
                sage: f1(x) = -1
                sage: f2(x) = 2
                sage: f = piecewise([[(-pi,pi/2),f1],[(pi/2,pi),f2]])
                sage: f.fourier_series_partial_sum(3,pi)
                -3*cos(x)/pi - 3*sin(2*x)/pi + 3*sin(x)/pi - 1/4
            """
            from sage.all import pi, sin, cos, srange
            x = self.default_variable()
            a0 = self.fourier_series_cosine_coefficient(0, L)
            result = a0 / 2 + sum(
                [(self.fourier_series_cosine_coefficient(n, L) *
                  cos(n * pi * x / L) + self.fourier_series_sine_coefficient(
                      n, L) * sin(n * pi * x / L)) for n in srange(1, N)])
            return SR(result).expand()
Пример #29
0
def max_at_to_sage(expr):
    r"""
    Special conversion rule for AT expressions.

    INPUT:

    - ``expr`` - ECL object; a Maxima AT expression

    OUTPUT: symbolic expression

    EXAMPLES::

        sage: from sage.interfaces.maxima_lib import maxima_lib, max_at_to_sage
        sage: a=maxima_lib("'at(f(x,y,z),[x=1,y=2,z=3])")
        sage: a
        'at(f(x,y,z),[x=1,y=2,z=3])
        sage: max_at_to_sage(a.ecl())
        f(1, 2, 3)
        sage: a=maxima_lib("'at(f(x,y,z),x=1)")
        sage: a
        'at(f(x,y,z),x=1)
        sage: max_at_to_sage(a.ecl())
        f(1, y, z)
    """
    arg=max_to_sr(expr.cadr())
    subsarg=caddr(expr)
    if caar(subsarg)==mlist:
        subsvalues=dict( (v.lhs(),v.rhs()) for v in max_to_sr(subsarg))
    else:
        v=max_to_sr(subsarg)
        subsvalues=dict([(v.lhs(),v.rhs())])
    return SR(arg).subs(subsvalues)
Пример #30
0
 def check_splittingField(self):
     """
     Verify that the splitting field of a Q-polynomial scheme
     with principal multiplicity more than 2
     is at most a degree 2 extension of the field of rational numbers.
     """
     if checkNonneg(2 - self._.m[1]):
         return
     if self._has("Q"):
         M = self._.Q
     elif self._has("P"):
         M = self._.P
     else:
         M = self.dualEigenmatrix()
     t = None
     for r in M[1:, 1:]:
         for v in r:
             if len(SR(v).variables()) > 0:
                 continue
             mp = v.minpoly()
             if mp.degree() == 1:
                 continue
             elif mp.degree() == 2:
                 if t is None:
                     t = QQ.extension(mp, 'a')['t'].gen()
                     continue
                 elif not mp(t).is_irreducible():
                     continue
             raise InfeasibleError("splitting field of Q-polynomial scheme"
                                   " with m[1] > 2 is more than degree 2"
                                   " extension of rationals",
                                   ["CerzoSuzuki09", "MartinWilliford09"])
Пример #31
0
def spin_polynomial(part, weight, length):
    """
    Returns the spin polynomial associated to ``part``, ``weight``, and
    ``length``.

    EXAMPLES::

        sage: from sage.combinat.ribbon_tableau import spin_polynomial
        sage: spin_polynomial([6,6,6],[4,2],3)
        t^6 + t^5 + 2*t^4 + t^3 + t^2
        sage: spin_polynomial([6,6,6],[4,1,1],3)
        t^6 + 2*t^5 + 3*t^4 + 2*t^3 + t^2
        sage: spin_polynomial([3,3,3,2,1], [2,2], 3)
        t^(7/2) + t^(5/2)
        sage: spin_polynomial([3,3,3,2,1], [2,1,1], 3)
        2*t^(7/2) + 2*t^(5/2) + t^(3/2)
        sage: spin_polynomial([3,3,3,2,1], [1,1,1,1], 3)
        3*t^(7/2) + 5*t^(5/2) + 3*t^(3/2) + sqrt(t)
        sage: spin_polynomial([5,4,3,2,1,1,1], [2,2,1], 3)
        2*t^(9/2) + 6*t^(7/2) + 2*t^(5/2)
        sage: spin_polynomial([[6]*6, [3,3]], [4,4,2], 3)
        3*t^9 + 5*t^8 + 9*t^7 + 6*t^6 + 3*t^5
    """
    from sage.symbolic.ring import SR
    sp = spin_polynomial_square(part, weight, length)
    t = SR.var('t')
    c = sp.coefficients(sparse=False)
    return sum([c[i] * t**(QQ(i) / 2) for i in range(len(c))])
Пример #32
0
    def bilinear_form(self, R=None):
        """
        Return the bilinear form over ``R`` associated to ``self``.

        INPUT:

        - ``R`` -- (default: universal cyclotomic field) a ring used to
          compute the bilinear form

        EXAMPLES::

            sage: CoxeterType(['A', 2, 1]).bilinear_form()
            [   1 -1/2 -1/2]
            [-1/2    1 -1/2]
            [-1/2 -1/2    1]
            sage: CoxeterType(['H', 3]).bilinear_form()
            [                      1                    -1/2                       0]
            [                   -1/2                       1 1/2*E(5)^2 + 1/2*E(5)^3]
            [                      0 1/2*E(5)^2 + 1/2*E(5)^3                       1]
            sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]])
            sage: C.bilinear_form()
            [ 1 -1 -1]
            [-1  1 -1]
            [-1 -1  1]
        """

        n = self.rank()
        mat = self.coxeter_matrix()._matrix
        base_ring = mat.base_ring()

        from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField
        UCF = UniversalCyclotomicField()

        if R is None:
            R = UCF
        # if UCF.has_coerce_map_from(base_ring):
        #     R = UCF
        # else:
        #     R = base_ring

        # Compute the matrix with entries `- \cos( \pi / m_{ij} )`.
        if R is UCF:
            val = lambda x: (R.gen(2 * x) + ~R.gen(2 * x)) / R(
                -2) if x > -1 else R.one() * x
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi
            val = lambda x: -R(cos(pi / SR(x))) if x > -1 else x

        MS = MatrixSpace(R, n, sparse=True)
        MC = MS._get_matrix_class()

        bilinear = MC(MS,
                      entries={(i, j): val(mat[i, j])
                               for i in range(n) for j in range(n)
                               if mat[i, j] != 2},
                      coerce=True,
                      copy=True)
        bilinear.set_immutable()
        return bilinear
Пример #33
0
def maxima_integrator(expression, v, a=None, b=None):
    """
    Integration using Maxima

    EXAMPLES::

        sage: from sage.symbolic.integration.external import maxima_integrator
        sage: maxima_integrator(sin(x), x)
        -cos(x)
        sage: maxima_integrator(cos(x), x)
        sin(x)
        sage: f(x) = function('f')(x)
        sage: maxima_integrator(f(x), x)
        integrate(f(x), x)

    TESTS:

    Check that :trac:`25817` is fixed::

        sage: maxima_integrator(log(e^x*log(x)*sin(x))/x^2, x)
        1/2*(x*(Ei(-log(x)) + conjugate(Ei(-log(x))))
        - 2*x*integrate(sin(x)/(x*cos(x)^2 + x*sin(x)^2
        + 2*x*cos(x) + x), x) + 2*x*integrate(sin(x)/(x*cos(x)^2
        + x*sin(x)^2 - 2*x*cos(x) + x), x) + 2*x*log(x) + 2*log(2)
        - log(cos(x)^2 + sin(x)^2 + 2*cos(x) + 1) - log(cos(x)^2
        + sin(x)^2 - 2*cos(x) + 1) - 2*log(log(x)))/x
    """
    from sage.calculus.calculus import maxima
    if not isinstance(expression, Expression):
        expression = SR(expression)
    if a is None:
        result = maxima.sr_integral(expression, v)
    else:
        result = maxima.sr_integral(expression, v, a, b)
    return result._sage_()
Пример #34
0
    def populate_polyhedra(self):
        from sage.geometry.polyhedron.constructor import Polyhedron
        from sage.symbolic.ring import SR

        def get_vector(inequality, vars):
            coefficients = list(inequality.coefficient(var) for var in vars)
            constant = inequality - sum(c*v for c, v in zip(coefficients, vars))
            return [constant] + coefficients

        d = self.dimension()
        prefix = self.trees[0].PREFIX
        vars = list(SR(prefix + "{}".format(j)) for j in range(d+1))
        for tree in self.trees:
            others = list(self.trees)
            others.remove(tree)
            ineqs = [other.partition_cost() - tree.partition_cost()
                     for other in others] + vars
            ineq_matrix = [get_vector(ineq, vars) for ineq in ineqs]
            P = Polyhedron(ieqs=ineq_matrix)
            if self.is_disjoint():
                P = polyhedron_break_tie(P)
            tree.polyhedron = P

        nonnegative_orthant = Polyhedron(ieqs=[dd*(0,) + (1,) + (d+1-dd)*(0,)
                                               for dd in range(1, d+1+1)])
        assert all(A.polyhedron & nonnegative_orthant == A.polyhedron
                   for A in self.trees)
        if self.is_disjoint():
            assert all((A.polyhedron & B.polyhedron).is_empty()
                       for A in self.trees for B in self.trees if A != B)
Пример #35
0
def spin_polynomial(part, weight, length):
    """
    Returns the spin polynomial associated to ``part``, ``weight``, and
    ``length``.

    EXAMPLES::

        sage: from sage.combinat.ribbon_tableau import spin_polynomial
        sage: spin_polynomial([6,6,6],[4,2],3)
        t^6 + t^5 + 2*t^4 + t^3 + t^2
        sage: spin_polynomial([6,6,6],[4,1,1],3)
        t^6 + 2*t^5 + 3*t^4 + 2*t^3 + t^2
        sage: spin_polynomial([3,3,3,2,1], [2,2], 3)
        t^(7/2) + t^(5/2)
        sage: spin_polynomial([3,3,3,2,1], [2,1,1], 3)
        2*t^(7/2) + 2*t^(5/2) + t^(3/2)
        sage: spin_polynomial([3,3,3,2,1], [1,1,1,1], 3)
        3*t^(7/2) + 5*t^(5/2) + 3*t^(3/2) + sqrt(t)
        sage: spin_polynomial([5,4,3,2,1,1,1], [2,2,1], 3)
        2*t^(9/2) + 6*t^(7/2) + 2*t^(5/2)
        sage: spin_polynomial([[6]*6, [3,3]], [4,4,2], 3)
        3*t^9 + 5*t^8 + 9*t^7 + 6*t^6 + 3*t^5
    """
    from sage.symbolic.ring import SR
    sp = spin_polynomial_square(part,weight,length)
    t = SR.var('t')
    c = sp.coefficients(sparse=False)
    return sum([c[i]*t**(QQ(i)/2) for i in range(len(c))])
Пример #36
0
    def _element_constructor_(self, fun):
        """
        Coerce a given function (element of the symbolic ring)
        into a differential form of degree zero.

        EXAMPLES::

            sage: x, y, z = var('x, y, z')
            sage: U = CoordinatePatch((x, y, z))
            doctest:...: DeprecationWarning: Use Manifold instead.
            See http://trac.sagemath.org/24444 for details.
            sage: F = DifferentialForms(U); F
            doctest:...:  DeprecationWarning: For the set of differential forms of
             degree p, use U.diff_form_module(p), where U is the base manifold
             (type U.diff_form_module? for details).
            See http://trac.sagemath.org/24444 for details.
            Algebra of differential forms in the variables x, y, z
            sage: F(sin(x*y))    # indirect doctest
            doctest:...: DeprecationWarning: Use U.diff_form(degree) instead,
             where U is the base manifold (type U.diff_form? for details).
            See http://trac.sagemath.org/24444 for details.
            sin(x*y)

        """


        fun = SR(fun)
        if fun not in self:
            raise ValueError("Function not an element of this algebra of differential forms.")

        return DifferentialForm(self, 0, fun)
Пример #37
0
def random_expr(
    size,
    nvars=1,
    ncoeffs=None,
    var_frac=0.5,
    internal=full_internal,
    nullary=full_nullary,
    nullary_frac=0.2,
    coeff_generator=QQ.random_element,
    verbose=False,
):
    r"""
    Produce a random symbolic expression of the given size.  By
    default, the expression involves (at most) one variable, an arbitrary
    number of coefficients, and all of the symbolic functions and constants
    (from the probability lists full_internal and full_nullary).  It is
    possible to adjust the ratio of leaves between symbolic constants,
    variables, and coefficients (var_frac gives the fraction of variables,
    and nullary_frac the fraction of symbolic constants; the remaining
    leaves are coefficients).

    The actual mix of symbolic constants and internal nodes can be modified
    by specifying different probability lists.

    To use a different type for coefficients, you can specify
    coeff_generator, which should be a function that will return
    a random coefficient every time it is called.

    This function will often raise an error because it tries to create
    an erroneous expression (such as a division by zero).

    EXAMPLES::

        sage: from sage.symbolic.random_tests import *
        sage: set_random_seed(53)
        sage: random_expr(50, nvars=3, coeff_generator=CDF.random_element) # random
        (v1^(0.97134084277 + 0.195868299334*I)/csc(-pi + v1^2 + v3) + sgn(1/
        ((-v3 - 0.760455994772 - 0.554367254855*I)*erf(v3 + 0.982759757946 -
        0.0352136502348*I)) + binomial(arccoth(v1^pi), 0.760455994772 +
        0.554367254855*I) + arccosh(2*v2 - (v2 + 0.841911550437 -
        0.303757179824*I)/sinh_integral(pi) + arccoth(v3 + 0.530133230474 +
        0.532140303485*I))))/v2
        sage: random_expr(5, verbose=True) # random
        About to apply <built-in function inv> to [31]
        About to apply sgn to [v1]
        About to apply <built-in function add> to [1/31, sgn(v1)]
        sgn(v1) + 1/31

    """
    vars = [(1.0, SR.var("v%d" % (n + 1))) for n in range(nvars)]
    if ncoeffs is None:
        ncoeffs = size
    coeffs = [(1.0, coeff_generator()) for _ in range(ncoeffs)]
    leaves = [(var_frac, vars), (1.0 - var_frac - nullary_frac, coeffs), (nullary_frac, nullary)]
    leaves = normalize_prob_list(leaves)

    internal = normalize_prob_list(internal)

    return random_expr_helper(size, internal, leaves, verbose)
Пример #38
0
def symbol(a=None):
    """
    Return a variable from the symbolic ring with the given name.
    If an expression is given, it is returned unchanged.
    """
    if isinstance(a, Expression):
        return a
    return SR.symbol(a)
Пример #39
0
def EllipticCurve_from_cubic(F, P):
    r"""
    Construct an elliptic curve from a ternary cubic with a rational point.

    INPUT:

    - ``F`` -- a homogeneous cubic in three variables with rational
      coefficients (either as a polynomial ring element or as a
      string) defining a smooth plane cubic curve.

    - ``P`` -- a 3-tuple `(x,y,z)` defining a projective point on the
      curve `F=0`.

    OUTPUT:

    (elliptic curve) An elliptic curve (in minimal Weierstrass form)
    isomorphic to the curve `F=0`.

    .. note::

       USES MAGMA - This function will not work on computers that
       do not have magma installed.

    TO DO: implement this without using MAGMA.

    For a more general version, see the function
    ``EllipticCurve_from_plane_curve()``.

    EXAMPLES:

    First we find that the Fermat cubic is isomorphic to the curve
    with Cremona label 27a1::

        sage: E = EllipticCurve_from_cubic('x^3 + y^3 + z^3', [1,-1,0])  # optional - magma
        sage: E         # optional - magma
        Elliptic Curve defined by y^2 + y = x^3 - 7 over Rational Field
        sage: E.cremona_label()     # optional - magma
        '27a1'

    Next we find the minimal model and conductor of the Jacobian of the
    Selmer curve.

    ::

        sage: E = EllipticCurve_from_cubic('u^3 + v^3 + 60*w^3', [1,-1,0])   # optional - magma
        sage: E                # optional - magma
        Elliptic Curve defined by y^2  = x^3 - 24300 over Rational Field
        sage: E.conductor()    # optional - magma
        24300
    """
    from sage.interfaces.all import magma
    cmd = "P<%s,%s,%s> := ProjectivePlane(RationalField());" % SR(
        F).variables()
    magma.eval(cmd)
    cmd = 'aInvariants(MinimalModel(EllipticCurve(Curve(Scheme(P, %s)),P!%s)));' % (
        F, P)
    s = magma.eval(cmd)
    return EllipticCurve(rings.RationalField(), eval(s))
Пример #40
0
def random_expr(size,
                nvars=1,
                ncoeffs=None,
                var_frac=0.5,
                internal=full_internal,
                nullary=full_nullary,
                nullary_frac=0.2,
                coeff_generator=QQ.random_element,
                verbose=False):
    r"""
    Produce a random symbolic expression of the given size.  By
    default, the expression involves (at most) one variable, an arbitrary
    number of coefficients, and all of the symbolic functions and constants
    (from the probability lists full_internal and full_nullary).  It is
    possible to adjust the ratio of leaves between symbolic constants,
    variables, and coefficients (var_frac gives the fraction of variables,
    and nullary_frac the fraction of symbolic constants; the remaining
    leaves are coefficients).

    The actual mix of symbolic constants and internal nodes can be modified
    by specifying different probability lists.

    To use a different type for coefficients, you can specify
    coeff_generator, which should be a function that will return
    a random coefficient every time it is called.

    This function will often raise an error because it tries to create
    an erroneous expression (such as a division by zero).

    EXAMPLES::

        sage: from sage.symbolic.random_tests import *
        sage: set_random_seed(53)
        sage: random_expr(50, nvars=3, coeff_generator=CDF.random_element) # random
        (v1^(0.97134084277 + 0.195868299334*I)/csc(-pi + v1^2 + v3) + sgn(1/
        ((-v3 - 0.760455994772 - 0.554367254855*I)*erf(v3 + 0.982759757946 -
        0.0352136502348*I)) + binomial(arccoth(v1^pi), 0.760455994772 +
        0.554367254855*I) + arccosh(2*v2 - (v2 + 0.841911550437 -
        0.303757179824*I)/sinh_integral(pi) + arccoth(v3 + 0.530133230474 +
        0.532140303485*I))))/v2
        sage: random_expr(5, verbose=True) # random
        About to apply <built-in function inv> to [31]
        About to apply sgn to [v1]
        About to apply <built-in function add> to [1/31, sgn(v1)]
        sgn(v1) + 1/31

    """
    vars = [(1.0, SR.var('v%d' % (n + 1))) for n in range(nvars)]
    if ncoeffs is None:
        ncoeffs = size
    coeffs = [(1.0, coeff_generator()) for _ in range(ncoeffs)]
    leaves = [(var_frac, vars), (1.0 - var_frac - nullary_frac, coeffs),
              (nullary_frac, nullary)]
    leaves = normalize_prob_list(leaves)

    internal = normalize_prob_list(internal)

    return random_expr_helper(size, internal, leaves, verbose)
Пример #41
0
 def test_issue_4023():
     from sage.symbolic.ring import SR
     from sage.functions.all import log
     from sympy import integrate, simplify
     a,x = SR.var("a x")
     i = integrate(log(x)/a, (x, a, a + 1))
     i2 = simplify(i)
     s = SR(i2)
     assert s == (a*log(1 + a) - a*log(a) + log(1 + a) - 1)/a
Пример #42
0
def _sympysage_symbol(self):
    """
    EXAMPLES::

        sage: from sympy import Symbol
        sage: assert x._sympy_() == Symbol('x')
        sage: assert x == Symbol('x')._sage_()
    """
    from sage.symbolic.ring import SR
    return SR.var(self.name)
Пример #43
0
def check_expression(expr, var_symbols, only_from_sympy=False):
    """
    Does ``eval(expr)`` both in Sage and SymPy and does other checks.

    EXAMPLES::

        sage: from sage.interfaces.sympy import check_expression
        sage: check_expression("1.123*x", "x")
    """
    from sage import __dict__ as sagedict
    from sage.symbolic.ring import SR
    from sympy import (__dict__ as sympydict, Basic, S, var as svar)
    # evaluate the expression in the context of Sage:
    if var_symbols:
        SR.var(var_symbols)
    is_different = False
    try:
        e_sage = SR(expr)
        assert not isinstance(e_sage, Basic)
    except (NameError, TypeError):
        is_different = True
        pass

    # evaluate the expression in the context of SymPy:
    if var_symbols:
        sympy_vars = svar(var_symbols)
    b = globals().copy()
    b.update(sympydict)
    assert "sin" in b
    b.update(sympydict)
    e_sympy = eval(expr, b)
    assert isinstance(e_sympy, Basic)

    # Sympy func may have specific _sage_ method
    if is_different:
        _sage_method = getattr(e_sympy.func, "_sage_")
        e_sage = _sage_method(S(e_sympy))

    # Do the actual checks:
    if not only_from_sympy:
        assert S(e_sage) == e_sympy
    assert e_sage == SR(e_sympy)
Пример #44
0
def fricas_integrator(expression, v, a=None, b=None, noPole=True):
    """
    Integration using FriCAS

    EXAMPLES::

        sage: from sage.symbolic.integration.external import fricas_integrator  # optional - fricas
        sage: fricas_integrator(sin(x), x)                                      # optional - fricas
        -cos(x)
        sage: fricas_integrator(cos(x), x)                                      # optional - fricas
        sin(x)
        sage: fricas_integrator(1/(x^2-2), x, 0, 1)                             # optional - fricas
        1/4*sqrt(2)*(log(3*sqrt(2) - 4) - log(sqrt(2)))
        sage: fricas_integrator(1/(x^2+6), x, -oo, oo)                          # optional - fricas
        1/6*sqrt(6)*pi
    """
    if not isinstance(expression, Expression):
        expression = SR(expression)
    if a is None:
        result = expression._fricas_().integrate(v)
    else:
        import sage.rings.infinity
        if a == sage.rings.infinity.PlusInfinity():
            a = "%plusInfinity"
        elif a == sage.rings.infinity.MinusInfinity():
            a = "%minusInfinity"
        if b == sage.rings.infinity.PlusInfinity():
            b = "%plusInfinity"
        elif b == sage.rings.infinity.MinusInfinity():
            b = "%minusInfinity"

        if noPole:
            result = expression._fricas_().integrate("{}={}..{}".format(v, a, b), '"noPole"')
        else:
            result = expression._fricas_().integrate("{}={}..{}".format(v, a, b))

    locals = {str(v): v for v in expression.variables()}
    if str(result) == "potentialPole":
        raise ValueError("The integrand has a potential pole"
                         " in the integration interval")

    return result.sage()
Пример #45
0
def matrice_systeme(systeme, variables):
    """
    Renvoie une matrice par block représentant un programme linéaire sous forme standard.

    INPUT::

    - ``systeme`` -- Un programme linéaire sous forme standard
    - ``variables`` -- La liste des variables du système

    EXAMPLES::

        sage: x = x1,x2,x3 = var('x1,x2,x3')
        sage: Chvatal13 = [[2*x1 + 3*x2 +   x3 <=  5,
        ....:               4*x1 +   x2 + 2*x3 <= 11,
        ....:               3*x1 + 4*x2 + 2*x3 <=  8],
        ....:               5*x1 + 4*x2 + 3*x3]

        sage: m = matrice_systeme(Chvatal13, x); m
        [ z|s1 s2 s3|x1 x2 x3| 0]
        [--+--------+--------+--]
        [ 1| 0  0  0|-5 -4 -3| 0]
        [--+--------+--------+--]
        [ 0| 1  0  0| 2  3  1| 5]
        [ 0| 0  1  0| 4  1  2|11]
        [ 0| 0  0  1| 3  4  2| 8]
    """

    def liste_coeffs(expression):
        return [expression.coeff(v) for v in variables]

    inequations = systeme[0]
    m = matrix([liste_coeffs(ineq.lhs()) for ineq in inequations])
    rhs = vector(ineq.rhs() for ineq in inequations).column()
    slack = SR.var(",".join("s%s" % i for i in range(1, len(inequations) + 1)))
    z = SR.var("z")
    return block_matrix(
        [
            [z, matrix([slack]), matrix([variables]), ZZ(0)],
            [ZZ(1), ZZ(0), -matrix([liste_coeffs(systeme[1])]), ZZ(0)],
            [ZZ(0), ZZ(1), m, rhs],
        ]
    )
Пример #46
0
def fricas_integrator(expression, v, a=None, b=None):
    """
    Integration using FriCAS

    EXAMPLES::

        sage: from sage.symbolic.integration.external import fricas_integrator  # optional - fricas
        sage: fricas_integrator(sin(x), x)                                      # optional - fricas
        -cos(x)
        sage: fricas_integrator(cos(x), x)                                      # optional - fricas
        sin(x)
        sage: fricas_integrator(1/(x^2-2), x, 0, 1)                             # optional - fricas
        1/4*(log(3*sqrt(2) - 4) - log(sqrt(2)))*sqrt(2)
        sage: fricas_integrator(1/(x^2+6), x, -oo, oo)                          # optional - fricas
        1/6*pi*sqrt(6)
    """
    if not isinstance(expression, Expression):
        expression = SR(expression)
    if a is None:
        result = expression._fricas_().integrate(v)
    else:
        import sage.rings.infinity
        if a == sage.rings.infinity.PlusInfinity():
            a = "%plusInfinity"
        elif a == sage.rings.infinity.MinusInfinity():
            a = "%minusInfinity"
        if b == sage.rings.infinity.PlusInfinity():
            b = "%plusInfinity"
        elif b == sage.rings.infinity.MinusInfinity():
            b = "%minusInfinity"

        result = expression._fricas_().integrate("{}={}..{}".format(v, a, b))
    locals = {str(v): v for v in expression.variables()}
    if str(result) == "potentialPole":
        raise ValueError("The integrand has a potential pole"
                         " in the integration interval")
    parsed_result = result.unparsed_input_form()
    import sage.misc.sage_eval
    try:
        return sage.misc.sage_eval.sage_eval(parsed_result, locals=locals)
    except:
        raise ValueError("Unable to parse: {}".format(parsed_result))
Пример #47
0
 def test_undefined_function():
     from sage.symbolic.ring import SR
     from sage.calculus.var import function
     from sympy import Symbol, Function
     f = function('f')
     sf = Function('f')
     x,y = SR.var('x y')
     sx = Symbol('x')
     sy = Symbol('y')
     assert f(x)._sympy_() == sf(sx)
     assert f(x) == sf(sx)._sage_()
     assert f(x,y)._sympy_() == sf(sx, sy)
     assert f(x,y) == sf(sx, sy)._sage_()
     assert f._sympy_() == sf
     assert f == sf._sage_()
    def weight_integrand(self, simplify_factor=True):
        """
        Weight integrand as a rational function.

        The Jacobian determinant of some coordinate transformation.
        """
        def arg(x,y):
            return arctan(y/x) # up to a constant, but it doesn't matter
        def phi(x,y,a,b):
            z = (a+I*b-x-I*y)*(a - I*b - x - I*y)
            w = z.real()
            q = z.imag()
            return arg(w,q).full_simplify()
        n = len(self.internal_vertices())
        coordinates = lambda v: SR.var(chr(97+2*(v-1)) + ',' + chr(97+2*(v-1)+1)) \
                                if v in self.internal_vertices() else \
                                [(0,0), (1,0)][self.ground_vertices().index(v)]
        internal_coordinates = sum((list(coordinates(v)) for v in
                                    sorted(self.internal_vertices())), [])
        U = CoordinatePatch(internal_coordinates)
        F = DifferentialForms(U)
        psi = 0
        two_forms = []
        for v in self.internal_vertices():
            x,y = coordinates(v)
            outgoing_edges = self.outgoing_edges([v])
            left_target = filter(lambda (x, y, z): z == 'L', outgoing_edges)[0][1]
            right_target = filter(lambda (x, y, z): z == 'R', outgoing_edges)[0][1]
            one_forms = []
            for target in [left_target, right_target]:
                a,b = coordinates(target)
                one_form = DifferentialForm(F, 1)
                for v in internal_coordinates:
                    index = internal_coordinates.index(v)
                    one_form[index] = phi(x,y,a,b).diff(v)
                    if simplify_factor:
                        one_form[index] = SR(one_form[index]).full_simplify()
                one_forms.append(one_form)
            two_form = one_forms[0]*one_forms[1]
            two_forms.append(two_form)
        import operator
        two_n_form = reduce(operator.mul, two_forms, 1)
        return two_n_form[range(0,2*n)]
Пример #49
0
        def fourier_series_cosine_coefficient(cls, self, parameters, variable, n, L):
            r"""
            Returns the n-th Fourier series coefficient of
            `\cos(n\pi x/L)`, `a_n`.

            INPUT:


            -  ``self`` - the function f(x), defined over -L x L

            -  ``n`` - an integer n=0

            -  ``L`` - (the period)/2


            OUTPUT:
            `a_n = \frac{1}{L}\int_{-L}^L f(x)\cos(n\pi x/L)dx`

            EXAMPLES::

                sage: f(x) = x^2
                sage: f = piecewise([[(-1,1),f]])
                sage: f.fourier_series_cosine_coefficient(2,1)
                pi^(-2)
                sage: f(x) = x^2
                sage: f = piecewise([[(-pi,pi),f]])
                sage: f.fourier_series_cosine_coefficient(2,pi)
                1
                sage: f1(x) = -1
                sage: f2(x) = 2
                sage: f = piecewise([[(-pi,pi/2),f1],[(pi/2,pi),f2]])
                sage: f.fourier_series_cosine_coefficient(5,pi)
                -3/5/pi
            """
            from sage.all import cos, pi
            x = SR.var('x')
            result = 0
            for domain, f in parameters:
                for interval in domain:
                    a = interval.lower()
                    b = interval.upper()
                    result += (f*cos(pi*x*n/L)/L).integrate(x, a, b)
            return SR(result).simplify_trig()
Пример #50
0
    def __init__(self, n, delta=0.01, m=None):
        """
        Construct LWE instance parameterised by security parameter ``n`` where
        the modulus ``q`` and the ``stddev`` of the noise is chosen as in
        [LP2011]_.

        INPUT:

        - ``n`` - security parameter (integer > 0)
        - ``delta`` - error probability per symbol (default: 0.01)
        - ``m`` - number of allowed samples or ``None`` in which case ``m=2*n +
          128`` as in [LP2011]_ (default: ``None``)

        EXAMPLES::

            sage: from sage.crypto.lwe import LindnerPeikert
            sage: LindnerPeikert(n=20)
            LWE(20, 2053, Discrete Gaussian sampler over the Integers with sigma = 3.600954 and c = 0, 'noise', 168)
        """
        if m is None:
            m = 2*n + 128
        # Find c>=1 such that c*exp((1-c**2)/2))**(2*n) == 2**-40
        #         (c*exp((1-c**2)/2))**(2*n) == 2**-40
        #    log((c*exp((1-c**2)/2))**(2*n)) == -40*log(2)
        #       (2*n)*log(c*exp((1-c**2)/2)) == -40*log(2)
        #  2*n*(log(c)+log(exp((1-c**2)/2))) == -40*log(2)
        #            2*n*(log(c)+(1-c**2)/2) == -40*log(2)
        #              2*n*log(c)+n*(1-c**2) == -40*log(2)
        #  2*n*log(c)+n*(1-c**2) + 40*log(2) == 0
        c = SR.var('c')
        c = find_root(2*n*log(c)+n*(1-c**2) + 40*log(2) == 0, 1, 10)
        # Upper bound on s**2/t
        s_t_bound = (sqrt(2) * pi / c / sqrt(2*n*log(2/delta))).n()
        # Interpretation of "choose q just large enough to allow for a Gaussian parameter s>=8" in [LP2011]_
        q = next_prime(floor(2**round(log(256 / s_t_bound, 2))))
        # Gaussian parameter as defined in [LP2011]_
        s = sqrt(s_t_bound*floor(q/4))
        # Transform s into stddev
        stddev = s/sqrt(2*pi.n())
        D   = DiscreteGaussianDistributionIntegerSampler(stddev)
        LWE.__init__(self, n=n, q=q, D=D, secret_dist='noise', m=m)
Пример #51
0
    def __call__(self, *args):
        """
        EXAMPLES::

            sage: from sage.symbolic.operators import FDerivativeOperator
            sage: x,y = var('x,y')
            sage: f = function('foo')
            sage: op = FDerivativeOperator(f, [0,1])
            sage: op(x,y)
            diff(foo(x, y), x, y)
            sage: op(x,x^2)
            D[0, 1](foo)(x, x^2)

        TESTS:

        We should be able to operate on functions evaluated at a
        point, not just a symbolic variable, :trac:`12796`::

           sage: from sage.symbolic.operators import FDerivativeOperator
           sage: f = function('f')
           sage: op = FDerivativeOperator(f, [0])
           sage: op(1)
           D[0](f)(1)

        """
        if (not all(is_SymbolicVariable(x) for x in args) or
                len(args) != len(set(args))):
            # An evaluated derivative of the form f'(1) is not a
            # symbolic variable, yet we would like to treat it
            # like one. So, we replace the argument `1` with a
            # temporary variable e.g. `t0` and then evaluate the
            # derivative f'(t0) symbolically at t0=1. See trac
            # #12796.
            temp_args=[SR.var("t%s"%i) for i in range(len(args))]
            vars=[temp_args[i] for i in self._parameter_set]
            return self._f(*temp_args).diff(*vars).function(*temp_args)(*args)
        vars = [args[i] for i in self._parameter_set]
        return self._f(*args).diff(*vars)
Пример #52
0
    def __init__(self, N, delta=0.01, m=None):
        """
        Construct a Ring-LWE oracle in dimension ``n=phi(N)`` where
        the modulus ``q`` and the ``stddev`` of the noise is chosen as in
        [LP2011]_.

        INPUT:

        - ``N`` - index of cyclotomic polynomial (integer > 0, must be power of 2)
        - ``delta`` - error probability per symbol (default: 0.01)
        - ``m`` - number of allowed samples or ``None`` in which case ``3*n`` is
          used (default: ``None``)

        EXAMPLES::

            sage: from sage.crypto.lwe import RingLindnerPeikert
            sage: RingLindnerPeikert(N=16)
            RingLWE(16, 1031, Discrete Gaussian sampler for polynomials of degree < 8 with σ=2.803372 in each component, x^8 + 1, 'noise', 24)
        """
        n = euler_phi(N)
        if m is None:
            m = 3*n
        # Find c>=1 such that c*exp((1-c**2)/2))**(2*n) == 2**-40
        #  i.e c>=1 such that 2*n*log(c)+n*(1-c**2) + 40*log(2) == 0
        c = SR.var('c')
        c = find_root(2*n*log(c)+n*(1-c**2) + 40*log(2) == 0, 1, 10)
        # Upper bound on s**2/t
        s_t_bound = (sqrt(2) * pi / c / sqrt(2*n*log(2/delta))).n()
        # Interpretation of "choose q just large enough to allow for a Gaussian parameter s>=8" in [LP2011]_
        q = next_prime(floor(2**round(log(256 / s_t_bound, 2))))
        # Gaussian parameter as defined in [LP2011]_
        s = sqrt(s_t_bound*floor(q/4))
        # Transform s into stddev
        stddev = s/sqrt(2*pi.n())
        D = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], n, stddev)
        RingLWE.__init__(self, N=N, q=q, D=D, poly=None, secret_dist='noise', m=m)
Пример #53
0
        def __call__(cls, self, parameters, variable, value=None, **kwds):
            """
            Call the piecewise function

            EXAMPLES::

                sage: f = piecewise([([0,0], sin(x)), ((0,2), cos(x))]);  f
                piecewise(x|-->sin(x) on {0}, x|-->cos(x) on (0, 2); x)
                sage: f(0)
                0
                sage: f(1)
                cos(1)
                sage: f(2)
                Traceback (most recent call last):
                ...
                ValueError: point 2 is not in the domain
            """
            self = piecewise(parameters, var=variable)
            substitution = dict()
            for k, v in kwds.items():
                substitution[SR.var(k)] = v
            if value is not None:
                substitution[variable] = value
            return self.subs(substitution)
Пример #54
0
    def __call__(self, function_pieces, **kwds):
        r"""
        Piecewise functions

        INPUT:
   
        - ``function_pieces`` -- a list of pairs consisting of a
          domain and a symbolic function.

        - ``var=x`` -- a symbolic variable or ``None`` (default). The
        real variable in which the function is piecewise in.

        OUTPUT:

        A piecewise-defined function. A ``ValueError`` will be raised
        if the domains of the pieces are not pairwise disjoint.
    
        EXAMPLES::
        
            sage: my_abs = piecewise([((-1, 0), -x), ([0, 1], x)], var=x);  my_abs
            piecewise(x|-->-x on (-1, 0), x|-->x on [0, 1]; x)
            sage: [ my_abs(i/5) for i in range(-4, 5)]
            [4/5, 3/5, 2/5, 1/5, 0, 1/5, 2/5, 3/5, 4/5]

        TESTS::

            sage: piecewise([([-1, 0], -x), ([0, 1], x)], var=x)
            Traceback (most recent call last):
            ...
            ValueError: domains must be pairwise disjoint

            sage: step = piecewise([((-1, 0), -1), ([0, 0], 0), ((0, 1), 1)], var=x);  step
            piecewise(x|-->-1 on (-1, 0), x|-->0 on {0}, x|-->1 on (0, 1); x)
            sage: step(-1/2), step(0), step(1/2)
            (-1, 0, 1)
        """
        from types import FunctionType
        var = kwds.pop('var', None)
        parameters = []
        domain_list = []
        for piece in function_pieces:
            domain, function = piece
            if not isinstance(domain, RealSet):
                domain = RealSet(domain)
            if domain.is_empty():
                continue
            if isinstance(function, FunctionType):
                if var is None:
                    var = SR.var('x')
                if function.func_code.co_argcount == 0:
                    function = function()
                else:
                    function = function(var)
            function = SR(function)
            if var is None and len(function.variables()) > 0:
                var = function.variables()[0]
            parameters.append((domain, function))
            domain_list.append(domain)
        if not RealSet.are_pairwise_disjoint(*domain_list):
            raise ValueError('domains must be pairwise disjoint')
        if var is None:
            var = self.default_variable()
        parameters = SR._force_pyobject(tuple(parameters), recursive=False)
        return BuiltinFunction.__call__(self, parameters, var, **kwds)
Пример #55
0
        def convolution(cls, self, parameters, variable, other):
            """
            Return the convolution function,
            `f*g(t)=\int_{-\infty}^\infty f(u)g(t-u)du`, for compactly
            supported `f,g`.

            EXAMPLES::

                sage: x = PolynomialRing(QQ,'x').gen()
                sage: f = piecewise([[[0,1],1]])  ## example 0
                sage: g = f.convolution(f); g
                piecewise(x|-->x on (0, 1], x|-->-x + 2 on (1, 2]; x)
                sage: h = f.convolution(g); h
                piecewise(x|-->1/2*x^2 on (0, 1], x|-->-x^2 + 3*x - 3/2 on (1, 2], x|-->1/2*x^2 - 3*x + 9/2 on (2, 3]; x)
                sage: f = piecewise([[(0,1),1],[(1,2),2],[(2,3),1]])  ## example 1
                sage: g = f.convolution(f)
                sage: h = f.convolution(g); h
                piecewise(x|-->1/2*x^2 on (0, 1], x|-->2*x^2 - 3*x + 3/2 on (1, 3], x|-->-2*x^2 + 21*x - 69/2 on (3, 4], x|-->-5*x^2 + 45*x - 165/2 on (4, 5], x|-->-2*x^2 + 15*x - 15/2 on (5, 6], x|-->2*x^2 - 33*x + 273/2 on (6, 8], x|-->1/2*x^2 - 9*x + 81/2 on (8, 9]; x)
                sage: f = piecewise([[(-1,1),1]])                             ## example 2
                sage: g = piecewise([[(0,3),x]])
                sage: f.convolution(g)
                piecewise(x|-->1/2*x^2 + x + 1/2 on (-1, 1], x|-->2*x on (1, 2], x|-->-1/2*x^2 + x + 4 on (2, 4]; x)
                sage: g = piecewise([[(0,3),1],[(3,4),2]])
                sage: f.convolution(g)
                piecewise(x|-->x + 1 on (-1, 1], x|-->2 on (1, 2], x|-->x on (2, 3], x|-->-x + 6 on (3, 4], x|-->-2*x + 10 on (4, 5]; x)

            Check that the bugs raised in :trac:`12123` are fixed::

                sage: f = piecewise([[(-2, 2), 2]])
                sage: g = piecewise([[(0, 2), 3/4]])
                sage: f.convolution(g)
                piecewise(x|-->3/2*x + 3 on (-2, 0], x|-->3 on (0, 2], x|-->-3/2*x + 6 on (2, 4]; x)
                sage: f = piecewise([[(-1, 1), 1]])
                sage: g = piecewise([[(0, 1), x], [(1, 2), -x + 2]])
                sage: f.convolution(g)
                piecewise(x|-->1/2*x^2 + x + 1/2 on (-1, 0], x|-->-1/2*x^2 + x + 1/2 on (0, 2], x|-->1/2*x^2 - 3*x + 9/2 on (2, 3]; x)
            """
            from sage.symbolic.integration.integral import definite_integral
            f = self
            g = other
            if len(f.end_points())*len(g.end_points()) == 0:
                raise ValueError('one of the piecewise functions is nowhere defined')
            M = min(min(f.end_points()),min(g.end_points()))
            N = max(max(f.end_points()),max(g.end_points()))
            tt = SR.var('tt')
            uu = SR.var('uu')
            conv = 0
            fd,f0 = parameters[0]
            gd,g0 = next(other.items())
            if len(f)==1 and len(g)==1:
                f = f.unextend_zero()
                g = g.unextend_zero()
                a1 = fd[0].lower()
                a2 = fd[0].upper()
                b1 = gd[0].lower()
                b2 = gd[0].upper()
                i1 = f0.subs({variable: uu})
                i2 = g0.subs({variable: tt-uu})
                fg1 = definite_integral(i1*i2, uu, a1, tt-b1).subs(tt = variable)
                fg2 = definite_integral(i1*i2, uu, tt-b2, tt-b1).subs(tt = variable)
                fg3 = definite_integral(i1*i2, uu, tt-b2, a2).subs(tt = variable)
                fg4 = definite_integral(i1*i2, uu, a1, a2).subs(tt = variable)
                if a1-b1<a2-b2:
                    if a2+b1!=a1+b2:
                        h = piecewise([[(a1+b1,a1+b2),fg1],[(a1+b2,a2+b1),fg2],[(a2+b1,a2+b2),fg3]])
                    else:
                        h = piecewise([[(a1+b1,a1+b2),fg1],[(a1+b2,a2+b2),fg3]])
                else:
                    if a1+b2!=a2+b1:
                        h = piecewise([[(a1+b1,a2+b1),fg1],[(a2+b1,a1+b2),fg4],[(a1+b2,a2+b2),fg3]])
                    else:
                        h = piecewise([[(a1+b1,a2+b1),fg1],[(a2+b1,a2+b2),fg3]])
                return (piecewise([[(minus_infinity,infinity),0]]).piecewise_add(h)).unextend_zero()

            if len(f)>1 or len(g)>1:
                z = piecewise([[(0,0),0]])
                for fpiece in f.pieces():
                    for gpiece in g.pieces():
                        h = gpiece.convolution(fpiece)
                        z = z.piecewise_add(h)
                return z.unextend_zero()
Пример #56
0
def airy_bi(alpha, x=None, hold_derivative=True, **kwds):
    r"""
    The Airy Bi function

    The Airy Bi function `\operatorname{Bi}(x)` is (along with
    `\operatorname{Ai}(x)`) one of the two linearly independent standard
    solutions to the Airy differential equation `f''(x) - x f(x) = 0`. It is
    defined by the initial conditions:

    .. MATH::

        \operatorname{Bi}(0)=\frac{1}{3^{1/6} \Gamma\left(\frac{2}{3}\right)},

        \operatorname{Bi}'(0)=\frac{3^{1/6}}{ \Gamma\left(\frac{1}{3}\right)}.

    Another way to define the Airy Bi function is:

    .. MATH::

        \operatorname{Bi}(x)=\frac{1}{\pi}\int_0^\infty
        \left[ \exp\left( xt -\frac{t^3}{3} \right)
        +\sin\left(xt + \frac{1}{3}t^3\right) \right ] dt.

    INPUT:

    - ``alpha`` -- Return the `\alpha`-th order fractional derivative with
      respect to `z`.
      For `\alpha = n = 1,2,3,\ldots` this gives the derivative
      `\operatorname{Bi}^{(n)}(z)`, and for `\alpha = -n = -1,-2,-3,\ldots`
      this gives the `n`-fold iterated integral.

    .. MATH::

        f_0(z) = \operatorname{Bi}(z)

        f_n(z) = \int_0^z f_{n-1}(t) dt

    - ``x`` -- The argument of the function

    - ``hold_derivative`` -- Whether or not to stop from returning higher
      derivatives in terms of `\operatorname{Bi}(x)` and
      `\operatorname{Bi}'(x)`

    .. SEEALSO:: :func:`airy_ai`

    EXAMPLES::

        sage: n, x = var('n x')
        sage: airy_bi(x)
        airy_bi(x)

    It can return derivatives or integrals::

        sage: airy_bi(2, x)
        airy_bi(2, x)
        sage: airy_bi(1, x, hold_derivative=False)
        airy_bi_prime(x)
        sage: airy_bi(2, x, hold_derivative=False)
        x*airy_bi(x)
        sage: airy_bi(-2, x, hold_derivative=False)
        airy_bi(-2, x)
        sage: airy_bi(n, x)
        airy_bi(n, x)

    It can be evaluated symbolically or numerically for real or complex
    values::

        sage: airy_bi(0)
        1/3*3^(5/6)/gamma(2/3)
        sage: airy_bi(0.0)
        0.614926627446001
        sage: airy_bi(I)
        airy_bi(I)
        sage: airy_bi(1.0*I)
        0.648858208330395 + 0.344958634768048*I

    The functions can be evaluated numerically using mpmath,
    which can compute the values to arbitrary precision, and scipy::

        sage: airy_bi(2).n(prec=100)
        3.2980949999782147102806044252
        sage: airy_bi(2).n(algorithm='mpmath', prec=100)
        3.2980949999782147102806044252
        sage: airy_bi(2).n(algorithm='scipy')  # rel tol 1e-10
        3.2980949999782134

    And the derivatives can be evaluated::

        sage: airy_bi(1, 0)
        3^(1/6)/gamma(1/3)
        sage: airy_bi(1, 0.0)
        0.448288357353826

    Plots::

        sage: plot(airy_bi(x), (x, -10, 5)) + plot(airy_bi_prime(x),
        ....:  (x, -10, 5), color='red')
        Graphics object consisting of 2 graphics primitives

    **References**

    - Abramowitz, Milton; Stegun, Irene A., eds. (1965), "Chapter 10"

    - :wikipedia:`Airy_function`
    """
    # We catch the case with no alpha
    if x is None:
        x = alpha
        return airy_bi_simple(x, **kwds)

    # We take care of all other cases.
    if not alpha in ZZ and not isinstance(alpha, Expression):
        return airy_bi_general(alpha, x, **kwds)
    if hold_derivative:
        return airy_bi_general(alpha, x, **kwds)
    elif alpha == 0:
        return airy_bi_simple(x, **kwds)
    elif alpha == 1:
        return airy_bi_prime(x, **kwds)
    elif alpha > 1:
        # We use a different variable here because if x is a
        # particular value, we would be differentiating a constant
        # which would return 0. What we want is the value of
        # the derivative at the value and not the derivative of
        # a particular value of the function.
        v = SR.symbol()
        return derivative(airy_bi_simple(v, **kwds), v, alpha).subs({v: x})
    else:
        return airy_bi_general(alpha, x, **kwds)
Пример #57
0
    def __call__(self, *args, **kwds):
        """
        EXAMPLES::

            sage: max_symbolic(3,5,x)
            max(x, 5)
            sage: max_symbolic(3,5,x, hold=True)
            max(3, 5, x)
            sage: max_symbolic([3,5,x])
            max(x, 5)

        ::

            sage: min_symbolic(3,5,x)
            min(x, 3)
            sage: min_symbolic(3,5,x, hold=True)
            min(3, 5, x)
            sage: min_symbolic([3,5,x])
            min(x, 3)

        TESTS:

        We get an exception if no arguments are given::

            sage: max_symbolic()
            Traceback (most recent call last):
            ...
            ValueError: number of arguments must be > 0

        Check if we return None, when the builtin function would::

            sage: max_symbolic([None]) is None
            True
            sage: max_symbolic([None, None]) is None
            True
            sage: min_symbolic([None]) is None
            True
            sage: min_symbolic([None, None]) is None
            True

        Check if a single argument which is not iterable works::

            sage: max_symbolic(None)
            Traceback (most recent call last):
            ...
            TypeError: 'NoneType' object is not iterable
            sage: max_symbolic(5)
            Traceback (most recent call last):
            ...
            TypeError: 'sage.rings.integer.Integer' object is not iterable
            sage: max_symbolic(x)
            Traceback (most recent call last):
            ...
            TypeError: 'sage.symbolic.expression.Expression' object is not iterable
            sage: min_symbolic(5)
            Traceback (most recent call last):
            ...
            TypeError: 'sage.rings.integer.Integer' object is not iterable
            sage: min_symbolic(x)
            Traceback (most recent call last):
            ...
            TypeError: 'sage.symbolic.expression.Expression' object is not iterable
        """
        if len(args) == 0:
            raise ValueError("number of arguments must be > 0")
        if len(args) == 1:
            try:
                args=(SR._force_pyobject(iter(args[0])),)
            except TypeError as e:
                raise e

        try:
            return BuiltinFunction.__call__(self, *args, **kwds)
        except ValueError as e:
            if e.args[0] == "return None":
                return None
Пример #58
0
def simplify_sqrt_real(expr):
    r"""
    Simplify ``sqrt`` in symbolic expressions in the real domain.

    EXAMPLES:

    Simplifications of basic expressions::

        sage: from sage.manifolds.utilities import simplify_sqrt_real
        sage: simplify_sqrt_real( sqrt(x^2) )
        abs(x)
        sage: assume(x<0)
        sage: simplify_sqrt_real( sqrt(x^2) )
        -x
        sage: simplify_sqrt_real( sqrt(x^2-2*x+1) )
        -x + 1
        sage: simplify_sqrt_real( sqrt(x^2) + sqrt(x^2-2*x+1) )
        -2*x + 1

    This improves over Sage's
    :meth:`~sage.symbolic.expression.Expression.canonicalize_radical`,
    which yields incorrect results when ``x < 0``::

        sage: forget()  # removes the assumption x<0
        sage: sqrt(x^2).canonicalize_radical()
        x
        sage: assume(x<0)
        sage: sqrt(x^2).canonicalize_radical() # wrong output
        x
        sage: sqrt(x^2-2*x+1).canonicalize_radical() # wrong output
        x - 1
        sage: ( sqrt(x^2) + sqrt(x^2-2*x+1) ).canonicalize_radical() # wrong output
        2*x - 1

    Simplification of nested ``sqrt``'s::

        sage: forget()  # removes the assumption x<0
        sage: simplify_sqrt_real( sqrt(1 + sqrt(x^2)) )
        sqrt(abs(x) + 1)
        sage: assume(x<0)
        sage: simplify_sqrt_real( sqrt(1 + sqrt(x^2)) )
        sqrt(-x + 1)
        sage: simplify_sqrt_real( sqrt(x^2 + sqrt(4*x^2) + 1) )
        -x + 1

    Again, :meth:`~sage.symbolic.expression.Expression.canonicalize_radical`
    fails on the last one::

        sage: (sqrt(x^2 + sqrt(4*x^2) + 1)).canonicalize_radical()  # wrong output
        x + 1

    """
    from sage.symbolic.ring import SR
    from sage.functions.other import sqrt
    # 1/ Search for the sqrt's in expr
    sexpr = str(expr)
    if 'sqrt(' not in sexpr:  # no sqrt to simplify
        return expr
    if 'D[' in sexpr:
        return expr    #!# the code below is not capable of simplifying
                       # expressions with symbolic derivatives denoted by Pynac
                       # symbols of the type D[0]
    # Lists to store the positions of all the top-level sqrt's in sexpr:
    pos_sqrts = []  # position of first character, i.e. 's' of 'sqrt(...)'
    pos_after = []  # position of character immediatelty after 'sqrt(...)'
    the_sqrts = []  # the sqrt sub-expressions in sexpr, i.e. 'sqrt(...)'
    pos_max = len(sexpr) - 6
    pos = 0
    while pos < pos_max:
        if sexpr[pos:pos+5] == 'sqrt(':
            pos_sqrts.append(pos)
            parenth = 1
            scan = pos+5
            while parenth != 0:
                if sexpr[scan] == '(': parenth += 1
                if sexpr[scan] == ')': parenth -= 1
                scan += 1
            the_sqrts.append( sexpr[pos:scan] )
            pos_after.append(scan)
            pos = scan
        else:
            pos += 1
    # 2/ Search for sub-sqrt's:
    for i in range(len(the_sqrts)):
        argum = the_sqrts[i][5:-1]  # the sqrt argument
        if 'sqrt(' in argum:
            simpl = simplify_sqrt_real(SR(argum))
            the_sqrts[i] = 'sqrt(' + str(simpl) + ')'
    # 3/ Simplifications of the sqrt's
    new_expr = ""    # will contain the result
    pos0 = 0
    for i, pos in enumerate(pos_sqrts):
        # radcan is called on each sqrt:
        x = SR(the_sqrts[i])
        argum = x.operands()[0] # the argument of sqrt
        den = argum.denominator()
        if not (den == 1):  # the argument of sqrt is a fraction
            # NB: after #19312 (integrated in Sage 6.10.beta7), the above
            # cannot be written as
            #    if den != 1!:
            num = argum.numerator()
            if num < 0 or den < 0:
                x = sqrt(-num) / sqrt(-den)  # new equivalent expression for x
        simpl = SR(x._maxima_().radcan())
        if str(simpl)[:5] == 'sqrt(' or str(simpl)[:7] == '1/sqrt(':
            # no further simplification seems possible:
            ssimpl = str(simpl)
        else:
            # the absolute value of radcan's output is taken, the call to
            # simplify() taking into account possible assumptions regarding the
            # sign of simpl:
            ssimpl = str(abs(simpl).simplify())
        # search for abs(1/sqrt(...)) term to simplify it into 1/sqrt(...):
        pstart = ssimpl.find('abs(1/sqrt(')
        if pstart != -1:
            ssimpl = ssimpl[:pstart] + ssimpl[pstart+3:] # getting rid of 'abs'
        new_expr += sexpr[pos0:pos] + '(' + ssimpl + ')'
        pos0 = pos_after[i]
    new_expr += sexpr[pos0:]
    return SR(new_expr)
Пример #59
0
def bezier3d(path, **options):
    """
    Draw a 3-dimensional bezier path.

    Input is similar to bezier_path, but each point in the path and
    each control point is required to have 3 coordinates.

    INPUT:

    -  ``path`` -- a list of curves, which each is a list of points. See further
        detail below.

    -  ``thickness`` -- (default: 2)

    - ``color`` -- a string (``"red"``, ``"green"`` etc)
      or a tuple (r, g, b) with r, g, b numbers between 0 and 1

    -  ``opacity`` -- (default: 1) if less than 1 then is
       transparent

    -  ``aspect_ratio`` -- (default:[1,1,1])

    The path is a list of curves, and each curve is a list of points.
    Each point is a tuple (x,y,z).

    The first curve contains the endpoints as the first and last point
    in the list.  All other curves assume a starting point given by the
    last entry in the preceding list, and take the last point in the list
    as their opposite endpoint.  A curve can have 0, 1 or 2 control points
    listed between the endpoints.  In the input example for path below,
    the first and second curves have 2 control points, the third has one,
    and the fourth has no control points::

        path = [[p1, c1, c2, p2], [c3, c4, p3], [c5, p4], [p5], ...]

    In the case of no control points, a straight line will be drawn
    between the two endpoints.  If one control point is supplied, then
    the curve at each of the endpoints will be tangent to the line from
    that endpoint to the control point.  Similarly, in the case of two
    control points, at each endpoint the curve will be tangent to the line
    connecting that endpoint with the control point immediately after or
    immediately preceding it in the list.

    So in our example above, the curve between p1 and p2 is tangent to the
    line through p1 and c1 at p1, and tangent to the line through p2 and c2
    at p2.  Similarly, the curve between p2 and p3 is tangent to line(p2,c3)
    at p2 and tangent to line(p3,c4) at p3.  Curve(p3,p4) is tangent to
    line(p3,c5) at p3 and tangent to line(p4,c5) at p4.  Curve(p4,p5) is a
    straight line.

    EXAMPLES::

        sage: path = [[(0,0,0),(.5,.1,.2),(.75,3,-1),(1,1,0)],[(.5,1,.2),(1,.5,0)],[(.7,.2,.5)]]
        sage: b = bezier3d(path, color='green')
        sage: b
        Graphics3d Object

    To construct a simple curve, create a list containing a single list::

        sage: path = [[(0,0,0),(1,0,0),(0,1,0),(0,1,1)]]
        sage: curve = bezier3d(path, thickness=5, color='blue')
        sage: curve
        Graphics3d Object
    """
    from . import parametric_plot3d as P3D
    from sage.modules.free_module_element import vector
    from sage.symbolic.ring import SR

    p0 = vector(path[0][-1])
    t = SR.var('t')
    if len(path[0]) > 2:
        B = (1-t)**3*vector(path[0][0])+3*t*(1-t)**2*vector(path[0][1])+3*t**2*(1-t)*vector(path[0][-2])+t**3*p0
        G = P3D.parametric_plot3d(list(B), (0, 1), color=options['color'], aspect_ratio=options['aspect_ratio'], thickness=options['thickness'], opacity=options['opacity'])
    else:
        G = line3d([path[0][0], p0], color=options['color'], thickness=options['thickness'], opacity=options['opacity'])

    for curve in path[1:]:
        if len(curve) > 1:
            p1 = vector(curve[0])
            p2 = vector(curve[-2])
            p3 = vector(curve[-1])
            B = (1-t)**3*p0+3*t*(1-t)**2*p1+3*t**2*(1-t)*p2+t**3*p3
            G += P3D.parametric_plot3d(list(B), (0, 1), color=options['color'], aspect_ratio=options['aspect_ratio'], thickness=options['thickness'], opacity=options['opacity'])
        else:
            G += line3d([p0,curve[0]], color=options['color'], thickness=options['thickness'], opacity=options['opacity'])
        p0 = curve[-1]
    return G
Пример #60
0
    def inverse(self, chartname1=None, chartname2=None): 
        r"""
        Returns the inverse diffeomorphism. 
        
        INPUT:
    
        - ``chartname1`` -- (default: None) string defining the chart in which
          the computation of the inverse is performed; if none is provided, the
          default chart of self.manifold1 will be used
        - ``chartname2`` -- (default: None) string defining the chart in which
          the computation of the inverse is performed; if none is provided, the
          default chart of self.manifold2 will be used
        
        OUTPUT:
        
        - the inverse diffeomorphism
        
        EXAMPLES:
        
            The inverse of a rotation in the plane::
            
                sage: m = Manifold(2, "plane")
                sage: c_cart = Chart(m, 'x y', 'cart')
                sage: # A pi/3 rotation around the origin:
                sage: rot = Diffeomorphism(m, m, ((x - sqrt(3)*y)/2, (sqrt(3)*x + y)/2))
                sage: p = Point(m,(1,2))
                sage: q = rot(p)
                sage: irot = rot.inverse()
                sage: p1 = irot(q)
                sage: p1 == p
                True
        """
        from sage.symbolic.ring import SR
        from sage.symbolic.relation import solve
        from utilities import simplify_chain
        if self._inverse is not None:
            return self._inverse
            
        if chartname1 is None: chartname1 = self.manifold1.def_chart.name
        if chartname2 is None: chartname2 = self.manifold2.def_chart.name

        coord_map = self.coord_expression[(chartname1, chartname2)]
        chart1 = self.manifold1.atlas[chartname1]
        chart2 = self.manifold2.atlas[chartname2]
        
        n1 = len(chart1.xx)
        n2 = len(chart2.xx)
        
        # New symbolic variables (different from chart2.xx to allow for a 
        #  correct solution even when chart2 = chart1):
        x2 = [ SR.var('xxxx' + str(i)) for i in range(n2) ]
        equations = [x2[i] == coord_map.functions[i] for i in range(n2) ]
        solutions = solve(equations, chart1.xx, solution_dict=True)
        if len(solutions) == 0: 
            raise ValueError("No solution found")
        if len(solutions) > 1: 
            raise ValueError("Non-unique solution found")
            
        #!# This should be the Python 2.7 form: 
        # substitutions = {x2[i]: chart2.xx[i] for i in range(n2)}
        #
        # Here we use a form compatible with Python 2.6:
        substitutions = dict([(x2[i], chart2.xx[i]) for i in range(n2)])
       
        inv_functions = [solutions[0][chart1.xx[i]].subs(substitutions) 
                           for i in range(n1)]
        for i in range(n1):
            x = inv_functions[i]
            try:
                inv_functions[i] = simplify_chain(x)
            except AttributeError:
                pass        
        self._inverse = Diffeomorphism(self.manifold2, self.manifold1, 
                                       inv_functions, chartname2, chartname1)
        return self._inverse