a
    d%                     @   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 dd	lmZmZ dd
lmZ ddlmZ ddlmZmZ eeee
eeeeeeeedZd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RK4)AdamsBashforthAdamsBashforthMoulton)Dopri8Solver)ScipyWrapperODESolver)_check_inputs_flat_to_shape)dopri8dopri5bosh3	fehlberg2adaptive_heunZeulerZmidpointZrk4Zexplicit_adamsZimplicit_adamsfixed_adamsZscipy_solvergHz>g&.>)rtolatolmethodoptionsevent_fnc             
   C   s   t | |||||||t	\
}} }}}}}}}}	t| f | |||d|}
|du r\|
|}n(|
|d |\}}||}|	r| }|durt|t|f|}|du r|S ||fS d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   SOLVERSZ	integrateZintegrate_until_eventtor   len)r   r   tr   r   r   r   r   shapesZt_is_reversedZsolversolutionevent_t r%   a/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/torchdiffeq/_impl/odeint.pyodeint   s    ),
r'   F)reverse_timeodeint_interfacec             
   K   s6  |r(t |d|d d g}n"t |d|d d g}|| ||fd|i|\}}	t| ||dddd|t	\
}
}}}}}}}}}|
durt dd |	D }n|	d }|r| }t||||\}}|r| }|
durt|d|
}t	d	d
 t
|	|D }	nt j|	dd |d gdd}	||	fS )z8Automatically links up the gradient from the event time.g      ?r   g        Nc                 S   s   g | ]}|d   d qS )r*   )reshape).0sr%   r%   r&   
<listcomp>k       z odeint_event.<locals>.<listcomp>r%   c                 s   s0   | ](\}}t j|d d |d  gddV  qd S )Nr*   r   Zdim)torchcat)r,   r-   Zs_tr%   r%   r&   	<genexpr>{   r/   zodeint_event.<locals>.<genexpr>r   r0   )r1   r2   r+   detachr   r   ImplicitFnGradientReroutingapplyr   tuplezip)r   r   t0r   r(   r)   kwargsr!   r$   r#   r"   Z_func_state_tr%   r%   r&   odeint_event]   s$    $",
r=   c                   @   s$   e Zd Zedd Zedd ZdS )r5   c                 C   s(   || _ || _| || | | fS )z% event_t is the solution to event_fn )r   r   Zsave_for_backwardr4   )ctxr   r   r$   r<   r%   r%   r&   forward   s    z#ImplicitFnGradientRerouting.forwardc                 C   s   | j }| j}| j\}}|  d}|  d}|||}t & t|||f\}\}	}
W d    n1 sx0    Y  |	t	|
|  }|t	||  }|
| |d  
| }
||
 }d d d |fS )NTg-q=)r   r   Zsaved_tensorsr4   cloneZrequires_grad_r1   Zenable_gradr   sumZ
reshape_as)r>   Zgrad_tZ
grad_stater   r   r$   r<   Zf_valcZpar_dtZdstateZdcdtr%   r%   r&   backward   s    


4z$ImplicitFnGradientRerouting.backwardN)__name__
__module____qualname__staticmethodr?   rC   r%   r%   r%   r&   r5      s   
r5   )r1   Ztorch.autograd.functionalr   r   r   r   r   r   r   r   r   Z
fixed_gridr   r	   r
   r   r   r   r   r   Zscipy_wrapperr   miscr   r   r   r'   r=   ZautogradZFunctionr5   r%   r%   r%   r&   <module>   s4   >%