
    MZd˹                         d dl mZ 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mZ d d	lmZ d d
lmZ d dlmZ d dlmZm Z  d dl!m"Z" d dl#m$Z$m%Z% d dl&m'Z' d Z(d Z) G d de"      Z*y)    )Rational)S)is_eq)	conjugateimresign)explog)sqrt)acosasinatan2)cossin)trigsimp	integrate)MutableDenseMatrix)sympify_sympify)Expr)	fuzzy_notfuzzy_or)prec_to_dpsc                     |h|j                   r[|j                  du rt        d      t        d | D              }|r-t	        |dz  t        d | D                    du rt        d      yyyy)z$validate if input norm is consistentNFzInput norm must be positive.c              3   T   K   | ]   }|j                   xr |j                  d u  " yw)TN)	is_numberis_real.0is     ;/usr/lib/python3/dist-packages/sympy/algebras/quaternion.py	<genexpr>z_check_norm.<locals>.<genexpr>   s%     La9		T(99Ls   &(   c              3   &   K   | ]	  }|d z    yw)r%   N r    s     r#   r$   z_check_norm.<locals>.<genexpr>   s     +CQAqD+Cs   zIncompatible value for norm.)r   is_positive
ValueErrorallr   sum)elementsnorm	numericals      r#   _check_normr/      st    DNNu$;<<L8LL	tQw+C(+C(CDM;<< N9 +    c                    t        |       t        k7  rt        d      t        |       dk7  rt        dj	                  |             | j                         }| j                         }|s|st        d      | j                         \  }}}||k(  s||k(  rt        d      t        |       t        d      z
  }|r)t        dj	                  dj                  |                  |S )	zGvalidate seq and return True if seq is lowercase and False if uppercasezExpected seq to be a string.   zExpected 3 axes, got `{}`.zkseq must either be fully uppercase (for extrinsic rotations), or fully lowercase, for intrinsic rotations).z"Consecutive axes must be differentxyzXYZzNExpected axes from `seq` to be from ['x', 'y', 'z'] or ['X', 'Y', 'Z'], got {} )
typestrr)   lenformatisupperislowerlowersetjoin)seq	intrinsic	extrinsicr"   jkbads          r#   _is_extrinsicrD      s    CyC788
3x1}5<<SABBII ' ( 	( iikGAq!	QAF=>>
c(S]
"C
 ""(&"68 	8 r0   c                      e Zd ZdZdZdZd<dZd Zed        Z	ed        Z
ed	        Zed
        Zed        Zed        Zed        Zd=dZed        Zed        Zd>dZed        Zed        Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Z d Z!d Z"d  Z#e$d!        Z%d" Z&d# Z'd$ Z(d% Z)d& Z*d' Z+d( Z,d) Z-d* Z.d+ Z/d, Z0e$d-        Z1d. Z2d?d/Z3d0 Z4d1 Z5d2 Z6d3 Z7d4 Z8d5 Z9d6 Z:ed7        Z;d8 Z<d9 Z=d: Z>d; Z?y)@
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).

    Parameters
    ==========

    norm : None or number
        Pre-defined quaternion norm. If a value is given, Quaternion.norm
        returns this pre-defined value instead of calculating the norm

    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

    Defining symbolic unit quaternions:
    >>> from sympy import Quaternion
    >>> from sympy.abc import w, x, y, z
    >>> q = Quaternion(w, x, y, z, norm=1)
    >>> q
    w + x*i + y*j + z*k
    >>> q.norm()
    1

    References
    ==========

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

    g      &@FNc                    t        t        ||||f      \  }}}}t        d ||||fD              rt        d      t	        j
                  | ||||      }||_        ||_        ||_        ||_	        ||_
        |j                  |       |S )Nc              3   8   K   | ]  }|j                   d u   yw)FN)is_commutativer    s     r#   r$   z%Quaternion.__new__.<locals>.<genexpr>p   s     ?Qq5(?s   z arguments have to be commutative)mapr   anyr)   r   __new___a_b_c_d_real_fieldset_norm)clsabcd
real_fieldr-   objs           r#   rL   zQuaternion.__new__m   s    1aA,/
1a?1aA,???@@,,sAq!Q/CCFCFCFCF(COLLJr0   c                 T    t        |      }t        | j                  |       || _        y)a  Sets norm of an already instantiated quaternion.

        Parameters
        ==========

        norm : None or number
            Pre-defined quaternion norm. If a value is given, Quaternion.norm
            returns this pre-defined value instead of calculating the norm

        Examples
        ========

        >>> from sympy import Quaternion
        >>> from sympy.abc import a, b, c, d
        >>> q = Quaternion(a, b, c, d)
        >>> q.norm()
        sqrt(a**2 + b**2 + c**2 + d**2)

        Setting the norm:

        >>> q.set_norm(1)
        >>> q.norm()
        1

        Removing set norm:

        >>> q.set_norm(None)
        >>> q.norm()
        sqrt(a**2 + b**2 + c**2 + d**2)

        N)r   r/   args_norm)selfr-   s     r#   rR   zQuaternion.set_norm|   s#    @ t}DIIt$
r0   c                     | j                   S N)rM   r]   s    r#   rT   zQuaternion.a       wwr0   c                     | j                   S r_   )rN   r`   s    r#   rU   zQuaternion.b   ra   r0   c                     | j                   S r_   )rO   r`   s    r#   rV   zQuaternion.c   ra   r0   c                     | j                   S r_   )rP   r`   s    r#   rW   zQuaternion.d   ra   r0   c                     | j                   S r_   )rQ   r`   s    r#   rX   zQuaternion.real_field   s    r0   c           	         t        | j                  | j                   | j                   | j                   g| j                  | j                  | j                   | j                  g| j                  | j                  | j                  | j                   g| j                  | j                   | j                  | j                  gg      S )a  Returns 4 x 4 Matrix equivalent to a Hamilton product from the
        left. This can be useful when treating quaternion elements as column
        vectors. Given a quaternion $q = a + bi + cj + dk$ where a, b, c and d
        are real numbers, the product matrix from the left is:

        .. math::

            M  =  \begin{bmatrix} a  &-b  &-c  &-d \\
                                  b  & a  &-d  & c \\
                                  c  & d  & a  &-b \\
                                  d  &-c  & b  & a \end{bmatrix}

        Examples
        ========

        >>> from sympy import Quaternion
        >>> from sympy.abc import a, b, c, d
        >>> q1 = Quaternion(1, 0, 0, 1)
        >>> q2 = Quaternion(a, b, c, d)
        >>> q1.product_matrix_left
        Matrix([
        [1, 0,  0, -1],
        [0, 1, -1,  0],
        [0, 1,  1,  0],
        [1, 0,  0,  1]])

        >>> q1.product_matrix_left * q2.to_Matrix()
        Matrix([
        [a - d],
        [b - c],
        [b + c],
        [a + d]])

        This is equivalent to:

        >>> (q1 * q2).to_Matrix()
        Matrix([
        [a - d],
        [b - c],
        [b + c],
        [a + d]])
        MatrixrT   rU   rV   rW   r`   s    r#   product_matrix_leftzQuaternion.product_matrix_left   s    X $&&466'DFF73$&&$&&1$&&1$&&$&&$&&1	3 4 	4r0   c           	         t        | j                  | j                   | j                   | j                   g| j                  | j                  | j                  | j                   g| j                  | j                   | j                  | j                  g| j                  | j                  | j                   | j                  gg      S )aM  Returns 4 x 4 Matrix equivalent to a Hamilton product from the
        right. This can be useful when treating quaternion elements as column
        vectors. Given a quaternion $q = a + bi + cj + dk$ where a, b, c and d
        are real numbers, the product matrix from the left is:

        .. math::

            M  =  \begin{bmatrix} a  &-b  &-c  &-d \\
                                  b  & a  & d  &-c \\
                                  c  &-d  & a  & b \\
                                  d  & c  &-b  & a \end{bmatrix}


        Examples
        ========

        >>> from sympy import Quaternion
        >>> from sympy.abc import a, b, c, d
        >>> q1 = Quaternion(a, b, c, d)
        >>> q2 = Quaternion(1, 0, 0, 1)
        >>> q2.product_matrix_right
        Matrix([
        [1, 0, 0, -1],
        [0, 1, 1, 0],
        [0, -1, 1, 0],
        [1, 0, 0, 1]])

        Note the switched arguments: the matrix represents the quaternion on
        the right, but is still considered as a matrix multiplication from the
        left.

        >>> q2.product_matrix_right * q1.to_Matrix()
        Matrix([
        [ a - d],
        [ b + c],
        [-b + c],
        [ a + d]])

        This is equivalent to:

        >>> (q1 * q2).to_Matrix()
        Matrix([
        [ a - d],
        [ b + c],
        [-b + c],
        [ a + d]])
        rg   r`   s    r#   product_matrix_rightzQuaternion.product_matrix_right   s    b $&&466'DFF73$&&1$&&$&&$&&1$&&$&&1	3 4 	4r0   c                 `    |rt        | j                  dd       S t        | j                        S )a  Returns elements of quaternion as a column vector.
        By default, a Matrix of length 4 is returned, with the real part as the
        first element.
        If vector_only is True, returns only imaginary part as a Matrix of
        length 3.

        Parameters
        ==========

        vector_only : bool
            If True, only imaginary part is returned.
            Default value: False

        Returns
        =======

        Matrix
            A column vector constructed by the elements of the quaternion.

        Examples
        ========

        >>> from sympy import Quaternion
        >>> from sympy.abc import a, b, c, d
        >>> q = Quaternion(a, b, c, d)
        >>> q
        a + b*i + c*j + d*k

        >>> q.to_Matrix()
        Matrix([
        [a],
        [b],
        [c],
        [d]])


        >>> q.to_Matrix(vector_only=True)
        Matrix([
        [b],
        [c],
        [d]])

           N)rh   r[   )r]   vector_onlys     r#   	to_MatrixzQuaternion.to_Matrix  s,    X $))AB-(($))$$r0   c                     t        |      }|dk7  r|dk7  rt        dj                  |            |dk(  rt        dg| S t        | S )a  Returns quaternion from elements of a column vector`.
        If vector_only is True, returns only imaginary part as a Matrix of
        length 3.

        Parameters
        ==========

        elements : Matrix, list or tuple of length 3 or 4. If length is 3,
            assume real part is zero.
            Default value: False

        Returns
        =======

        Quaternion
            A quaternion created from the input elements.

        Examples
        ========

        >>> from sympy import Quaternion
        >>> from sympy.abc import a, b, c, d
        >>> q = Quaternion.from_Matrix([a, b, c, d])
        >>> q
        a + b*i + c*j + d*k

        >>> q = Quaternion.from_Matrix([b, c, d])
        >>> q
        0 + b*i + c*j + d*k

        r2      z7Input elements must have length 3 or 4, got {} elementsr   )r7   r)   r8   rF   )rS   r,   lengths      r#   from_MatrixzQuaternion.from_MatrixN  sZ    B XQ;6Q; ((.v8 8 Q;a+(++x((r0   c                    t        |      dk7  rt        d      t        |      }|j                         \  }}}dD cg c]  }||k(  rdnd }}dD cg c]  }||k(  rdnd }	}dD cg c]  }||k(  rdnd }
}| j	                  ||d         }| j	                  |	|d         }| j	                  |
|d         }|rt        ||z  |z        S t        ||z  |z        S c c}w c c}w c c}w )a  Returns quaternion equivalent to rotation represented by the Euler
        angles, in the sequence defined by ``seq``.

        Parameters
        ==========

        angles : list, tuple or Matrix of 3 numbers
            The Euler angles (in radians).
        seq : string of length 3
            Represents the sequence of rotations.
            For intrinsic rotations, seq must be all lowercase and its elements
            must be from the set ``{'x', 'y', 'z'}``
            For extrinsic rotations, seq must be all uppercase and its elements
            must be from the set ``{'X', 'Y', 'Z'}``

        Returns
        =======

        Quaternion
            The normalized rotation quaternion calculated from the Euler angles
            in the given sequence.

        Examples
        ========

        >>> from sympy import Quaternion
        >>> from sympy import pi
        >>> q = Quaternion.from_euler([pi/2, 0, 0], 'xyz')
        >>> q
        sqrt(2)/2 + sqrt(2)/2*i + 0*j + 0*k

        >>> q = Quaternion.from_euler([0, pi/2, pi] , 'zyz')
        >>> q
        0 + (-sqrt(2)/2)*i + 0*j + sqrt(2)/2*k

        >>> q = Quaternion.from_euler([0, pi/2, pi] , 'ZYZ')
        >>> q
        0 + sqrt(2)/2*i + 0*j + sqrt(2)/2*k

        r2   z3 angles must be given.xyzrm   r   r%   )r7   r)   rD   r;   from_axis_angler   )rS   anglesr>   r@   r"   rA   rB   neiejekqiqjqks                 r#   
from_eulerzQuaternion.from_eulery  s   V v;!677!#&	))+1a +00Q16aq 00*/0Q16aq 00*/0Q16aq 00   VAY/  VAY/  VAY/BGbL))BGbL)) 100s   CC#)C(c           	         | j                         rt        d      g d}t        |      }|j                         \  }}}dj	                  |      dz   }dj	                  |      dz   }dj	                  |      dz   }|s||}}||k(  }	|	rd|z
  |z
  }||z
  ||z
  z  ||z
  z  dz  }
| j
                  | j                  | j                  | j                  g}|d   }||   }||   }||   |
z  }|	s||z
  ||z   ||z   ||z
  f\  }}}}|ry|	r:| j                         dz  }t        ||z  ||z  z   ||z  z
  ||z  z
  |z        |d<   nd| j                         dz  z  }t        ||z  ||z  z   ||z  z
  ||z  z
  |z        |d<   nVdt        t        ||z  ||z  z         t        ||z  ||z  z               z  |d<   |	s|dxx   t        j                  dz  z  cc<   d}t!        |t        j"                        rt!        |t        j"                        rd}t!        |t        j"                        rt!        |t        j"                        rd}|dk(  r~|r9t        ||      t        ||      z   |d<   t        ||      t        ||      z
  |d<   nt        ||z  ||z  z   ||z  ||z  z
        |d<   t        ||z  ||z  z
  ||z  ||z  z         |d<   n[t        j"                  |d| z  <   |dk(  rdt        ||      z  |d|z  <   n)dt        ||      z  |d|z  <   |d|z  xx   |rdndz  cc<   |	s|dxx   |
z  cc<   |rt%        |d	d	d         S t%        |      S )
a}  Returns Euler angles representing same rotation as the quaternion,
        in the sequence given by ``seq``. This implements the method described
        in [1]_.

        For degenerate cases (gymbal lock cases), the third angle is
        set to zero.

        Parameters
        ==========

        seq : string of length 3
            Represents the sequence of rotations.
            For intrinsic rotations, seq must be all lowercase and its elements
            must be from the set ``{'x', 'y', 'z'}``
            For extrinsic rotations, seq must be all uppercase and its elements
            must be from the set ``{'X', 'Y', 'Z'}``

        angle_addition : bool
            When True, first and third angles are given as an addition and
            subtraction of two simpler ``atan2`` expressions. When False, the
            first and third angles are each given by a single more complicated
            ``atan2`` expression. This equivalent expression is given by:

            .. math::

                \operatorname{atan_2} (b,a) \pm \operatorname{atan_2} (d,c) =
                \operatorname{atan_2} (bc\pm ad, ac\mp bd)

            Default value: True

        avoid_square_root : bool
            When True, the second angle is calculated with an expression based
            on ``acos``, which is slightly more complicated but avoids a square
            root. When False, second angle is calculated with ``atan2``, which
            is simpler and can be better for numerical reasons (some
            numerical implementations of ``acos`` have problems near zero).
            Default value: False


        Returns
        =======

        Tuple
            The Euler angles calculated from the quaternion

        Examples
        ========

        >>> from sympy import Quaternion
        >>> from sympy.abc import a, b, c, d
        >>> euler = Quaternion(a, b, c, d).to_euler('zyz')
        >>> euler
        (-atan2(-b, c) + atan2(d, a),
         2*atan2(sqrt(b**2 + c**2), sqrt(a**2 + d**2)),
         atan2(-b, c) + atan2(d, a))


        References
        ==========

        .. [1] https://doi.org/10.1371/journal.pone.0276302

        z(Cannot convert a quaternion with norm 0.)r   r   r   ru   rm      r%   r   N)is_zero_quaternionr)   rD   r;   indexrT   rU   rV   rW   r-   r   r   r   r   r   Pir   Zerotuple)r]   r>   angle_additionavoid_square_rootrw   r@   r"   rA   rB   	symmetricr	   r,   rT   rU   rV   rW   n2cases                     r#   to_eulerzQuaternion.to_euler  sy   @ ""$GHH!#&	))+1a KKNQKKNQKKNQaqA F	A	A A!a% AE*a/ FFDFFDFFDFF3QKQKQKQK$QAq1ua!e3JAq!QYY[!^ !a%!a%-!a%"7!a%"?2!EFq	a' !a%!a%-!a%"7!a%"?2!EFq	E$q1uq1u}"5tAEAEM7JKKF1Iq	QTTAX%	 AFFa 0DAFFa 0D19!!QK%1+5q	!!QK%1+5q	!!A#!)QqS1Q3Y7q	!!A#!)QqS1Q3Y7q	 +,&&F1I&'qy()E!QKq9}%()E!QKq9}%q9}%	"qA% 1II"&&= r0   c                    |\  }}}t        |dz  |dz  z   |dz  z         }||z  ||z  ||z  }}}t        |t        j                  z        }t	        |t        j                  z        }||z  }	||z  }
||z  } | ||	|
|      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   r   Halfr   )rS   vectoranglexyzr-   srT   rU   rV   rW   s               r#   rv   zQuaternion.from_axis_angleG  s    8 	AqAqD1a4K!Q$&'Xq4xTqAEEE 1aAr0   c                    |j                         t        dd      z  }t        ||d   z   |d   z   |d   z         dz  }t        ||d   z   |d   z
  |d   z
        dz  }t        ||d   z
  |d   z   |d   z
        dz  }t        ||d   z
  |d   z
  |d   z         dz  }|t        |d   |d   z
        z  }|t        |d	   |d
   z
        z  }|t        |d   |d   z
        z  }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

        rm   r2   )r   r   )rm   rm   )r%   r%   r%   )r%   rm   )rm   r%   )r   r%   )r%   r   )rm   r   )r   rm   )detr   r   r	   rF   )rS   MabsQrT   rU   rV   rW   s          r#   from_rotation_matrixzQuaternion.from_rotation_matrixr  s#   > uuwA&$!D')AdG34q8$!D')AdG34q8$!D')AdG34q8$!D')AdG34q8QtWqw&''QtWqw&''QtWqw&''!Q1%%r0   c                 $    | j                  |      S r_   addr]   others     r#   __add__zQuaternion.__add__      xxr0   c                 $    | j                  |      S r_   r   r   s     r#   __radd__zQuaternion.__radd__  r   r0   c                 *    | j                  |dz        S Nr   r   r   s     r#   __sub__zQuaternion.__sub__  s    xxb!!r0   c                 8    | j                  | t        |            S r_   _generic_mulr   r   s     r#   __mul__zQuaternion.__mul__  s      x77r0   c                 8    | j                  t        |      |       S r_   r   r   s     r#   __rmul__zQuaternion.__rmul__  s      %$77r0   c                 $    | j                  |      S r_   )pow)r]   ps     r#   __pow__zQuaternion.__pow__  s    xx{r0   c                 v    t        | j                   | j                   | j                   | j                         S r_   )rF   rM   rN   rO   rW   r`   s    r#   __neg__zQuaternion.__neg__  s+    477(TWWHtwwh@@r0   c                 $    | t        |      dz  z  S r   r   r   s     r#   __truediv__zQuaternion.__truediv__  s    genb(((r0   c                 $    t        |      | dz  z  S r   r   r   s     r#   __rtruediv__zQuaternion.__rtruediv__  s    u~b((r0   c                       | j                   | S r_   r   r]   r[   s     r#   _eval_IntegralzQuaternion._eval_Integral  s    t~~t$$r0   c           
          |j                  dd        | j                  | j                  D cg c]  } |j                  |i | c} S c c}w )NevaluateT)
setdefaultfuncr[   diff)r]   symbolskwargsrT   s       r#   r   zQuaternion.diff  sE    *d+tyy		J!616675f5JKKJs   A
c                 |   | }t        |      }t        |t              s|j                  rZ|j                  rNt        t        |      |j                  z   t        |      |j                  z   |j                  |j                        S |j                  r9t        |j                  |z   |j                  |j                  |j                        S t        d      t        |j                  |j                  z   |j                  |j                  z   |j                  |j                  z   |j                  |j                  z         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   
isinstancerF   rX   
is_complexr   rT   r   rU   rV   rW   rI   r)   )r]   r   q1q2s       r#   r   zQuaternion.add  s    N U^ "j)}}!"R&244-B"$$bddKK""!"$$)RTT244>> !_``"$$+rttbdd{BDD244KDDB! " 	"r0   c                 8    | j                  | t        |            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   s     r#   mulzQuaternion.mul  s    N   x77r0   c                    t        | t              st        |t              s| |z  S t        | t              s|j                  r/| j                  r#t        t	        |       t        |       dd      |z  S | j                  rBt        | |j                  z  | |j                  z  | |j                  z  | |j                  z        S t        d      t        |t              s| j                  r/|j                  r#| t        t	        |      t        |      dd      z  S |j                  rBt        || j                  z  || j                  z  || j                  z  || j                  z        S t        d      | j                  |j                  d}n!| j                         |j                         z  }t        | j                   |j                  z  | j                  |j                  z  z
  | j                  |j                  z  z
  | j                  |j                  z  z   | j                  |j                  z  | j                  |j                  z  z   | j                  |j                  z  z
  | j                  |j                  z  z   | j                   |j                  z  | j                  |j                  z  z   | j                  |j                  z  z   | j                  |j                  z  z   | j                  |j                  z  | j                  |j                  z  z
  | j                  |j                  z  z   | j                  |j                  z  z   |      S )an  Generic multiplication.

        Parameters
        ==========

        q1 : Quaternion or symbol
        q2 : Quaternion or symbol

        It is 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, S
        >>> 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, S(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 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.Nr-   )r   rF   rX   r   r   r   rI   rT   rU   rV   rW   r)   r\   r-   )r   r   r-   s      r#   r   zQuaternion._generic_mul  sf   V "j)*R2L7N "j)}}!"R&"R&!Q7"<<""!"rtt)R"$$YRTT	29MM !dee "j)}}Jr"vr"vq!<<<""!"rtt)R"$$YRTT	29MM !dee 88 0D779rwwy(D244%*rttBDDy02449<rttBDDyH$$rtt)bdd244i/"$$rtt);bdd244iG44%*rttBDDy02449<rttBDDyH$$rtt)bdd244i/"$$rtt);bddRTTkI#	% 	%r0   c                     | }t        |j                  |j                   |j                   |j                   |j
                        S )z(Returns the conjugate of the quaternion.r   )rF   rT   rU   rV   rW   r\   r]   qs     r#   _eval_conjugatezQuaternion._eval_conjugatek  s4    !##taccTACC4agg>>r0   c                     | j                   X| }t        t        |j                  dz  |j                  dz  z   |j
                  dz  z   |j                  dz  z               | _         | j                   S )z#Returns the norm of the quaternion.r%   )r\   r   r   rT   rU   rV   rW   r   s     r#   r-   zQuaternion.normp  s\    ::A hqssAvQa'?!##q&'HIJDJzzr0   c                 2    | }|d|j                         z  z  S )z.Returns the normalized form of the quaternion.rm   r   r   s     r#   	normalizezQuaternion.normalizez  s    AaffhJr0   c                     | }|j                         st        d      t        |      d|j                         dz  z  z  S )z&Returns the inverse of the quaternion.z6Cannot compute inverse for a quaternion with zero normrm   r%   )r-   r)   r   r   s     r#   inversezQuaternion.inverse  s9    vvxUVV|q1}--r0   c                     t        |      }| }|dk(  r|j                         S d}|j                  st        S |dk  r|j                         | }}|dkD  r|dz  dk(  r||z  }|dz  }||z  }|dkD  r|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   rm   r   r%   )r   r   
is_IntegerNotImplemented)r]   r   r   ress       r#   r   zQuaternion.pow  s    2 AJ799;||!!q599;qA!e1uz#g1AAA !e 
r0   c                    | }t        |j                  dz  |j                  dz  z   |j                  dz  z         }t	        |j
                        t        |      z  }t	        |j
                        t        |      z  |j                  z  |z  }t	        |j
                        t        |      z  |j                  z  |z  }t	        |j
                        t        |      z  |j                  z  |z  }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   rU   rV   rW   r
   rT   r   r   rF   )r]   r   vector_normrT   rU   rV   rW   s          r#   r
   zQuaternion.exp  s    , 1336ACCF?QSS!V34Hs;''Hs;''!##-;Hs;''!##-;Hs;''!##-;!Q1%%r0   c                    | }t        |j                  dz  |j                  dz  z   |j                  dz  z         }|j	                         }t        |      }|j                  t        |j                  |z        z  |z  }|j                  t        |j                  |z        z  |z  }|j                  t        |j                  |z        z  |z  }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   rU   rV   rW   r-   lnr   rT   rF   )r]   r   r   q_normrT   rU   rV   rW   s           r#   _lnzQuaternion._ln  s      1336ACCF?QSS!V34vJCC$qssV|$${2CC$qssV|$${2CC$qssV|$${2!Q1%%r0   c                     | j                   D cg c]  } |j                  |  }}| j                  }	  |j                  | }t	        ||       t        |d|iS c c}w # t        $ r Y 'w xY w)Nr-   )r[   subsr\   AttributeErrorr/   rF   )r]   r[   r"   r,   r-   s        r#   
_eval_subszQuaternion._eval_subs  sv    +/995aFAFFDM55zz	499d#D 	Hd#8/$// 6  		s   AA 	A+*A+c                     t        |      }t        | j                  D cg c]  }|j                  |       c} S c c}w )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

        )rx   )r   rF   r[   evalf)r]   precnprecargs       r#   _eval_evalfzQuaternion._eval_evalf  s6    , D!$))D3CIII.DEEDs   <c                     | }|j                         \  }}t        j                  |||z        }||j                         |z  z  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_anglerF   rv   r-   )r]   r   r   vr   r   s         r#   pow_cos_sinzQuaternion.pow_cos_sin  sD    < __&
E''1u95QVVXq[!!r0   c           	          t        t        | j                  g| t        | j                  g| t        | j                  g| t        | j
                  g|       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

        )rF   r   rT   rU   rV   rW   r   s     r#   r   zQuaternion.integrate3  sT    < )DFF2T2Idff4Lt4L#DFF2T2Idff4Lt4LN 	Nr0   c                    t        |t              rt        j                  |d   |d         }n|j	                         }|t        d| d   | d   | d         z  t        |      z  }|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   rm   r%   )	r   r   rF   rv   r   r   rU   rV   rW   )pinrr   pouts       r#   rotate_pointzQuaternion.rotate_pointT  sy    H a**1Q416A A:aQQQ889Q<G''r0   c                    | }|j                   j                  r|dz  }|j                         }t        dt	        |j                         z        }t        d|j                   |j                   z  z
        }t        |j                  |z        }t        |j                  |z        }t        |j                  |z        }|||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%   rm   )	rT   is_negativer   r   r   r   rU   rV   rW   )	r]   r   r   r   r   r   r   r   ts	            r#   r   zQuaternion.to_axis_angle  s    * 33??BAKKMT!##Y' QSSWQSS1WQSS1WQSS1W1IJr0   c           	      ^   | }|j                         dz  }|r||j                  dz  |j                  dz  z   |j                  dz  z
  |j                  dz  z
  z  }||j                  dz  |j                  dz  z
  |j                  dz  z   |j                  dz  z
  z  }||j                  dz  |j                  dz  z
  |j                  dz  z
  |j                  dz  z   z  }nxdd|z  |j                  dz  |j                  dz  z   z  z
  }dd|z  |j                  dz  |j                  dz  z   z  z
  }dd|z  |j                  dz  |j                  dz  z   z  z
  }d|z  |j                  |j                  z  |j                  |j                  z  z
  z  }d|z  |j                  |j                  z  |j                  |j                  z  z   z  }	d|z  |j                  |j                  z  |j                  |j                  z  z   z  }
d|z  |j                  |j                  z  |j                  |j                  z  z
  z  }d|z  |j                  |j                  z  |j                  |j                  z  z
  z  }d|z  |j                  |j                  z  |j                  |j                  z  z   z  }|st        |||	g|
||g|||gg      S |\  }}}|||z  z
  ||z  z
  ||	z  z
  }|||
z  z
  ||z  z
  ||z  z
  }|||z  z
  ||z  z
  ||z  z
  }dx}x}}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
        homogeneous : bool
            When True, gives an expression that may be more efficient for
            symbolic calculations but less so for direct evaluation. Both
            formulas are mathematically equivalent.
            Default value: True

        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.
        r%   rm   r   )r-   rT   rU   rV   rW   rh   )r]   r   homogeneousr   r   m00m11m22m01m02m10m12m20m21r   r   r   m03m13m23m30m31m32m33s                           r#   to_rotation_matrixzQuaternion.to_rotation_matrix  s$   N FFHbL QSS!Vacc1f_qssAv-Q67CQSS!Vacc1f_qssAv-Q67CQSS!Vacc1f_qssAv-Q67Cac1336ACCF?++Cac1336ACCF?++Cac1336ACCF?++Cc133qss7QSSW$%c133qss7QSSW$%c133qss7QSSW$%c133qss7QSSW$%c133qss7QSSW$%c133qss7QSSW$%Cc?S#sOc3_MNN IQ1ae)ae#ae+Cae)ae#ae+Cae)ae#ae+CC#CCc3/#sC1ES#.c30DF G Gr0   c                     | j                   S )am  Returns scalar part($\mathbf{S}(q)$) of the quaternion q.

        Explanation
        ===========

        Given a quaternion $q = a + bi + cj + dk$, returns $\mathbf{S}(q) = a$.

        Examples
        ========

        >>> from sympy.algebras.quaternion import Quaternion
        >>> q = Quaternion(4, 8, 13, 12)
        >>> q.scalar_part()
        4

        )rT   r`   s    r#   scalar_partzQuaternion.scalar_part  s    $ vvr0   c                 Z    t        d| j                  | j                  | j                        S )a  
        Returns vector part($\mathbf{V}(q)$) of the quaternion q.

        Explanation
        ===========

        Given a quaternion $q = a + bi + cj + dk$, returns $\mathbf{V}(q) = bi + cj + dk$.

        Examples
        ========

        >>> from sympy.algebras.quaternion import Quaternion
        >>> q = Quaternion(1, 1, 1, 1)
        >>> q.vector_part()
        0 + 1*i + 1*j + 1*k

        >>> q = Quaternion(4, 8, 13, 12)
        >>> q.vector_part()
        0 + 8*i + 13*j + 12*k

        r   )rF   rU   rV   rW   r`   s    r#   vector_partzQuaternion.vector_part	  s!    . !TVVTVVTVV44r0   c                     | j                         j                         }t        d|j                  |j                  |j
                        S )a  
        Returns the axis($\mathbf{Ax}(q)$) of the quaternion.

        Explanation
        ===========

        Given a quaternion $q = a + bi + cj + dk$, returns $\mathbf{Ax}(q)$  i.e., the versor of the vector part of that quaternion
        equal to $\mathbf{U}[\mathbf{V}(q)]$.
        The axis is always an imaginary unit with square equal to $-1 + 0i + 0j + 0k$.

        Examples
        ========

        >>> from sympy.algebras.quaternion import Quaternion
        >>> q = Quaternion(1, 1, 1, 1)
        >>> q.axis()
        0 + sqrt(3)/3*i + sqrt(3)/3*j + sqrt(3)/3*k

        See Also
        ========

        vector_part

        r   )r  r   rF   rU   rV   rW   )r]   axiss     r#   r  zQuaternion.axis"  s8    2 !++-!TVVTVVTVV44r0   c                 .    | j                   j                  S )a  
        Returns true if the quaternion is pure, false if the quaternion is not pure
        or returns none if it is unknown.

        Explanation
        ===========

        A pure quaternion (also a vector quaternion) is a quaternion with scalar
        part equal to 0.

        Examples
        ========

        >>> from sympy.algebras.quaternion import Quaternion
        >>> q = Quaternion(0, 8, 13, 12)
        >>> q.is_pure()
        True

        See Also
        ========
        scalar_part

        )rT   is_zeror`   s    r#   is_purezQuaternion.is_pure?  s    2 vv~~r0   c                 6    | j                         j                  S )a  
        Returns true if the quaternion is a zero quaternion or false if it is not a zero quaternion
        and None if the value is unknown.

        Explanation
        ===========

        A zero quaternion is a quaternion with both scalar part and
        vector part equal to 0.

        Examples
        ========

        >>> from sympy.algebras.quaternion import Quaternion
        >>> q = Quaternion(1, 0, 0, 0)
        >>> q.is_zero_quaternion()
        False

        >>> q = Quaternion(0, 0, 0, 0)
        >>> q.is_zero_quaternion()
        True

        See Also
        ========
        scalar_part
        vector_part

        )r-   r  r`   s    r#   r   zQuaternion.is_zero_quaternionZ  s    < yy{"""r0   c                 n    t        | j                         j                         | j                               S )a  
        Returns the angle of the quaternion measured in the real-axis plane.

        Explanation
        ===========

        Given a quaternion $q = a + bi + cj + dk$ where a, b, c and d
        are real numbers, returns the angle of the quaternion given by

        .. math::
            angle := atan2(\sqrt{b^2 + c^2 + d^2}, {a})

        Examples
        ========

        >>> from sympy.algebras.quaternion import Quaternion
        >>> q = Quaternion(1, 4, 4, 4)
        >>> q.angle()
        atan(4*sqrt(3))

        )r   r  r-   r
  r`   s    r#   r   zQuaternion.anglez  s,    . T%%',,.0@0@0BCCr0   c                 &   | j                         s|j                         rt        d      t        | j                         |j                         z
  j                         | j                         |j                         z   j                         g      S )aS  
        Returns True if the transformation arcs represented by the input quaternions happen in the same plane.

        Explanation
        ===========

        Two quaternions are said to be coplanar (in this arc sense) when their axes are parallel.
        The plane of a quaternion is the one normal to its axis.

        Parameters
        ==========

        other : a Quaternion

        Returns
        =======

        True : if the planes of the two quaternions are the same, apart from its orientation/sign.
        False : if the planes of the two quaternions are not the same, apart from its orientation/sign.
        None : if plane of either of the quaternion is unknown.

        Examples
        ========

        >>> from sympy.algebras.quaternion import Quaternion
        >>> q1 = Quaternion(1, 4, 4, 4)
        >>> q2 = Quaternion(3, 8, 8, 8)
        >>> Quaternion.arc_coplanar(q1, q2)
        True

        >>> q1 = Quaternion(2, 8, 13, 12)
        >>> Quaternion.arc_coplanar(q1, q2)
        False

        See Also
        ========

        vector_coplanar
        is_pure

        z)Neither of the given quaternions can be 0)r   r)   r   r  r   s     r#   arc_coplanarzQuaternion.arc_coplanar  sp    T ##%5+C+C+EHII$))+

4HHJTYY[[`[e[e[gMgL{L{L}~r0   c                    t        |j                               s2t        |j                               st        |j                               rt        d      t        |j                  |j
                  |j                  g|j                  |j
                  |j                  g|j                  |j
                  |j                  gg      j                         }|j                  S )a  
        Returns True if the axis of the pure quaternions seen as 3D vectors
        q1, q2, and q3 are coplanar.

        Explanation
        ===========

        Three pure quaternions are vector coplanar if the quaternions seen as 3D vectors are coplanar.

        Parameters
        ==========

        q1
            A pure Quaternion.
        q2
            A pure Quaternion.
        q3
            A pure Quaternion.

        Returns
        =======

        True : if the axis of the pure quaternions seen as 3D vectors
        q1, q2, and q3 are coplanar.
        False : if the axis of the pure quaternions seen as 3D vectors
        q1, q2, and q3 are not coplanar.
        None : if the axis of the pure quaternions seen as 3D vectors
        q1, q2, and q3 are coplanar is unknown.

        Examples
        ========

        >>> from sympy.algebras.quaternion import Quaternion
        >>> q1 = Quaternion(0, 4, 4, 4)
        >>> q2 = Quaternion(0, 8, 8, 8)
        >>> q3 = Quaternion(0, 24, 24, 24)
        >>> Quaternion.vector_coplanar(q1, q2, q3)
        True

        >>> q1 = Quaternion(0, 8, 16, 8)
        >>> q2 = Quaternion(0, 8, 3, 12)
        >>> Quaternion.vector_coplanar(q1, q2, q3)
        False

        See Also
        ========

        axis
        is_pure

        "The given quaternions must be pure)	r   r  r)   rh   rU   rV   rW   r   r  )rS   r   r   q3r   s        r#   vector_coplanarzQuaternion.vector_coplanar  s    l RZZ\"i

&=2::<AXABBRTT244&rttRTT(:RTT244<NOPTTVyyr0   c                     t        | j                               st        |j                               rt        d      | |z  || z  z
  j                         S )a  
        Returns True if the two pure quaternions seen as 3D vectors are parallel.

        Explanation
        ===========

        Two pure quaternions are called parallel when their vector product is commutative which
        implies that the quaternions seen as 3D vectors have same direction.

        Parameters
        ==========

        other : a Quaternion

        Returns
        =======

        True : if the two pure quaternions seen as 3D vectors are parallel.
        False : if the two pure quaternions seen as 3D vectors are not parallel.
        None : if the two pure quaternions seen as 3D vectors are parallel is unknown.

        Examples
        ========

        >>> from sympy.algebras.quaternion import Quaternion
        >>> q = Quaternion(0, 4, 4, 4)
        >>> q1 = Quaternion(0, 8, 8, 8)
        >>> q.parallel(q1)
        True

        >>> q1 = Quaternion(0, 8, 13, 12)
        >>> q.parallel(q1)
        False

        z%The provided quaternions must be purer   r  r)   r   r   s     r#   parallelzQuaternion.parallel  sH    J T\\^$	%--/(BDEEU
U4Z';;==r0   c                     t        | j                               st        |j                               rt        d      | |z  || z  z   j                         S )a|  
        Returns the orthogonality of two quaternions.

        Explanation
        ===========

        Two pure quaternions are called orthogonal when their product is anti-commutative.

        Parameters
        ==========

        other : a Quaternion

        Returns
        =======

        True : if the two pure quaternions seen as 3D vectors are orthogonal.
        False : if the two pure quaternions seen as 3D vectors are not orthogonal.
        None : if the two pure quaternions seen as 3D vectors are orthogonal is unknown.

        Examples
        ========

        >>> from sympy.algebras.quaternion import Quaternion
        >>> q = Quaternion(0, 4, 4, 4)
        >>> q1 = Quaternion(0, 8, 8, 8)
        >>> q.orthogonal(q1)
        False

        >>> q1 = Quaternion(0, 2, 2, 0)
        >>> q = Quaternion(0, 2, -2, 0)
        >>> q.orthogonal(q1)
        True

        r  r  r   s     r#   
orthogonalzQuaternion.orthogonal)  sH    J T\\^$	%--/(BABBU
U4Z';;==r0   c                 D    | j                         | j                         z  S )a  
        Returns the index vector of the quaternion.

        Explanation
        ===========

        Index vector is given by $\mathbf{T}(q)$ multiplied by $\mathbf{Ax}(q)$ where $\mathbf{Ax}(q)$ is the axis of the quaternion q,
        and mod(q) is the $\mathbf{T}(q)$ (magnitude) of the quaternion.

        Returns
        =======

        Quaternion: representing index vector of the provided quaternion.

        Examples
        ========

        >>> from sympy.algebras.quaternion import Quaternion
        >>> q = Quaternion(2, 4, 2, 4)
        >>> q.index_vector()
        0 + 4*sqrt(10)/3*i + 2*sqrt(10)/3*j + 4*sqrt(10)/3*k

        See Also
        ========

        axis
        norm

        )r-   r  r`   s    r#   index_vectorzQuaternion.index_vectorS  s    > yy{TYY[((r0   c                 4    t        | j                               S )aj  
        Returns the natural logarithm of the norm(magnitude) of the quaternion.

        Examples
        ========

        >>> from sympy.algebras.quaternion import Quaternion
        >>> q = Quaternion(2, 4, 2, 4)
        >>> q.mensor()
        log(2*sqrt(10))
        >>> q.norm()
        2*sqrt(10)

        See Also
        ========

        norm

        )r   r-   r`   s    r#   mensorzQuaternion.mensort  s    * $))+r0   )r   r   r   r   TN)F)TF)NT)@__name__
__module____qualname____doc___op_priorityrI   rL   rR   propertyrT   rU   rV   rW   rX   ri   rk   ro   classmethodrs   r   r   rv   r   r   r   r   r   r   r   r   r   r   r   r   r   r   staticmethodr   r   r-   r   r   r   r
   r   r   r   r   r   r   r   r  r
  r  r  r  r   r   r  r  r  r  r   r"  r'   r0   r#   rF   rF   9   s   .^ LN"H             /4 /4b 44 44l/%b () ()T =* =*~L!\ ( (T )& )&V"88A))%L4"l'8R I% I%V?
 
.,\&>&40F2!"FNB *( *(X&PJGX(525:6#@D4-@^ 9 9v(>T(>T)Br0   rF   N)+sympy.core.numbersr   sympy.core.singletonr   sympy.core.relationalr   $sympy.functions.elementary.complexesr   r   r   r	   &sympy.functions.elementary.exponentialr
   r   r   (sympy.functions.elementary.miscellaneousr   (sympy.functions.elementary.trigonometricr   r   r   r   r   sympy.simplify.trigsimpr   sympy.integrals.integralsr   sympy.matrices.denser   rh   sympy.core.sympifyr   r   sympy.core.exprr   sympy.core.logicr   r   mpmath.libmp.libmpfr   r/   rD   rF   r'   r0   r#   <module>r9     sP    ' " ' J J C 9 H H ? , / = 0   0 +=6P Pr0   