B
    d3                 @   s   d 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mZmZ ddlmZ ddlmZ dd	lmZ d
d ZG dd dejZG dd dejZdd ZdS )a  
While the ligolw module provides classes and parser support for reading and
writing LIGO Light Weight XML documents, this module supplements that code
with classes and parsers that add intelligence to the in-RAM document
representation.

In particular, the document tree associated with an Array element is
enhanced.  During parsing, the Stream element in this module converts the
character data contained within it into the elements of a numpy array
object.  The array has the appropriate dimensions and type.  When the
document is written out again, the Stream element serializes the array back
into character data.

The array is stored as an attribute of the Array element.
    N)escape)AttributesImpl   )
__author____date____version__)ligolw)	tokenizer)typesc             C   s   t | |S )z3
	Deprecated.  use Array.get_array(xmldoc, name).
	)Array	get_array)xmldocname r   Z/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/ligo/lw/array.pyr   C   s    r   c                   sV   e Zd ZdZejdddZ fddZdd Zd	d
 Z	dd Z
ejdfddZ  ZS )ArrayStreamz
	High-level Stream element for use inside Arrays.  This element
	knows how to parse the delimited character stream into the parent's
	array attribute, and knows how to turn the parent's array attribute
	back into a character stream.
		Delimiter )defaultc                sR   t t| j|  y
| j W n tk
r.   Y nX td| j t| j	| _
d S )NzMnon-default encoding '%s' not supported.  if this is critical, please report.)superr   __init__ZEncodingAttributeErrorr   ZElementErrorr	   	Tokenizerr   
_tokenizer)selfargs)	__class__r   r   r   ]   s    
zArrayStream.__init__c             C   sD   | j tj|j g t|jtj|j |_	|j	j
j| _d| _| S )Nr   )r   Z	set_typesligolwtypesZToPyTypeTypenumpyZzerosshapeZToNumPyTypearrayTflat_array_view_index)r   
parentNoder   r   r   configg   s
    zArrayStream.configc             C   s8   t | j|}| jt| }|| j| j|< || _d S )N)tupler   appendr%   lenr$   )r   contenttokensZ
next_indexr   r   r   
appendDatap   s    zArrayStream.appendDatac             C   s@   |  | j | jt| jkr4td| jt| jf | `| `d S )NzFlength of Stream (%d elements) does not match array size (%d elements))r-   r   r%   r*   r$   
ValueError)r   r   r   r   
endElementw   s
    zArrayStream.endElement c             C   s   |j }|| | | jj}|d k	r|jr| jjd }|j| }tttj	| jj
 |jj}tj}| jj}	d| tj }
||
 |t|	||| | j|
 }
x2t|d D ]"}||
 |t|	||| qW |d| | d  d S )Nr   
r   )writeZ	start_tagr&   r!   sizer    itermapr   Z
FormatFuncr   r"   r#   	itertoolsislicer   joinr   ZIndent	xmlescaperangeZend_tag)r   fileobjindentwr!   Zlinelenlinesr,   r7   r8   newlineir   r   r   r2      s"    

zArrayStream.write)__name__
__module____qualname____doc__r   attributeproxyr   r   r'   r-   r/   sysstdoutr2   __classcell__r   r   )r   r   r   S   s   
	
r   c                   s   e Zd ZdZG dd dejZejdejedZ	 fddZ
edd	 Zejd
d	 ZedddZedd ZedddZ fddZ  ZS )r   a\  
	High-level Array element.

	Examples:

	>>> import numpy
	>>> x = numpy.mgrid[0:5,0:3][0]
	>>> x
	array([[0, 0, 0],
	       [1, 1, 1],
	       [2, 2, 2],
	       [3, 3, 3],
	       [4, 4, 4]])
	>>> x.shape
	(5, 3)
	>>> elem = Array.build("test", x, ["dim0", "dim1"])
	>>> elem.shape
	(5, 3)
	>>> import sys
	>>> elem.write(sys.stdout)	# doctest: +NORMALIZE_WHITESPACE
	<Array Type="int_8s" Name="test:array">
		<Dim Name="dim1">3</Dim>
		<Dim Name="dim0">5</Dim>
		<Stream Type="Local" Delimiter=" ">
			0 1 2 3 4
			0 1 2 3 4
			0 1 2 3 4
		</Stream>
	</Array>
	>>> # change the Array shape.  the internal array is changed, too
	>>> elem.shape = 15
	>>> elem.write(sys.stdout)	# doctest: +NORMALIZE_WHITESPACE
	<Array Type="int_8s" Name="test:array">
		<Dim Name="dim0">15</Dim>
		<Stream Type="Local" Delimiter=" ">
			0 0 0 1 1 1 2 2 2 3 3 3 4 4 4
		</Stream>
	</Array>
	>>> # replace the internal array with one with a different number
	>>> # of dimensions.  assign to .array first, then fix .shape
	>>> elem.array = numpy.mgrid[0:4,0:3,0:2][0]
	>>> elem.shape = elem.array.shape
	>>> elem.write(sys.stdout)	# doctest: +NORMALIZE_WHITESPACE
	<Array Type="int_8s" Name="test:array">
		<Dim>2</Dim>
		<Dim>3</Dim>
		<Dim Name="dim0">4</Dim>
		<Stream Type="Local" Delimiter=" ">
			0 1 2 3
			0 1 2 3
			0 1 2 3
			0 1 2 3
			0 1 2 3
			0 1 2 3
		</Stream>
	</Array>
	c               @   s   e Zd ZedZdZdS )zArray.ArrayNamez (?P<Name>[a-zA-Z0-9_:]+):array\Zz%s:arrayN)rA   rB   rC   recompileZdec_patternZenc_patternr   r   r   r   	ArrayName   s   
rK   Name)encdecc                s   t t| j|  d| _dS )z%
		Initialize a new Array element.
		N)r   r   r   r!   )r   r   )r   r   r   r      s    zArray.__init__c             C   s\   t dd | tjjD ddd }| jdk	rX| jj|krXtdt|t| jjf |S )aO  
		The Array's dimensions.  If the shape described by the Dim
		child elements is not consistent with the shape of the
		internal array object then ValueError is raised.

		When assigning to this property, the internal array object
		is adjusted as well, and an error will be raised if the
		re-shape is not allowed (see numpy documentation for the
		rules).  If the number of dimensions is being changed, and
		the Array object requires additional Dim child elements to
		be added, they are created with higher ranks than the
		existing dimensions, with no Name attributes assigned;
		likewise if Dim elements need to be removed, the highest
		rank dimensions are removed first.  NOTE: Dim elements are
		stored in reverse order, so the highest rank dimension
		corresponds to the first Dim element in the XML tree.

		NOTE:  the shape of the internal numpy array and the shape
		described by the Dim child elements are only weakly related
		to one another.  There are some sanity checks watching out
		for inconsistencies, for example when retrieving the value
		of this property, or when writing the XML tree to a file,
		but in general there is no mechanism preventing
		sufficiently quirky code from getting the .array attribute
		out of sync with the Dim child elements.  Calling code
		should ensure it contains its own safety checks where
		needed.
		c             s   s   | ]}|j V  qd S )N)n).0cr   r   r   	<genexpr>  s    zArray.shape.<locals>.<genexpr>NzDshape of Dim children not consistent with shape of .array:  %s != %s)	r(   getElementsByTagNamer   DimtagNamer!   r    r.   str)r   r    r   r   r   r       s    &zArray.shapec             C   s.  | j d k	r|| j _| tjj}yt| W n tk
rF   |f}Y nX x(t|t|krp| |	d
  qJW xt|t|k r|r| t |d }nV| jrt| jdkr| jd jtjjkstd| t | jd }n| t }|d| qtW x"t|t|D ]\}}||_qW d S )Nr   r   rS   zinvalid children)r!   r    rT   r   rU   rV   r*   	TypeErrorZremoveChildpopunlinkZinsertBeforeZ
childNodesStreamAssertionErrorappendChildinsertzipreversedrO   )r   r    ZdimsdimrO   r   r   r   r      s&    
*Nc             C   s   | t dtjt|j i}||_|j|_|dk	rxt|t|jkrLtdx*t	|
tjjt|D ]\}}||_qfW |tt tjjtjjd ||_|S )a  
		Construct a LIGO Light Weight XML Array document subtree
		from a numpy array object.

		Example:

		>>> import numpy, sys
		>>> a = numpy.arange(12, dtype = "double")
		>>> a.shape = (4, 3)
		>>> Array.build(u"test", a).write(sys.stdout)	# doctest: +NORMALIZE_WHITESPACE
		<Array Type="real_8" Name="test:array">
			<Dim>3</Dim>
			<Dim>4</Dim>
			<Stream Type="Local" Delimiter=" ">
				0 3 6 9
				1 4 7 10
				2 5 8 11
			</Stream>
		</Array>
		r   Nz5dim_names must be same length as number of dimensions)r   r   )
Attributesr   ZFromNumPyTyperW   ZdtyperL   r    r*   r.   r_   rT   r   rU   rV   r`   r]   r   r   r   r   r!   )clsr   r!   Z	dim_namesr   childr   r   r   build,  s    "
 zArray.buildc                s     | fddS )zR
		Return a list of arrays with name name under elem.

		See also .get_array().
		c                s   | j  j ko| jkS )N)rV   rL   )e)rc   r   r   r   <lambda>Y      z'Array.getArraysByName.<locals>.<lambda>)rK   ZgetElements)rc   elemr   r   )rc   r   r   getArraysByNameQ  s    
zArray.getArraysByNamec             C   s@   |dkr| j }| ||}t|dkr8td| | |d S )a=  
		Scan xmldoc for an array named name.  Raises ValueError if
		not exactly 1 such array is found.  If name is None
		(default), then the .arrayName attribute of this class is
		used.  The Array class does not provide a .arrayName
		attribute, but sub-classes could choose to do so.

		See also .getArraysByName().
		Nr   z*document must contain exactly one %s arrayr   )Z	arrayNamerj   r*   r.   rK   )rc   r   r   Zelemsr   r   r   r   [  s    zArray.get_arrayc                s   t t|   d| _dS )zp
		Break internal references within the document tree rooted
		on this element to promote garbage collection.
		N)r   r   rZ   r!   )r   )r   r   r   rZ   q  s    zArray.unlink)N)N)rA   rB   rC   rD   r   ZLLWNameAttrrK   rE   rM   rL   r   propertyr    setterclassmethodre   rj   r   rZ   rH   r   r   )r   r   r      s   9#%$
r   c             C   s&   | j fdd}dd }|| _ || _| S )av  
	Modify ContentHandler, a sub-class of
	ligo.lw.ligolw.LIGOLWContentHandler, to cause it to use the Array
	and ArrayStream classes defined in this module when parsing XML
	documents.

	Example:

	>>> from ligo.lw import ligolw
	>>> class MyContentHandler(ligolw.LIGOLWContentHandler):
	...	pass
	...
	>>> use_in(MyContentHandler)
	<class 'ligo.lw.array.MyContentHandler'>
	c             S   s(   |j tjj krt||S || ||S )N)rV   r   r   r   r'   )r   parentattrsZ__orig_startStreamr   r   r   startStream  s    zuse_in.<locals>.startStreamc             S   s   t |S )N)r   )r   rn   ro   r   r   r   
startArray  s    zuse_in.<locals>.startArray)rp   rq   )ZContentHandlerrp   rq   r   r   r   use_in  s
    rr   )rD   r6   r   rI   rF   Zxml.sax.saxutilsr   r9   Zxml.sax.xmlreaderr   rb   r0   r   r   r   r   r	   r
   r   r   r[   r   r   rr   r   r   r   r   <module>)   s   J l