from dataclasses import dataclass
from typing import Optional

import numpy as np
import torch
import torch.nn as nn

from ..utils import BaseOutput, is_torch_version, randn_tensor
from .attention_processor import SpatialNorm
from .unet_ad_blocks import UNetMidBlockaD, get_down_block, get_up_block
@dataclass
class   _lowerCAmelCase		(     UpperCamelCase_				):
							_UpperCAmelCase						    =     4_2


class   _lowerCAmelCase		(     nn.Module				):







							def __init__(				self     :    List[Any]	,					__snake_case     :    int=3	,					__snake_case     :    Optional[int]=3	,					__snake_case     :    Union[str, Any]=("DownEncoderBlock2D",)	,					__snake_case     :    Tuple=(64,)	,					__snake_case     :    List[str]=2	,					__snake_case     :    Union[str, Any]=32	,					__snake_case     :    str="silu"	,					__snake_case     :    int=True	,					):
										super().__init__()
										lowerCamelCase						:int						  =     layers_per_block

										lowerCamelCase						:Dict						  =     torch.nn.Convad(
										    UpperCamelCase__	,					block_out_channels[0]	,					kernel_size=3	,					stride=1	,					padding=1	,					)

										lowerCamelCase						:Optional[Any]						  =     None
										lowerCamelCase						:Union[str, Any]						  =     nn.ModuleList([]		)

										# down
										lowerCamelCase						:Union[str, Any]						  =     block_out_channels[0]
										for i, down_block_type in enumerate(UpperCamelCase__		):
													lowerCamelCase						:Optional[int]						  =     output_channel
													lowerCamelCase						:List[str]						  =     block_out_channels[i]
													lowerCamelCase						:Tuple						  =     i == len(UpperCamelCase__		) - 1

													lowerCamelCase						:Any						  =     get_down_block(
													    UpperCamelCase__	,					num_layers=self.layers_per_block	,					in_channels=UpperCamelCase__	,					out_channels=UpperCamelCase__	,					add_downsample=not is_final_block	,					resnet_eps=1e-6	,					downsample_padding=0	,					resnet_act_fn=UpperCamelCase__	,					resnet_groups=UpperCamelCase__	,					attention_head_dim=UpperCamelCase__	,					temb_channels=UpperCamelCase__	,					)
													self.down_blocks.append(UpperCamelCase__		)

										# mid
										lowerCamelCase						:Optional[int]						  =     UNetMidBlockaD(
										    in_channels=block_out_channels[-1]	,					resnet_eps=1e-6	,					resnet_act_fn=UpperCamelCase__	,					output_scale_factor=1	,					resnet_time_scale_shift='''default'''	,					attention_head_dim=block_out_channels[-1]	,					resnet_groups=UpperCamelCase__	,					temb_channels=UpperCamelCase__	,					)

										# out
										lowerCamelCase						:Any						  =     nn.GroupNorm(num_channels=block_out_channels[-1]	,					num_groups=UpperCamelCase__	,					eps=1e-6		)
										lowerCamelCase						:Optional[int]						  =     nn.SiLU()

										lowerCamelCase						:int						  =     2 * out_channels if double_z else out_channels
										lowerCamelCase						:int						  =     nn.Convad(block_out_channels[-1]	,					UpperCamelCase__	,					3	,					padding=1		)

										lowerCamelCase						:List[Any]						  =     False







							def 				snake_case  (				self     :    Tuple	,					__snake_case     :    List[str]		):
										lowerCamelCase						:Any						  =     x
										lowerCamelCase						:Tuple						  =     self.conv_in(UpperCamelCase__		)

										if self.training and self.gradient_checkpointing:

													def create_custom_forward(__snake_case     :    Union[str, Any]		):
																def custom_forward(*__snake_case     :    List[str]		):
																			return module(*UpperCamelCase__		)

																return custom_forward

													# down
													if is_torch_version('''>='''	,					'''1.11.0'''		):
																for down_block in self.down_blocks:
																			lowerCamelCase						:Optional[int]						  =     torch.utils.checkpoint.checkpoint(
																			    create_custom_forward(UpperCamelCase__		)	,					UpperCamelCase__	,					use_reentrant=UpperCamelCase__		)
																# middle
																lowerCamelCase						:Any						  =     torch.utils.checkpoint.checkpoint(
																    create_custom_forward(self.mid_block		)	,					UpperCamelCase__	,					use_reentrant=UpperCamelCase__		)
													else:
																for down_block in self.down_blocks:
																			lowerCamelCase						:Union[str, Any]						  =     torch.utils.checkpoint.checkpoint(create_custom_forward(UpperCamelCase__		)	,					UpperCamelCase__		)
																# middle
																lowerCamelCase						:Tuple						  =     torch.utils.checkpoint.checkpoint(create_custom_forward(self.mid_block		)	,					UpperCamelCase__		)

										else:
													# down
													for down_block in self.down_blocks:
																lowerCamelCase						:str						  =     down_block(UpperCamelCase__		)

													# middle
													lowerCamelCase						:Optional[Any]						  =     self.mid_block(UpperCamelCase__		)

										# post-process
										lowerCamelCase						:Dict						  =     self.conv_norm_out(UpperCamelCase__		)
										lowerCamelCase						:Union[str, Any]						  =     self.conv_act(UpperCamelCase__		)
										lowerCamelCase						:Any						  =     self.conv_out(UpperCamelCase__		)

										return sample


class   _lowerCAmelCase		(     nn.Module				):







							def __init__(				self     :    List[str]	,					__snake_case     :    int=3	,					__snake_case     :    Optional[Any]=3	,					__snake_case     :    Any=("UpDecoderBlock2D",)	,					__snake_case     :    Union[str, Any]=(64,)	,					__snake_case     :    List[Any]=2	,					__snake_case     :    Optional[int]=32	,					__snake_case     :    List[Any]="silu"	,					__snake_case     :    Optional[Any]="group"	,					):
										super().__init__()
										lowerCamelCase						:Dict						  =     layers_per_block

										lowerCamelCase						:List[Any]						  =     nn.Convad(
										    UpperCamelCase__	,					block_out_channels[-1]	,					kernel_size=3	,					stride=1	,					padding=1	,					)

										lowerCamelCase						:List[str]						  =     None
										lowerCamelCase						:Tuple						  =     nn.ModuleList([]		)

										lowerCamelCase						:int						  =     in_channels if norm_type == '''spatial''' else None

										# mid
										lowerCamelCase						:Any						  =     UNetMidBlockaD(
										    in_channels=block_out_channels[-1]	,					resnet_eps=1e-6	,					resnet_act_fn=UpperCamelCase__	,					output_scale_factor=1	,					resnet_time_scale_shift='''default''' if norm_type == '''group''' else norm_type	,					attention_head_dim=block_out_channels[-1]	,					resnet_groups=UpperCamelCase__	,					temb_channels=UpperCamelCase__	,					)

										# up
										lowerCamelCase						:int						  =     list(reversed(UpperCamelCase__		)		)
										lowerCamelCase						:List[Any]						  =     reversed_block_out_channels[0]
										for i, up_block_type in enumerate(UpperCamelCase__		):
													lowerCamelCase						:List[str]						  =     output_channel
													lowerCamelCase						:Optional[int]						  =     reversed_block_out_channels[i]

													lowerCamelCase						:int						  =     i == len(UpperCamelCase__		) - 1

													lowerCamelCase						:Dict						  =     get_up_block(
													    UpperCamelCase__	,					num_layers=self.layers_per_block + 1	,					in_channels=UpperCamelCase__	,					out_channels=UpperCamelCase__	,					prev_output_channel=UpperCamelCase__	,					add_upsample=not is_final_block	,					resnet_eps=1e-6	,					resnet_act_fn=UpperCamelCase__	,					resnet_groups=UpperCamelCase__	,					attention_head_dim=UpperCamelCase__	,					temb_channels=UpperCamelCase__	,					resnet_time_scale_shift=UpperCamelCase__	,					)
													self.up_blocks.append(UpperCamelCase__		)
													lowerCamelCase						:Optional[int]						  =     output_channel

										# out
										if norm_type == "spatial":
													lowerCamelCase						:List[str]						  =     SpatialNorm(block_out_channels[0]	,					UpperCamelCase__		)
										else:
													lowerCamelCase						:List[Any]						  =     nn.GroupNorm(num_channels=block_out_channels[0]	,					num_groups=UpperCamelCase__	,					eps=1e-6		)
										lowerCamelCase						:List[Any]						  =     nn.SiLU()
										lowerCamelCase						:str						  =     nn.Convad(block_out_channels[0]	,					UpperCamelCase__	,					3	,					padding=1		)

										lowerCamelCase						:Any						  =     False







							def 				snake_case  (				self     :    Optional[int]	,					__snake_case     :    Any	,					__snake_case     :    Dict=None		):
										lowerCamelCase						:int						  =     z
										lowerCamelCase						:Any						  =     self.conv_in(UpperCamelCase__		)

										lowerCamelCase						:Any						  =     next(iter(self.up_blocks.parameters()		)		).dtype
										if self.training and self.gradient_checkpointing:

													def create_custom_forward(__snake_case     :    Optional[int]		):
																def custom_forward(*__snake_case     :    Dict		):
																			return module(*UpperCamelCase__		)

																return custom_forward

													if is_torch_version('''>='''	,					'''1.11.0'''		):
																# middle
																lowerCamelCase						:List[str]						  =     torch.utils.checkpoint.checkpoint(
																    create_custom_forward(self.mid_block		)	,					UpperCamelCase__	,					UpperCamelCase__	,					use_reentrant=UpperCamelCase__		)
																lowerCamelCase						:Optional[int]						  =     sample.to(UpperCamelCase__		)

																# up
																for up_block in self.up_blocks:
																			lowerCamelCase						:List[str]						  =     torch.utils.checkpoint.checkpoint(
																			    create_custom_forward(UpperCamelCase__		)	,					UpperCamelCase__	,					UpperCamelCase__	,					use_reentrant=UpperCamelCase__		)
													else:
																# middle
																lowerCamelCase						:Dict						  =     torch.utils.checkpoint.checkpoint(
																    create_custom_forward(self.mid_block		)	,					UpperCamelCase__	,					UpperCamelCase__		)
																lowerCamelCase						:List[str]						  =     sample.to(UpperCamelCase__		)

																# up
																for up_block in self.up_blocks:
																			lowerCamelCase						:Tuple						  =     torch.utils.checkpoint.checkpoint(create_custom_forward(UpperCamelCase__		)	,					UpperCamelCase__	,					UpperCamelCase__		)
										else:
													# middle
													lowerCamelCase						:Optional[Any]						  =     self.mid_block(UpperCamelCase__	,					UpperCamelCase__		)
													lowerCamelCase						:Optional[int]						  =     sample.to(UpperCamelCase__		)

													# up
													for up_block in self.up_blocks:
																lowerCamelCase						:Any						  =     up_block(UpperCamelCase__	,					UpperCamelCase__		)

        # post-process
										if latent_embeds is None:
													lowerCamelCase						:str						  =     self.conv_norm_out(UpperCamelCase__		)
										else:
													lowerCamelCase						:Dict						  =     self.conv_norm_out(UpperCamelCase__	,					UpperCamelCase__		)
										lowerCamelCase						:str						  =     self.conv_act(UpperCamelCase__		)
										lowerCamelCase						:Union[str, Any]						  =     self.conv_out(UpperCamelCase__		)

										return sample


class   _lowerCAmelCase		(     nn.Module				):







							def __init__(				self     :    int	,					__snake_case     :    Union[str, Any]	,					__snake_case     :    Dict	,					__snake_case     :    List[Any]	,					__snake_case     :    Optional[Any]=None	,					__snake_case     :    Tuple="random"	,					__snake_case     :    Dict=False	,					__snake_case     :    Optional[Any]=True		):
										super().__init__()
										lowerCamelCase						:Optional[Any]						  =     n_e
										lowerCamelCase						:Tuple						  =     vq_embed_dim
										lowerCamelCase						:Union[str, Any]						  =     beta
										lowerCamelCase						:List[str]						  =     legacy

										lowerCamelCase						:Dict						  =     nn.Embedding(self.n_e	,					self.vq_embed_dim		)
										self.embedding.weight.data.uniform_(-1.0 / self.n_e	,					1.0 / self.n_e		)

										lowerCamelCase						:str						  =     remap
										if self.remap is not None:
													self.register_buffer('''used'''	,					torch.tensor(np.load(self.remap		)		)		)
													lowerCamelCase						:Union[str, Any]						  =     self.used.shape[0]
													lowerCamelCase						:List[str]						  =     unknown_index  # "random" or "extra" or integer
													if self.unknown_index == "extra":
																lowerCamelCase						:List[str]						  =     self.re_embed
																lowerCamelCase						:Tuple						  =     self.re_embed + 1
													print(
													    F"Remapping {self.n_e} indices to {self.re_embed} indices. "
													    F"Using {self.unknown_index} for unknown indices."		)
										else:
													lowerCamelCase						:Dict						  =     n_e

										lowerCamelCase						:int						  =     sane_index_shape







							def 				snake_case  (				self     :    Tuple	,					__snake_case     :    Union[str, Any]		):
										lowerCamelCase						:Union[str, Any]						  =     inds.shape
										assert len(UpperCamelCase__		) > 1
										lowerCamelCase						:Optional[int]						  =     inds.reshape(ishape[0]	,					-1		)
										lowerCamelCase						:int						  =     self.used.to(UpperCamelCase__		)
										lowerCamelCase						:List[str]						  =     (inds[:, :, None] == used[None, None, ...]).long()
										lowerCamelCase						:Union[str, Any]						  =     match.argmax(-1		)
										lowerCamelCase						:List[Any]						  =     match.sum(2		) < 1
										if self.unknown_index == "random":
													lowerCamelCase						:Optional[Any]						  =     torch.randint(0	,					self.re_embed	,					size=new[unknown].shape		).to(device=new.device		)
										else:
													lowerCamelCase						:str						  =     self.unknown_index
										return new.reshape(UpperCamelCase__		)







							def 				snake_case  (				self     :    List[str]	,					__snake_case     :    Dict		):
										lowerCamelCase						:Optional[Any]						  =     inds.shape
										assert len(UpperCamelCase__		) > 1
										lowerCamelCase						:List[Any]						  =     inds.reshape(ishape[0]	,					-1		)
										lowerCamelCase						:Optional[Any]						  =     self.used.to(UpperCamelCase__		)
										if self.re_embed > self.used.shape[0]:  # extra token
													lowerCamelCase						:Any						  =     0  # simply set to zero
										lowerCamelCase						:Any						  =     torch.gather(used[None, :][inds.shape[0] * [0], :]	,					1	,					UpperCamelCase__		)
										return back.reshape(UpperCamelCase__		)







							def 				snake_case  (				self     :    int	,					__snake_case     :    Dict		):
										lowerCamelCase						:List[Any]						  =     z.permute(0	,					2	,					3	,					1		).contiguous()
										lowerCamelCase						:Any						  =     z.view(-1	,					self.vq_embed_dim		)

										# distances from z to embeddings e_j (z - e)^2 = z^2 + e^2 - 2 e * z
										lowerCamelCase						:Dict						  =     torch.argmin(torch.cdist(UpperCamelCase__	,					self.embedding.weight		)	,					dim=1		)

										lowerCamelCase						:List[Any]						  =     self.embedding(UpperCamelCase__		).view(z.shape		)
										lowerCamelCase						:Union[str, Any]						  =     None
										lowerCamelCase						:Any						  =     None

										# compute loss for embedding
										if not self.legacy:
													lowerCamelCase						:Optional[int]						  =     self.beta * torch.mean((z_q.detach() - z) ** 2		) + torch.mean((z_q - z.detach()) ** 2		)
										else:
													lowerCamelCase						:Union[str, Any]						  =     torch.mean((z_q.detach() - z) ** 2		) + self.beta * torch.mean((z_q - z.detach()) ** 2		)

										# preserve gradients
										lowerCamelCase						:List[Any]						  =     z + (z_q - z).detach()

										# reshape back to match original input shape
										lowerCamelCase						:Optional[Any]						  =     z_q.permute(0	,					3	,					1	,					2		).contiguous()

										if self.remap is not None:
													lowerCamelCase						:Optional[Any]						  =     min_encoding_indices.reshape(z.shape[0]	,					-1		)  # add batch axis
													lowerCamelCase						:Optional[Any]						  =     self.remap_to_used(UpperCamelCase__		)
													lowerCamelCase						:str						  =     min_encoding_indices.reshape(-1	,					1		)  # flatten

										if self.sane_index_shape:
													lowerCamelCase						:List[Any]						  =     min_encoding_indices.reshape(z_q.shape[0]	,					z_q.shape[2]	,					z_q.shape[3]		)

										return z_q, loss, (perplexity, min_encodings, min_encoding_indices)







							def 				snake_case  (				self     :    Union[str, Any]	,					__snake_case     :    Optional[Any]	,					__snake_case     :    Any		):





										if self.remap is not None:
													lowerCamelCase						:Any						  =     indices.reshape(shape[0]	,					-1		)  # add batch axis
													lowerCamelCase						:List[str]						  =     self.unmap_to_all(UpperCamelCase__		)
													lowerCamelCase						:int						  =     indices.reshape(-1		)  # flatten again

										# get quantized latent vectors
										lowerCamelCase						:Any						  =     self.embedding(UpperCamelCase__		)

										if shape is not None:
													lowerCamelCase						:List[Any]						  =     z_q.view(UpperCamelCase__		)
													# reshape back to match original input shape
													lowerCamelCase						:Dict						  =     z_q.permute(0	,					3	,					1	,					2		).contiguous()

										return z_q


class   _lowerCAmelCase		(     UpperCamelCase_				):







							def __init__(				self     :    Union[str, Any]	,					__snake_case     :    Any	,					__snake_case     :    List[str]=False		):
										lowerCamelCase						:List[Any]						  =     parameters
										lowerCamelCase						:Dict						  =     torch.chunk(UpperCamelCase__	,					2	,					dim=1		)
										lowerCamelCase						:Any						  =     torch.clamp(self.logvar	,					-3_0.0	,					2_0.0		)
										lowerCamelCase						:Optional[int]						  =     deterministic
										lowerCamelCase						:Optional[Any]						  =     torch.exp(0.5 * self.logvar		)
										lowerCamelCase						:Tuple						  =     torch.exp(self.logvar		)
										if self.deterministic:
													lowerCamelCase						:int						  =     torch.zeros_like(
													    self.mean	,					device=self.parameters.device	,					dtype=self.parameters.dtype		)







							def 				snake_case  (				self     :    Any	,					__snake_case     :    Optional[torch.Generator] = None		):
										lowerCamelCase						:int						  =     randn_tensor(
										    self.mean.shape	,					generator=UpperCamelCase__	,					device=self.parameters.device	,					dtype=self.parameters.dtype		)
										lowerCamelCase						:Union[str, Any]						  =     self.mean + self.std * sample
										return x







							def 				snake_case  (				self     :    str	,					__snake_case     :    str=None		):





										if self.deterministic:
													return torch.Tensor([0.0]		)
										else:
													if other is None:
																return 0.5 * torch.sum(torch.pow(self.mean	,					2		) + self.var - 1.0 - self.logvar	,					dim=[1, 2, 3]		)
													else:
																return 0.5 * torch.sum(
																    torch.pow(self.mean - other.mean	,					2		) / other.var
																    + self.var / other.var
																    - 1.0
																    - self.logvar
																    + other.logvar	,					dim=[1, 2, 3]	,					)







							def 				snake_case  (				self     :    List[Any]	,					__snake_case     :    Tuple	,					__snake_case     :    str=[1, 2, 3]		):





										if self.deterministic:
													return torch.Tensor([0.0]		)
										lowerCamelCase						:Optional[Any]						  =     np.log(2.0 * np.pi		)
										return 0.5 * torch.sum(logtwopi + self.logvar + torch.pow(sample - self.mean	,					2		) / self.var	,					dim=UpperCamelCase__		)







							def 				snake_case  (				self     :    List[str]		):
										return self.mean




def  _lowerCamelCase					(   a_				: str						,			a_				: str):
			lowerCamelCase						:List[str]						  =     len(a_)
			lowerCamelCase						:List[str]						  =     len(a_)
			lowerCamelCase						:int						  =     [[False for _ in range(m + 1)] for _ in range(n + 1)]
			lowerCamelCase						:Optional[Any]						  =     True
			for i in range(a_):
						for j in range(m + 1):
									if dp[i][j]:
												if j < m and a[i].upper() == b[j]:
															lowerCamelCase						:Any						  =     True
												if a[i].islower():
															lowerCamelCase						:List[str]						  =     True
			return dp[n][m]


if __name__ == "__main__":
			import doctest

			doctest.testmod()



