B
    cdT                 @   s   d dl mZ d dlmZ d dlmZmZmZmZ d dl	m
Z
mZ d dlmZ d dlmZmZmZ d dlmZ d dlmZ d d	lmZ d d
lmZ d dlmZ d dlmZ G dd deZ dS )    )Rational)S)	conjugateimresign)explog)sqrt)acoscossin)trigsimp)	integrate)MutableDenseMatrix)sympify)Expr)prec_to_dpsc               @   sX  e Zd ZdZdZdZdMddZedd	 Zed
d Z	edd Z
edd Zedd Zedd Zedd Zdd Zdd Zdd Zdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Zd,d- Zd.d/ Zed0d1 Zd2d3 Zd4d5 Z d6d7 Z!d8d9 Z"d:d; Z#d<d= Z$d>d? Z%d@dA Z&dBdC Z'dDdE Z(edFdG Z)dHdI Z*dNdKdLZ+dJS )O
QuaternionaJ  Provides basic quaternion operations.
    Quaternion objects can be instantiated as Quaternion(a, b, c, d)
    as in (a + b*i + c*j + d*k).

    Examples
    ========

    >>> from sympy import Quaternion
    >>> q = Quaternion(1, 2, 3, 4)
    >>> q
    1 + 2*i + 3*j + 4*k

    Quaternions over complex fields can be defined as :

    >>> from sympy import Quaternion
    >>> from sympy import symbols, I
    >>> x = symbols('x')
    >>> q1 = Quaternion(x, x**3, x, x**2, real_field = False)
    >>> q2 = Quaternion(3 + 4*I, 2 + 5*I, 0, 7 + 8*I, real_field = False)
    >>> q1
    x + x**3*i + x*j + x**2*k
    >>> q2
    (3 + 4*I) + (2 + 5*I)*i + 0*j + (7 + 8*I)*k

    References
    ==========

    .. [1] http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/
    .. [2] https://en.wikipedia.org/wiki/Quaternion

    g      &@Fr   Tc             C   s|   t |}t |}t |}t |}tdd ||||gD rDtdn4t| ||||}||_||_||_||_||_	|S d S )Nc             s   s   | ]}|j d kV  qdS )FN)is_commutative).0i r   f/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/sympy/algebras/quaternion.py	<genexpr>:   s    z%Quaternion.__new__.<locals>.<genexpr>z arguments have to be commutative)
r   any
ValueErrorr   __new___a_b_c_d_real_field)clsabcd
real_fieldobjr   r   r   r   4   s    
zQuaternion.__new__c             C   s   | j S )N)r   )selfr   r   r   r$   E   s    zQuaternion.ac             C   s   | j S )N)r   )r*   r   r   r   r%   I   s    zQuaternion.bc             C   s   | j S )N)r    )r*   r   r   r   r&   M   s    zQuaternion.cc             C   s   | j S )N)r!   )r*   r   r   r   r'   Q   s    zQuaternion.dc             C   s   | j S )N)r"   )r*   r   r   r   r(   U   s    zQuaternion.real_fieldc             C   s   |\}}}t |d |d  |d  }|| || ||   }}}t|tj }t|tj }|| }	|| }
|| }| ||	|
|S )a  Returns a rotation quaternion given the axis and the angle of rotation.

        Parameters
        ==========

        vector : tuple of three numbers
            The vector representation of the given axis.
        angle : number
            The angle by which axis is rotated (in radians).

        Returns
        =======

        Quaternion
            The normalized rotation quaternion calculated from the given axis and the angle of rotation.

        Examples
        ========

        >>> from sympy import Quaternion
        >>> from sympy import pi, sqrt
        >>> q = Quaternion.from_axis_angle((sqrt(3)/3, sqrt(3)/3, sqrt(3)/3), 2*pi/3)
        >>> q
        1/2 + 1/2*i + 1/2*j + 1/2*k

           )r
   r   r   ZHalfr   )r#   Zvectoranglexyznormsr$   r%   r&   r'   r   r   r   from_axis_angleY   s    
zQuaternion.from_axis_anglec             C   s   |  tdd }t||d  |d  |d  d }t||d  |d  |d  d }t||d  |d  |d  d }t||d  |d  |d  d }|t|d |d   }|t|d	 |d
   }|t|d |d   }t||||S )a  Returns the equivalent quaternion of a matrix. The quaternion will be normalized
        only if the matrix is special orthogonal (orthogonal and det(M) = 1).

        Parameters
        ==========

        M : Matrix
            Input matrix to be converted to equivalent quaternion. M must be special
            orthogonal (orthogonal and det(M) = 1) for the quaternion to be normalized.

        Returns
        =======

        Quaternion
            The quaternion equivalent to given matrix.

        Examples
        ========

        >>> from sympy import Quaternion
        >>> from sympy import Matrix, symbols, cos, sin, trigsimp
        >>> x = symbols('x')
        >>> M = Matrix([[cos(x), -sin(x), 0], [sin(x), cos(x), 0], [0, 0, 1]])
        >>> q = trigsimp(Quaternion.from_rotation_matrix(M))
        >>> q
        sqrt(2)*sqrt(cos(x) + 1)/2 + 0*i + 0*j + sqrt(2 - 2*cos(x))*sign(sin(x))/2*k

              )r   r   )r3   r3   )r+   r+   r+   )r+   r3   )r3   r+   )r   r+   )r+   r   )r3   r   )r   r3   )Zdetr   r
   r   r   )r#   MZabsQr$   r%   r&   r'   r   r   r   from_rotation_matrix   s    $$$$zQuaternion.from_rotation_matrixc             C   s
   |  |S )N)add)r*   otherr   r   r   __add__   s    zQuaternion.__add__c             C   s
   |  |S )N)r7   )r*   r8   r   r   r   __radd__   s    zQuaternion.__radd__c             C   s   |  |d S )N)r7   )r*   r8   r   r   r   __sub__   s    zQuaternion.__sub__c             C   s   |  | |S )N)_generic_mul)r*   r8   r   r   r   __mul__   s    zQuaternion.__mul__c             C   s   |  || S )N)r=   )r*   r8   r   r   r   __rmul__   s    zQuaternion.__rmul__c             C   s
   |  |S )N)pow)r*   pr   r   r   __pow__   s    zQuaternion.__pow__c             C   s   t | j | j | j | j S )N)r   r   r   r    r'   )r*   r   r   r   __neg__   s    zQuaternion.__neg__c             C   s   | t |d  S )Nr;   )r   )r*   r8   r   r   r   __truediv__   s    zQuaternion.__truediv__c             C   s   t || d  S )Nr;   )r   )r*   r8   r   r   r   __rtruediv__   s    zQuaternion.__rtruediv__c             G   s
   | j | S )N)r   )r*   argsr   r   r   _eval_Integral   s    zQuaternion._eval_Integralc                s(     dd | j fdd| jD  S )NevaluateTc                s   g | ]}|j  qS r   )diff)r   r$   )kwargssymbolsr   r   
<listcomp>   s    z#Quaternion.diff.<locals>.<listcomp>)
setdefaultfuncrF   )r*   rK   rJ   r   )rJ   rK   r   rI      s    zQuaternion.diffc             C   s   | }t |}t|tsp|jrH|jrHtt||j t||j |j	|j
S |jrht|j| |j|j	|j
S tdt|j|j |j|j |j	|j	 |j
|j
 S )a  Adds quaternions.

        Parameters
        ==========

        other : Quaternion
            The quaternion to add to current (self) quaternion.

        Returns
        =======

        Quaternion
            The resultant quaternion after adding self to other

        Examples
        ========

        >>> from sympy import Quaternion
        >>> from sympy import symbols
        >>> q1 = Quaternion(1, 2, 3, 4)
        >>> q2 = Quaternion(5, 6, 7, 8)
        >>> q1.add(q2)
        6 + 8*i + 10*j + 12*k
        >>> q1 + 5
        6 + 2*i + 3*j + 4*k
        >>> x = symbols('x', real = True)
        >>> q1.add(x)
        (x + 1) + 2*i + 3*j + 4*k

        Quaternions over complex fields :

        >>> from sympy import Quaternion
        >>> from sympy import I
        >>> q3 = Quaternion(3 + 4*I, 2 + 5*I, 0, 7 + 8*I, real_field = False)
        >>> q3.add(2 + 3*I)
        (5 + 7*I) + (2 + 5*I)*i + 0*j + (7 + 8*I)*k

        z<Only commutative expressions can be added with a Quaternion.)r   
isinstancer   r(   
is_complexr   r$   r   r%   r&   r'   r   r   )r*   r8   q1q2r   r   r   r7      s    '
&$zQuaternion.addc             C   s   |  | |S )a  Multiplies quaternions.

        Parameters
        ==========

        other : Quaternion or symbol
            The quaternion to multiply to current (self) quaternion.

        Returns
        =======

        Quaternion
            The resultant quaternion after multiplying self with other

        Examples
        ========

        >>> from sympy import Quaternion
        >>> from sympy import symbols
        >>> q1 = Quaternion(1, 2, 3, 4)
        >>> q2 = Quaternion(5, 6, 7, 8)
        >>> q1.mul(q2)
        (-60) + 12*i + 30*j + 24*k
        >>> q1.mul(2)
        2 + 4*i + 6*j + 8*k
        >>> x = symbols('x', real = True)
        >>> q1.mul(x)
        x + 2*x*i + 3*x*j + 4*x*k

        Quaternions over complex fields :

        >>> from sympy import Quaternion
        >>> from sympy import I
        >>> q3 = Quaternion(3 + 4*I, 2 + 5*I, 0, 7 + 8*I, real_field = False)
        >>> q3.mul(2 + 3*I)
        (2 + 3*I)*(3 + 4*I) + (2 + 3*I)*(2 + 5*I)*i + 0*j + (2 + 3*I)*(7 + 8*I)*k

        )r=   )r*   r8   r   r   r   mul  s    'zQuaternion.mulc             C   s  t | } t |}t| ts,t|ts,| | S t| ts|jr\| jr\tt| t| dd| S | jrt| |j | |j	 | |j
 | |j S tdt|ts| jr|jr| tt|t|dd S |jrt|| j || j	 || j
 || j S tdt| j	 |j	 | j
|j
  | j|j  | j|j  | j	|j | j
|j  | j|j
  | j|j	  | j	 |j | j
|j  | j|j	  | j|j
  | j	|j
 | j
|j	  | j|j  | j|j  S )a  Generic multiplication.

        Parameters
        ==========

        q1 : Quaternion or symbol
        q2 : Quaternion or symbol

        It's important to note that if neither q1 nor q2 is a Quaternion,
        this function simply returns q1 * q2.

        Returns
        =======

        Quaternion
            The resultant quaternion after multiplying q1 and q2

        Examples
        ========

        >>> from sympy import Quaternion
        >>> from sympy import Symbol
        >>> q1 = Quaternion(1, 2, 3, 4)
        >>> q2 = Quaternion(5, 6, 7, 8)
        >>> Quaternion._generic_mul(q1, q2)
        (-60) + 12*i + 30*j + 24*k
        >>> Quaternion._generic_mul(q1, 2)
        2 + 4*i + 6*j + 8*k
        >>> x = Symbol('x', real = True)
        >>> Quaternion._generic_mul(q1, x)
        x + 2*x*i + 3*x*j + 4*x*k

        Quaternions over complex fields :

        >>> from sympy import Quaternion
        >>> from sympy import I
        >>> q3 = Quaternion(3 + 4*I, 2 + 5*I, 0, 7 + 8*I, real_field = False)
        >>> Quaternion._generic_mul(q3, 2 + 3*I)
        (2 + 3*I)*(3 + 4*I) + (2 + 3*I)*(2 + 5*I)*i + 0*j + (2 + 3*I)*(7 + 8*I)*k

        r   zAOnly commutative expressions can be multiplied with a Quaternion.)r   rO   r   r(   rP   r   r   r   r$   r%   r&   r'   r   )rQ   rR   r   r   r   r=   1  s(    +
&
&2.0zQuaternion._generic_mulc             C   s    | }t |j|j |j |j S )z(Returns the conjugate of the quaternion.)r   r$   r%   r&   r'   )r*   qr   r   r   _eval_conjugatez  s    zQuaternion._eval_conjugatec             C   s4   | }t t|jd |jd  |jd  |jd  S )z#Returns the norm of the quaternion.r+   )r
   r   r$   r%   r&   r'   )r*   rT   r   r   r   r0     s    zQuaternion.normc             C   s   | }|d|    S )z.Returns the normalized form of the quaternion.r3   )r0   )r*   rT   r   r   r   	normalize  s    zQuaternion.normalizec             C   s,   | }|  stdt|d|  d   S )z&Returns the inverse of the quaternion.z6Cannot compute inverse for a quaternion with zero normr3   r+   )r0   r   r   )r*   rT   r   r   r   inverse  s    zQuaternion.inversec             C   sx   t |}| }|dkr| S d}|js*tS |dk rB| |  }}x0|dkrr|d dkr`|| }|d }|| }qDW |S )a  Finds the pth power of the quaternion.

        Parameters
        ==========

        p : int
            Power to be applied on quaternion.

        Returns
        =======

        Quaternion
            Returns the p-th power of the current quaternion.
            Returns the inverse if p = -1.

        Examples
        ========

        >>> from sympy import Quaternion
        >>> q = Quaternion(1, 2, 3, 4)
        >>> q.pow(4)
        668 + (-224)*i + (-336)*j + (-448)*k

        r;   r3   r   r+   )r   rW   Z
is_IntegerNotImplemented)r*   rA   rT   resr   r   r   r@     s    
zQuaternion.powc             C   s   | }t |jd |jd  |jd  }t|jt| }t|jt| |j | }t|jt| |j | }t|jt| |j | }t||||S )a  Returns the exponential of q (e^q).

        Returns
        =======

        Quaternion
            Exponential of q (e^q).

        Examples
        ========

        >>> from sympy import Quaternion
        >>> q = Quaternion(1, 2, 3, 4)
        >>> q.exp()
        E*cos(sqrt(29))
        + 2*sqrt(29)*E*sin(sqrt(29))/29*i
        + 3*sqrt(29)*E*sin(sqrt(29))/29*j
        + 4*sqrt(29)*E*sin(sqrt(29))/29*k

        r+   )	r
   r%   r&   r'   r   r$   r   r   r   )r*   rT   vector_normr$   r%   r&   r'   r   r   r   r     s    "zQuaternion.expc             C   s   | }t |jd |jd  |jd  }| }t|}|jt|j|  | }|jt|j|  | }|jt|j|  | }t||||S )ae  Returns the natural logarithm of the quaternion (_ln(q)).

        Examples
        ========

        >>> from sympy import Quaternion
        >>> q = Quaternion(1, 2, 3, 4)
        >>> q._ln()
        log(sqrt(30))
        + 2*sqrt(29)*acos(sqrt(30)/30)/29*i
        + 3*sqrt(29)*acos(sqrt(30)/30)/29*j
        + 4*sqrt(29)*acos(sqrt(30)/30)/29*k

        r+   )	r
   r%   r&   r'   r0   lnr   r$   r   )r*   rT   rZ   Zq_normr$   r%   r&   r'   r   r   r   _ln  s    "zQuaternion._lnc                s    t | t fdd| jD  S )a  Returns the floating point approximations (decimal numbers) of the quaternion.

        Returns
        =======

        Quaternion
            Floating point approximations of quaternion(self)

        Examples
        ========

        >>> from sympy import Quaternion
        >>> from sympy import sqrt
        >>> q = Quaternion(1/sqrt(1), 1/sqrt(2), 1/sqrt(3), 1/sqrt(4))
        >>> q.evalf()
        1.00000000000000
        + 0.707106781186547*i
        + 0.577350269189626*j
        + 0.500000000000000*k

        c                s   g | ]}|j  d qS ))n)Zevalf)r   arg)nprecr   r   rL     s    z*Quaternion._eval_evalf.<locals>.<listcomp>)r   r   rF   )r*   precr   )r_   r   _eval_evalf  s    zQuaternion._eval_evalfc             C   s0   | }|  \}}t||| }|| |  S )aY  Computes the pth power in the cos-sin form.

        Parameters
        ==========

        p : int
            Power to be applied on quaternion.

        Returns
        =======

        Quaternion
            The p-th power in the cos-sin form.

        Examples
        ========

        >>> from sympy import Quaternion
        >>> q = Quaternion(1, 2, 3, 4)
        >>> q.pow_cos_sin(4)
        900*cos(4*acos(sqrt(30)/30))
        + 1800*sqrt(29)*sin(4*acos(sqrt(30)/30))/29*i
        + 2700*sqrt(29)*sin(4*acos(sqrt(30)/30))/29*j
        + 3600*sqrt(29)*sin(4*acos(sqrt(30)/30))/29*k

        )to_axis_angler   r2   r0   )r*   rA   rT   vr,   rR   r   r   r   pow_cos_sin  s    zQuaternion.pow_cos_sinc             G   s>   t t| jf| t| jf| t| jf| t| jf| S )a  Computes integration of quaternion.

        Returns
        =======

        Quaternion
            Integration of the quaternion(self) with the given variable.

        Examples
        ========

        Indefinite Integral of quaternion :

        >>> from sympy import Quaternion
        >>> from sympy.abc import x
        >>> q = Quaternion(1, 2, 3, 4)
        >>> q.integrate(x)
        x + 2*x*i + 3*x*j + 4*x*k

        Definite integral of quaternion :

        >>> from sympy import Quaternion
        >>> from sympy.abc import x
        >>> q = Quaternion(1, 2, 3, 4)
        >>> q.integrate((x, 1, 5))
        4 + 8*i + 12*j + 16*k

        )r   r   r$   r%   r&   r'   )r*   rF   r   r   r   r   5  s    zQuaternion.integratec             C   s^   t |tr t|d |d }n| }|td| d | d | d  t| }|j|j|jfS )a  Returns the coordinates of the point pin(a 3 tuple) after rotation.

        Parameters
        ==========

        pin : tuple
            A 3-element tuple of coordinates of a point which needs to be
            rotated.
        r : Quaternion or tuple
            Axis and angle of rotation.

            It's important to note that when r is a tuple, it must be of the form
            (axis, angle)

        Returns
        =======

        tuple
            The coordinates of the point after rotation.

        Examples
        ========

        >>> from sympy import Quaternion
        >>> from sympy import symbols, trigsimp, cos, sin
        >>> x = symbols('x')
        >>> q = Quaternion(cos(x/2), 0, 0, sin(x/2))
        >>> trigsimp(Quaternion.rotate_point((1, 1, 1), q))
        (sqrt(2)*cos(x + pi/4), sqrt(2)*sin(x + pi/4), 1)
        >>> (axis, angle) = q.to_axis_angle()
        >>> trigsimp(Quaternion.rotate_point((1, 1, 1), (axis, angle)))
        (sqrt(2)*cos(x + pi/4), sqrt(2)*sin(x + pi/4), 1)

        r   r3   r+   )	rO   tupler   r2   rV   r   r%   r&   r'   )ZpinrrT   Zpoutr   r   r   rotate_pointV  s
    $
&zQuaternion.rotate_pointc       	      C   s   | }|j jr|d }| }tdt|j  }td|j |j   }t|j| }t|j| }t|j| }|||f}||f}|S )a  Returns the axis and angle of rotation of a quaternion

        Returns
        =======

        tuple
            Tuple of (axis, angle)

        Examples
        ========

        >>> from sympy import Quaternion
        >>> q = Quaternion(1, 1, 1, 1)
        >>> (axis, angle) = q.to_axis_angle()
        >>> axis
        (sqrt(3)/3, sqrt(3)/3, sqrt(3)/3)
        >>> angle
        2*pi/3

        r;   r+   r3   )	r$   Zis_negativerV   r   r   r
   r%   r&   r'   )	r*   rT   r,   r1   r-   r.   r/   rc   tr   r   r   rb     s    
zQuaternion.to_axis_angleNc             C   s  | }|  d }dd| |jd |jd    }d| |j|j |j|j   }d| |j|j |j|j   }d| |j|j |j|j   }dd| |jd |jd    }d| |j|j |j|j   }	d| |j|j |j|j   }
d| |j|j |j|j   }dd| |jd |jd    }|sVt|||g|||	g|
||ggS |\}}}|||  ||  ||  }|||  ||  ||	  }|||
  ||  ||  }d } }}d}t||||g|||	|g|
|||g||||ggS dS )a  Returns the equivalent rotation transformation matrix of the quaternion
        which represents rotation about the origin if v is not passed.

        Parameters
        ==========

        v : tuple or None
            Default value: None

        Returns
        =======

        tuple
            Returns the equivalent rotation transformation matrix of the quaternion
            which represents rotation about the origin if v is not passed.

        Examples
        ========

        >>> from sympy import Quaternion
        >>> from sympy import symbols, trigsimp, cos, sin
        >>> x = symbols('x')
        >>> q = Quaternion(cos(x/2), 0, 0, sin(x/2))
        >>> trigsimp(q.to_rotation_matrix())
        Matrix([
        [cos(x), -sin(x), 0],
        [sin(x),  cos(x), 0],
        [     0,       0, 1]])

        Generates a 4x4 transformation matrix (used for rotation about a point
        other than the origin) if the point(v) is passed as an argument.

        Examples
        ========

        >>> from sympy import Quaternion
        >>> from sympy import symbols, trigsimp, cos, sin
        >>> x = symbols('x')
        >>> q = Quaternion(cos(x/2), 0, 0, sin(x/2))
        >>> trigsimp(q.to_rotation_matrix((1, 1, 1)))
         Matrix([
        [cos(x), -sin(x), 0,  sin(x) - cos(x) + 1],
        [sin(x),  cos(x), 0, -sin(x) - cos(x) + 1],
        [     0,       0, 1,                    0],
        [     0,       0, 0,                    1]])

        r3   r+   r   N)r0   r&   r'   r%   r$   Matrix)r*   rc   rT   r1   Zm00Zm01Zm02Zm10Zm11Zm12Zm20Zm21Zm22r-   r.   r/   Zm03Zm13Zm23Zm30Zm31Zm32Zm33r   r   r   to_rotation_matrix  s*    1          
zQuaternion.to_rotation_matrix)r   r   r   r   T)N),__name__
__module____qualname____doc__Z_op_priorityr   r   propertyr$   r%   r&   r'   r(   classmethodr2   r6   r9   r:   r<   r>   r?   rB   rC   rD   rE   rG   rI   r7   rS   staticmethodr=   rU   r0   rV   rW   r@   r   r\   ra   rd   r   rg   rb   rk   r   r   r   r   r      sL   
+,6)I.#!-(r   N)!Zsympy.core.numbersr   Zsympy.core.singletonr   Z$sympy.functions.elementary.complexesr   r   r   r   Z&sympy.functions.elementary.exponentialr   r	   r[   Z(sympy.functions.elementary.miscellaneousr
   Z(sympy.functions.elementary.trigonometricr   r   r   Zsympy.simplify.trigsimpr   Zsympy.integrals.integralsr   Zsympy.matrices.denser   rj   Zsympy.core.sympifyr   Zsympy.core.exprr   Zmpmath.libmp.libmpfr   r   r   r   r   r   <module>   s   