o
    Ni                     @   s  d dl Z d dlmZ ddlmZ ddlmZ ddlmZ ddl	m
Z
 ddlmZmZmZmZmZ dd	lmZmZ dd
lmZ ddlmZ ddlmZmZ ddlmZ eeee
eeeeeeeeeedZddddddddZdddddddZdedddZ G dd de j!j"Z#dS )    N)vjp   )Dopri5Solver)Bosh3Solver)AdaptiveHeunSolver)	Fehlberg2)EulerMidpointHeun2Heun3RK4)AdamsBashforthAdamsBashforthMoulton)Dopri8Solver)ScipyWrapperODESolver)_check_inputs_flat_to_shape)_interp_evaluate)dopri8dopri5bosh3	fehlberg2adaptive_heuneulermidpointheun2heun3rk4explicit_adamsimplicit_adamsfixed_adamsscipy_solvergHz>g&.>)rtolatolmethodoptionsevent_fnc             
   C   s   t | |||||||t	\
}} }}}}}}}}	t| d| |||d|}
|du r.|
|}n|
|d |\}}||}|	rB| }|durOt|t|f|}|du rU|S ||fS )a  Integrate a system of ordinary differential equations.

    Solves the initial value problem for a non-stiff system of first order ODEs:
        ```
        dy/dt = func(t, y), y(t[0]) = y0
        ```
    where y is a Tensor or tuple of Tensors of any shape.

    Output dtypes and numerical precision are based on the dtypes of the inputs `y0`.

    Args:
        func: Function that maps a scalar Tensor `t` and a Tensor holding the state `y`
            into a Tensor of state derivatives with respect to time. Optionally, `y`
            can also be a tuple of Tensors.
        y0: N-D Tensor giving starting value of `y` at time point `t[0]`. Optionally, `y0`
            can also be a tuple of Tensors.
        t: 1-D Tensor holding a sequence of time points for which to solve for
            `y`, in either increasing or decreasing order. The first element of
            this sequence is taken to be the initial time point.
        rtol: optional float64 Tensor specifying an upper bound on relative error,
            per element of `y`.
        atol: optional float64 Tensor specifying an upper bound on absolute error,
            per element of `y`.
        method: optional string indicating the integration method to use.
        options: optional dict of configuring options for the indicated integration
            method. Can only be provided if a `method` is explicitly set.
        event_fn: Function that maps the state `y` to a Tensor. The solve terminates when
            event_fn evaluates to zero. If this is not None, all but the first elements of
            `t` are ignored.

    Returns:
        y: Tensor, where the first dimension corresponds to different
            time points. Contains the solved value of y for each desired time point in
            `t`, with the initial value `y0` being the first element along the first
            dimension.

    Raises:
        ValueError: if an invalid `method` is provided.
    funcy0r"   r#   Nr    )r   SOLVERS	integrateintegrate_until_eventtor   len)r(   r)   tr"   r#   r$   r%   r&   shapest_is_reversedsolversolutionevent_tr*   r*   L/home/ubuntu/.local/lib/python3.10/site-packages/torchdiffeq/_impl/odeint.pyodeint"   s   ,)
r7   )r"   r#   r$   r%   c             
      s  t |sJ t ||g|}t| ||||||d t	\
}	} }}}}}}}
}
|dks-J td	| |||d|}t jt|g|j	j
R |j	j|j	jd}|j	|d< ||j}|| |jj}|gg  tdt|D ]A}|| }||jjkr||j|_|jj}||kr|}|  t |jj ||jjkszt|jj|jj|jj|||< qnt d t    fdd}|S )
Nr   r'   )dtypedevicer   r   c                    sP   t j| dd  d  }  } fddtjd D }t|||| S )Nright)sider   c                    s   g | ]
} d   | qS )r   r*   ).0i)idxinterp_coeffsr*   r6   
<listcomp>   s    z9odeint_dense.<locals>.dense_output_fn.<locals>.<listcomp>)torchsearchsortedrangeshaper   )t_evalt0t1coefr@   times)r?   r6   dense_output_fn   s
   z%odeint_dense.<locals>.dense_output_fnr*   )rB   	is_tensortensorr.   r   r+   r   emptyr/   r)   rE   r8   r9   _before_integraterk_staterG   rD   rH   _adaptive_stepappendstackinterp_coeffr   reshapecpu)r(   r)   rG   rH   r"   r#   r$   r%   r0   r1   _r3   r4   r>   next_trL   r*   rJ   r6   odeint_dense`   s6   ,*


 

rZ   F)reverse_timeodeint_interfacec             
   K   s:  |rt |d|d d g}nt |d|d d g}|| ||fd|i|\}}	t| ||dddd|t	\
}
}}}}}}}}}|
durXt dd |	D }n|	d }|ra| }t||||\}}|rp| }|
durt|d|
}t	d	d
 t
|	|D }	||	fS t j|	dd |d gdd}	||	fS )z8Automatically links up the gradient from the event time.r:   g      ?r&   g        Nc                 S   s   g | ]	}|d   d qS )r:   )rV   )r=   sr*   r*   r6   rA      s    z odeint_event.<locals>.<listcomp>r*   c                 s   s2    | ]\}}t j|d d |d  gddV  qd S )Nr:   r   dim)rB   cat)r=   r]   s_tr*   r*   r6   	<genexpr>   s   0 zodeint_event.<locals>.<genexpr>r   r^   )rB   r`   rV   detachr   r+   ImplicitFnGradientReroutingapplyr   tuplezip)r(   r)   rG   r&   r[   r\   kwargsr0   r5   r4   r1   _funcrX   state_tr*   r*   r6   odeint_event   s&   $",rk   c                   @   s$   e Zd Zedd Zedd ZdS )rd   c                 C   s(   || _ || _| || | | fS )z% event_t is the solution to event_fn )r(   r&   save_for_backwardrc   )ctxr(   r&   r5   rj   r*   r*   r6   forward   s   z#ImplicitFnGradientRerouting.forwardc                 C   s   | j }| j}| j\}}|  d}|  d}|||}t  t|||f\}\}	}
W d    n1 s<w   Y  |	t	|
|  }|t	||  }|
| |d  
| }
||
 }d d d |fS )NTg-q=)r(   r&   saved_tensorsrc   clonerequires_grad_rB   enable_gradr   sum
reshape_as)rm   grad_t
grad_stater(   r&   r5   rj   f_valcpar_dtdstatedcdtr*   r*   r6   backward   s   


z$ImplicitFnGradientRerouting.backwardN)__name__
__module____qualname__staticmethodrn   r|   r*   r*   r*   r6   rd      s
    
rd   )$rB   torch.autograd.functionalr   r   r   r   r   r   r   r   r   
fixed_gridr   r	   r
   r   r   r    r   r   r   r   scipy_wrapperr   miscr   r   interpr   r+   r7   rZ   rk   autogradFunctionrd   r*   r*   r*   r6   <module>   s>    >1%