Ejemplo n.º 1
0
def subexpressions_list(f, pars=None):
    """
    Construct the lists with the intermediate steps on the evaluation of the
    function.

    INPUT:

    - ``f`` -- a symbolic function of several components.

    - ``pars`` -- a list of the parameters that appear in the function
      this should be the symbolic constants that appear in f but are not
      arguments.

    OUTPUT:

    - a list of the intermediate subexpressions that appear in the evaluation
      of f.

    - a list with the operations used to construct each of the subexpressions.
      each element of this list is a tuple, formed by a string describing the
      operation made, and the operands.

    For the trigonometric functions, some extra expressions will be added.
    These extra expressions will be used later to compute their derivatives.


    EXAMPLES::

        sage: from sage.interfaces.tides import subexpressions_list
        sage: var('x,y')
        (x, y)
        sage: f(x,y) = [x^2+y, cos(x)/log(y)]
        sage: subexpressions_list(f)
        ([x^2, x^2 + y, sin(x), cos(x), log(y), cos(x)/log(y)],
        [('mul', x, x),
        ('add', y, x^2),
        ('sin', x),
        ('cos', x),
        ('log', y),
        ('div', log(y), cos(x))])

    ::

        sage: f(a)=[cos(a), arctan(a)]
        sage: from sage.interfaces.tides import subexpressions_list
        sage: subexpressions_list(f)
        ([sin(a), cos(a), a^2, a^2 + 1, arctan(a)],
        [('sin', a), ('cos', a), ('mul', a, a), ('add', 1, a^2), ('atan', a)])

    ::

        sage: from sage.interfaces.tides import subexpressions_list
        sage: var('s,b,r')
        (s, b, r)
        sage: f(t,x,y,z)= [s*(y-x),x*(r-z)-y,x*y-b*z]
        sage: subexpressions_list(f,[s,b,r])
        ([-y,
        x - y,
        s*(x - y),
        -s*(x - y),
        -z,
        r - z,
        (r - z)*x,
        -y,
        (r - z)*x - y,
        x*y,
        b*z,
        -b*z,
        x*y - b*z],
        [('mul', -1, y),
        ('add', -y, x),
        ('mul', x - y, s),
        ('mul', -1, s*(x - y)),
        ('mul', -1, z),
        ('add', -z, r),
        ('mul', x, r - z),
        ('mul', -1, y),
        ('add', -y, (r - z)*x),
        ('mul', y, x),
        ('mul', z, b),
        ('mul', -1, b*z),
        ('add', -b*z, x*y)])

    ::

        sage: var('x, y')
        (x, y)
        sage: f(x,y)=[exp(x^2+sin(y))]
        sage: from sage.interfaces.tides import *
        sage: subexpressions_list(f)
        ([x^2, sin(y), cos(y), x^2 + sin(y), e^(x^2 + sin(y))],
        [('mul', x, x),
        ('sin', y),
        ('cos', y),
        ('add', sin(y), x^2),
        ('exp', x^2 + sin(y))])


    """
    from sage.functions.trig import sin, cos, arcsin, arctan, arccos
    variables = f[0].arguments()
    if not pars:
        parameters = []
    else:
        parameters = pars
    varpar = list(parameters) + list(variables)
    F = symbolic_expression([i(*variables) for i in f]).function(*varpar)
    lis = flatten([fast_callable(i,vars=varpar).op_list() for i in F], max_level=1)
    stack = []
    const =[]
    stackcomp=[]
    detail=[]
    for i in lis:
        if i[0] == 'load_arg':
            stack.append(varpar[i[1]])
        elif i[0] == 'ipow':
            if i[1] in NN:
                basis = stack[-1]
                for j in range(i[1]-1):
                    a=stack.pop(-1)
                    detail.append(('mul', a, basis))
                    stack.append(a*basis)
                    stackcomp.append(stack[-1])
            else:
                detail.append(('pow',stack[-1],i[1]))
                stack[-1]=stack[-1]**i[1]
                stackcomp.append(stack[-1])

        elif i[0] == 'load_const':
            const.append(i[1])
            stack.append(i[1])
        elif i == 'mul':
            a=stack.pop(-1)
            b=stack.pop(-1)
            detail.append(('mul', a, b))
            stack.append(a*b)
            stackcomp.append(stack[-1])

        elif i == 'div':
            a=stack.pop(-1)
            b=stack.pop(-1)
            detail.append(('div', a, b))
            stack.append(b/a)
            stackcomp.append(stack[-1])

        elif i == 'add':
            a=stack.pop(-1)
            b=stack.pop(-1)
            detail.append(('add',a,b))
            stack.append(a+b)
            stackcomp.append(stack[-1])

        elif i == 'pow':
            a=stack.pop(-1)
            b=stack.pop(-1)
            detail.append(('pow', b, a))
            stack.append(b**a)
            stackcomp.append(stack[-1])

        elif i[0] == 'py_call' and str(i[1])=='log':
            a=stack.pop(-1)
            detail.append(('log', a))
            stack.append(log(a))
            stackcomp.append(stack[-1])

        elif i[0] == 'py_call' and str(i[1])=='exp':
            a=stack.pop(-1)
            detail.append(('exp', a))
            stack.append(exp(a))
            stackcomp.append(stack[-1])

        elif i[0] == 'py_call' and str(i[1])=='sin':
            a=stack.pop(-1)
            detail.append(('sin', a))
            detail.append(('cos', a))
            stackcomp.append(sin(a))
            stackcomp.append(cos(a))
            stack.append(sin(a))

        elif i[0] == 'py_call' and str(i[1])=='cos':
            a=stack.pop(-1)
            detail.append(('sin', a))
            detail.append(('cos', a))
            stackcomp.append(sin(a))
            stackcomp.append(cos(a))
            stack.append(cos(a))

        elif i[0] == 'py_call' and str(i[1])=='tan':
            a=stack.pop(-1)
            b = sin(a)
            c = cos(a)
            detail.append(('sin', a))
            detail.append(('cos', a))
            detail.append(('div', b, c))
            stackcomp.append(b)
            stackcomp.append(c)
            stackcomp.append(b/c)
            stack.append(b/c)

        elif i[0] == 'py_call' and str(i[1])=='arctan':
            a=stack.pop(-1)
            detail.append(('mul', a, a))
            detail.append(('add', 1, a*a))
            detail.append(('atan', a))
            stackcomp.append(a*a)
            stackcomp.append(1+a*a)
            stackcomp.append(arctan(a))
            stack.append(arctan(a))

        elif i[0] == 'py_call' and str(i[1])=='arcsin':
            a=stack.pop(-1)
            detail.append(('mul', a, a))
            detail.append(('mul', -1, a*a))
            detail.append(('add', 1, -a*a))
            detail.append(('pow', 1- a*a, 0.5))
            detail.append(('asin', a))
            stackcomp.append(a*a)
            stackcomp.append(-a*a)
            stackcomp.append(1-a*a)
            stackcomp.append(sqrt(1-a*a))
            stackcomp.append(arcsin(a))
            stack.append(arcsin(a))

        elif i[0] == 'py_call' and str(i[1])=='arccos':
            a=stack.pop(-1)
            detail.append(('mul', a, a))
            detail.append(('mul', -1, a*a))
            detail.append(('add', 1, -a*a))
            detail.append(('pow', 1- a*a, 0.5))
            detail.append(('mul', -1, sqrt(1-a*a)))
            detail.append(('acos', a))
            stackcomp.append(a*a)
            stackcomp.append(-a*a)
            stackcomp.append(1-a*a)
            stackcomp.append(sqrt(1-a*a))
            stackcomp.append(-sqrt(1-a*a))
            stackcomp.append(arccos(a))
            stack.append(arccos(a))

        elif i[0] == 'py_call' and 'sqrt' in str(i[1]):
            a=stack.pop(-1)
            detail.append(('pow', a, 0.5))
            stackcomp.append(sqrt(a))
            stack.append(sqrt(a))


        elif i == 'neg':
            a = stack.pop(-1)
            detail.append(('mul', -1, a))
            stack.append(-a)
            stackcomp.append(-a)

    return stackcomp,detail
    first_vector=first_point-center
    second_vector=second_point-center
    radius=norm(first_vector)
    if norm(second_vector)!=radius:
        raise ValueError("Ellipse not implemented")
    first_unit_vector=first_vector/radius
    second_unit_vector=second_vector/radius
    normal_vector=second_vector-(second_vector*first_unit_vector)*first_unit_vector
    if norm(normal_vector)==0:
        print (first_point,second_point)
        return
    normal_unit_vector=normal_vector/norm(normal_vector)
    scalar_product=first_unit_vector*second_unit_vector
    if abs(scalar_product) == 1:
        raise ValueError("The points are alligned")
    angle=arccos(scalar_product)
    var('t')
    return parametric_plot3d(center+first_vector*cos(t)+radius*normal_unit_vector*sin(t),(0,angle),**kwds)
     

     
def _arc(p,q,s,**kwds):
    #rewrite this to use polar_plot and get points to do filled triangles
    from sage.misc.functional import det
    from sage.plot.line import line
    from sage.misc.functional import norm
    from sage.symbolic.all import pi
    from sage.plot.arc import arc
     
    p,q,s = map( lambda x: vector(x), [p,q,s])
     
Ejemplo n.º 3
0
    def angle(self, other):  # UHP
        r"""
        Return the angle between any two given completed geodesics if
        they intersect.

        INPUT:

        - ``other`` -- a hyperbolic geodesic in the UHP model

        OUTPUT:

        - the angle in radians between the two given geodesics

        EXAMPLES::

            sage: UHP = HyperbolicPlane().UHP()
            sage: g = UHP.get_geodesic(2, 4)
            sage: h = UHP.get_geodesic(3, 3 + I)
            sage: g.angle(h)
            1/2*pi
            sage: numerical_approx(g.angle(h))
            1.57079632679490

        If the geodesics are identical, return angle 0::

            sage: g.angle(g)
            0

        It is an error to ask for the angle of two geodesics that do not
        intersect::

            sage: g = UHP.get_geodesic(2, 4)
            sage: h = UHP.get_geodesic(5, 7)
            sage: g.angle(h)
            Traceback (most recent call last):
            ...
            ValueError: geodesics do not intersect
        """
        if self.is_parallel(other):
            raise ValueError("geodesics do not intersect")
        # Make sure the segments are complete or intersect
        if (not(self.is_complete() and other.is_complete())
                and not self.intersection(other)):
            print("Warning: Geodesic segments do not intersect. "
                  "The angle between them is not defined.\n"
                  "Returning the angle between their completions.")

        # Make sure both are in the same model
        if other._model is not self._model:
            other = other.to_model(self._model)

        (p1, p2) = sorted([k.coordinates()
                           for k in self.ideal_endpoints()], key=str)
        (q1, q2) = sorted([k.coordinates()
                           for k in other.ideal_endpoints()], key=str)
        # if the geodesics are equal, the angle between them is 0
        if (abs(p1 - q1) < EPSILON
                and abs(p2 - q2) < EPSILON):
            return 0
        elif p2 != infinity:  # geodesic not a straight line
            # So we send it to the geodesic with endpoints [0, oo]
            T = HyperbolicGeodesicUHP._crossratio_matrix(p1, (p1 + p2) / 2, p2)
        else:
            # geodesic is a straight line, so we send it to the geodesic
            # with endpoints [0,oo]
            T = HyperbolicGeodesicUHP._crossratio_matrix(p1, p1 + 1, p2)
        # b1 and b2 are the endpoints of the image of other
        b1, b2 = [mobius_transform(T, k) for k in [q1, q2]]
        # If other is now a straight line...
        if (b1 == infinity or b2 == infinity):
            # then since they intersect, they are equal
            return 0
        return real(arccos((b1 + b2) / abs(b2 - b1)))
Ejemplo n.º 4
0
    def angle(self, other):  # UHP
        r"""
        Return the angle between any two given completed geodesics if
        they intersect.

        INPUT:

        - ``other`` -- a hyperbolic geodesic in the UHP model

        OUTPUT:

        - the angle in radians between the two given geodesics

        EXAMPLES::

            sage: UHP = HyperbolicPlane().UHP()
            sage: g = UHP.get_geodesic(2, 4)
            sage: h = UHP.get_geodesic(3, 3 + I)
            sage: g.angle(h)
            1/2*pi
            sage: numerical_approx(g.angle(h))
            1.57079632679490

        If the geodesics are identical, return angle 0::

            sage: g.angle(g)
            0

        It is an error to ask for the angle of two geodesics that do not
        intersect::

            sage: g = UHP.get_geodesic(2, 4)
            sage: h = UHP.get_geodesic(5, 7)
            sage: g.angle(h)
            Traceback (most recent call last):
            ...
            ValueError: geodesics do not intersect
        """
        if self.is_parallel(other):
            raise ValueError("geodesics do not intersect")
        # Make sure the segments are complete or intersect
        if (not (self.is_complete() and other.is_complete())
                and not self.intersection(other)):
            print("Warning: Geodesic segments do not intersect. "
                  "The angle between them is not defined.\n"
                  "Returning the angle between their completions.")

        # Make sure both are in the same model
        if other._model is not self._model:
            other = other.to_model(self._model)

        (p1, p2) = sorted([k.coordinates() for k in self.ideal_endpoints()],
                          key=str)
        (q1, q2) = sorted([k.coordinates() for k in other.ideal_endpoints()],
                          key=str)
        # if the geodesics are equal, the angle between them is 0
        if (abs(p1 - q1) < EPSILON and abs(p2 - q2) < EPSILON):
            return 0
        elif p2 != infinity:  # geodesic not a straight line
            # So we send it to the geodesic with endpoints [0, oo]
            T = HyperbolicGeodesicUHP._crossratio_matrix(p1, (p1 + p2) / 2, p2)
        else:
            # geodesic is a straight line, so we send it to the geodesic
            # with endpoints [0,oo]
            T = HyperbolicGeodesicUHP._crossratio_matrix(p1, p1 + 1, p2)
        # b1 and b2 are the endpoints of the image of other
        b1, b2 = [mobius_transform(T, k) for k in [q1, q2]]
        # If other is now a straight line...
        if (b1 == infinity or b2 == infinity):
            # then since they intersect, they are equal
            return 0
        return real(arccos((b1 + b2) / abs(b2 - b1)))
Ejemplo n.º 5
0
    second_vector = second_point - center
    radius = norm(first_vector)
    if norm(second_vector) != radius:
        raise ValueError("Ellipse not implemented")
    first_unit_vector = first_vector / radius
    second_unit_vector = second_vector / radius
    normal_vector = second_vector - (second_vector *
                                     first_unit_vector) * first_unit_vector
    if norm(normal_vector) == 0:
        print(first_point, second_point)
        return
    normal_unit_vector = normal_vector / norm(normal_vector)
    scalar_product = first_unit_vector * second_unit_vector
    if abs(scalar_product) == 1:
        raise ValueError("The points are alligned")
    angle = arccos(scalar_product)
    var('t')
    return parametric_plot3d(
        center + first_vector * cos(t) + radius * normal_unit_vector * sin(t),
        (0, angle), **kwds)


def _arc(p, q, s, **kwds):
    #rewrite this to use polar_plot and get points to do filled triangles
    from sage.misc.functional import det
    from sage.plot.line import line
    from sage.misc.functional import norm
    from sage.symbolic.all import pi
    from sage.plot.arc import arc

    p, q, s = map(lambda x: vector(x), [p, q, s])