o
    GiF@                     @   s   d Z ddlmZ ddlZddlmZmZ ddlmZm	Z	 ddl
mZ dd	lmZ e	eZeG d
d deZG dd deeZdS )aM  
LTXEulerAncestralRFScheduler

This scheduler implements a K-diffusion style Euler-Ancestral sampler specialized for flow / CONST parameterization,
closely mirroring ComfyUI's `sample_euler_ancestral_RF` implementation used for LTX-Video.

Reference implementation (ComfyUI):
    comfy.k_diffusion.sampling.sample_euler_ancestral_RF
    )	dataclassN   )ConfigMixinregister_to_config)
BaseOutputlogging)randn_tensor   )SchedulerMixinc                   @   s   e Zd ZU dZejed< dS )"LTXEulerAncestralRFSchedulerOutputz
    Output class for the scheduler's `step` function output.

    Args:
        prev_sample (`torch.FloatTensor`):
            Updated sample for the next step in the denoising process.
    prev_sampleN)__name__
__module____qualname____doc__torchFloatTensor__annotations__ r   r   j/home/ubuntu/.local/lib/python3.10/site-packages/diffusers/schedulers/scheduling_ltx_euler_ancestral_rf.pyr   &   s   
 r   c                   @   sn  e Zd ZdZdgZdZe			d.dededefd	d
Z	e
defddZe
defddZd/defddZ	d0deejB dejdB defddZdeejB fddZ					d1dedB deejB dB dee ejB dB dee ejB dB dedB f
d d!Zd"ejd#ejdejfd$d%Z		&d2d'ejdeejB d#ejd(ejdB d)edeeej B fd*d+Zdefd,d-ZdS )3LTXEulerAncestralRFScheduleraI  
    Euler-Ancestral scheduler for LTX-Video (RF / CONST parametrization).

    This scheduler is intended for models where the network is trained with a CONST-like parameterization (as in LTXV /
    FLUX). It approximates ComfyUI's `sample_euler_ancestral_RF` sampler and is useful when reproducing ComfyUI
    workflows inside diffusers.

    The scheduler can either:
    - reuse the [`FlowMatchEulerDiscreteScheduler`] sigma / timestep logic when only `num_inference_steps` is provided
      (default diffusers-style usage), or
    - follow an explicit ComfyUI-style sigma schedule when `sigmas` (or `timesteps`) are passed to [`set_timesteps`].

    Args:
        num_train_timesteps (`int`, defaults to 1000):
            Included for config compatibility; not used to build the schedule.
        eta (`float`, defaults to 1.0):
            Stochasticity parameter. `eta=0.0` yields deterministic DDIM-like sampling; `eta=1.0` matches ComfyUI's
            default RF behavior.
        s_noise (`float`, defaults to 1.0):
            Global scaling factor for the stochastic noise term.
    FlowMatchEulerDiscreteSchedulerr	           ?num_train_timestepsetas_noisec                 C   s"   d | _ d | _d | _d | _d | _d S N)num_inference_stepssigmas	timesteps_step_index_begin_index)selfr   r   r   r   r   r   __init__N   s
   
z%LTXEulerAncestralRFScheduler.__init__returnc                 C      | j S r   )r!   r#   r   r   r   
step_index\   s   z'LTXEulerAncestralRFScheduler.step_indexc                 C   r&   )z
        The index for the first timestep. It can be set from a pipeline with `set_begin_index` to support
        image-to-image like workflows that start denoising part-way through the schedule.
        r"   r'   r   r   r   begin_index`   s   z(LTXEulerAncestralRFScheduler.begin_indexr   r*   c                 C   s
   || _ dS )z
        Included for API compatibility; not strictly needed here but kept to allow pipelines that call
        `set_begin_index`.
        Nr)   )r#   r*   r   r   r   set_begin_indexh   s   
z,LTXEulerAncestralRFScheduler.set_begin_indexNtimestepschedule_timestepsc                 C   sx   |du r| j du rtd| j }t|tjr||j}||k }t|dkr*dnd}t|dkr6td|| 	 S )a  
        Map a (continuous) `timestep` value to an index into `self.timesteps`.

        This follows the convention used in other discrete schedulers: if the same timestep value appears multiple
        times in the schedule (which can happen when starting in the middle of the schedule), the *second* occurrence
        is used for the first `step` call so that no sigma is accidentally skipped.
        N8Timesteps have not been set. Call `set_timesteps` first.r	   r   zaPassed `timestep` is not in `self.timesteps`. Make sure to use values from `scheduler.timesteps`.)
r    
ValueError
isinstancer   Tensortodevicenonzerolenitem)r#   r,   r-   indicesposr   r   r   index_for_timestepo   s   

z/LTXEulerAncestralRFScheduler.index_for_timestepc                 C   sR   | j du r	td| jdu r#t|tjr|| j j}| || _	dS | j
| _	dS )zO
        Initialize the internal step index based on a given timestep.
        Nr.   )r    r/   r*   r0   r   r1   r2   r3   r9   r!   r"   )r#   r,   r   r   r   _init_step_index   s   

z-LTXEulerAncestralRFScheduler._init_step_indexr   r3   r   r    muc                 K   s  |du rB|du rB|du rt dddlm} || j}|j||d|dd |j| _|jj|d| _|j	j|d| _	d| _
d| _dS |du rH|}t|trVtj|tjd}	nt|tjrd|jtjd}	n
tdt| d	|	jdkr~t d
t|	j d	|	d   dkrtd|	d   |dur|	|}	|	| _tt| jdd}
|	|
 | _	|dur|t|d krtd|t|d  t|d | _d| _
d| _dS )a  
        Set the sigma / timestep schedule for sampling.

        When `sigmas` or `timesteps` are provided explicitly, they are used as the RF sigma schedule (ComfyUI-style)
        and are expected to include the terminal 0.0. When both are `None`, the scheduler reuses the
        [`FlowMatchEulerDiscreteScheduler`] logic to generate sigmas from `num_inference_steps` and the stored config
        (including any resolution-dependent shifting, Karras/beta schedules, etc.).

        Args:
            num_inference_steps (`int`, *optional*):
                Number of denoising steps. If provided together with explicit `sigmas`/`timesteps`, they are expected
                to be consistent and are otherwise ignored with a warning.
            device (`str` or `torch.device`, *optional*):
                Device to move the internal tensors to.
            sigmas (`list[float]` or `torch.Tensor`, *optional*):
                Explicit sigma schedule, e.g. `[1.0, 0.99, ..., 0.0]`.
            timesteps (`list[float]` or `torch.Tensor`, *optional*):
                Optional alias for `sigmas`. If `sigmas` is None and `timesteps` is provided, timesteps are treated as
                sigmas.
            mu (`float`, *optional*):
                Optional shift parameter used when delegating to [`FlowMatchEulerDiscreteScheduler.set_timesteps`] and
                `config.use_dynamic_shifting` is `True`.
        NzzLTXEulerAncestralRFScheduler.set_timesteps requires either explicit `sigmas`/`timesteps` or a `num_inference_steps` value.r	   )r   )r   r3   r   r;   r    )r3   )dtypez-`sigmas` must be a list or torch.Tensor, got .z(`sigmas` must be a 1D tensor, got shape gư>zThe last sigma in the schedule is not zero (%.6f). For best compatibility with ComfyUI's RF sampler, the terminal sigma should be 0.0.r   r   z{Provided `num_inference_steps=%d` does not match `len(sigmas)-1=%d`. Overriding `num_inference_steps` with `len(sigmas)-1`.)r/   $scheduling_flow_match_euler_discreter   from_configconfigset_timestepsr   r   r2   r    r!   r"   r0   listr   tensorfloat32r1   	TypeErrortypendimtupleshapeabsr6   loggerwarningfloatgetattrr5   )r#   r   r3   r   r    r;   kwargsr   base_schedulersigmas_tensor	num_trainr   r   r   rB      s`   !






z*LTXEulerAncestralRFScheduler.set_timestepssigmasamplec                 C   s2   |j |j k r|jg |jdR  }|j |j k s|S )zN
        Helper to broadcast a scalar sigma to the shape of `sample`.
        r	   )rH   viewrJ   )r#   rT   rU   r   r   r   _sigma_broadcast  s   z-LTXEulerAncestralRFScheduler._sigma_broadcastTmodel_output	generatorreturn_dictc                 C   s&  t |ttjtjfrtd| jdu s| jdu rtd| jdu r&| 	| | j}|t
| jd kr5|}n|tj}|tj}	| j| }
| j|d  }| |
d|}| |d|}|||	  }|  dk rp|}nt| jj}t| jj}d||
 d |  }|| }d| }d| }| |d|}| |d|}| |d|}|| }|| d| |  }|dkr|dkr|d |d |d  |d d	   jdd
 }t|j||j|jd}||d	  | || |  }||j}t| jd t
| jd | _|s|fS t|dS )aQ  
        Perform a single Euler-Ancestral RF update step.

        Args:
            model_output (`torch.FloatTensor`):
                Raw model output at the current step. Interpreted under the CONST parametrization as `v_t`, with
                denoised state reconstructed as `x0 = x_t - sigma_t * v_t`.
            timestep (`float` or `torch.Tensor`):
                The current sigma value (must match one entry in `self.timesteps`).
            sample (`torch.FloatTensor`):
                Current latent sample `x_t`.
            generator (`torch.Generator`, *optional*):
                Optional generator for reproducible noise.
            return_dict (`bool`):
                If `True`, return a `LTXEulerAncestralRFSchedulerOutput`; otherwise return a tuple where the first
                element is the updated sample.
        zPassing integer indices (e.g. from `enumerate(timesteps)`) as timesteps to `LTXEulerAncestralRFScheduler.step()` is not supported. Make sure to pass one of the `scheduler.timesteps` values as `timestep`.NzGScheduler has not been initialized. Call `set_timesteps` before `step`.r	   g:0yE>r   g        r   g-q=)min)rY   r3   r<   )r   )r0   intr   	IntTensor
LongTensorr/   r   r    r!   r:   r5   r2   rE   rW   rV   rK   r6   rN   rA   r   r   clampsqrtr   rJ   r3   r<   r[   r   )r#   rX   r,   rU   rY   rZ   ir   sample_fmodel_output_frT   
sigma_nextsigma_bsigma_next_bdenoisedxr   r   downstep_ratio
sigma_down	alpha_ip1
alpha_downsigma_down_balpha_ip1_balpha_down_bsigma_ratiorenoise_coeffnoiser   r   r   step  s\   


"
z!LTXEulerAncestralRFScheduler.stepc                 C   s   t t| jddS )Nr   r   )r\   rO   rA   r'   r   r   r   __len__~  s   z$LTXEulerAncestralRFScheduler.__len__)r   r   r   )r   r   )NNNNN)NT)r   r   r   r   _compatiblesorderr   r\   rN   r$   propertyr(   r*   r+   r   r1   r9   r:   strr3   rC   rB   rW   r   	Generatorboolr   rI   rs   rt   r   r   r   r   r   3   s|    
!
o
ir   )r   dataclassesr   r   configuration_utilsr   r   utilsr   r   utils.torch_utilsr   scheduling_utilsr
   
get_loggerr   rL   r   r   r   r   r   r   <module>   s   

