o
    8VaT                     @   s   d dl mZmZ d dl mZmZmZmZ d dl mZmZm	Z	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 )    )SRational)reim	conjugatesign)sqrtsincosacosexpln)trigsimp	integrate)Matrixsympify)prec_to_dps)Exprc                   @   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
Quaterniona  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.algebras.quaternion 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.algebras.quaternion 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

    g      &@Fr   Tc                 C   sv   t |}t |}t |}t |}tdd ||||fD r!tdt| ||||}||_||_||_||_||_	|S )Nc                 s   s    | ]}|j d u V  qdS )FN)is_commutative).0i r   ;/usr/lib/python3/dist-packages/sympy/algebras/quaternion.py	<genexpr>3   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   -   s   zQuaternion.__new__c                 C      | j S N)r    selfr   r   r   r&   >      zQuaternion.ac                 C   r,   r-   )r!   r.   r   r   r   r'   B   r0   zQuaternion.bc                 C   r,   r-   )r"   r.   r   r   r   r(   F   r0   zQuaternion.cc                 C   r,   r-   )r#   r.   r   r   r   r)   J   r0   zQuaternion.dc                 C   r,   r-   )r$   r.   r   r   r   r*   N   r0   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.algebras.quaternion 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_angleR   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.algebras.quaternion 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   )r9   r9   )r1   r1   r1   )r1   r9   )r9   r1   )r   r1   )r1   r   )r9   r   )r   r9   )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 r-   addr/   otherr   r   r   __add__      
zQuaternion.__add__c                 C   r=   r-   r>   r@   r   r   r   __radd__   rC   zQuaternion.__radd__c                 C   s   |  |d S Nr>   r@   r   r   r   __sub__   s   zQuaternion.__sub__c                 C      |  | |S r-   _generic_mulr@   r   r   r   __mul__      zQuaternion.__mul__c                 C   s   |  || S r-   rI   r@   r   r   r   __rmul__   rL   zQuaternion.__rmul__c                 C   r=   r-   )pow)r/   pr   r   r   __pow__   rC   zQuaternion.__pow__c                 C   s   t | j | j | j | j S r-   )r   r    r!   r"   r)   r.   r   r   r   __neg__   s   zQuaternion.__neg__c                 C   s   | t |d  S rE   r   r@   r   r   r   __truediv__      zQuaternion.__truediv__c                 C   s   t || d  S rE   r   r@   r   r   r   __rtruediv__   rS   zQuaternion.__rtruediv__c                 G   s
   | j | S r-   r   r/   argsr   r   r   _eval_Integral   rC   zQuaternion._eval_Integralc                    s(     dd | j fdd| jD  S )NZevaluateTc                    s   g | ]
}|j i  qS r   )diff)r   r&   kwargssymbolsr   r   
<listcomp>       z#Quaternion.diff.<locals>.<listcomp>)
setdefaultfuncrV   )r/   r[   rZ   r   rY   r   rX      s   zQuaternion.diffc                 C   s   | }t |}t|ts8|jr$|jr$tt||j t||j |j	|j
S |jr4t|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.algebras.quaternion 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.algebras.quaternion 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/   rA   q1q2r   r   r   r?      s   '
&$zQuaternion.addc                 C   rH   )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.algebras.quaternion 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.algebras.quaternion 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

        rI   r@   r   r   r   mul  s   'zQuaternion.mulc                 C   s  t | } t |}t| tst|ts| | S t| tsH|jr.| jr.tt| t| dd| S | jrDt| |j | |j	 | |j
 | |j S tdt|tsz| jr`|jr`| tt|t|dd S |jrvt|| 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.algebras.quaternion 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.algebras.quaternion 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   r`   r   r*   ra   r   r   r   r&   r'   r(   r)   r   )rb   rc   r   r   r   rJ   *  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_conjugates  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.r1   )r   r   r&   r'   r(   r)   re   r   r   r   r6   x  s   0zQuaternion.normc                 C   s   | }|d|    S )z.Returns the normalized form of the quaternion.r9   )r6   re   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 normr9   r1   )r6   r   r   re   r   r   r   inverse  s   zQuaternion.inversec                 C   sz   t |}| }|dkr| S d}|jstS |dk r!| | }}|dkr;|d dkr/|| }|d }|| }|dks%|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.algebras.quaternion import Quaternion
        >>> q = Quaternion(1, 2, 3, 4)
        >>> q.pow(4)
        668 + (-224)*i + (-336)*j + (-448)*k

        rF   r9   r   r1   )r   ri   Z
is_IntegerNotImplemented)r/   rO   rf   resr   r   r   rN     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.algebras.quaternion 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

        r1   )	r   r'   r(   r)   r   r&   r
   r	   r   )r/   rf   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 )ay  Returns the natural logarithm of the quaternion (_ln(q)).

        Examples
        ========

        >>> from sympy.algebras.quaternion 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

        r1   )	r   r'   r(   r)   r6   r   r   r&   r   )r/   rf   rl   Zq_normr&   r'   r(   r)   r   r   r   _ln  s   "zQuaternion._lnc                    s   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.algebras.quaternion 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 t d qS ))n)Zevalfr   )r   argprecr   r   r\   	  r]   z*Quaternion._eval_evalf.<locals>.<listcomp>)r   rV   )r/   rq   r   rp   r   _eval_evalf  s   zQuaternion._eval_evalfc                 C   s0   | }|  \}}t||| }|| |  S )am  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.algebras.quaternion 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   r8   r6   )r/   rO   rf   vr2   rc   r   r   r   pow_cos_sin  s   zQuaternion.pow_cos_sinc                 G   sF   t t| jg|R  t| jg|R  t| jg|R  t| jg|R  S )a  Computes integration of quaternion.

        Returns
        =======

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

        Examples
        ========

        Indefinite Integral of quaternion :

        >>> from sympy.algebras.quaternion 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.algebras.quaternion 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)   rU   r   r   r   r   .  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.algebras.quaternion 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   r9   r1   )	r`   tupler   r8   rh   r   r'   r(   r)   )Zpinrrf   Zpoutr   r   r   rotate_pointO  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.algebras.quaternion 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

        rF   r1   r9   )	r&   Zis_negativerh   r   r   r   r'   r(   r)   )	r/   rf   r2   r7   r3   r4   r5   rt   tr   r   r   rs   |  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    }|st|||g|||	g|
||ggS |\}}}|||  ||  ||  }|||  ||  ||	  }|||
  ||  ||  }d } }}d}t||||g|||	|g|
|||g||||gg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.algebras.quaternion 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.algebras.quaternion 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]])

        r9   r1   r   )r6   r(   r)   r'   r&   r   )r/   rt   rf   r7   Zm00Zm01Zm02Zm10Zm11Zm12Zm20Zm21Zm22r3   r4   r5   Zm03Zm13Zm23Zm30Zm31Zm32Zm33r   r   r   to_rotation_matrix  s,   1          
zQuaternion.to_rotation_matrix)r   r   r   r   Tr-   ),__name__
__module____qualname____doc__Z_op_priorityr   r   propertyr&   r'   r(   r)   r*   classmethodr8   r<   rB   rD   rG   rK   rM   rP   rQ   rR   rT   rW   rX   r?   rd   staticmethodrJ   rg   r6   rh   ri   rN   r   rm   rr   ru   r   rx   rs   r{   r   r   r   r   r      s`    






*
+6)
H.#!
,(r   N)Zsympyr   r   r   r   r   r   r   r	   r
   r   r   r   r   r   r   r   Zsympy.core.evalfr   Zsympy.core.exprr   r   r   r   r   r   <module>   s    