B
    d3T                 @   s   d dl mZ yd dlmZmZ W n$ ek
rD   edZedZY nX d dlZd dlZG dd de	Z
G dd	 d	e
ZG d
d de
ZG dd de
ZG dd de
ZG dd de
ZG dd deZG dd de	ZG dd de	ZdS )    )bisect_right)PosInfNegInfz+infz-infNc               @   sH   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dS )Binsz
    Parent class for 1-dimensional binnings.

    Not intended to be used directly, but to be subclassed for use in real
    bins classes.
    c             C   sL   t |tst||dk r"t|||kr6t||f|| _|| _|| _dS )a   
        Initialize a Bins instance.  The three arguments are the
        minimum and maximum of the values spanned by the bins, and
        the number of bins to place between them.  Subclasses may
        require additional arguments, or different arguments
        altogether.
           N)
isinstanceint	TypeError
ValueErrorminvmaxvn)selfr   r   r    r   \/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/pycbc/bin_utils.py__init__   s    

zBins.__init__c             C   s   | j S )N)r   )r   r   r   r   __len__(   s    zBins.__len__c             C   sf   t |tr^|jdk	r$tdt| t|jdk	r:| |j nd|jdk	rT| |j d nt| S tdS )a<  
        Convert a co-ordinate to a bin index.  The co-ordinate can
        be a single value, or a Python slice instance describing a
        range of values.  If a single value is given, it is mapped
        to the bin index corresponding to that value.  If a slice
        is given, it is converted to a slice whose lower bound is
        the index of the bin in which the slice's lower bound
        falls, and whose upper bound is 1 greater than the index of
        the bin in which the slice's upper bound falls.  Steps are
        not supported in slices.
        Nzstep not supported: %sr   r   )r   slicestepNotImplementedErrorreprstartstoplen)r   xr   r   r   __getitem__+   s    


zBins.__getitem__c             C   s   t dS )z
        If __iter__ does not exist, Python uses __getitem__ with
        range(0) as input to define iteration. This is nonsensical
        for bin objects, so explicitly unsupport iteration.
        N)r   )r   r   r   r   __iter__?   s    zBins.__iter__c             C   s   t dS )zg
        Return an array containing the locations of the lower
        boundaries of the bins.
        N)r   )r   r   r   r   lowerG   s    z
Bins.lowerc             C   s   t dS )zV
        Return an array containing the locations of the bin
        centres.
        N)r   )r   r   r   r   centresN   s    zBins.centresc             C   s   t dS )zg
        Return an array containing the locations of the upper
        boundaries of the bins.
        N)r   )r   r   r   r   upperU   s    z
Bins.upperN)__name__
__module____qualname____doc__r   r   r   r   r   r   r   r   r   r   r   r      s   r   c                   s@   e Zd ZdZdd Z fddZdd Zdd	 Zd
d Z  Z	S )IrregularBinsa@  
    Bins with arbitrary, irregular spacing.  We only require strict
    monotonicity of the bin boundaries.  N boundaries define N-1 bins.

    Example:

    >>> x = IrregularBins([0.0, 11.0, 15.0, numpy.inf])
    >>> len(x)
    3
    >>> x[1]
    0
    >>> x[1.5]
    0
    >>> x[13]
    1
    >>> x[25]
    2
    >>> x[4:17]
    slice(0, 3, None)
    >>> IrregularBins([0.0, 15.0, 11.0])
    Traceback (most recent call last):
        ...
    ValueError: non-monotonic boundaries provided
    >>> y = IrregularBins([0.0, 11.0, 15.0, numpy.inf])
    >>> x == y
    True
    c             C   sx   t |dk rtdt|}tdd t|dd |dd D rLtd|| _t |d | _|d	 | _|d | _dS )
z
        Initialize a set of custom bins with the bin boundaries.
        This includes all left edges plus the right edge.  The
        boundaries must be monotonic and there must be at least two
        elements.
           z!less than two boundaries providedc             s   s   | ]\}}||kV  qd S )Nr   ).0abr   r   r   	<genexpr>   s    z)IrregularBins.__init__.<locals>.<genexpr>Nr   z!non-monotonic boundaries providedr   )	r   r
   tupleanyzip
boundariesr   r   r   )r   r.   r   r   r   r   z   s    (
zIrregularBins.__init__c                sj   t |trtt| |S | j|  kr2| jk rFn nt| j|d S || jkr^t	| jd S t
|d S )Nr   r%   )r   r   superr$   r   r   r   r   r.   r   
IndexError)r   r   )	__class__r   r   r      s    

zIrregularBins.__getitem__c             C   s   t | jd d S )Nr*   )numpyarrayr.   )r   r   r   r   r      s    zIrregularBins.lowerc             C   s   t | jdd  S )Nr   )r2   r3   r.   )r   r   r   r   r      s    zIrregularBins.upperc             C   s   |   |   d S )Ng       @)r   r   )r   r   r   r   r      s    zIrregularBins.centres)
r    r!   r"   r#   r   r   r   r   r   __classcell__r   r   )r1   r   r$   ]   s   
r$   c                   sD   e Zd ZdZ fddZ fddZdd Zdd	 Zd
d Z  Z	S )
LinearBinsa  
    Linearly-spaced bins.  There are n bins of equal size, the first
    bin starts on the lower bound and the last bin ends on the upper
    bound inclusively.

    Example:

    >>> x = LinearBins(1.0, 25.0, 3)
    >>> x.lower()
    array([  1.,   9.,  17.])
    >>> x.upper()
    array([  9.,  17.,  25.])
    >>> x.centres()
    array([  5.,  13.,  21.])
    >>> x[1]
    0
    >>> x[1.5]
    0
    >>> x[10]
    1
    >>> x[25]
    2
    >>> x[0:27]
    Traceback (most recent call last):
        ...
    IndexError: 0
    >>> x[1:25]
    slice(0, 3, None)
    >>> x[:25]
    slice(0, 3, None)
    >>> x[10:16.9]
    slice(1, 2, None)
    >>> x[10:17]
    slice(1, 3, None)
    >>> x[10:]
    slice(1, 3, None)
    c                s*   t t| ||| t|| | | _d S )N)r/   r5   r   floatdelta)r   r   r   r   )r1   r   r   r      s    zLinearBins.__init__c                sr   t |trtt| |S | j|  kr2| jk rPn ntt	|| j | j
 S || jkrft| d S t|d S )Nr   )r   r   r/   r5   r   r   r   r   mathfloorr7   r   r0   )r   r   )r1   r   r   r      s    

zLinearBins.__getitem__c             C   s   t | j| j| j t| S )N)r2   linspacer   r   r7   r   )r   r   r   r   r      s    zLinearBins.lowerc             C   s*   t | j| jd  | j| jd  t| S )Ng       @)r2   r:   r   r7   r   r   )r   r   r   r   r      s    zLinearBins.centresc             C   s   t | j| j | jt| S )N)r2   r:   r   r7   r   r   )r   r   r   r   r      s    zLinearBins.upper)
r    r!   r"   r#   r   r   r   r   r   r4   r   r   )r1   r   r5      s   &
r5   c                   sD   e Zd ZdZ fddZ fddZdd Zdd	 Zd
d Z  Z	S )LinearPlusOverflowBinsaY  
    Linearly-spaced bins with overflow at the edges.

    There are n-2 bins of equal size.  The bin 1 starts on the lower bound and
    bin n-2 ends on the upper bound.  Bins 0 and n-1 are overflow going from
    -infinity to the lower bound and from the upper bound to +infinity
    respectively.  Must have n >= 3.

    Example:

    >>> x = LinearPlusOverflowBins(1.0, 25.0, 5)
    >>> x.centres()
    array([-inf,   5.,  13.,  21.,  inf])
    >>> x.lower()
    array([-inf,   1.,   9.,  17.,  25.])
    >>> x.upper()
    array([  1.,   9.,  17.,  25.,  inf])
    >>> x[float("-inf")]
    0
    >>> x[0]
    0
    >>> x[1]
    1
    >>> x[10]
    2
    >>> x[24.99999999]
    3
    >>> x[25]
    4
    >>> x[100]
    4
    >>> x[float("+inf")]
    4
    >>> x[float("-inf"):9]
    slice(0, 3, None)
    >>> x[9:float("+inf")]
    slice(2, 5, None)
    c                s>   |dk rt dtt| ||| t|| |d  | _d S )N   zn must be >= 3r%   )r
   r/   r;   r   r6   r7   )r   r   r   r   )r1   r   r   r   	  s    zLinearPlusOverflowBins.__init__c                s   t |trtt| |S | j|  kr2| jk rTn ntt	|| j | j
 d S || jkrjt| d S || jk rxdS t|d S )Nr   r   )r   r   r/   r;   r   r   r   r   r8   r9   r7   r   r0   )r   r   )r1   r   r   r     s    


z"LinearPlusOverflowBins.__getitem__c          	   C   s<   t t tg| j| jt t| d   t | jgfS )Nr%   )	r2   concatenater3   r   r   r7   aranger   r   )r   r   r   r   r     s    
zLinearPlusOverflowBins.lowerc          	   C   s>   t t tg| j| jt t| d d   t tgfS )Nr%   g      ?)	r2   r=   r3   r   r   r7   r>   r   r   )r   r   r   r   r   #  s    
 zLinearPlusOverflowBins.centresc          	   C   s@   t t | jg| j| jt t| d d   t tgfS )Nr%   r   )r2   r=   r3   r   r7   r>   r   r   )r   r   r   r   r   *  s     zLinearPlusOverflowBins.upper)
r    r!   r"   r#   r   r   r   r   r   r4   r   r   )r1   r   r;      s   'r;   c                   sD   e Zd ZdZ fddZ fddZdd Zdd	 Zd
d Z  Z	S )LogarithmicBinsaX  
    Logarithmically-spaced bins.

    There are n bins, each of whose upper and lower bounds differ by the same
    factor.  The first bin starts on the lower bound, and the last bin ends on
    the upper bound inclusively.

    Example:

    >>> x = LogarithmicBins(1.0, 25.0, 3)
    >>> x[1]
    0
    >>> x[5]
    1
    >>> x[25]
    2
    c                s2   t t| ||| t|t| | | _d S )N)r/   r?   r   r8   logr7   )r   r   r   r   )r1   r   r   r   E  s    zLogarithmicBins.__init__c                s~   t |trtt| |S | j|  kr2| jk r\n n&tt	t
|t
| j | j S || jkrrt| d S t|d S )Nr   )r   r   r/   r?   r   r   r   r   r8   r9   r@   r7   r   r0   )r   r   )r1   r   r   r   I  s    

zLogarithmicBins.__getitem__c             C   s.   t t t| jt| j| j t| S )N)	r2   expr:   r8   r@   r   r   r7   r   )r   r   r   r   r   T  s    zLogarithmicBins.lowerc             C   s8   t t t| jt| j| j t| | jd  S )Ng       @)	r2   rA   r:   r8   r@   r   r   r7   r   )r   r   r   r   r   Z  s    zLogarithmicBins.centresc             C   s.   t t t| j| j t| jt| S )N)	r2   rA   r:   r8   r@   r   r7   r   r   )r   r   r   r   r   `  s    zLogarithmicBins.upper)
r    r!   r"   r#   r   r   r   r   r   r4   r   r   )r1   r   r?   2  s   r?   c                   sD   e Zd ZdZ fddZ fddZdd Zdd	 Zd
d Z  Z	S )LogarithmicPlusOverflowBinsa  
    Logarithmically-spaced bins plus one bin at each end that goes to
    zero and positive infinity respectively.  There are n-2 bins each
    of whose upper and lower bounds differ by the same factor.  Bin 1
    starts on the lower bound, and bin n-2 ends on the upper bound
    inclusively.  Bins 0 and n-1 are overflow bins extending from 0 to
    the lower bound and from the upper bound to +infinity respectively.
    Must have n >= 3.

    Example:

    >>> x = LogarithmicPlusOverflowBins(1.0, 25.0, 5)
    >>> x[0]
    0
    >>> x[1]
    1
    >>> x[5]
    2
    >>> x[24.999]
    3
    >>> x[25]
    4
    >>> x[100]
    4
    >>> x.lower()
    array([ 0.   ,  1.        ,  2.92401774,  8.54987973, 25.      ])
    >>> x.upper()
    array([ 1.   ,  2.92401774,  8.54987973, 25.        ,       inf])
    >>> x.centres()
    array([ 0.   ,  1.70997595,  5.        , 14.62008869,       inf])
    c                sF   |dk rt dtt| ||| t|t| |d  | _d S )Nr<   zn must be >= 3r%   )r
   r/   rB   r   r8   r@   r7   )r   r   r   r   )r1   r   r   r     s    z$LogarithmicPlusOverflowBins.__init__c                s   t |trtt| |S | j|  kr2| jk r`n n*dtt	t
|t
| j | j  S || jkrvt| d S || jk rdS t|d S )Nr   r   )r   r   r/   rB   r   r   r   r   r8   r9   r@   r7   r   r0   )r   r   )r1   r   r   r     s    


z'LogarithmicPlusOverflowBins.__getitem__c             C   s>   t t dgt t t| jt| jt	| d fS )Ng        r   )
r2   r=   r3   rA   r:   r8   r@   r   r   r   )r   r   r   r   r     s    
z!LogarithmicPlusOverflowBins.lowerc             C   sX   t t dgt t t| jt| j| j	 t
| d | j	d  t tgfS )Ng        r%   g       @)r2   r=   r3   rA   r:   r8   r@   r   r   r7   r   r   )r   r   r   r   r     s
    
z#LogarithmicPlusOverflowBins.centresc          
   C   s>   t t t t| jt| jt| d t 	t
gfS )Nr   )r2   r=   rA   r:   r8   r@   r   r   r   r3   r   )r   r   r   r   r     s    z!LogarithmicPlusOverflowBins.upper)
r    r!   r"   r#   r   r   r   r   r   r4   r   r   )r1   r   rB   g  s    	rB   c               @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )NDBinsa  
    Multi-dimensional co-ordinate binning.  An instance of this object
    is used to convert a tuple of co-ordinates into a tuple of bin
    indices.  This can be used to allow the contents of an array object
    to be accessed with real-valued coordinates.

    NDBins is a subclass of the tuple builtin, and is initialized with
    an iterable of instances of subclasses of Bins.  Each Bins subclass
    instance describes the binning to apply in the corresponding
    co-ordinate direction, and the number of them sets the dimensions
    of the binning.

    Example:

    >>> x = NDBins((LinearBins(1, 25, 3), LogarithmicBins(1, 25, 3)))
    >>> x[1, 1]
    (0, 0)
    >>> x[1.5, 1]
    (0, 0)
    >>> x[10, 1]
    (1, 0)
    >>> x[1, 5]
    (0, 1)
    >>> x[1, 1:5]
    (0, slice(0, 2, None))
    >>> x.centres()
    (array([ 5., 13., 21.]), array([ 1.70997595,  5.        , 14.62008869]))

    Note that the co-ordinates to be converted must be a tuple, even if
    it is only a 1-dimensional co-ordinate.
    c             G   sP   t j| f| }t dd |D |_t dd |D |_t dd |D |_|S )Nc             s   s   | ]}|j V  qd S )N)r   )r&   r(   r   r   r   r)     s    z!NDBins.__new__.<locals>.<genexpr>c             s   s   | ]}|j V  qd S )N)r   )r&   r(   r   r   r   r)     s    c             s   s   | ]}t |V  qd S )N)r   )r&   r(   r   r   r   r)     s    )r+   __new__r   r   shape)clsargsnewr   r   r   rD     s
    zNDBins.__new__c             C   sF   t |tr6t|t| kr"tdttdd | |S t| |S dS )a  
        When coords is a tuple, it is interpreted as an
        N-dimensional co-ordinate which is converted to an N-tuple
        of bin indices by the Bins instances in this object.
        Otherwise coords is interpeted as an index into the tuple,
        and the corresponding Bins instance is returned.

        Example:

        >>> x = NDBins((LinearBins(1, 25, 3), LogarithmicBins(1, 25, 3)))
        >>> x[1, 1]
        (0, 0)
        >>> type(x[1])
        <class 'pylal.rate.LogarithmicBins'>

        When used to convert co-ordinates to bin indices, each
        co-ordinate can be anything the corresponding Bins instance
        will accept.  Note that the co-ordinates to be converted
        must be a tuple, even if it is only a 1-dimensional
        co-ordinate.
        zdimension mismatchc             S   s   | | S )Nr   )r(   cr   r   r   <lambda>      z$NDBins.__getitem__.<locals>.<lambda>N)r   r+   r   r
   mapr   )r   coordsr   r   r   r     s
    
zNDBins.__getitem__c             C   s   t dd | D S )z
        Return a tuple of arrays, where each array contains the
        locations of the lower boundaries of the bins in the
        corresponding dimension.
        c             s   s   | ]}|  V  qd S )N)r   )r&   r(   r   r   r   r)     s    zNDBins.lower.<locals>.<genexpr>)r+   )r   r   r   r   r     s    zNDBins.lowerc             C   s   t dd | D S )z
        Return a tuple of arrays, where each array contains the
        locations of the bin centres for the corresponding
        dimension.
        c             s   s   | ]}|  V  qd S )N)r   )r&   r(   r   r   r   r)   	  s    z!NDBins.centres.<locals>.<genexpr>)r+   )r   r   r   r   r     s    zNDBins.centresc             C   s   t dd | D S )z
        Return a tuple of arrays, where each array contains the
        locations of the upper boundaries of the bins in the
        corresponding dimension.
        c             s   s   | ]}|  V  qd S )N)r   )r&   r(   r   r   r   r)     s    zNDBins.upper.<locals>.<genexpr>)r+   )r   r   r   r   r     s    zNDBins.upperN)	r    r!   r"   r#   rD   r   r   r   r   r   r   r   r   rC     s    rC   c               @   s\   e Zd ZdZdddZdd Zdd	 Zd
d Zdd Zdd Z	dd Z
dd ZdddZdS )BinnedArraya  
    A convenience wrapper, using the NDBins class to provide access to
    the elements of an array object.  Technical reasons preclude
    providing a subclass of the array object, so the array data is made
    available as the "array" attribute of this class.

    Examples:

    Note that even for 1 dimensional arrays the index must be a tuple.

    >>> x = BinnedArray(NDBins((LinearBins(0, 10, 5),)))
    >>> x.array
    array([ 0.,  0.,  0.,  0.,  0.])
    >>> x[0,] += 1
    >>> x[0.5,] += 1
    >>> x.array
    array([ 2.,  0.,  0.,  0.,  0.])
    >>> x.argmax()
    (1.0,)

    Note the relationship between the binning limits, the bin centres,
    and the co-ordinates of the BinnedArray

    >>> x = BinnedArray(NDBins((LinearBins(-0.5, 1.5, 2),     LinearBins(-0.5, 1.5, 2))))
    >>> x.bins.centres()
    (array([ 0.,  1.]), array([ 0.,  1.]))
    >>> x[0, 0] = 0
    >>> x[0, 1] = 1
    >>> x[1, 0] = 2
    >>> x[1, 1] = 4
    >>> x.array
    array([[ 0.,  1.],
           [ 2.,  4.]])
    >>> x[0, 0]
    0.0
    >>> x[0, 1]
    1.0
    >>> x[1, 0]
    2.0
    >>> x[1, 1]
    4.0
    >>> x.argmin()
    (0.0, 0.0)
    >>> x.argmax()
    (1.0, 1.0)
    Ndoublec             C   s@   || _ |d kr"tj|j|d| _n|j|jkr6td|| _d S )N)dtypez3input array and input bins must have the same shape)binsr2   ZzerosrE   r3   r
   )r   rQ   r3   rP   r   r   r   r   E  s    zBinnedArray.__init__c             C   s   | j | j|  S )N)r3   rQ   )r   rM   r   r   r   r   O  s    zBinnedArray.__getitem__c             C   s   || j | j| < d S )N)r3   rQ   )r   rM   valr   r   r   __setitem__R  s    zBinnedArray.__setitem__c             C   s
   t | jS )N)r   r3   )r   r   r   r   r   U  s    zBinnedArray.__len__c             C   s   t | | j| j S )zm
        Return a copy of the BinnedArray.  The .bins attribute is
        shared with the original.
        )typerQ   r3   copy)r   r   r   r   rU   X  s    zBinnedArray.copyc             C   s
   | j  S )za
        Return a tuple of arrays containing the bin centres for
        each dimension.
        )rQ   r   )r   r   r   r   r   _  s    zBinnedArray.centresc             C   s.   t dd t|  t| j | jjD S )z
        Return the co-ordinates of the bin centre containing the
        minimum value.  Same as numpy.argmin(), converting the
        indexes to bin co-ordinates.
        c             s   s   | ]\}}|| V  qd S )Nr   )r&   r   indexr   r   r   r)   l  s    z%BinnedArray.argmin.<locals>.<genexpr>)r+   r-   r   r2   unravel_indexr3   argminrE   )r   r   r   r   rX   f  s    zBinnedArray.argminc             C   s.   t dd t|  t| j | jjD S )z
        Return the co-ordinates of the bin centre containing the
        maximum value.  Same as numpy.argmax(), converting the
        indexes to bin co-ordinates.
        c             s   s   | ]\}}|| V  qd S )Nr   )r&   r   rV   r   r   r   r)   v  s    z%BinnedArray.argmax.<locals>.<genexpr>)r+   r-   r   r2   rW   r3   argmaxrE   )r   r   r   r   rY   p  s    zBinnedArray.argmax       c             C   s   || j | j dk< | S )z
        Find bins <= 0, and set them to epsilon, This has the
        effect of allowing the logarithm of the array to be
        evaluated without error.
        r   )r3   )r   epsilonr   r   r   logregularizez  s    zBinnedArray.logregularize)NrO   )rZ   )r    r!   r"   r#   r   r   rS   r   rU   r   rX   rY   r\   r   r   r   r   rN     s   0



rN   c               @   s`   e Zd ZdZdddZdd Zdd Zdd
dZdddZdd Z	dd Z
dddZdd ZdS )BinnedRatiosa  
    Like BinnedArray, but provides a numerator array and a denominator
    array.  The incnumerator() method increments a bin in the numerator
    by the given weight, and the incdenominator() method increments a
    bin in the denominator by the given weight.  There are no methods
    provided for setting or decrementing either, but the they are
    accessible as the numerator and denominator attributes, which are
    both BinnedArray objects.
    rO   c             C   s    t ||d| _t ||d| _d S )N)rP   )rN   	numeratordenominator)r   rQ   rP   r   r   r   r     s    zBinnedRatios.__init__c             C   s   | j | | j|  S )N)r^   r_   )r   rM   r   r   r   r     s    zBinnedRatios.__getitem__c             C   s   | j jS )N)r^   rQ   )r   r   r   r   rQ     s    zBinnedRatios.binsr   c             C   s   | j |  |7  < dS )z<
        Add weight to the numerator bin at coords.
        N)r^   )r   rM   weightr   r   r   incnumerator  s    zBinnedRatios.incnumeratorc             C   s   | j |  |7  < dS )z>
        Add weight to the denominator bin at coords.
        N)r_   )r   rM   r`   r   r   r   incdenominator  s    zBinnedRatios.incdenominatorc             C   s   | j j| jj S )z9
        Compute and return the array of ratios.
        )r^   r3   r_   )r   r   r   r   ratio  s    zBinnedRatios.ratioc             C   s   d| j j| j jdk< | S )aA  
        Find bins in the denominator that are 0, and set them to 1.
        Presumably the corresponding bin in the numerator is also
        0, so this has the effect of allowing the ratio array to be
        evaluated without error, returning zeros in those bins that
        have had no weight added to them.
        r   r   )r_   r3   )r   r   r   r   
regularize  s    zBinnedRatios.regularize       c             C   s,   || j j| jjdk< d| jj| jjdk< | S )a  
        Find bins in the denominator that are 0, and set them to 1,
        while setting the corresponding bin in the numerator to
        float epsilon.  This has the effect of allowing the
        logarithm of the ratio array to be evaluated without error.
        r   r   )r^   r3   r_   )r   r[   r   r   r   r\     s    zBinnedRatios.logregularizec             C   s   | j j S )za
        Return a tuple of arrays containing the bin centres for
        each dimension.
        )r^   rQ   r   )r   r   r   r   r     s    zBinnedRatios.centresN)rO   )r   )r   )re   )r    r!   r"   r#   r   r   rQ   ra   rb   rc   rd   r\   r   r   r   r   r   r]     s   




r]   )bisectr   Zfpconstr   r   ImportErrorr6   r2   r8   objectr   r$   r5   r;   r?   rB   r+   rC   rN   r]   r   r   r   r   <module>   s    QD@Q5O^p