
     i              	          d Z ddlZddlZddlZddlZddlZddlmZ ddl	m
Z
 ddlmZ d Zd Zd	 Zd
 Zd ZdhdZd ZdidZd Z	 djdZdkdZdkdZd Zd Zd Z	 dldZd ZdmdZdndZ dndZ!dndZ"dndZ#d  Z$d! Z%dkd"Z&d# Z'd$ Z(d% Z)d& Z*d' Z+dod(Z,dhd)Z-dhd*Z. G d+ d,e/          Z0d- Z1d. Z2d/ Z3 ej4        e5          j6        d0z  Z7g d1Z8i dd2d3d4d5d6d7d8d9d:d;d<d=d>d?d@dAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZZ9 e:d[ e9;                                D                       Z<did\Z=did]Z>d^ Z?d_ Z@d` ZAda ZBdpddZCde ZD eCdf           dgZEdS )qa  
Homogeneous Transformation Matrices and Quaternions --- :mod:`MDAnalysis.lib.transformations`
==============================================================================================

A library for calculating 4x4 matrices for translating, rotating, reflecting,
scaling, shearing, projecting, orthogonalizing, and superimposing arrays of
3D homogeneous coordinates as well as for converting between rotation matrices,
Euler angles, and quaternions. Also includes an Arcball control object and
functions to decompose transformation matrices.

:Authors:
  `Christoph Gohlke <http://www.lfd.uci.edu/~gohlke/>`__,
  Laboratory for Fluorescence Dynamics, University of California, Irvine
:Version: 2010.05.10
:Licence: BSD 3-clause

Requirements
------------

* `Python 2.6 or 3.1 <http://www.python.org>`__
* `Numpy 1.4 <http://numpy.scipy.org>`__
* `transformations.c 2010.04.10 <http://www.lfd.uci.edu/~gohlke/>`__
  (optional implementation of some functions in C)

Notes
-----

The API is not stable yet and is expected to change between revisions.

This Python code is not optimized for speed. Refer to the transformations.c
module for a faster implementation of some functions.

Documentation in HTML format can be generated with epydoc.

Matrices (M) can be inverted using ``numpy.linalg.inv(M)``, concatenated using
``numpy.dot(M0, M1)``, or used to transform homogeneous coordinates (v) using
``numpy.dot(M, v)`` for shape ``(4, *)`` "point of arrays", respectively
``numpy.dot(v, M.T)`` for shape ``(*, 4)`` "array of points".

Use the transpose of transformation matrices for OpenGL ``glMultMatrixd()``.

Calculations are carried out with ``numpy.float64`` precision.

Vector, point, quaternion, and matrix function arguments are expected to be
"array like", i.e. tuple, list, or numpy arrays.

Return types are numpy arrays unless specified otherwise.

Angles are in radians unless specified otherwise.

Quaternions w+ix+jy+kz are represented as ``[w, x, y, z]``.

A triple of Euler angles can be applied/interpreted in 24 ways, which can
be specified using a 4 character string or encoded 4-tuple:

  - *Axes 4-string*: e.g. 'sxyz' or 'ryxy'

    - first character : rotations are applied to 's'tatic or 'r'otating frame
    - remaining characters : successive rotation axis 'x', 'y', or 'z'

  - *Axes 4-tuple*: e.g. (0, 0, 0, 0) or (1, 1, 1, 1)

    - inner axis: code of axis ('x':0, 'y':1, 'z':2) of rightmost matrix.
    - parity : even (0) if inner axis 'x' is followed by 'y', 'y' is followed
      by 'z', or 'z' is followed by 'x'. Otherwise odd (1).
    - repetition : first and last axis are same (1) or different (0).
    - frame : rotations are applied to static (0) or rotating (1) frame.

.. rubric:: References

.. footbibliography::

Examples
--------

>>> from MDAnalysis.lib.transformations import *
>>> import numpy as np
>>> alpha, beta, gamma = 0.123, -1.234, 2.345
>>> origin, xaxis, yaxis, zaxis = (0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)
>>> I = identity_matrix()
>>> Rx = rotation_matrix(alpha, xaxis)
>>> Ry = rotation_matrix(beta, yaxis)
>>> Rz = rotation_matrix(gamma, zaxis)
>>> R = concatenate_matrices(Rx, Ry, Rz)
>>> euler = euler_from_matrix(R, 'rxyz')
>>> np.allclose([alpha, beta, gamma], euler)
True
>>> Re = euler_matrix(alpha, beta, gamma, 'rxyz')
>>> is_same_transform(R, Re)
True
>>> al, be, ga = euler_from_matrix(Re, 'rxyz')
>>> is_same_transform(Re, euler_matrix(al, be, ga, 'rxyz'))
True
>>> qx = quaternion_about_axis(alpha, xaxis)
>>> qy = quaternion_about_axis(beta, yaxis)
>>> qz = quaternion_about_axis(gamma, zaxis)
>>> q = quaternion_multiply(qx, qy)
>>> q = quaternion_multiply(q, qz)
>>> Rq = quaternion_matrix(q)
>>> is_same_transform(R, Rq)
True
>>> S = scale_matrix(1.23, origin)
>>> T = translation_matrix((1, 2, 3))
>>> Z = shear_matrix(beta, xaxis, origin, zaxis)
>>> R = random_rotation_matrix(np.random.rand(3))
>>> M = concatenate_matrices(T, R, Z, S)
>>> scale, shear, angles, trans, persp = decompose_matrix(M)
>>> np.allclose(scale, 1.23)
True
>>> np.allclose(trans, (1, 2, 3))
True
>>> np.allclose(shear, (0, math.tan(beta), 0))
True
>>> is_same_transform(R, euler_matrix(axes='sxyz', *angles))
True
>>> M1 = compose_matrix(scale, shear, angles, trans, persp)
>>> is_same_transform(M, M1)
True

Functions
---------

.. See `help(MDAnalysis.lib.transformations)` for a listing of functions or
.. the online help.


.. versionchanged:: 0.11.0
   Transformations library moved from MDAnalysis.core.transformations to
   MDAnalysis.lib.transformations
    N)norm)no_copy_shim   )anglec                  B    t          j        dt           j                  S )aA  Return 4x4 identity/unit matrix.

    >>> from MDAnalysis.lib.transformations import identity_matrix
    >>> import numpy as np
    >>> I = identity_matrix()
    >>> np.allclose(I, np.dot(I, I))
    True
    >>> np.sum(I), np.trace(I)
    (4.0, 4.0)
    >>> np.allclose(I, np.identity(4, dtype=np.float64))
    True

       dtype)npidentityfloat64     h/srv/www/vhosts/g4struct/public_html/venv/lib/python3.11/site-packages/MDAnalysis/lib/transformations.pyidentity_matrixr      s     ;q
++++r   c                 P    t          j        d          }| dd         |dddf<   |S )zReturn matrix to translate by direction vector.

    >>> from MDAnalysis.lib.transformations import translation_matrix
    >>> import numpy as np
    >>> v = np.random.random(3) - 0.5
    >>> np.allclose(v, translation_matrix(v)[:3, 3])
    True

    r   N   )r   r   )	directionMs     r   translation_matrixr      s/     	AA!}Abqb!eHHr   c                 f    t          j        | d          dddf                                         S )aJ  Return translation vector from translation matrix.

    >>> from MDAnalysis.lib.transformations import (translation_matrix,
    ...     translation_from_matrix)
    >>> import numpy as np
    >>> v0 = np.random.random(3) - 0.5
    >>> v1 = translation_from_matrix(translation_matrix(v0))
    >>> np.allclose(v0, v1)
    True

    FcopyNr   )r   arrayr   matrixs    r   translation_from_matrixr      s2     8F'''A.33555r   c                    t          |dd                   }t          j        d          }|ddddfxx         dt          j        ||          z  z  cc<   dt          j        | dd         |          z  |z  |dddf<   |S )a  Return matrix to mirror at plane defined by point and normal vector.

    >>> from MDAnalysis.lib.transformations import reflection_matrix
    >>> import numpy as np
    >>> v0 = np.random.random(4) - 0.5
    >>> v0[3] = 1.0
    >>> v1 = np.random.random(3) - 0.5
    >>> R = reflection_matrix(v0, v1)
    >>> np.allclose(2., np.trace(R))
    True
    >>> np.allclose(v0, np.dot(R, v0))
    True
    >>> v2 = v0.copy()
    >>> v2[:3] += v1
    >>> v3 = v0.copy()
    >>> v2[:3] -= v1
    >>> np.allclose(v2, np.dot(R, v3))
    True

    Nr   r          @)unit_vectorr   r   outerdot)pointnormalr   s      r   reflection_matrixr%      s    * $$F
AAbqb"1"fIIIrx////IIIbfU2A2Y///69Abqb!eHHr   c                 R   t          j        | t           j        d          }t           j                            |ddddf                   \  }}t          j        t          t          j        |          dz             dk               d         }t          |          st          d          t          j        |dd|d         f                   
                                }t           j                            |          \  }}t          j        t          t          j        |          dz
            dk               d         }t          |          st          d	          t          j        |dd|d
         f                   
                                }||d         z  }||fS )a  Return mirror plane point and normal vector from reflection matrix.

    >>> from MDAnalysis.lib.transformations import (reflection_matrix,
    ...     reflection_from_matrix, is_same_transform)
    >>> import numpy as np
    >>> v0 = np.random.random(3) - 0.5
    >>> v1 = np.random.random(3) - 0.5
    >>> M0 = reflection_matrix(v0, v1)
    >>> point, normal = reflection_from_matrix(M0)
    >>> M1 = reflection_matrix(point, normal)
    >>> is_same_transform(M0, M1)
    True

    Fr
   r   Nr         ?:0yE>r   z2no unit eigenvector corresponding to eigenvalue -11no unit eigenvector corresponding to eigenvalue 1)r   r   r   linalgeigwhereabsreallen
ValueErrorsqueeze)r   r   lVir$   r#   s          r   reflection_from_matrixr7      s`    	rz666A9==2A2rr6##DAq
RWQZZ#%&&-..q1Aq66 OMNNNWQqqq!A$wZ  ((**F9==DAq
RWQZZ#%&&-..q1Aq66 NLMMMGAaaa2hK  ((**E	U1XE&=r   c                    t          j        |           }t          j        |           }t          |dd                   }t	          j        |ddfd|dfdd|fft          j                  }|t	          j        ||          d|z
  z  z  }||z  }|t	          j        d|d          |d         f|d         d|d          f|d          |d         dfft          j                  z  }t	          j        d	          }||ddddf<   |Mt	          j        |dd         t          j        t          
          }|t	          j
        ||          z
  |dddf<   |S )a  Return matrix to rotate about axis defined by point and direction.

    >>> from MDAnalysis.lib.transformations import (rotation_matrix,
    ...     is_same_transform)
    >>> import random, math
    >>> import numpy as np
    >>> R = rotation_matrix(math.pi/2.0, [0, 0, 1], [1, 0, 0])
    >>> np.allclose(np.dot(R, [0, 0, 0, 1]), [ 1., -1.,  0.,  1.])
    True
    >>> angle = (random.random() - 0.5) * (2*math.pi)
    >>> direc = np.random.random(3) - 0.5
    >>> point = np.random.random(3) - 0.5
    >>> R0 = rotation_matrix(angle, direc, point)
    >>> R1 = rotation_matrix(angle-2*math.pi, direc, point)
    >>> is_same_transform(R0, R1)
    True
    >>> R0 = rotation_matrix(angle, direc, point)
    >>> R1 = rotation_matrix(-angle, -direc, point)
    >>> is_same_transform(R0, R1)
    True
    >>> I = np.identity(4, np.float64)
    >>> np.allclose(I, rotation_matrix(math.pi*2, direc))
    True
    >>> np.allclose(2., np.trace(rotation_matrix(math.pi/2,
    ...                                                direc, point)))
    True

    Nr           r	   r(      r   r   r   r'   )mathsincosr    r   r   r   r!   r   r   r"   )r   r   r#   sinacosaRr   s          r   rotation_matrixrA     st   : 8E??D8E??DIbqbM**I
3$#t	

 j	 	 	A )Y	'	'3:	66AI9Q<-1.q\31.l]IaL#.	

 j
 
 
 A 	AAAbqb"1"fIrr"*<HHH26!U+++"1"a%Hr   c                    t          j        | t           j        d          }|ddddf         }t           j                            |j                  \  }}t          j        t          t          j        |          dz
            dk               d         }t          |          st          d          t          j        |dd|d	         f                                                   }t           j                            |          \  }}t          j        t          t          j        |          dz
            dk               d         }t          |          st          d          t          j        |dd|d	         f                                                   }||d         z  }t          j        |          dz
  d
z  }	t          |d                   dk    r*|d         |	dz
  |d         z  |d         z  z   |d         z  }
nlt          |d                   dk    r*|d         |	dz
  |d         z  |d         z  z   |d         z  }
n)|d         |	dz
  |d         z  |d         z  z   |d         z  }
t          j        |
|	          }|||fS )a<  Return rotation angle and axis from rotation matrix.

    >>> from MDAnalysis.lib.transformations import (rotation_matrix,
    ...     is_same_transform, rotation_from_matrix)
    >>> import random, math
    >>> import numpy as np
    >>> angle = (random.random() - 0.5) * (2*math.pi)
    >>> direc = np.random.random(3) - 0.5
    >>> point = np.random.random(3) - 0.5
    >>> R0 = rotation_matrix(angle, direc, point)
    >>> angle, direc, point = rotation_from_matrix(R0)
    >>> R1 = rotation_matrix(angle, direc, point)
    >>> is_same_transform(R0, R1)
    True

    Fr'   Nr   r(   r)   r   r*   r+   r   r:   r   r   r   r   r:   r:   r   )r   r   r   r,   r-   Tr.   r/   r0   r1   r2   r3   tracer;   atan2)r   r@   R33r4   Wr6   r   Qr#   r?   r>   r   s               r   rotation_from_matrixrL   Y  sZ   " 	rz666A
BQBF)C9==DAq
RWQZZ#%&&-..q1Aq66 NLMMM!!!QrU($$,,..I9==DAq
RWQZZ#%&&-..q1Aq66 NLMMMGAaaa2hK  ((**E	U1XEHSMMC3&D
9Q<4dGtczYq\1IaL@@aL 
Yq\		T	!	!dGtczYq\1IaL@@aL
 dGtczYq\1IaL@@aL JtT""E)U""r   c                    |[t          j        | dddfd| ddfdd| dfdft           j                  }|(|dd         |dddf<   |dddfxx         d| z
  z  cc<   nt          |dd                   }d| z
  } t          j        d          }|ddddfxx         | t          j        ||          z  z  cc<   |*| t          j        |dd         |          z  |z  |dddf<   |S )aV  Return matrix to scale by factor around origin in direction.

    Use factor -1 for point symmetry.

    >>> from MDAnalysis.lib.transformations import scale_matrix
    >>> import random
    >>> import numpy as np
    >>> v = (np.random.rand(4, 5) - 0.5) * 20.0
    >>> v[3] = 1.0
    >>> S = scale_matrix(-1.234)
    >>> np.allclose(np.dot(S, v)[:3], -1.234*v[:3])
    True
    >>> factor = random.random() * 10 - 5
    >>> origin = np.random.random(3) - 0.5
    >>> direct = np.random.random(3) - 0.5
    >>> S = scale_matrix(factor, origin)
    >>> S = scale_matrix(factor, origin, direct)

    Nr9   r9   r9   r9   r(   r	   r   r(   r   )r   r   r   r    r   r!   r"   )factororiginr   r   s       r   scale_matrixrQ     s1   ( Hc3'fc3'c63'$	 *
 
 
 bqbzAbqb!eHbqb!eHHHf$HHH  	"1"..	vKNN	"1"bqb&			Vbhy)<<<<			rr
I!>!>>)KAbqb!eHHr   c                    t          j        | t           j        d          }|ddddf         }t          j        |          dz
  }	 t           j                            |          \  }}t          j        t          t          j        |          |z
            dk               d         d         }t          j        |dd|f                   	                                }|t          |          z  }n# t          $ r |dz   dz  }d}Y nw xY wt           j                            |          \  }}t          j        t          t          j        |          d	z
            dk               d         }t          |          st          d
          t          j        |dd|d         f                   	                                }||d         z  }|||fS )a  Return scaling factor, origin and direction from scaling matrix.

    >>> from MDAnalysis.lib.transformations import (scale_matrix,
    ...      scale_from_matrix, is_same_transform)
    >>> import random
    >>> import numpy as np
    >>> factor = random.random() * 10 - 5
    >>> origin = np.random.random(3) - 0.5
    >>> direct = np.random.random(3) - 0.5
    >>> S0 = scale_matrix(factor, origin)
    >>> factor, origin, direction = scale_from_matrix(S0)
    >>> S1 = scale_matrix(factor, origin, direction)
    >>> is_same_transform(S0, S1)
    True
    >>> S0 = scale_matrix(factor, origin, direct)
    >>> factor, origin, direction = scale_from_matrix(S0)
    >>> S1 = scale_matrix(factor, origin, direction)
    >>> is_same_transform(S0, S1)
    True

    Fr'   Nr   r   r)   r         @r(   ,no eigenvector corresponding to eigenvalue 1r+   )r   r   r   rG   r,   r-   r.   r/   r0   r3   vector_norm
IndexErrorr1   r2   )	r   r   M33rO   r4   r5   r6   r   rP   s	            r   scale_from_matrixrX     s   , 	rz666A
BQBF)CXc]]S F	y}}S!!1HSf,--455a8;GAaaadG$$,,..	[+++		   3,#%			
 9==DAq
RWQZZ#%&&-..q1Aq66 IGHHHWQqqq!B%x[!!))++F
fQiF69$$s   B*C3 3D
	D
Fc                    t          j        d          }t          j        | dd         t           j        t                    } t          |dd                   }|t          j        |dd         t           j        d          }t          j        || z
  |          x|d<   x|d<   |d<   |ddddfxx         t          j        ||          z  cc<   |rL|ddddfxx         t          j        ||          z  cc<   t          j        | |          ||z   z  |dddf<   nt          j        | |          |z  |dddf<   | |dddf<   t          j        ||          |d	<   n|t          j        |dd         t           j        t                    }t          j        ||          }|ddddfxx         t          j        ||          |z  z  cc<   |t          j        | |          |z  z  |dddf<   nH|ddddfxx         t          j        ||          z  cc<   t          j        | |          |z  |dddf<   |S )
a  Return matrix to project onto plane defined by point and normal.

    Using either perspective point, projection direction, or none of both.

    If pseudo is True, perspective projections will preserve relative depth
    such that Perspective = dot(Orthogonal, PseudoPerspective).

    >>> from MDAnalysis.lib.transformations import (projection_matrix,
    ...     is_same_transform)
    >>> import numpy as np
    >>> P = projection_matrix((0, 0, 0), (1, 0, 0))
    >>> np.allclose(P[1:, 1:], np.identity(4)[1:, 1:])
    True
    >>> point = np.random.random(3) - 0.5
    >>> normal = np.random.random(3) - 0.5
    >>> direct = np.random.random(3) - 0.5
    >>> persp = np.random.random(3) - 0.5
    >>> P0 = projection_matrix(point, normal)
    >>> P1 = projection_matrix(point, normal, direction=direct)
    >>> P2 = projection_matrix(point, normal, perspective=persp)
    >>> P3 = projection_matrix(point, normal, perspective=persp, pseudo=True)
    >>> is_same_transform(P2, np.dot(P0, P3))
    True
    >>> P = projection_matrix((3, 0, 0), (1, 1, 0), (1, 0, 0))
    >>> v0 = (np.random.rand(4, 5) - 0.5) * 20.0
    >>> v0[3] = 1.0
    >>> v1 = np.dot(P, v0)
    >>> np.allclose(v1[1], v0[1])
    True
    >>> np.allclose(v1[0], 3.0-v1[1])
    True

    r   Nr   r'   Fr   r   r   r   r:   r:   r   r   )r   r   r   r   r   r    r"   r!   )r#   r$   r   perspectivepseudor   scales          r   projection_matrixra     se   H 	AAHU2A2Ybj|DDDE$$Fh{2A2bjuMMM&(f[5-@&&I&II$I!D'AdG	"1"bqb&			RXk6222			 	;bqb"1"fIII&&111IIIveV,,f0DEAbqb!eHHveV,,{:Abqb!eH7!RaR%&f--$		HbqbM,
 
 
	 y&))	"1"bqb&			RXi00588			uf 5 5 =>"1"a% 	
"1"bqb&			RXff---			6%((61"1"a%Hr   c                    t          j        | t           j        d          }|ddddf         }t           j                            |          \  }}t          j        t          t          j        |          dz
            dk               d         }|st          |          rt          j        |dd|d         f                   	                                }||d         z  }t           j                            |          \  }}t          j        t          t          j        |                    dk               d         }t          |          st          d	          t          j        |dd|d         f                   	                                }|t          |          z  }t           j                            |j                  \  }}t          j        t          t          j        |                    dk               d         }t          |          rOt          j        |dd|d         f                   	                                }	|	t          |	          z  }	||	|ddfS ||dddfS t          j        t          t          j        |                    dk              d         }t          |          st          d
          t          j        |dd|d         f                   	                                }||d         z  }|dddf          }	|dddf         t          j        |dd         |	          z  }
|r|
|	z  }
||	d|
|fS )a'  Return projection plane and perspective point from projection matrix.

    Return values are same as arguments for projection_matrix function:
    point, normal, direction, perspective, and pseudo.

    >>> from MDAnalysis.lib.transformations import (projection_matrix,
    ...     projection_from_matrix, is_same_transform)
    >>> import numpy as np
    >>> point = np.random.random(3) - 0.5
    >>> normal = np.random.random(3) - 0.5
    >>> direct = np.random.random(3) - 0.5
    >>> persp = np.random.random(3) - 0.5
    >>> P0 = projection_matrix(point, normal)
    >>> result = projection_from_matrix(P0)
    >>> P1 = projection_matrix(*result)
    >>> is_same_transform(P0, P1)
    True
    >>> P0 = projection_matrix(point, normal, direct)
    >>> result = projection_from_matrix(P0)
    >>> P1 = projection_matrix(*result)
    >>> is_same_transform(P0, P1)
    True
    >>> P0 = projection_matrix(point, normal, perspective=persp, pseudo=False)
    >>> result = projection_from_matrix(P0, pseudo=False)
    >>> P1 = projection_matrix(*result)
    >>> is_same_transform(P0, P1)
    True
    >>> P0 = projection_matrix(point, normal, perspective=persp, pseudo=True)
    >>> result = projection_from_matrix(P0, pseudo=True)
    >>> P1 = projection_matrix(*result)
    >>> is_same_transform(P0, P1)
    True

    Fr'   Nr   r(   r)   r   r+   z,no eigenvector corresponding to eigenvalue 0z0no eigenvector not corresponding to eigenvalue 0)r   r   r   r,   r-   r.   r/   r0   r1   r3   r2   rU   rF   r"   )r   r_   r   rW   r4   r5   r6   r#   r   r$   r^   s              r   projection_from_matrixrc   (  s   F 	rz666A
BQBF)C9==DAq
RWQZZ#%&&-..q1A #8c!ff #8!!!QrU($$,,..qy}}S!!1HS__t+,,Q/1vv 	MKLLLGAaaa1gJ''//11	[+++	y}}SU##1HS__t+,,Q/q66 	7WQqqq!A$wZ((0022Fk&)))F&)T588 )T466 HS__t+,,Q/1vv 	B   !!!QrU($$,,..qArrE(Ahbqb	6!:!:: 	"6!KfdK77r   c                    | |k    s||k    s||k    rt          d          |re|t          k    rt          d          d|z  }| || z
  z  d|| z   || z
  z  dfd| ||z
  z  ||z   ||z
  z  dfdd||z    ||z
  z  ||z  ||z
  z  fdf}n?d|| z
  z  dd|| z   | |z
  z  fdd||z
  z  d||z   ||z
  z  fddd||z
  z  ||z   ||z
  z  fdf}t          j        |t          j                  S )aR  Return matrix to obtain normalized device coordinates from frustrum.

    The frustrum bounds are axis-aligned along x (left, right),
    y (bottom, top) and z (near, far).

    Normalized device coordinates are in range [-1, 1] if coordinates are
    inside the frustrum.

    If perspective is True the frustrum is a truncated pyramid with the
    perspective point at origin and direction along z axis, otherwise an
    orthographic canonical view volume (a box).

    Homogeneous coordinates transformed by the perspective clip matrix
    need to be dehomogenized (devided by w coordinate).

    >>> from MDAnalysis.lib.transformations import clip_matrix
    >>> import numpy as np
    >>> frustrum = np.random.rand(6)
    >>> frustrum[1] += frustrum[0]
    >>> frustrum[3] += frustrum[2]
    >>> frustrum[5] += frustrum[4]
    >>> M = clip_matrix(perspective=False, *frustrum)
    >>> np.dot(M, [frustrum[0], frustrum[2], frustrum[4], 1.0])
    array([-1., -1., -1.,  1.])
    >>> np.dot(M, [frustrum[1], frustrum[3], frustrum[5], 1.0])
    array([1., 1., 1., 1.])
    >>> M = clip_matrix(perspective=True, *frustrum)
    >>> v = np.dot(M, [frustrum[0], frustrum[2], frustrum[4], 1.0])
    >>> v / v[3]
    array([-1., -1., -1.,  1.])
    >>> v = np.dot(M, [frustrum[1], frustrum[3], frustrum[4], 1.0])
    >>> v / v[3]
    array([ 1.,  1., -1.,  1.])

    zinvalid frustrumzinvalid frustrum: near <= 0r   r9   )r9   r9         r9   rN   r	   )r2   _EPSr   r   r   )	leftrightbottomtopnearfarr^   tr   s	            r   clip_matrixrn   u  s]   H u}}#+,,, 
4<<:;;;$JR54< #'FL1"f%fv'FL#t}d
3QWd
5KL!	
 EDL!3edlte|-LM#v&cFlv|-LM#scDj)C$J4#:+FG 	
 8ARZ((((r   c                    t          |dd                   }t          |dd                   }t          t          j        ||                    dk    rt	          d          t          j        |           } t          j        d          }|ddddfxx         | t          j        ||          z  z  cc<   |  t          j        |dd         |          z  |z  |dddf<   |S )am  Return matrix to shear by angle along direction vector on shear plane.

    The shear plane is defined by a point and normal vector. The direction
    vector must be orthogonal to the plane's normal vector.

    A point P is transformed by the shear matrix into P" such that
    the vector P-P" is parallel to the direction vector and its extent is
    given by the angle of P-P'-P", where P' is the orthogonal projection
    of P onto the shear plane.

    >>> from MDAnalysis.lib.transformations import shear_matrix
    >>> import random, math
    >>> import numpy as np
    >>> angle = (random.random() - 0.5) * 4*math.pi
    >>> direct = np.random.random(3) - 0.5
    >>> point = np.random.random(3) - 0.5
    >>> normal = np.cross(direct, np.random.random(3))
    >>> S = shear_matrix(angle, direct, point, normal)
    >>> np.allclose(1.0, np.linalg.det(S))
    True

    Nr   gư>z/direction and normal vectors are not orthogonalr   )	r    r/   r   r"   r2   r;   tanr   r!   )r   r   r#   r$   r   s        r   shear_matrixrq     s    . $$FIbqbM**I
26&)$$%%,,JKKKHUOOE
AAbqb"1"fIII)V4444IIIvuRaRy&111I=Abqb!eHHr   c                    t          j        | t           j        d          }|ddddf         }t           j                            |          \  }}t          j        t          t          j        |          dz
            dk               d         }t          |          dk     r"t          d	
                    |                    t          j        |dd|f                                                   j        }d
}dD ]?\  }}t          j        ||         ||                   }	t          |	          }||k    r|}|	}
@|
|z  }
t          j        |t          j        d          z
  |
          }t          |          }||z  }t#          j        |          }t           j                            |          \  }}t          j        t          t          j        |          dz
            dk               d         }t          |          st          d          t          j        |dd|d         f                                                   }||d         z  }||||
fS )a  Return shear angle, direction and plane from shear matrix.

    >>> from MDAnalysis.lib.transformations import (shear_matrix,
    ...     shear_from_matrix, is_same_transform)
    >>> import random, math
    >>> import numpy as np
    >>> angle = (random.random() - 0.5) * 4*math.pi
    >>> direct = np.random.random(3) - 0.5
    >>> point = np.random.random(3) - 0.5
    >>> normal = np.cross(direct, np.random.random(3))
    >>> S0 = shear_matrix(angle, direct, point, normal)
    >>> angle, direct, point, normal = shear_from_matrix(S0)
    >>> S1 = shear_matrix(angle, direct, point, normal)
    >>> is_same_transform(S0, S1)
    True

    Fr'   Nr   r(   g-C6?r   r:   z2no two linear independent eigenvectors found {0!s}re   )r   r   rD   r   r:   r)   rT   r+   )r   r   r   r,   r-   r.   r/   r0   r1   r2   formatr3   rF   crossrU   r"   r   r;   atan)r   r   rW   r4   r5   r6   lenormi0i1nr$   r   r   r#   s                 r   shear_from_matrixr|     s   $ 	rz666A
BQBF)C9==DAq
RWQZZ#%&&-..q1A
1vvzz@GGJJ
 
 	
 	!!!Q$  ""$AF*  BHQrUAbE""NNv::FF
fFsR[^^+V44I	""EIIeE9==DAq
RWQZZ#%&&-..q1Aq66 IGHHHGAaaa2hK  ((**E	U1XE)UF**r   c                 \   t          j        | t           j        d          j        }t	          |d                   t
          k     rt          d          ||d         z  }|                                }d|dddf<   t           j        	                    |          st          d          t          j
        d	t           j        
          }g d}g d}t          t	          |dddf                   t
          k              rKt          j        |dddf         t           j                            |j                            }d|dddf<   n t          j        dt           j        
          }|dddf                                         }d|dddf<   |ddddf                                         }t          |d                   |d<   |dxx         |d         z  cc<   t          j        |d         |d                   |d<   |dxx         |d         |d         z  z  cc<   t          |d                   |d<   |dxx         |d         z  cc<   |dxx         |d         z  cc<   t          j        |d         |d                   |d<   |dxx         |d         |d         z  z  cc<   t          j        |d         |d                   |d<   |dxx         |d         |d         z  z  cc<   t          |d                   |d<   |dxx         |d         z  cc<   |ddxx         |d         z  cc<   t          j        |d         t          j        |d         |d                             dk     r
|dz  }|dz  }t!          j        |d                    |d<   t!          j        |d                   rIt!          j        |d         |d                   |d<   t!          j        |d         |d                   |d<   n*t!          j        |d          |d                   |d<   d|d<   |||||fS )a  Return sequence of transformations from transformation matrix.

    matrix : array_like
        Non-degenerative homogeneous transformation matrix

    Return tuple of:
        scale : vector of 3 scaling factors
        shear : list of shear factors for x-y, x-z, y-z axes
        angles : list of Euler angles about static x, y, z axes
        translate : translation vector along x, y, z axes
        perspective : perspective partition of matrix

    Raise ValueError if matrix is of wrong type or degenerative.

    >>> from MDAnalysis.lib.transformations import (translation_matrix,
    ...     decompose_matrix, scale_matrix, euler_matrix)
    >>> import numpy as np
    >>> T0 = translation_matrix((1, 2, 3))
    >>> scale, shear, angles, trans, persp = decompose_matrix(T0)
    >>> T1 = translation_matrix(trans)
    >>> np.allclose(T0, T1)
    True
    >>> S = scale_matrix(0.123)
    >>> scale, shear, angles, trans, persp = decompose_matrix(S)
    >>> scale[0]
    0.123
    >>> R0 = euler_matrix(1, 2, 3)
    >>> scale, shear, angles, trans, persp = decompose_matrix(R0)
    >>> R1 = euler_matrix(*angles)
    >>> np.allclose(R0, R1)
    True

    Tr'   r]   zM[3, 3] is zeror   r   r   r   Nr   zmatrix is singular)r   r	   )r   r   r   r   r   r:   r+   rD   rt   r\   rs   rZ   rE   r[   r9   )r   r   r   rF   r/   rf   r2   r   r,   detzerosanyr"   invrU   rv   r;   asinr=   rH   )	r   r   Pr`   shearanglesr^   	translaterows	            r   decompose_matrixr     s   F 	rz5557A
1T7||d*+++4LA	AAaaadG9== /-...HT,,,EIIEYYF
3q!Qx==4   ?fQqqq!tWbimmAC&8&899!!!Q$h|2:>>>!RaR%IAa!eH
BQBF)..

C3q6""E!HFFFeAhFFFvc!fc!f%%E!HFFFc!fuQxFFF3q6""E!HFFFeAhFFF	!HHHaHHHvc!fc!f%%E!HFFFc!fuQxFFFvc!fc!f%%E!HFFFc!fuQxFFF3q6""E!HFFFeAhFFF	!""IIIqIII	vc!fbhs1vs1v..//!33r		3t9*%%F1Ixq	 Js4y#d)44q	Js4y#d)44q		 JD	z3t955q	q	%K77r   c                    t          j        d          }|:t          j        d          }|dd         |dddf<   t          j        ||          }|:t          j        d          }|dd         |dddf<   t          j        ||          }|9t          |d         |d         |d         d          }t          j        ||          }|Jt          j        d          }	|d         |	d<   |d         |	d	<   |d         |	d
<   t          j        ||	          }| Jt          j        d          }
| d         |
d<   | d         |
d<   | d         |
d<   t          j        ||
          }||d         z  }|S )a  Return transformation matrix from sequence of transformations.

    This is the inverse of the decompose_matrix function.

    Sequence of transformations:
        scale : vector of 3 scaling factors
        shear : list of shear factors for x-y, x-z, y-z axes
        angles : list of Euler angles about static x, y, z axes
        translate : translation vector along x, y, z axes
        perspective : perspective partition of matrix

    >>> from MDAnalysis.lib.transformations import (compose_matrix,
    ...     decompose_matrix, is_same_transform)
    >>> import math
    >>> import numpy as np
    >>> scale = np.random.random(3) - 0.5
    >>> shear = np.random.random(3) - 0.5
    >>> angles = (np.random.random(3) - 0.5) * (2*math.pi)
    >>> trans = np.random.random(3) - 0.5
    >>> persp = np.random.random(4) - 0.5
    >>> M0 = compose_matrix(scale, shear, angles, trans, persp)
    >>> result = decompose_matrix(M0)
    >>> M1 = compose_matrix(*result)
    >>> is_same_transform(M0, M1)
    True

    r   Nr   r   r   r:   sxyzrt   rD   rs   rZ   r[   r\   r]   )r   r   r"   euler_matrix)r`   r   r   r   r^   r   r   rF   r@   ZSs              r   compose_matrixr   ]  s_   < 	AAKNNbqb/!QQQ$F1aLLKNNRaR="1"a%F1aLLF1Ivay&AAF1aLLKNN($($($F1aLLKNN($($($F1aLL4LAHr   c                 n   | \  }}}t          j        |          }t          j        |          \  }}}t          j        |          \  }}	}
||	z  |
z
  ||z  z  }t          j        ||z  t          j        d||z  z
            z  dddf| |z  |z  ||z  ddf||	z  ||z  |dfdft           j                  S )a  Return orthogonalization matrix for crystallographic cell coordinates.

    Angles are expected in degrees.

    The de-orthogonalization matrix is the inverse.

    >>> from MDAnalysis.lib.transformations import orthogonalization_matrix
    >>> import numpy as np
    >>> O = orthogonalization_matrix((10., 10., 10.), (90., 90., 90.))
    >>> np.allclose(O[:3, :3], np.identity(3, float) * 10)
    True
    >>> O = orthogonalization_matrix([9.8, 12.0, 15.5], [87.2, 80.7, 69.7])
    >>> np.allclose(np.sum(O), 43.063229)
    True

    r(   r9   rN   r	   )r   radiansr<   r=   r   r;   sqrtr   )lengthsr   abcr>   sinb_r?   cosbcosgcos               r   orthogonalization_matrixr     s    " GAq!ZFF6NNMD$vf~~D$
+
	-B8X	#R-000#sC@R$Y^QXsC0Xq4xC( 		
 j   r   Tc                    t          j        | t           j        t                    dd         } t          j        |t           j        t                    dd         }| j        |j        k    s| j        d         dk     rt          d          t          j        | d          }t          j        |d          }| |                    dd          z
  } ||                    dd          z
  }|rt           j        	                    t          j
        || j                            \  }}}t          j
        ||          }	t           j                            |	          dk     r?|	t          j        |dddf         |dddf         d	z            z  }	|d
xx         dz  cc<   t          j        d          }
|	|
ddddf<   nt          j        d| |          \  }}}t          j        d| t          j        |d
d                    \  }}}t          j        d| t          j        |dd                    \  }}}||z   |z   dddf||z
  ||z
  |z
  ddf||z
  ||z   | |z   |z
  df||z
  ||z   ||z   | |z
  |z   ff}t           j                            |          \  }}|ddt          j        |          f         }|t'          |          z  }t)          |          }
|rS|
ddddfxx         t+          j        t          j        d||          t          j        d| |           z            z  cc<   ||
dddf<   t          j        d          }| |dddf<   t          j
        |
|          }
|
S )a  Return matrix to transform given vector set into second vector set.

    `v0` and `v1` are shape `(3, *)` or `(4, *)` arrays of at least 3 vectors.

    If `usesvd` is ``True``, the weighted sum of squared deviations (RMSD) is
    minimized according to the algorithm by W. Kabsch [8]. Otherwise the
    quaternion based algorithm by B. Horn [9] is used (slower when using
    this Python implementation).

    The returned matrix performs rotation, translation and uniform scaling
    (if specified).

    >>> from MDAnalysis.lib.transformations import (superimposition_matrix,
    ... random_rotation_matrix, scale_matrix, translation_matrix,
    ... concatenate_matrices)
    >>> import random
    >>> import numpy as np
    >>> v0 = np.random.rand(3, 10)
    >>> M = superimposition_matrix(v0, v0)
    >>> np.allclose(M, np.identity(4))
    True
    >>> R = random_rotation_matrix(np.random.random(3))
    >>> v0 = ((1,0,0), (0,1,0), (0,0,1), (1,1,1))
    >>> v1 = np.dot(R, v0)
    >>> M = superimposition_matrix(v0, v1)
    >>> np.allclose(v1, np.dot(M, v0))
    True
    >>> v0 = (np.random.rand(4, 100) - 0.5) * 20.0
    >>> v0[3] = 1.0
    >>> v1 = np.dot(R, v0)
    >>> M = superimposition_matrix(v0, v1)
    >>> np.allclose(v1, np.dot(M, v0))
    True
    >>> S = scale_matrix(random.random())
    >>> T = translation_matrix(np.random.random(3)-0.5)
    >>> M = concatenate_matrices(T, R, S)
    >>> v1 = np.dot(M, v0)
    >>> v0[:3] += np.random.normal(0.0, 1e-9, 300).reshape(3, -1)
    >>> M = superimposition_matrix(v0, v1, scaling=True)
    >>> np.allclose(v1, np.dot(M, v0))
    True
    >>> M = superimposition_matrix(v0, v1, scaling=True, usesvd=False)
    >>> np.allclose(v1, np.dot(M, v0))
    True
    >>> v = np.empty((4, 100, 3), dtype=np.float64)
    >>> v[:, :, 0] = v0
    >>> M = superimposition_matrix(v0, v1, scaling=True, usesvd=False)
    >>> np.allclose(v1, np.dot(M, v[:, :, 0]))
    True

    r'   Nr   r   z&vector sets are of wrong shape or typeaxisr9   r:   r   r+   re   r   zij,ij->ir   zij,ij->)r   r   r   r   shaper2   meanreshaper,   svdr"   rF   r   r!   r   einsumrolleighargmaxrU   quaternion_matrixr;   r   )v0v1scalingusesvdt0t1usvhr@   r   xxyyzzxyyzzxxzyxzyNr4   r5   qrF   s                            r   superimposition_matrixr     sf   h 
"BJ\	:	:	:2A2	>B	"BJ\	:	:	:2A2	>B	x28rx{QABBB 
!			B	!			B	bjjA	B	bjjA	B !9==BD!1!1221bF1bMM9==c!!!AAAqD'2ad8c>222AbEEETMEEEKNN"1"bqb&		 Yz2r22
BYz2rwr2A/F/F/FGG
BYz2rwr2A/F/F/FGG
B"Wr\3S)"Wb2glC-"Wb2gsRx"}c2"Wb2grBwb26	
 y~~a  1aaa1o	[^^a    
	"1"bqb&			TYIiR((29YB+G+GG
 
 	
			
 Abqb!eH
AAsAbqb!eH
q!AHr   r   c                    	 t           |         \  }}}}n+# t          t          f$ r t          |         }|\  }}}}Y nw xY w|}	t          |	|z            }
t          |	|z
  dz            }|r|| }} |r	|  | | }}} t          j        |           t          j        |          t          j        |          }}}t          j        |           t          j        |          t          j        |          }}}||z  ||z  }}||z  ||z  }}t          j	        d          }|rg|||	|	f<   ||z  ||	|
f<   ||z  ||	|f<   ||z  ||
|	f<   | |z  |z   ||
|
f<   | |z  |z
  ||
|f<   | |z  |||	f<   ||z  |z   |||
f<   ||z  |z
  |||f<   nd||z  ||	|	f<   ||z  |z
  ||	|
f<   ||z  |z   ||	|f<   ||z  ||
|	f<   ||z  |z   ||
|
f<   ||z  |z
  ||
|f<   | |||	f<   ||z  |||
f<   ||z  |||f<   |S )a  Return homogeneous rotation matrix from Euler angles and axis sequence.

    ai, aj, ak : Euler's roll, pitch and yaw angles
    axes : One of 24 axis sequences as string or encoded tuple

    >>> from MDAnalysis.lib.transformations import (euler_matrix,
    ... _AXES2TUPLE, _TUPLE2AXES)
    >>> import math
    >>> import numpy as np
    >>> R = euler_matrix(1, 2, 3, 'syxz')
    >>> np.allclose(np.sum(R[0]), -1.34786452)
    True
    >>> R = euler_matrix(1, 2, 3, (0, 1, 0, 1))
    >>> np.allclose(np.sum(R[0]), -0.383436184)
    True
    >>> ai, aj, ak = (4.0*math.pi) * (np.random.random(3) - 0.5)
    >>> for axes in _AXES2TUPLE.keys():
    ...    R = euler_matrix(ai, aj, ak, axes)
    >>> for axes in _TUPLE2AXES.keys():
    ...    R = euler_matrix(ai, aj, ak, axes)

    r   r   )
_AXES2TUPLEAttributeErrorKeyError_TUPLE2AXES
_NEXT_AXISr;   r<   r=   r   r   )aiajakaxes	firstaxisparity
repetitionframer   r6   jksisjskcicjckcccsscssr   s                          r   r   r   $  s   .4/:4/@,	6:uuH% 4 4 4/3,	6:uuu4 	A1v:A1v:>"A RB #S2#sB"tx||TXb\\BB"tx||TXb\\BB"Wb2gB"Wb2gB
AA !Q$r'!Q$r'!Q$r'!Q$#(R-!Q$#(R-!Q$#(!Q$r'B,!Q$r'B,!Q$r'!Q$r'B,!Q$r'B,!Q$r'!Q$r'B,!Q$r'B,!Q$#!Q$r'!Q$r'!Q$Hs    %==c                 V   	 t           |                                         \  }}}}n+# t          t          f$ r t          |         }|\  }}}}Y nw xY w|}t
          ||z            }t
          ||z
  dz            }	t          j        | t          j        d          ddddf         }
|rt          j
        |
||f         |
||f         z  |
||	f         |
||	f         z  z             }|t          k    rjt          j        |
||f         |
||	f                   }t          j        ||
||f                   }t          j        |
||f         |
|	|f                    }n=t          j        |
||	f          |
||f                   }t          j        ||
||f                   }d}nt          j
        |
||f         |
||f         z  |
||f         |
||f         z  z             }|t          k    rit          j        |
|	|f         |
|	|	f                   }t          j        |
|	|f          |          }t          j        |
||f         |
||f                   }nFt          j        |
||	f          |
||f                   }t          j        |
|	|f          |          }d}|r	| | | }}}|r||}}|||fS )a1  Return Euler angles from rotation matrix for specified axis sequence.

    axes : One of 24 axis sequences as string or encoded tuple

    Note that many Euler angle triplets can describe one matrix.

    >>> from MDAnalysis.lib.transformations import (euler_matrix,
    ... euler_from_matrix, _AXES2TUPLE)
    >>> import math
    >>> import numpy as np
    >>> R0 = euler_matrix(1, 2, 3, 'syxz')
    >>> al, be, ga = euler_from_matrix(R0, 'syxz')
    >>> R1 = euler_matrix(al, be, ga, 'syxz')
    >>> np.allclose(R0, R1)
    True
    >>> angles = (4.0*math.pi) * (np.random.random(3) - 0.5)
    >>> for axes in _AXES2TUPLE.keys():
    ...    R0 = euler_matrix(axes=axes, *angles)
    ...    R1 = euler_matrix(axes=axes, *euler_from_matrix(R0, axes))
    ...    if not np.allclose(R0, R1): print(axes, "failed")

    r   Fr'   Nr   r9   )r   lowerr   r   r   r   r   r   r   r;   r   rf   rH   )r   r   r   r   r   r   r   r6   r   r   r   syaxayazcys                   r   euler_from_matrixr   g  s   .4/:4::<</H,	6:uuH% 4 4 4/3,	6:uuu4 	A1v:A1v:>"A
rz666rr2A2v>A YqAw1a4(1QT7Qq!tW+<<==99AadGQq!tW--BB!Q$((BAadGa1gX..BBQq!tWHa1g..BB!Q$((BBBYqAw1a4(1QT7Qq!tW+<<==99AadGQq!tW--BQq!tWHb))BAadGQq!tW--BBQq!tWHa1g..BQq!tWHb))BB #S2#sB RBr2:   $' %AAc                 <    t          t          |           |          S )a&  Return Euler angles from quaternion for specified axis sequence.

    >>> from MDAnalysis.lib.transformations import euler_from_quaternion
    >>> import numpy as np
    >>> angles = euler_from_quaternion([0.99810947, 0.06146124, 0, 0])
    >>> np.allclose(angles, [0.123, 0, 0])
    True

    )r   r   )
quaternionr   s     r   euler_from_quaternionr     s     .z::DAAAr   c                    	 t           |                                         \  }}}}n+# t          t          f$ r t          |         }|\  }}}}Y nw xY w|dz   }	t
          |	|z   dz
           dz   }
t
          |	|z
           dz   }|r|| }} |r| }| dz  } |dz  }|dz  }t          j        |           }t          j        |           }t          j        |          }t          j        |          }t          j        |          }t          j        |          }||z  }||z  }||z  }||z  }t          j
        dt          j                  }|r-|||z
  z  |d<   |||z   z  ||	<   |||z   z  ||
<   |||z
  z  ||<   n8||z  ||z  z   |d<   ||z  ||z  z
  ||	<   ||z  ||z  z   ||
<   ||z  ||z  z
  ||<   |r||
xx         dz  cc<   |S )ax  Return quaternion from Euler angles and axis sequence.

    ai, aj, ak : Euler's roll, pitch and yaw angles
    axes : One of 24 axis sequences as string or encoded tuple

    >>> from MDAnalysis.lib.transformations import quaternion_from_euler
    >>> q = quaternion_from_euler(1, 2, 3, 'ryxz')
    >>> np.allclose(q, [0.435953, 0.310622, -0.718287, 0.444435])
    True

    r   r   r   r	   r   r+   )r   r   r   r   r   r   r;   r=   r<   r   emptyr   )r   r   r   r   r   r   r   r   r   r6   r   r   r   r   r   r   r   r   r   r   r   r   r   s                          r   quaternion_from_eulerr     s"   4/:4::<</H,	6:uuH% 4 4 4/3,	6:uuu4 	AA1v:>"Q&A1v:"A RB S#IB#IB#IB	"B	"B	"B	"B	"B	"B	bB	bB	bB	bB$bj111J 	*b2g
1b2g
1b2g
1b2g
1R"r')
1R"r')
1R"r')
1R"r')
1 1r   c                 *   t          j        dt           j                  }|d         |d<   |d         |d<   |d         |d<   t          |          }|t          k    r|t          j        | dz            |z  z  }t          j        | dz            |d<   |S )a	  Return quaternion for rotation about axis.

    >>> from MDAnalysis.lib.transformations import quaternion_about_axis
    >>> import numpy as np
    >>> q = quaternion_about_axis(0.123, (1, 0, 0))
    >>> np.allclose(q, [0.99810947, 0.06146124, 0, 0])
    True

    r   r	   r   r   r:   r   r   )r   r   r   rU   rf   r;   r<   r=   )r   r   r   qlens       r   quaternion_about_axisr     s     $bj111JGJqMGJqMGJqMz""Dd{{dhus{++d22
HUS[))JqMr   c           	         t          j        | dd         t           j        d          }t          j        ||          }|t          k     rt          j        d          S |t          j        d|z            z  }t          j        ||          }t          j        d|d         z
  |d         z
  |d	         |d
         z
  |d         |d         z   df|d	         |d
         z   d|d         z
  |d         z
  |d         |d         z
  df|d         |d         z
  |d         |d         z   d|d         z
  |d         z
  dfdft           j                  S )a  Return homogeneous rotation matrix from quaternion.

    >>> from MDAnalysis.lib.transformations import (identity_matrix,
    ...     quaternion_matrix, rotation_matrix)
    >>> import numpy as np
    >>> M = quaternion_matrix([0.99810947, 0.06146124, 0, 0])
    >>> np.allclose(M, rotation_matrix(0.123, (1, 0, 0)))
    True
    >>> M = quaternion_matrix([1, 0, 0, 0])
    >>> np.allclose(M, identity_matrix())
    True
    >>> M = quaternion_matrix([0, 1, 0, 0])
    >>> np.allclose(M, np.diag([1, -1, -1, 1]))
    True

    Nr   Tr'   r   r(   r\   r]   rt   )r   r   )r   r   r:   r   r9   r[   )r:   r   rC   rN   r	   )	r   r   r   r"   rf   r   r;   r   r!   )r   r   nqs      r   r   r     sU   " 	BQBrz===A	1B	Dyy{1~~38		A
AA8 ag$'$!D'!$!D'!	 $!D'!ag$'$!D'!	 $!D'!$!D'!ag$'	 !'	
* j-   r   c           
         t          j        | t           j        t                    ddddf         }|rTt          j        dt           j                  }t          j        |          }||d         k    rB||d<   |d         |d	         z
  |d
<   |d         |d         z
  |d<   |d         |d         z
  |d<   nd\  }}}|d         |d         k    rd\  }}}|d         |||f         k    rd\  }}}|||f         |||f         |||f         z   z
  |d         z   }|||<   |||f         |||f         z   ||<   |||f         |||f         z   ||<   |||f         |||f         z
  |d
<   |dt          j        ||d         z            z  z  }n|d         }|d	         }	|d         }
|d         }|d         }|d         }|d         }|d         }|d         }t          j        ||z
  |z
  dddf|	|z   ||z
  |z
  ddf|
|z   ||z   ||z
  |z
  df||z
  |
|z
  ||	z
  ||z   |z   ff          }|dz  }t           j        	                    |          \  }}|g dt          j
        |          f         }|d         dk     r|dz  }|S )a  Return quaternion from rotation matrix.

    If isprecise=True, the input matrix is assumed to be a precise rotation
    matrix and a faster algorithm is used.

    >>> from MDAnalysis.lib.transformations import (identity_matrix,
    ...     quaternion_from_matrix, rotation_matrix, random_rotation_matrix,
    ...     is_same_transform, quaternion_matrix)
    >>> import numpy as np
    >>> q = quaternion_from_matrix(identity_matrix(), True)
    >>> np.allclose(q, [1., 0., 0., 0.])
    True
    >>> q = quaternion_from_matrix(np.diag([1., -1., -1., 1.]))
    >>> np.allclose(q, [0, 1, 0, 0]) or np.allclose(q, [0, -1, 0, 0])
    True
    >>> R = rotation_matrix(0.123, (1, 2, 3))
    >>> q = quaternion_from_matrix(R, True)
    >>> np.allclose(q, [0.9981095, 0.0164262, 0.0328524, 0.0492786])
    True
    >>> R = [[-0.545, 0.797, 0.260, 0], [0.733, 0.603, -0.313, 0],
    ...      [-0.407, 0.021, -0.913, 0], [0, 0, 0, 1]]
    >>> q = quaternion_from_matrix(R)
    >>> np.allclose(q, [0.19069, 0.43736, 0.87485, -0.083611])
    True
    >>> R = [[0.395, 0.362, 0.843, 0], [-0.626, 0.796, -0.056, 0],
    ...      [-0.677, -0.498, 0.529, 0], [0, 0, 0, 1]]
    >>> q = quaternion_from_matrix(R)
    >>> np.allclose(q, [0.82336615, -0.13610694, 0.46344705, -0.29792603])
    True
    >>> R = random_rotation_matrix()
    >>> q = quaternion_from_matrix(R)
    >>> is_same_transform(R, quaternion_matrix(q))
    True

    r'   Nr   r   r	   r]   r   rC   rs   r   rD   r   r:   rE   rt   r   )r   r:   r   r[   rZ   )r:   r   r   r\   )r   r   r:   g      ?r9   rS   )r   r   r   r:   re   )r   r   r   r   r   rG   r;   r   r,   r   r   )r   	ispreciser   r   rm   r6   r   r   m00m01m02m10m11m12m20m21m22Kr4   r5   s                       r   quaternion_from_matrixr   2  s   H 	rz===bqb"1"fEA **HT,,,HQKKqw;;AaDT7QtW$AaDT7QtW$AaDT7QtW$AaDDGAq!w4  !1aw1a4  !1a!Q$1QT7Qq!tW,-$7AAaDQT7Qq!tW$AaDQT7Qq!tW$AaDQT7Qq!tW$AaD	S49Q4[))))gggggggggHsS#sC0sC#IOS#6sC#IsSy3<sC#IsSy#)c/B	
 
 	
Sy~~a  1lllBIaLL()tczz	T	Hr   c                    |\  }}}}| \  }}}}	t          j        | |z  ||z  z
  |	|z  z
  ||z  z   ||z  ||z  z   |	|z  z
  ||z  z   | |z  ||z  z   |	|z  z   ||z  z   ||z  ||z  z
  |	|z  z   ||z  z   ft           j                  S )a  Return multiplication of two quaternions.

    >>> from MDAnalysis.lib.transformations import quaternion_multiply
    >>> import numpy as np
    >>> q = quaternion_multiply([4, 1, -2, 3], [8, -5, 6, 7])
    >>> np.allclose(q, [28, -44, -14, 48])
    True

    r	   r   r   r   )
quaternion1quaternion0w0x0y0z0w1x1y1z1s
             r   quaternion_multiplyr    s     !NBB NBB8C"HrBwb(272Gb2gR'"r'1C"HrBwb(272Gb2gR'"r'1		
 j   r   c                     t          j        | d         | d          | d          | d          ft           j                  S )a,  Return conjugate of quaternion.

    >>> from MDAnalysis.lib.transformations import (random_quaternion,
    ...     quaternion_conjugate)
    >>> import numpy as np
    >>> q0 = random_quaternion()
    >>> q1 = quaternion_conjugate(q0)
    >>> q1[0] == q0[0] and all(q1[1:] == -q0[1:])
    True

    r   r   r:   r   r	   r   r   s    r   quaternion_conjugater    sD     8	AAAAGj   r   c                 L    t          |           t          j        | |           z  S )a3  Return inverse of quaternion.

    >>> from MDAnalysis.lib.transformations import (random_quaternion,
    ...     quaternion_inverse)
    >>> import numpy as np
    >>> q0 = random_quaternion()
    >>> q1 = quaternion_inverse(q0)
    >>> np.allclose(quaternion_multiply(q0, q1), [1, 0, 0, 0])
    True

    )r  r   r"   r
  s    r   quaternion_inverser    s#      
++bfZ.L.LLLr   c                     | d         S )zReturn real part of quaternion.

    >>> from MDAnalysis.lib.transformations import quaternion_real
    >>> quaternion_real([3.0, 0.0, 1.0, 2.0])
    3.0

    r   r   r
  s    r   quaternion_realr    s     a=r   c                     | dd         S )zReturn imaginary part of quaternion.

    >>> from MDAnalysis.lib.transformations import quaternion_imag
    >>> quaternion_imag([3.0, 0.0, 1.0, 2.0])
    [0.0, 1.0, 2.0]

    r   r   r   r
  s    r   quaternion_imagr    s     ac?r   c                 N   t          | dd                   }t          |dd                   }|dk    r|S |dk    r|S t          j        ||          }t          t          |          dz
            t          k     r|S |r|dk     r| }|dz  }t          j        |          |t
          j        z  z   }t          |          t          k     r|S dt          j        |          z  }	|t          j        d|z
  |z            |	z  z  }|t          j        ||z            |	z  z  }||z  }|S )a  Return spherical linear interpolation between two quaternions.

    >>> from MDAnalysis.lib.transformations import (random_quaternion,
    ...     quaternion_slerp)
    >>> import math
    >>> import numpy as np
    >>> q0 = random_quaternion()
    >>> q1 = random_quaternion()
    >>> q = quaternion_slerp(q0, q1, 0.0)
    >>> np.allclose(q, q0)
    True
    >>> q = quaternion_slerp(q0, q1, 1.0, 1)
    >>> np.allclose(q, q1)
    True
    >>> q = quaternion_slerp(q0, q1, 0.5)
    >>> angle = math.acos(np.dot(q0, q))
    >>> np.allclose(2.0, math.acos(np.dot(q0, q1)) / angle) or \
    ... np.allclose(2.0, math.acos(-np.dot(q0, q1)) / angle)
    True

    Nr   r9   r(   re   )	r    r   r"   r/   rf   r;   acospir<   )
quat0quat1fractionspinshortestpathq0q1dr   isins
             r   quaternion_slerpr    s)   , 
U2A2Y		B	U2A2Y		B3		S	
r2A
3q66C<4	 CB
d
IaLL4$'>)E
5zzD	% D$(C(Ne+
,
,t
33B$(8e#
$
$t
++B"HBIr   c                    |  t           j                            d          } nt          |           dk    sJ t          j        d| d         z
            }t          j        | d                   }t
          j        dz  }|| d         z  }|| d         z  }t          j        t          j        |          |z  t          j	        |          |z  t          j        |          |z  t          j	        |          |z  ft           j
                  S )	a  Return uniform random unit quaternion.

    rand: array like or None
        Three independent random variables that are uniformly distributed
        between 0 and 1.

    >>> from MDAnalysis.lib.transformations import (random_quaternion,
    ...     vector_norm)
    >>> import numpy as np
    >>> q = random_quaternion()
    >>> np.allclose(1.0, vector_norm(q))
    True
    >>> q = random_quaternion(np.random.random(3))
    >>> len(q.shape), q.shape[0]==4
    (1, True)

    Nr   r(   r   r   r   r:   r	   )r   randomrandr1   r   r;   r  r   r=   r<   r   )r!  r1r2pi2r   t2s         r   random_quaternionr&    s    $ |y~~a  4yyA~~~~	tAw		B	a		B
'C-C	tAwB	tAwB8F2JJOF2JJOF2JJOF2JJO		
 j   r   c                 :    t          t          |                     S )a  Return uniform random rotation matrix.

    rnd: array like
        Three independent random variables that are uniformly distributed
        between 0 and 1 for each returned quaternion.

    >>> from MDAnalysis.lib.transformations import random_rotation_matrix
    >>> import numpy as np
    >>> R = random_rotation_matrix()
    >>> np.allclose(np.dot(R.T, R), np.identity(4))
    True

    )r   r&  )r!  s    r   random_rotation_matrixr(  )  s     .t44555r   c                   L    e Zd ZdZddZd Zd Zd Zd Zd Z	d	 Z
ddZd ZdS )Arcballa  Virtual Trackball Control.

    >>> from MDAnalysis.lib.transformations import Arcball
    >>> import numpy as np
    >>> ball = Arcball()
    >>> ball = Arcball(initial=np.identity(4))
    >>> ball.place([320, 320], 320)
    >>> ball.down([500, 250])
    >>> ball.drag([475, 275])
    >>> R = ball.matrix()
    >>> np.allclose(np.sum(R), 3.90583455)
    True
    >>> ball = Arcball(initial=[1, 0, 0, 0])
    >>> ball.place([320, 320], 320)
    >>> ball.setaxes([1,1,0], [-1, 1, 0])
    >>> ball.setconstrain(True)
    >>> ball.down([400, 200])
    >>> ball.drag([200, 400])
    >>> R = ball.matrix()
    >>> np.allclose(np.sum(R), 0.2055924)
    True
    >>> ball.next()

    Nc                     d| _         d| _        d| _        ddg| _        t	          j        g dt          j                  | _        d| _        |(t	          j        g dt          j                  | _	        ntt	          j        |t          j                  }|j
        dk    rt          |          | _	        n4|j
        d	k    r|t          |          z  }|| _	        nt          d
          | j	        x| _        | _        dS )z`Initialize virtual trackball control.

        initial : quaternion or rotation matrix

        Nr(   r9   )r   r   r   r	   Fr   r   r   r   )r   r   r   z"initial not a quaternion or matrix)_axis_axes_radius_centerr   r   r   _vdown
_constrain_qdownr   r   rU   r2   _qnow_qpre)selfinitials     r   __init__zArcball.__init__T  s     

Szhyyy
;;;?(<<<rzBBBDKKhwbj999G}&&4W==$&&;w///% !EFFF"&+-
TZZZr   c                 n    t          |          | _        |d         | j        d<   |d         | j        d<   dS )zPlace Arcball, e.g. when window size changes.

        center : sequence[2]
            Window coordinates of trackball center.
        radius : float
            Radius of trackball in window coordinates.

        r   r   N)floatr/  r0  )r6  centerradiuss      r   placezArcball.placeo  s3     V}} )Q )Qr   c                 >    |	d| _         dS d |D             | _         dS )z Set axes to constrain rotations.Nc                 ,    g | ]}t          |          S r   )r    ).0r   s     r   
<listcomp>z#Arcball.setaxes.<locals>.<listcomp>  s     ===+d++===r   )r.  )r6  r   s     r   setaxeszArcball.setaxes|  s+    <DJJJ=====DJJJr   c                     |du | _         dS )z$Set state of constrain to axis mode.TNr2  )r6  	constrains     r   setconstrainzArcball.setconstrain  s    #t+r   c                     | j         S )z'Return state of constrain to axis mode.rD  r6  s    r   getconstrainzArcball.getconstrain  s
    r   c                    t          || j        | j                  | _        | j        x| _        | _        | j        rG| j        @t          | j        | j                  | _
        t          | j        | j
                  | _        dS d| _
        dS )z>Set initial cursor window coordinates and pick constrain-axis.N)arcball_map_to_spherer0  r/  r1  r4  r3  r5  r2  r.  arcball_nearest_axisr-  arcball_constrain_to_axis)r6  r#   s     r   downzArcball.down  ss    +E4<NN#':-dj? 	tz5-dk4:FFDJ3DKLLDKKKDJJJr   c                    t          || j        | j                  }| j        t	          || j                  }| j        | _        t          j        | j	        |          }t          j
        ||          t          k     r| j        | _        dS t          j
        | j	        |          |d         |d         |d         g}t          || j                  | _        dS )z)Update current cursor window coordinates.Nr   r   r:   )rK  r0  r/  r-  rM  r4  r5  r   rv   r1  r"   rf   r3  r  )r6  r#   vnowrm   r   s        r   dragzArcball.drag  s    $UDL$,GG:!,T4:>>DZ
HT[$''6!Q<<$DJJJT**AaD!A$!=A,Q<<DJJJr   r9   c                 l    t          | j        | j        d|z   d          }| j        |c| _        | _        dS )z,Continue rotation in direction of last drag.r   FN)r  r5  r4  )r6  accelerationr   s      r   nextzArcball.next  s4    TZS<5GOO!%Q
DJJJr   c                 *    t          | j                  S )z#Return homogeneous rotation matrix.)r   r4  rH  s    r   r   zArcball.matrix  s     ,,,r   N)r9   )__name__
__module____qualname____doc__r8  r=  rB  rF  rI  rN  rQ  rT  r   r   r   r   r*  r*  :  s         2. . . .6$ $ $> > >, , ,  	 	 	= = = / / / /
- - - - -r   r*  c                 J   t          j        | d         |d         z
  |z  |d         | d         z
  |z  dft           j                  }|d         |d         z  |d         |d         z  z   }|dk    r|t          j        |          z  }nt          j        d|z
            |d<   |S )z7Return unit sphere coordinates from window coordinates.r   r   r9   r	   r(   r:   )r   r   r   r;   r   )r#   r;  r<  vr{   s        r   rK  rK    s    
1Xq	!V+AYq!V+	

 j	 	 	A 	
!qtadQqTk!A3ww	TYq\\yq!!!Hr   c                    t          j        | t           j        d          }t          j        |t           j        d          }||t          j        ||          z  z  }t	          |          }|t
          k    r|d         dk     r|dz  }||z  }|S |d         dk    r"t          j        g dt           j                  S t          |d	          |d
         d
g          S )z*Return sphere point perpendicular to axis.Tr'   r:   r9   re   r(   r   r   r   r	   r   r   )r   r   r   r"   rU   rf   r    )r#   r   r\  r   r{   s        r   rM  rM    s    
bjt444A
RZd333ARVAq\\	AAA4xxQ4#::IA	Qts{{x			44441qtQ'(((r   c                     t          j        | t           j        d          } d}d}|D ]/}t          j        t	          | |          |           }||k    r|}|}0|S )z+Return axis, which arc is nearest to point.Fr'   Nre   )r   r   r   r"   rM  )r#   r   nearestmxr   rm   s         r   rL  rL    sh    HU"*5999EG	B  F,UD995AAr66GBNr   g      @)r   r:   r   r   )r   r   r   r   sxyx)r   r   r   r   sxzy)r   r   r   r   sxzx)r   r   r   r   syzxr,  syzy)r   r   r   r   syxz)r   r   r   r   syxy)r   r   r   r   szxy)r:   r   r   r   szxz)r:   r   r   r   szyx)r:   r   r   r   szyz)r:   r   r   r   rzyxr~   rxyx)r   r   r   r   ryzx)r   r   r   r   rxzx)r   r   r   r   rxzy)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   r   )r:   r   r   r   )ryzyrzxyryxyryxzrzxzrxyzrzyzc              #   $   K   | ]\  }}||fV  d S rV  r   )r@  r   r\  s      r   	<genexpr>rz    s*      ::daAq6::::::r   c                    t          j        | t           j        d          } |v| j        dk    r't	          j        t          j        | |                     S | | z  } t          j        t          j        | |                    }t          j        ||           |S | | z  } t          j        | ||           t          j        ||           dS )a  Return length, i.e. eucledian norm, of ndarray along axis.

    >>> from MDAnalysis.lib.transformations import vector_norm
    >>> import numpy as np
    >>> v = np.random.random(3)
    >>> n = vector_norm(v)
    >>> np.allclose(n, np.linalg.norm(v))
    True
    >>> v = np.random.rand(6, 5, 3)
    >>> n = vector_norm(v, axis=-1)
    >>> np.allclose(n, np.sqrt(np.sum(v*v, axis=2)))
    True
    >>> n = vector_norm(v, axis=1)
    >>> np.allclose(n, np.sqrt(np.sum(v*v, axis=1)))
    True
    >>> v = np.random.rand(5, 4, 3)
    >>> n = np.empty((5, 3), dtype=np.float64)
    >>> vector_norm(v, axis=1, out=n)
    >>> np.allclose(n, np.sqrt(np.sum(v*v, axis=1)))
    True
    >>> vector_norm([])
    0.0
    >>> vector_norm([1.0])
    1.0

    Tr'   Nr   r   )r   out)	r   r   r   ndimr;   r   r"   
atleast_1dsum)datar   r|  s      r   rU   rU     s    6 8D
666D
{9>>9RVD$//000mBF4d33344
S

t$C((((
Sr   c                    |Yt          j        | t           j        d          } | j        dk    r,| t	          j        t          j        | |                     z  } | S n!|| urt          j        | d          |dd<   |} t          j        t          j        | | z  |                    }t          j        ||           |t          j	        ||          }| |z  } || S dS )a0  Return ndarray normalized by length, i.e. eucledian norm, along axis.

    >>> from MDAnalysis.lib.transformations import unit_vector
    >>> import numpy as np
    >>> v0 = np.random.random(3)
    >>> v1 = unit_vector(v0)
    >>> np.allclose(v1, v0 / np.linalg.norm(v0))
    True
    >>> v0 = np.random.rand(5, 4, 3)
    >>> v1 = unit_vector(v0, axis=-1)
    >>> v2 = v0 / np.expand_dims(np.sqrt(np.sum(v0*v0, axis=2)), 2)
    >>> np.allclose(v1, v2)
    True
    >>> v1 = unit_vector(v0, axis=1)
    >>> v2 = v0 / np.expand_dims(np.sqrt(np.sum(v0*v0, axis=1)), 1)
    >>> np.allclose(v1, v2)
    True
    >>> v1 = np.empty((5, 4, 3), dtype=np.float64)
    >>> unit_vector(v0, axis=1, out=v1)
    >>> np.allclose(v1, v2)
    True
    >>> list(unit_vector([]))
    []
    >>> list(unit_vector([1.0]))
    [1.0]

    NTr'   r   Fr   )
r   r   r   r}  r;   r   r"   r~  r  expand_dims)r  r   r|  lengths       r   r    r      s    8 {xBJT:::9>>DIbfT400111DK  d??Xd///CF]26$+t4455FGFF--FND
{ {r   c                 @    t           j                            |           S )a_  Return array of random doubles in the half-open interval [0.0, 1.0).

    >>> from MDAnalysis.lib.transformations import random_vector
    >>> import numpy as np
    >>> v = random_vector(10000)
    >>> np.all(v >= 0.0) and np.all(v < 1.0)
    True
    >>> v0 = random_vector(10)
    >>> v1 = random_vector(10)
    >>> np.any(v0 == v1)
    False

    )r   r   )sizes    r   random_vectorr  M  s     9D!!!r   c                 @    t           j                            |           S )a  Return inverse of square transformation matrix.

    >>> from MDAnalysis.lib.transformations import (random_rotation_matrix,
    ...     inverse_matrix)
    >>> import numpy as np
    >>> M0 = random_rotation_matrix()
    >>> M1 = inverse_matrix(M0.T)
    >>> np.allclose(M1, np.linalg.inv(M0.T))
    True
    >>> for size in range(1, 7):
    ...     M0 = np.random.rand(size, size)
    ...     M1 = inverse_matrix(M0)
    ...     if not np.allclose(M1, np.linalg.inv(M0)): print(size)

    )r   r,   r   r   s    r   inverse_matrixr  ^  s      9==   r   c                  b    t          j        d          }| D ]}t          j        ||          }|S )a]  Return concatenation of series of transformation matrices.

    >>> from MDAnalysis.lib.transformations import concatenate_matrices
    >>> import numpy as np
    >>> M = np.random.rand(16).reshape((4, 4)) - 0.5
    >>> np.allclose(M, concatenate_matrices(M))
    True
    >>> np.allclose(np.dot(M, M.T), concatenate_matrices(M, M.T))
    True

    r   )r   r   r"   )matricesr   r6   s      r   concatenate_matricesr  q  s6     	AA  F1aLLHr   c                     t          j        | t           j        d          } | | d         z  } t          j        |t           j        d          }||d         z  }t          j        | |          S )aV  Return True if two matrices perform same transformation.

    >>> from MDAnalysis.lib.transformations import (is_same_transform,
    ...     random_rotation_matrix)
    >>> import numpy as np
    >>> is_same_transform(np.identity(4), np.identity(4))
    True
    >>> is_same_transform(np.identity(4), random_rotation_matrix())
    False

    Tr'   r]   )r   r   r   allclose)matrix0matrix1s     r   is_same_transformr    sb     hwbjt<<<Gwt}Ghwbjt<<<Gwt}G;w(((r   _py_r   c                    t           j                            t          j                            t
                               	 t          |           }t           j                                         t          |          D ]}|r|	                    |          r|rP|t                      v r't                      |         t                      ||z   <   n|rt          j        d|z              t          ||          t                      |<   dS # t          $ r> t           j                                         |rt          j        d| z              Y dS Y dS w xY w)zTry import all public attributes from module into global namespace.

    Existing attributes with name clashes are renamed with prefix.
    Attributes starting with underscore are ignored by default.

    Return True on successful import.

    zno Python implementation of Tzfailed to import module N)syspathappendosdirname__file__
__import__popdir
startswithglobalswarningswarngetattrImportError)module_namer  prefixignoremoduleattrs         r   _import_moduler    sX    HOOBGOOH--...K(( 	KK 	4 	4D $//&11  I799$$/6yyGIIftm,, IM"@4"GHHH%fd33GIIdOOt  D D D 	DM4{BCCCCCC	D 	D 	DDs   D AEEc                     t          j        | |          rt          j        g d          S t          j        | |          }|t           j                            |          z  S )a  Return the rotation axis to rotate vector a into b.

    Parameters
    ----------
    a, b : array_like
        two vectors

    Returns
    -------
    c : np.ndarray
        vector to rotate a into b


    Note
    ----
    If a == b this will always return [1, 0, 0]

    r^  )r   r  r   rv   r,   r   )r   r   r   s      r   rotaxisr    sT    & 
{1a #x			"""
AAry~~a    r   _transformationszrestructuredtext enrV  )NN)NNF)F)NNNNN)FT)r   )r   T)Tr  r   )FrZ  r;   r  r  r  numpyr   numpy.linalgr   MDAnalysis.lib.utilr   mdamathr   vecangler   r   r   r%   r7   rA   rL   rQ   rX   ra   rc   rn   rq   r|   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r  r  r&  r(  objectr*  rK  rM  rL  finfor:  epsrf   r   r   dictitemsr   rU   r    r  r  r  r  r  r  __docformat__r   r   r   <module>r     s7  DA AF  				 



            , , , , , , & & & & & &, , ,"  6 6 6  8  @9 9 9 9x/# /# /#d* * * *Z*% *% *%\ =B@ @ @ @FJ8 J8 J8 J8Z7) 7) 7) 7)t  D0+ 0+ 0+fV8 V8 V8t FJ7 7 7 7t  Bi i i iX@ @ @ @F; ; ; ;|
B 
B 
B 
B7 7 7 7t  *. . .bS S S Sl  .  $M M M    * * * *Z# # # #L6 6 6 6"s- s- s- s- s-f s- s- s-l  $) ) ) 
 
 
 rxS  \\
	
L	 ,	06	
L	 ,	06	 L	 !,	 17	 L		 !,		 17		
 L	
 !,	
 17	 L	 !,	 9E,,	 	 	 d::k&7&7&9&9:::::& & & &R+ + + +\" " ""! ! !&  $) ) )&   B! ! !2 ! " " " &r   