B
    zdO                 @   sH   d Z ddlZddlmZ ddlmZ ddlmZmZ G dd deZ	dS )	z%Classes for individual Markov chains.    N)JointProposal   )	BaseChain)	ChainDatadetect_dtypesc               @   s  e Zd ZdZdAddZdddd	Zed
d Zedd Zedd Z	edd Z
e
jdd Z
edd Zejdd Zdd Zedd Zejdd Zedd Zejdd Zedd Zed d! Zed"d# Zed$d% Zed&d' Zed(d) Zejd*d) Zed+d, Zed-d. Zd/d0 Zd1d2 Zed3d4 Zed5d6 Zed7d8 Zed9d: Zd;d< Zd=d> Zd?d@ Z dS )BChaina)	  A Markov chain.

    The chain requires a ``model`` to  be provided. This can be any object that
    can be called with keyword arguments that map parameter names to values.
    When called, the object must return a tuple of two or three elements. The
    first element must be a float representing the log likelihood at that
    point; the second must be a float representing the log prior at that point.
    Additionally, the model may return a dictionary as a third element in the
    tuple that maps strings to arbitrary data. This additional data will be
    stored as ``blob`` data.

    Parameters
    ----------
    parameters : list or tuple
        List of the parameter names to sample.
    model : object
        Any object that can be called with keyword arguments that map parameter
        names to values. When called, the object must a tuple of ``logl, logp``
        where ``logp`` is the log prior and ``logl`` is the log likelihood at
        the given point. The model may optionally return a dictionary in
        addition that maps strings to any arbitrary data.
    proposals : list of epsie.proposals instances
        List of proposal classes to use for the parameters. There must be one
        and only one proposal for every parameter. A single proposal may cover
        multiple parameters. Proposals must be instances of classes that
        inherit from :py:class:`epsie.proposals.BaseProposal`.
    bit_generator : :py:class:`epsie.BIT_GENERATOR` instance, optional
        Use the given random bit generator for generating random variates. If
        an int or None is provided, a generator will be created instead using
        ``bit_generator`` as a seed.
    chain_id : int, optional
        An interger identifying which chain this is. Default is 0.
    beta : float, optional
        The inverse temperature of the chain. Default is 1.

    Attributes
    ----------
    parameters
    iteration
    lastclear
    scratchlen
    positions
    stats
    acceptance
    blobs
    start_position
    stats0
    blob0
    current_position
    current_stats
    current_blob
    bit_generator
    random_state
    state
    hasblobs
    transdimensional
    chain_id : int or None
        Integer identifying the chain.
    proposal_dist : JointProposal
        The joint proposal used for all parameters.
    Nr         ?c             C   s   || _ || _d | _| j|d|i| _|| _|| _d| _d| _d| _	t
|| _t
ddg| _t
ddgdtid| _d | _d| _d | _d | _d | _d | _d | _d S )	Nbit_generatorr   logllogpZacceptance_ratioaccepted)dtypesF)
parametersmodeltransdimensional_store_proposalsproposal_distbetachain_id
_iteration
_lastclear_scratchlenr   
_positions_statsbool_acceptance_blobs	_hasblobs_start_proposed_positionZ_logp0Z_logl0_blob0)selfr   r   	proposalsr	   r   r    r#   ^/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/epsie/chain/chain.py__init__X   s*    

zChain.__init__)r	   c         	   G   sj   d}x@|D ]8}y|j r$d| _ |d7 }W q
 tk
r@   d|_ Y q
X q
W | j r\|dkr\tdt|d|iS )zJStore either a ``JointProposal`` or the transdimensional proposal
        r   Tr   Fz[Can only provide a single transdimensinal proposals that includes the constituent proposalsr	   )r   AttributeError
ValueErrorr   )r!   r	   r"   countpropr#   r#   r$   r   r   s    
zChain._store_proposalsc             C   s   | j S )z Whether the model returns blobs.)r   )r!   r#   r#   r$   hasblobs   s    zChain.hasblobsc             C   s   | j S )z/The number of times the chain has been stepped.)r   )r!   r#   r#   r$   	iteration   s    zChain.iterationc             C   s   | j S )zMReturns the iteration of the last time the chain memory was cleared.
        )r   )r!   r#   r#   r$   	lastclear   s    zChain.lastclearc             C   s   | j S )z%The length of the scratch space used.)r   )r!   r#   r#   r$   
scratchlen   s    zChain.scratchlenc             C   s   || _ y| j| W n tk
r*   Y nX y| j| W n tk
rP   Y nX y| j| W n tk
rv   Y nX | jry| j| W n tk
r   Y nX dS )a  Set the scratch length to the given value.

        This will immediately increase the scratch length to ``n``. If the
        chain is already longer than ``n``, this will have no immediate impact.
        However, the next time ``clear`` is called, the scratch length will
        be reset to ``n``.

        Parameters
        ----------
        n : int
            The length to set.
        N)r   r   Zset_lenr'   r   r   r*   r   )r!   nr#   r#   r$   r-      s$    c             C   s   | j dkrtd| j S )zDictionary mapping parameters to their start position.

        If the start position hasn't been set, raises a ``ValueError``.
        NzStarting position not set!)r   r'   )r!   r#   r#   r$   start_position   s    
zChain.start_positionc             C   s   |  | _t|| j_| jf |}| jr0|   y|\}}}d| _W n& t	k
rj   |\}}d}d| _Y nX | jrt
|tstdt| t|d| _||d| _|| _dS )a-  Sets the starting position.

        This also evaulates the log likelihood and log prior at the starting
        position, as well as determine if the model returns blob data.

        Parameters
        ----------
        position : dict
            Dictionary mapping parameters to values.
        TNFz+model must return blob data as a dictionary)r   )r
   r   )copyr   r   r   r   r   r   _activate_proposalsr   r'   
isinstancedict	TypeErrorr   keysr   stats0blob0)r!   positionrr
   r   blobr#   r#   r$   r/      s$    



c                s   x j jD ]}|jr
P q
W t j|j  j|j< xL|jD ]B}tt fdd|j	D rdd|_
nd|_
|jdkr:tdq:W tdd |jD  _dS )z+Decide which proposals are initially activec                s   g | ]} j | qS r#   )r   ).0p)r!   r#   r$   
<listcomp>   s    z-Chain._activate_proposals.<locals>.<listcomp>FTNz@must provide `birth distribution` for transdimensional proposalsc             S   s   g | ]
}|j qS r#   )active)r;   r<   r#   r#   r$   r=      s    )r   r"   r   intr   _indexallnumpyisnanr   r>   Zbirth_distributionr'   array_active_props)r!   r)   Zptdr#   )r!   r$   r1      s    
zChain._activate_proposalsc             C   s   | j }| jS )zDictionary of the log likelihood and log prior at the start
        position.

        Raises a ``ValueError`` if the start position has not been set yet.
        )r/   _stats0)r!   _r#   r#   r$   r6      s    zChain.stats0c             C   s&   |d t j krtd| | _dS )zSets the starting stats.

        Parameters
        ----------
        dict, numpy structred array of len 1, or numpy.void
            Dictionary or numpy array/void object mapping parameter names to
            the starting statistics.
        r   z*starting position is outside of the prior!N)rB   infr'   r0   rF   )r!   statsr#   r#   r$   r6     s    c             C   s    | j }| jdkrd}n| j}|S )zThe blob data of the starting position, as a dictionary.

        Raises a ``ValueError`` if ``set_start`` has not been run yet.
        N)r/   r    )r!   rG   r:   r#   r#   r$   r7     s
    
zChain.blob0c             C   s:   |dk	r0|  }| jdkr0t| t|d| _|| _dS )zSets the starting blob.

        Parameters
        ----------
        blob: dict
            Dictionary mapping blob parameters to their values.
        N)r   )r0   r   r   r5   r   r    )r!   r:   r#   r#   r$   r7   #  s    	
c             C   s$   | j dkrtd| jdt|  S )z:The history of all of the positions, as a structred array.r   zGNo positions as chain hasn't been stepped yet; run step() at least onceN)r+   r'   r   len)r!   r#   r#   r$   	positions4  s    
zChain.positionsc             C   s$   | j dkrtd| jdt|  S )z\The log likelihoods and log priors of the positions, as a structured
        array.
        r   zCNo stats as chain hasn't been stepped yet; run step() at least onceN)r+   r'   r   rJ   )r!   r#   r#   r$   rI   <  s    
zChain.statsc             C   s$   | j dkrtd| jd t|  S )Nr   zHNo acceptance as chain hasn't been stepped yet; run step() at least once)r+   r'   r   rJ   )r!   r#   r#   r$   
acceptanceF  s    
zChain.acceptancec             C   s4   | j dkrtd| jr,| jdt|  }nd}|S )zThe history of all of the blob data, as a structured array.

        If the model does not return blobs, this is just ``None``.
        r   zCNo blobs as chain hasn't been stepped yet; run step() at least onceN)r+   r'   r*   r   rJ   )r!   blobsr#   r#   r$   rM   M  s    
zChain.blobsc             C   s,   t | dkr| j}n| jt | d }|S )z0Dictionary of the current position of the chain.r   r   )rJ   r/   r   asdict)r!   posr#   r#   r$   current_position\  s    zChain.current_positionc             C   s   | j dkrtd| jS )z9Dictionary of the current proposed position of the chain.r   zONo proposed position as chain hasn't been stepped yet; run step() at least once)r+   r'   r   )r!   r#   r#   r$   proposed_positione  s    
zChain.proposed_positionc             C   s
   || _ dS )z0Sets the current proposed position of the chain.N)r   )r!   rQ   r#   r#   r$   rQ   m  s    c             C   s,   t | dkr| j}n| jt | d }|S )z\Dictionary giving the log likelihood and log prior of the current
        position.
        r   r   )rJ   r6   r   rN   )r!   rI   r#   r#   r$   current_statsr  s    zChain.current_statsc             C   s8   | j sd}n(t| dkr | j}n| jt| d }|S )zDictionary of the blob data of the current position.

        If the model does not return blobs, just returns ``None``.
        Nr   r   )r*   rJ   r7   r   rN   )r!   r:   r#   r#   r$   current_blob}  s    zChain.current_blobc             C   sl   | j dkr`| j| _| j| j | j| _| j| j | j	| j | j
r`| j| _| j| j | j | _| S )zClears memory of the current chain, and sets start position to the
        current position.

        New scratch space will be created with length equal to ``scratch_len``.
        r   )r   rP   r   r   clearr-   rR   rF   r   r   r*   rS   r    r   r   )r!   r#   r#   r$   rT     s    
zChain.clearc             C   sN   d|dk  |t |   }| j| | j| | j| d}| jrJ| j| |d< |S )z5Returns all of the chain data at the requested index.r   )rK   rI   rL   rM   )rJ   r   r   r   r   r   )r!   indexoutr#   r#   r$   __getitem__  s    zChain.__getitem__c             C   s   | j jS )N)r   r	   )r!   r#   r#   r$   r	     s    zChain.bit_generatorc             C   s   | j jS )z$Returns the random number generator.)r   random_generator)r!   r#   r#   r$   rY     s    zChain.random_generatorc             C   s   | j jS )z/Returns the current state of the bit generator.)r   random_state)r!   r#   r#   r$   rZ     s    zChain.random_statec             C   sj   i }| j |d< | jj|d< | j|d< | j|d< | j|d< | j|d< | j|d< | jrZ| j}nd}||d	< |S )
zReturns the current state of the chain.

        The state consists of everything needed such that setting a chain's
        state using another's state will result in identical results.
        r   r   r+   rP   rQ   rR   r*   NrS   )	r   r   stater+   rP   rQ   rR   r*   rS   )r!   r[   r:   r#   r#   r$   r[     s    





zChain.statec             C   s   |d | _ |   |d | _|d | _|d  | _|d | _|d | _|d | _|d | _	| j
|d  t| j| j_| jr|   d	S )
a@  Sets the state of the chain using the given dict.

        .. warning::
           Running this will clear the chain's current memory, and replace its
           current position with what is saved in the state.

        Parameters
        ----------
        state : dict
            Dictionary of state values.
        r   r+   rP   rR   r*   rS   rQ   r   N)r   rT   r   r   r0   r   r6   r   r7   rQ   r   	set_stater   r   r   r   r1   )r!   r[   r#   r#   r$   r\     s    






zChain.set_statec             C   s   ||| j   | || j   }| jjsD|| j||| j|| 7 }|dkrVd}d}	nDt|}t|rtd| j	| j ||| jj
| j }
|
|k}	|	|fS )z8Calculates the acceptance ratio and evaluates acceptancer   g      ?TzdNaN acceptance!
chain: {};
beta: {};
current position: {};
proposed position: {};
proposal state: {})r   r   Z	symmetricZlogpdfrB   exprC   r'   formatr   r[   rY   uniform)r!   r   r
   proposalcurrent_logpcurrent_loglcurrent_posZlogararacceptur#   r#   r$   _acceptance_ratio  s     


zChain._acceptance_ratioc             C   sB  | j }| j}| j}| jr(|d| ji | j|}| | _	| j
f |}| jr\|\}}}n|\}}d}|d }	|d }
|tj krd}d}n| ||||
|	|\}}|r| jr|d| _|}||d}n| jr|d}|}|}|}t| }|| j|< || j|< ||f| j|< | jr$|| j|< |  jd7  _| j|  | S )	z#Evolves the chain by a single step._stateNr
   r   Fg        )r
   r   r   )rP   rR   rS   r   updaterE   r   Zjumpr0   rQ   r   r   rB   rH   rg   poprJ   r   r   r   r   r   )r!   rc   rR   rS   r`   r9   r
   r   r:   rb   ra   re   rd   rO   rI   __rV   r#   r#   r$   step  sN    






z
Chain.step)Nr   r   )!__name__
__module____qualname____doc__r%   r   propertyr*   r+   r,   r-   setterr/   r1   r6   r7   rK   rI   rL   rM   rP   rQ   rR   rS   rT   rX   r	   rY   rZ   r[   r\   rg   rl   r#   r#   r#   r$   r      sD   = 
!
"
	r   )
rp   rB   Zepsie.proposalsr   baser   Z	chaindatar   r   r   r#   r#   r#   r$   <module>   s
   