o
    Ni4                     @   s   d dl Z d dlZd dlmZ ddlmZmZ ddlmZmZm	Z	m
Z
mZ G dd dejjZddddddddddd	
d
dZdd Zdd ZdS )    N   )SOLVERSodeint)_check_inputs_flat_to_shape_mixed_norm_all_callback_names_all_adjoint_callback_namesc                   @   s$   e Zd Zedd Zedd ZdS )OdeintAdjointMethodc                 G   s   || _ || _|
| _|| _|| _|| _|| _|	d u| _t	 = t
||||||||	d}|	d u r<|}| j||g|R   n|\}}| j|||g|R   W d    |S W d    |S 1 s^w   Y  |S )N)rtolatolmethodoptionsevent_fn)shapesfuncadjoint_rtoladjoint_atoladjoint_methodadjoint_optionst_requires_grad
event_modetorchno_gradr   save_for_backward)ctxr   r   y0tr   r   r   r   r   r   r   r   r   r   adjoint_paramsansyevent_t r"   M/home/ubuntu/.local/lib/python3.10/site-packages/torchdiffeq/_impl/adjoint.pyforward
   s,   






zOdeintAdjointMethod.forwardc                    s  t  / | j| j}| j}| j}| j}| j| j}|r:| j	^}}}	 |}
t 
|d d|	dg}|d }n
| j	^}} |d }t  t jd|j|jd|d |d g}|dd  D   fdd	}tttD ]\}}zt|}W n	 ty   Y qpw t||| qprt jt||j|jd}nd }tt|d ddD ]Y}r͈|| || }|d|| d}|d  |8  < |||< t|t|||d |d  d||||d
}dd |D }||d  |d< |d  ||d  7  < qr
|d |d< |r#r#t 
|d dt |
dd  g}|d }|dd  }W d    n	1 s8w   Y  d d ||d d d d d d d d d d g|R S )Nr   r   r"   )dtypedevicec                 S   s   g | ]}t |qS r"   r   
zeros_like.0paramr"   r"   r#   
<listcomp>A   s    z0OdeintAdjointMethod.backward.<locals>.<listcomp>c                    s  |d }|d }t  K |  }|d} | d}r"| n||}t | dd}t |dd}tdd  D }t jj|| |f  | ddd^}	}
}W d    n1 sZw   Y  |	d u rht | n|	}	|
d u rst |n|
}
dd	 t	 |D }|	||
g|R S )
Nr      Tr"   c                 s   s    | ]
}t |d d V  qdS )r"   N)r   
as_stridedr*   r"   r"   r#   	<genexpr>\   s    zKOdeintAdjointMethod.backward.<locals>.augmented_dynamics.<locals>.<genexpr>)allow_unusedretain_graphc                 S   s&   g | ]\}}|d u rt |n|qS Nr(   )r+   r,   	vjp_paramr"   r"   r#   r-   f   s    zLOdeintAdjointMethod.backward.<locals>.augmented_dynamics.<locals>.<listcomp>)
r   enable_graddetachrequires_grad_r/   tupleautogradgradr)   zip)r   y_augr    adj_yt_	func_eval_t_y_paramsvjp_tvjp_y
vjp_paramsr   r   r   r"   r#   augmented_dynamicsH   s*   

z8OdeintAdjointMethod.backward.<locals>.augmented_dynamics)r   r   r   r   c                 S   s   g | ]}|d  qS )r   r"   )r+   ar"   r"   r#   r-          r.      )r   r   r   r   r   r   r   r   r   saved_tensorscatreshaper8   zerosr&   r'   extendr;   r   r	   getattrAttributeErrorsetattremptylenrangedotr   flipr)   )r   grad_yr   r   r   r   r   r   r    r!   r@   	aug_staterG   callback_nameadjoint_callback_namecallback	time_vjpsir?   	dLd_cur_tr=   
adj_paramsr"   rF   r#   backward#   sf   
"$&&tzOdeintAdjointMethod.backwardN)__name__
__module____qualname__staticmethodr$   ra   r"   r"   r"   r#   r
      s
    
r
   gHz>g&.>)
r   r   r   r   r   r   r   r   r   r   c       
         C   s  |d u rt | tjstd|d u r|}|	d u r|}	|
d u r |}
|
|kr0|d ur0|d u r0td|d u rD|d urAdd | D ni }n| }|d u rStt| }nt|}t|}tdd |D }t||kryd|v ryt	|d ryt
d t| |||||||t	\
}} }}}}}}}}|d }t||| tj|| |||||||||	|
||jg|R  }|d u r|}n|\}}||}|r| }|d urt|t|f|}|d u r|S ||fS )	Nzfunc must be an instance of nn.Module to specify the adjoint parameters; alternatively they can be specified explicitly via the `adjoint_params` argument. If there are no parameters then it is allowable to set `adjoint_params=()`.zIf `adjoint_method != method` then we cannot infer `adjoint_options` from `options`. So as `options` has been passed then `adjoint_options` must be passed as well.c                 S   s   i | ]\}}|d kr||qS )normr"   r+   kvr"   r"   r#   
<dictcomp>   s    z"odeint_adjoint.<locals>.<dictcomp>c                 s   s    | ]}|j r|V  qd S r3   )requires_grad)r+   pr"   r"   r#   r0      s    z!odeint_adjoint.<locals>.<genexpr>rf   zAn adjoint parameter was passed without requiring gradient. For efficiency this will be excluded from the adjoint pass, and will not appear as a tensor in the adjoint norm.)
isinstancennModule
ValueErroritemscopyr8   find_parametersrT   callablewarningswarnr   r   handle_adjoint_norm_r
   applyrk   tor   )r   r   r   r   r   r   r   r   r   r   r   r   r   oldlen_r   decreasing_time
state_normr   solutionr!   r"   r"   r#   odeint_adjoint   sP    
,
r~   c                 C   sJ   t | tjsJ t| ddrdd }| j|d}dd |D S t|  S )N_is_replicaFc                 S   s   dd | j  D }|S )Nc                 S   s(   g | ]\}}t |r|jr||fqS r"   )r   	is_tensorrk   rg   r"   r"   r#   r-      s   ( zCfind_parameters.<locals>.find_tensor_attributes.<locals>.<listcomp>)__dict__rq   )moduletuplesr"   r"   r#   find_tensor_attributes   s   z/find_parameters.<locals>.find_tensor_attributes)get_members_fnc                 S   s   g | ]\}}|qS r"   r"   )r+   _r,   r"   r"   r#   r-      rI   z#find_parameters.<locals>.<listcomp>)rm   rn   ro   rP   _named_memberslist
parameters)r   r   genr"   r"   r#   rs      s   rs   c                    s   fdd}d| vr|| d< dS z| d  W n t y$   || d< Y dS w  dkr5fdd}|| d< dS du r;dS  fdd	}|| d< dS )
zJIn-place modifies the adjoint options to choose or wrap the norm function.c                    s*   | ^}}}}t |  | |t|S r3   )maxabsr   tensor_tupler   r    r=   r`   r|   r"   r#   default_adjoint_norm   s   z2handle_adjoint_norm_.<locals>.default_adjoint_normrf   seminormc                    s$   | ^}}}}t |  | |S r3   )r   r   r   r   r"   r#   adjoint_seminorm  s   z.handle_adjoint_norm_.<locals>.adjoint_seminormNc                    s<   | ^}}}}t |d}t |d} |g|||R S )Nr"   )r   r   )adjoint_normr   r"   r#   _adjoint_norm  s   z+handle_adjoint_norm_.<locals>._adjoint_norm)KeyError)r   r   r|   r   r   r   r"   )r   r   r|   r#   rw      s   rw   )ru   r   torch.nnrn   r   r   miscr   r   r   r   r	   r9   Functionr
   r~   rs   rw   r"   r"   r"   r#   <module>   s     

F