a
    <bT                     @   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 ||||fD rDtdn4t| ||||}||_||_||_||_||_	|S d S )Nc                 s   s   | ]}|j d u V  qdS )FN)is_commutative).0i r   i/Users/vegardjervell/Documents/master/model/venv/lib/python3.9/site-packages/sympy/algebras/quaternion.py	<genexpr>:       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 r-   )r"   r.   r   r   r   r(   I   s    zQuaternion.bc                 C   s   | j S r-   )r#   r.   r   r   r   r)   M   s    zQuaternion.cc                 C   s   | j S r-   )r$   r.   r   r   r   r*   Q   s    zQuaternion.dc                 C   s   | j S r-   )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   )r8   r8   )r0   r0   r0   )r0   r8   )r8   r0   )r   r0   )r0   r   )r8   r   )r   r8   )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 r-   addr/   otherr   r   r   __add__   s    zQuaternion.__add__c                 C   s
   |  |S r-   r<   r>   r   r   r   __radd__   s    zQuaternion.__radd__c                 C   s   |  |d S Nr<   r>   r   r   r   __sub__   s    zQuaternion.__sub__c                 C   s   |  | |S r-   _generic_mulr>   r   r   r   __mul__   s    zQuaternion.__mul__c                 C   s   |  || S r-   rE   r>   r   r   r   __rmul__   s    zQuaternion.__rmul__c                 C   s
   |  |S r-   )pow)r/   pr   r   r   __pow__   s    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 rB   r   r>   r   r   r   __truediv__   s    zQuaternion.__truediv__c                 C   s   t || d  S rB   r   r>   r   r   r   __rtruediv__   s    zQuaternion.__rtruediv__c                 G   s
   | j | S r-   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 i  qS r   )diff)r   r'   kwargssymbolsr   r   
<listcomp>   r   z#Quaternion.diff.<locals>.<listcomp>)
setdefaultfuncrP   )r/   rV   rU   r   rT   r   rS      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/   r?   q1q2r   r   r   r=      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

        rE   r>   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   rZ   r   r+   r[   r   r   r   r'   r(   r)   r*   r   )r\   r]   r   r   r   rF   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.r0   )r
   r   r'   r(   r)   r*   r_   r   r   r   r5     s    zQuaternion.normc                 C   s   | }|d|    S )z.Returns the normalized form of the quaternion.r8   )r5   r_   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 normr8   r0   )r5   r   r   r_   r   r   r   inverse  s    zQuaternion.inversec                 C   st   t |}| }|dkr| S d}|js*tS |dk rB| |  }}|dkrp|d dkr^|| }|d }|| }qB|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

        rC   r8   r   r0   )r   rc   Z
is_IntegerNotImplemented)r/   rJ   r`   resr   r   r   rI     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

        r0   )	r
   r(   r)   r*   r   r'   r   r   r   )r/   r`   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

        r0   )	r
   r(   r)   r*   r5   lnr   r'   r   )r/   r`   rf   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Znprecr   r   rW     r   z*Quaternion._eval_evalf.<locals>.<listcomp>)r   r   rP   )r/   precr   rk   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   r7   r5   )r/   rJ   r`   vr1   r]   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 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*   rO   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   r8   r0   )	rZ   tupler   r7   rb   r   r(   r)   r*   )Zpinrr`   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

        rC   r0   r8   )	r'   Zis_negativerb   r   r   r
   r(   r)   r*   )	r/   r`   r1   r6   r2   r3   r4   ro   tr   r   r   rn     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]])

        r8   r0   r   N)r5   r)   r*   r(   r'   Matrix)r/   ro   r`   r6   Zm00Zm01Zm02Zm10Zm11Zm12Zm20Zm21Zm22r2   r3   r4   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+   classmethodr7   r;   r@   rA   rD   rG   rH   rK   rL   rM   rN   rQ   rS   r=   r^   staticmethodrF   ra   r5   rb   rc   rI   r   rh   rm   rp   r   rs   rn   rw   r   r   r   r   r      s^   






*
+6)
H.#!
,(r   N)!Zsympy.core.numbersr   Zsympy.core.singletonr   Z$sympy.functions.elementary.complexesr   r   r   r   Z&sympy.functions.elementary.exponentialr   r	   rg   Z(sympy.functions.elementary.miscellaneousr
   Z(sympy.functions.elementary.trigonometricr   r   r   Zsympy.simplify.trigsimpr   Zsympy.integrals.integralsr   Zsympy.matrices.denser   rv   Zsympy.core.sympifyr   Zsympy.core.exprr   Zmpmath.libmp.libmpfr   r   r   r   r   r   <module>   s   