
    g                        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 dl(m)Z) d Z*d Z+ G d de"          Z,dS )    )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)as_int)prec_to_dpsc                     |u|j         rp|j        du rt          d          t          d | D                       }|r?t	          |dz  t          d | D                                 du rt          d          dS dS dS dS )z$validate if input norm is consistentNFzInput norm must be positive.c              3   6   K   | ]}|j         o|j        d u V  dS )TN)	is_numberis_real.0is     U/var/www/html/ai-engine/env/lib/python3.11/site-packages/sympy/algebras/quaternion.py	<genexpr>z_check_norm.<locals>.<genexpr>   s0      LLa9	T(9LLLLLL       c              3       K   | ]	}|d z  V  
dS )r'   N r!   s     r$   r%   z_check_norm.<locals>.<genexpr>   s&      +C+CQAqD+C+C+C+C+C+Cr&   zIncompatible value for norm.)r   is_positive
ValueErrorallr   sum)elementsnorm	numericals      r$   _check_normr1      s    DNu$$;<<<LL8LLLLL	 	=tQw+C+C(+C+C+C(C(CDDMM;<<< 
	= 	=MMr&   c                 F   t          |           t          k    rt          d          t          |           dk    r"t          d                    |                     |                                 }|                                 }|s|st          d          |                                 \  }}}||k    s||k    rt          d          t          |           t          d          z
  }|r5t          d                    d	                    |                              |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_extrinsicrE      s   CyyC7888
3xx1}}5<<SAABBBII ( ( ' ( ( 	( iikkGAq!	QAFF=>>>
c((S]]
"C
 8 ""(&"6"68 8 	8 r&   c                   V    e Zd ZdZdZdZd> f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/             Z1d0 Z2dAd1Z3d2 Z4d3 Z5d4 Z6d5 Z7d6 Z8d7 Z9d8 Z:ed9             Z;d: Z<d; Z=d< Z>d= Z? xZ@S )B
Quaterniona  Provides basic quaternion operations.
    Quaternion objects can be instantiated as ``Quaternion(a, b, c, d)``
    as in $q = a + bi + cj + dk$.

    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      &@Fr   TNc                    t          t          ||||f          \  }}}}t          d ||||fD                       rt          d          t	                                          | ||||          }||_        |                    |           |S )Nc              3   (   K   | ]}|j         d u V  dS )FN)is_commutativer!   s     r$   r%   z%Quaternion.__new__.<locals>.<genexpr>r   s*      ??Qq5(??????r&   z arguments have to be commutative)mapr   anyr+   super__new___real_fieldset_norm)	clsabcd
real_fieldr/   obj	__class__s	           r$   rN   zQuaternion.__new__o   s    1aA,//
1a??1aA,????? 	A?@@@ggooc1aA..$T
r&   c                 \    t          |          }t          | j        |           || _        dS )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   r1   args_norm)selfr/   s     r$   rP   zQuaternion.set_normy   s-    @ t}}DIt$$$


r&   c                     | j         d         S )Nr   rZ   r\   s    r$   rR   zQuaternion.a       y|r&   c                     | j         d         S )N   r^   r_   s    r$   rS   zQuaternion.b   r`   r&   c                     | j         d         S )Nr'   r^   r_   s    r$   rT   zQuaternion.c   r`   r&   c                     | j         d         S )Nr3   r^   r_   s    r$   rU   zQuaternion.d   r`   r&   c                     | j         S N)rO   r_   s    r$   rV   zQuaternion.real_field   s    r&   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]])
        MatrixrR   rS   rT   rU   r_   s    r$   product_matrix_leftzQuaternion.product_matrix_left   sx    X $&46'DF73$&$&1$&1$&$&$&1	3 4 4 	4r&   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]])
        rh   r_   s    r$   product_matrix_rightzQuaternion.product_matrix_right   sx    b $&46'DF73$&1$&$&$&1$&$&1	3 4 4 	4r&   c                 f    |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]])

        rb   N)ri   rZ   )r\   vector_onlys     r$   	to_MatrixzQuaternion.to_Matrix  s5    X  	%$)ABB-((($)$$$r&   c                     t          |          }|dk    r(|dk    r"t          d                    |                    |dk    rt          dg|R  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

        r3      z7Input elements must have length 3 or 4, got {} elementsr   )r8   r+   r9   rG   )rQ   r.   lengths      r$   from_MatrixzQuaternion.from_MatrixK  so    B XQ;;6Q;; ((.v8 8 8 Q;;a+(++++x((r&   c                   
 t          |          dk    rt          d          t          |          }|                                \  

fddD             }fddD             }fddD             }|                     ||d                   }|                     ||d                   }|                     ||d	                   }	|rt          |	|z  |z            S t          ||z  |	z            S )
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 extrinsic rotations, seq must be all lowercase and its elements
            must be from the set ``{'x', 'y', 'z'}``
            For intrinsic 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

        r3   z3 angles must be given.c                 $    g | ]}|k    rd ndS rb   r   r)   )r"   nr#   s     r$   
<listcomp>z)Quaternion.from_euler.<locals>.<listcomp>  %    000Q166aaq000r&   xyzc                 $    g | ]}|k    rd ndS rv   r)   )r"   rw   rB   s     r$   rx   z)Quaternion.from_euler.<locals>.<listcomp>  ry   r&   c                 $    g | ]}|k    rd ndS rv   r)   )r"   rw   rC   s     r$   rx   z)Quaternion.from_euler.<locals>.<listcomp>  ry   r&   r   rb   r'   )r8   r+   rE   r<   from_axis_angler   )rQ   anglesr?   rA   eiejekqiqjqkr#   rB   rC   s             @@@r$   
from_eulerzQuaternion.from_eulerv  s   V v;;!6777!#&&	))++1a 1000%0000000%0000000%000   VAY//  VAY//  VAY// 	*BGbL)))BGbL)))r&   c           	      V   |                                  rt          d          g d}t          |          }|                                \  }}}d                    |          dz   }d                    |          dz   }d                    |          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\  }}}}|r|	rB| 	                                dz  }t          ||z  ||z  z   ||z  z
  ||z  z
  |z            |d<   nd| 	                                dz  z  }t          ||z  ||z  z   ||z  z
  ||z  z
  |z            |d<   nad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|rIt          ||          t          ||          z   |d<   t          ||          t          ||          z
  |d<   nt          ||z  ||z  z   ||z  ||z  z
            |d<   t          ||z  ||z  z
  ||z  ||z  z             |d<   nct          j        |d| z  <   |dk    rdt          ||          z  |d|z  <   n0d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 extrinsic rotations, seq must be all lowercase and its elements
            must be from the set ``{'x', 'y', 'z'}``
            For intrinsic 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   rz   rb      r'   r   N)is_zero_quaternionr+   rE   r<   indexrR   rS   rT   rU   r/   r   r   r   r   r   Pir   Zerotuple)r\   r?   angle_additionavoid_square_rootr~   rA   r#   rB   rC   	symmetricr	   r.   rR   rS   rT   rU   n2cases                     r$   to_eulerzQuaternion.to_euler  s*   @ ""$$ 	IGHHH!#&&	))++1a KKNNQKKNNQKKNNQ 	aqA F	 	A	A A!a% AE*a/ FDFDFDF3QKQKQKQK$ 	4QAq1ua!e3JAq!Q 
	& GYY[[!^ !a%!a%-!a%"7!a%"?2!EFFq		a' !a%!a%-!a%"7!a%"?2!EFFq		E$q1uq1u}"5"5tAEAEM7J7JKKKF1I &q			QTAX%			 AF 	a 0 0 	DAF 	a 0 0 	D199 8!!QKK%1++5q	!!QKK%1++5q		!!A#!)QqS1Q3Y77q	!!A#!)QqS1Q3Y77q		 +,&F1I&'qyy()E!QKKq9}%%()E!QKKq9}%q9}%%%	*@""qA%%%  	1IIIIII 	!"&&&== r&   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   )rQ   vectoranglexyzr/   srR   rS   rT   rU   s               r$   r}   zQuaternion.from_axis_angleD  s    8 	AqAqD1a4K!Q$&''Xq4xTqAEEE s1aAr&   c                    |                                 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

        rb   r3   )r   r   )rb   rb   )r'   r'   r'   )r'   rb   )rb   r'   )r   r'   )r'   r   rv   )r   rb   )detr   r   r	   rG   )rQ   MabsQrR   rS   rT   rU   s          r$   from_rotation_matrixzQuaternion.from_rotation_matrixo  s?   > uuwwA&$!D')AdG344q8$!D')AdG344q8$!D')AdG344q8$!D')AdG344q8QtWqw&'''QtWqw&'''QtWqw&'''!Q1%%%r&   c                 ,    |                      |          S rf   addr\   others     r$   __add__zQuaternion.__add__      xxr&   c                 ,    |                      |          S rf   r   r   s     r$   __radd__zQuaternion.__radd__  r   r&   c                 2    |                      |dz            S Nr   r   r   s     r$   __sub__zQuaternion.__sub__  s    xxb!!!r&   c                 H    |                      | t          |                    S rf   _generic_mulr   r   s     r$   __mul__zQuaternion.__mul__  s      x777r&   c                 H    |                      t          |          |           S rf   r   r   s     r$   __rmul__zQuaternion.__rmul__  s      %$777r&   c                 ,    |                      |          S rf   )pow)r\   ps     r$   __pow__zQuaternion.__pow__  s    xx{{r&   c                 V    t          | j         | j         | j         | j                   S rf   )rG   rR   rS   rT   rU   r_   s    r$   __neg__zQuaternion.__neg__  s&    46'DF7TVGdfW===r&   c                 ,    | t          |          dz  z  S r   r   r   s     r$   __truediv__zQuaternion.__truediv__  s    gennb(((r&   c                 ,    t          |          | dz  z  S r   r   r   s     r$   __rtruediv__zQuaternion.__rtruediv__  s    u~~b((r&   c                      | j         | S rf   r   r\   rZ   s     r$   _eval_IntegralzQuaternion._eval_Integral  s    t~t$$r&   c                 j                         dd            | j        fd| j        D              S )NevaluateTc                 *    g | ]} |j         i S r)   )diff)r"   rR   kwargssymbolss     r$   rx   z#Quaternion.diff.<locals>.<listcomp>  s*    JJJ!61675f55JJJr&   )
setdefaultfuncrZ   )r\   r   r   s    ``r$   r   zQuaternion.diff  sC    *d+++tyJJJJJ	JJJKKr&   c                     | }t          |          }t          |t                    s|j        rM|j        rFt          t          |          |j        z   t          |          |j        z   |j	        |j
                  S |j        r)t          |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   
isinstancerG   rV   
is_complexr   rR   r   rS   rT   rU   rJ   r+   )r\   r   q1q2s       r$   r   zQuaternion.add  s    N U^^ "j)) 	a} a a!"R&&24-B"$bdKKK" a!"$)RT24>>> !_```"$+rtbd{BD24KDB! " " 	"r&   c                 H    |                      | 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77r&   c                 P   t          | t                    st          |t                    s| |z  S t          | t                    s|j        r6| j        r/t          t	          |           t          |           dd          |z  S | j        r2t          | |j        z  | |j        z  | |j	        z  | |j
        z            S t          d          t          |t                    s| j        r6|j        r/| t          t	          |          t          |          dd          z  S |j        r2t          || j        z  || j        z  || j	        z  || j
        z            S t          d          | j        
|j        d}n)|                                 |                                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   rG   rV   r   r   r   rJ   rR   rS   rT   rU   r+   r[   r/   )r   r   r/   s      r$   r   zQuaternion._generic_mul  st   V "j)) 	*R2L2L 	7N "j)) 	f} f f!"R&&"R&&!Q77"<<" f!"rt)R"$YRT	29MMM !deee "j)) 	f} f fJr"vvr"vvq!<<<<" f!"rt)R"$YRT	29MMM !deee 8 0DD7799rwwyy(D24%*rtBDy0249<rtBDyH$rt)bd24i/"$rt);bd24iG4%*rtBDy0249<rtBDyH$rt)bd24i/"$rt);bdRTkI#	% % % 	%r&   c                 f    | }t          |j        |j         |j         |j         |j                  S )z(Returns the conjugate of the quaternion.r   )rG   rR   rS   rT   rU   r[   r\   qs     r$   _eval_conjugatezQuaternion._eval_conjugateh  s0    !#tacTAC4ag>>>>r&   c                     | j         G| }t          t          |j        dz  |j        dz  z   |j        dz  z   |j        dz  z                       S | j         S )z#Returns the norm of the quaternion.Nr'   )r[   r   r   rR   rS   rT   rU   r   s     r$   r/   zQuaternion.normm  sU    :A a!#q&136!9ACF!BCCDDDzr&   c                 :    | }|d|                                 z  z  S )z.Returns the normalized form of the quaternion.rb   r   r   s     r$   	normalizezQuaternion.normalizew  s    AaffhhJr&   c                     | }|                                 st          d          t          |          d|                                 dz  z  z  S )z&Returns the inverse of the quaternion.z6Cannot compute inverse for a quaternion with zero normrb   r'   )r/   r+   r   r   s     r$   inversezQuaternion.inverse|  sH    vvxx 	WUVVV||q1}--r&   c                    	 | t          |          }}n# t          $ r
 t          cY S w xY w|dk     r|                                | }}|dk    r|S t	          dddd          }|dk    r|dz  r||z  }||z  }|dz  }|dk    |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   rb   )r   r+   NotImplementedr   rG   )r\   r   r   ress       r$   r   zQuaternion.pow  s    2	"qAA 	" 	" 	"!!!!	" q5599;;qA66HAq!$$!ee1u qFA!GA	 !ee 
s    ((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$, given by $e^q$.

        Returns
        =======

        Quaternion
            The exponential of the quaternion.

        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   rS   rT   rU   r
   rR   r   r   rG   )r\   r   vector_normrR   rS   rT   rU   s          r$   r
   zQuaternion.exp  s    , 136ACF?QS!V344HHs;'''HHs;'''!#-;HHs;'''!#-;HHs;'''!#-;!Q1%%%r&   c                    | }t          |j        dz  |j        dz  z   |j        dz  z             }|                                }t          |          }|j        t          |j        |z            z  |z  }|j        t          |j        |z            z  |z  }|j        t          |j        |z            z  |z  }t          ||||          S )ag  Returns the logarithm of the quaternion, given by $\log q$.

        Examples
        ========

        >>> from sympy import Quaternion
        >>> q = Quaternion(1, 2, 3, 4)
        >>> q.log()
        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   rS   rT   rU   r/   lnr   rR   rG   )r\   r   r   q_normrR   rS   rT   rU   s           r$   r   zQuaternion.log  s      136ACF?QS!V344vJJC$qsV|$$${2C$qsV|$$${2C$qsV|$$${2!Q1%%%r&   c                     fd| j         D             }| j        }|
 |j         }t          ||           t	          |d|iS )Nc                 $    g | ]} |j          S r)   )subs)r"   r#   rZ   s     r$   rx   z)Quaternion._eval_subs.<locals>.<listcomp>  s!    555aFAFDM555r&   r/   )rZ   r[   r   r1   rG   )r\   rZ   r.   r/   s    `  r$   
_eval_subszQuaternion._eval_subs  s\    555549555z49d#DHd###8/$///r&   c                 V    t          |          t          f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                 <    g | ]}|                                S ))rw   )evalf)r"   argnprecs     r$   rx   z*Quaternion._eval_evalf.<locals>.<listcomp>  s'    DDD3CIII..DDDr&   )r   rG   rZ   )r\   precr   s     @r$   _eval_evalfzQuaternion._eval_evalf  s4    , D!!DDDD$)DDDEEr&   c                     | }|                                 \  }}t                              |||z            }||                                |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_anglerG   r}   r/   )r\   r   r   vr   r   s         r$   pow_cos_sinzQuaternion.pow_cos_sin
  sL    < __&&
E''1u955QVVXXq[!!r&   c           	          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

        )rG   r   rR   rS   rT   rU   r   s     r$   r   zQuaternion.integrate-  sj    < )DF2T222Idf4Lt4L4L4L#DF2T222Idf4Lt4L4L4LN N 	Nr&   c                 :   t          |t                    r(t                              |d         |d                   }n|                                }|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   rb   r'   )	r   r   rG   r}   r   r   rS   rT   rU   )pinrr   pouts       r$   rotate_pointzQuaternion.rotate_pointN  s    H a 	**1Q4166AA A:aQQQ8889Q<<G''r&   c                 v   | }|j         j        r|dz  }|                                }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'   rb   )	rR   is_negativer   r   r   r   rS   rT   rU   )	r\   r   r   r   r   r   r   r   ts	            r$   r   zQuaternion.to_axis_angle{  s    * 3? 	BAKKMMT!#YY'' QSWQS1WQS1WQS1W1IJr&   c           	         | }|                                 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  }nZd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'   rb   r   )r/   rR   rS   rT   rU   ri   )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 FFHHbL  	,QS!Vac1f_qsAv-Q67CQS!Vac1f_qsAv-Q67CQS!Vac1f_qsAv-Q67CCac136ACF?++Cac136ACF?++Cac136ACF?++Cc13qs7QSW$%c13qs7QSW$%c13qs7QSW$%c13qs7QSW$%c13qs7QSW$%c13qs7QSW$% 	GCc?S#sOc3_MN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 Gr&   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

        )rR   r_   s    r$   scalar_partzQuaternion.scalar_part  s    $ vr&   c                 D    t          d| j        | j        | j                  S )a  
        Returns $\mathbf{V}(q)$, the vector part 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   )rG   rS   rT   rU   r_   s    r$   vector_partzQuaternion.vector_part  s    . !TVTVTV444r&   c                     |                                                                  }t          d|j        |j        |j                  S )a  
        Returns $\mathbf{Ax}(q)$, the axis of the quaternion $q$.

        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   rG   rS   rT   rU   )r\   axiss     r$   r  zQuaternion.axis  s;    2 !!++--!TVTVTV444r&   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

        )rR   is_zeror_   s    r$   is_purezQuaternion.is_pure9  s    2 v~r&   c                 4    |                                  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_quaternionT  s    < yy{{""r&   c                     dt          |                                                                 |                                           z  S )a7  
        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::
            \theta := 2 \operatorname{atan_2}\left(\sqrt{b^2 + c^2 + d^2}, {a}\right)

        Examples
        ========

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

        r'   )r   r  r/   r  r_   s    r$   r   zQuaternion.anglet  s=    . 5))++0022D4D4D4F4FGGGGr&   c                 v   |                                  s|                                 rt          d          t          |                                 |                                z
                                   |                                 |                                z                                    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  s    T ##%% 	J5+C+C+E+E 	JHIII$))++

4HHJJTYY[[[`[e[e[g[gMgL{L{L}L}~r&   c                    t          |                                          sBt          |                                          s!t          |                                          rt          d          t          |j        |j        |j        g|j        |j        |j        g|j        |j        |j        gg                                          }|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+   ri   rS   rT   rU   r   r  )rQ   r   r   q3r   s        r$   vector_coplanarzQuaternion.vector_coplanar  s    l RZZ\\"" 	Ci

&=&= 	C2::<<AXAX 	CABBBRT24&rtRT(:RT24<NOPPTTVVyr&   c                     t          |                                           s!t          |                                          rt          d          | |z  || z  z
                                  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  sd    J T\\^^$$ 	F	%--//(B(B 	FDEEEU
U4Z';;===r&   c                     t          |                                           s!t          |                                          rt          d          | |z  || z  z                                   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#  sd    J T\\^^$$ 	C	%--//(B(B 	CABBBU
U4Z';;===r&   c                 T    |                                  |                                 z  S )a  
        Returns the index vector of the quaternion.

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

        The index vector is given by $\mathbf{T}(q)$, the norm (or magnitude) of
        the quaternion $q$, multiplied by $\mathbf{Ax}(q)$, the axis of $q$.

        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_vectorM  s    > yy{{TYY[[((r&   c                 D    t          |                                           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.mensorn  s    * $))++r&   )r   r   r   r   TN)F)TF)NT)A__name__
__module____qualname____doc___op_priorityrJ   rN   rP   propertyrR   rS   rT   rU   rV   rj   rl   ro   classmethodrs   r   r   r}   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(  __classcell__)rX   s   @r$   rG   rG   :   sk       / /` LN     " " "H   X   X   X   X     X  /4 /4 X/4b 44 44 X44l/% /% /% /%b () () [()T =* =* [=*~L! L! L! L!\ ( ( [(T )& )& [)&V    " " "8 8 88 8 8  > > >) ) )) ) )% % %L L L4" 4" 4"l'8 '8 '8R I% I% \I%V? ? ?
       
. . .+ + +Z& & &>& & &40 0 0F F F2!" !" !"FN N NB *( *( \*(X& & &PJG JG JG JGX  (5 5 525 5 5:  6# # #@H H H4-@ -@ -@^ 9 9 [9v(> (> (>T(> (> (>T) ) )B      r&   rG   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   ri   sympy.core.sympifyr   r   sympy.core.exprr   sympy.core.logicr   r   sympy.utilities.miscr   mpmath.libmp.libmpfr   r1   rE   rG   r)   r&   r$   <module>rA     s   ' ' ' ' ' ' " " " " " " ' ' ' ' ' ' J J J J J J J J J J J J C C C C C C C C 9 9 9 9 9 9 H H H H H H H H H H ? ? ? ? ? ? ? ? , , , , , , / / / / / / = = = = = = 0 0 0 0 0 0 0 0             0 0 0 0 0 0 0 0 ' ' ' ' ' ' + + + + + += = =  6I I I I I I I I I Ir&   