


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      ):






			"""simple docstring"""






			_UpperCamelCase		:					torch.FloatTensor







class        lowerCamelCase__	(							nn.Module      ):






			"""simple docstring"""






			def __init__(							self      ,						snake_case=3      ,						snake_case=3      ,						snake_case=("DownEncoderBlock2D",)      ,						snake_case=(64,)      ,						snake_case=2      ,						snake_case=32      ,						snake_case="silu"      ,						snake_case=True      ,						):

						'''simple docstring'''


						super().__init__()
						UpperCamelCase__					=       layers_per_block

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

						UpperCamelCase__					=       None
						UpperCamelCase__					=       nn.ModuleList([]     )

						# down
						UpperCamelCase__					=       block_out_channels[0]
						for i, down_block_type in enumerate(snake_case     ):
									UpperCamelCase__					=       output_channel
									UpperCamelCase__					=       block_out_channels[i]
									UpperCamelCase__					=       i == len(snake_case     ) - 1

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

						# mid
						UpperCamelCase__					=       UNetMidBlockaD(
						    in_channels=block_out_channels[-1]      ,						resnet_eps=1E-6      ,						resnet_act_fn=snake_case      ,						output_scale_factor=1      ,						resnet_time_scale_shift="default"      ,						attention_head_dim=block_out_channels[-1]      ,						resnet_groups=snake_case      ,						temb_channels=snake_case      ,						)

						# out
						UpperCamelCase__					=       nn.GroupNorm(num_channels=block_out_channels[-1]      ,						num_groups=snake_case      ,						eps=1E-6     )
						UpperCamelCase__					=       nn.SiLU()

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

						UpperCamelCase__					=       False







			def 				snake_case__				(							self      ,						snake_case     ):

						'''simple docstring'''


						UpperCamelCase__					=       x
						UpperCamelCase__					=       self.conv_in(snake_case     )

						if self.training and self.gradient_checkpointing:

									def create_custom_forward(snake_case     ):
												def custom_forward(*snake_case     ):
															return module(*snake_case     )

												return custom_forward

									# down
									if is_torch_version(">="      ,						"1.11.0"     ):
												for down_block in self.down_blocks:
															UpperCamelCase__					=       torch.utils.checkpoint.checkpoint(
															    create_custom_forward(snake_case     )      ,						snake_case      ,						use_reentrant=snake_case     )
												# middle
												UpperCamelCase__					=       torch.utils.checkpoint.checkpoint(
												    create_custom_forward(self.mid_block     )      ,						snake_case      ,						use_reentrant=snake_case     )
									else:
												for down_block in self.down_blocks:
															UpperCamelCase__					=       torch.utils.checkpoint.checkpoint(create_custom_forward(snake_case     )      ,						snake_case     )
												# middle
												UpperCamelCase__					=       torch.utils.checkpoint.checkpoint(create_custom_forward(self.mid_block     )      ,						snake_case     )

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

									# middle
									UpperCamelCase__					=       self.mid_block(snake_case     )

						# post-process
						UpperCamelCase__					=       self.conv_norm_out(snake_case     )
						UpperCamelCase__					=       self.conv_act(snake_case     )
						UpperCamelCase__					=       self.conv_out(snake_case     )

						return sample







class        lowerCamelCase__	(							nn.Module      ):






			"""simple docstring"""






			def __init__(							self      ,						snake_case=3      ,						snake_case=3      ,						snake_case=("UpDecoderBlock2D",)      ,						snake_case=(64,)      ,						snake_case=2      ,						snake_case=32      ,						snake_case="silu"      ,						snake_case="group"      ,						):

						'''simple docstring'''


						super().__init__()
						UpperCamelCase__					=       layers_per_block

						UpperCamelCase__					=       nn.Convad(
						    snake_case      ,						block_out_channels[-1]      ,						kernel_size=3      ,						stride=1      ,						padding=1      ,						)

						UpperCamelCase__					=       None
						UpperCamelCase__					=       nn.ModuleList([]     )

						UpperCamelCase__					=       in_channels if norm_type == "spatial" else None

						# mid
						UpperCamelCase__					=       UNetMidBlockaD(
						    in_channels=block_out_channels[-1]      ,						resnet_eps=1E-6      ,						resnet_act_fn=snake_case      ,						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=snake_case      ,						temb_channels=snake_case      ,						)

						# up
						UpperCamelCase__					=       list(reversed(snake_case     )     )
						UpperCamelCase__					=       reversed_block_out_channels[0]
						for i, up_block_type in enumerate(snake_case     ):
									UpperCamelCase__					=       output_channel
									UpperCamelCase__					=       reversed_block_out_channels[i]

									UpperCamelCase__					=       i == len(snake_case     ) - 1

									UpperCamelCase__					=       get_up_block(
									    snake_case      ,						num_layers=self.layers_per_block + 1      ,						in_channels=snake_case      ,						out_channels=snake_case      ,						prev_output_channel=snake_case      ,						add_upsample=not is_final_block      ,						resnet_eps=1E-6      ,						resnet_act_fn=snake_case      ,						resnet_groups=snake_case      ,						attention_head_dim=snake_case      ,						temb_channels=snake_case      ,						resnet_time_scale_shift=snake_case      ,						)
									self.up_blocks.append(snake_case     )
									UpperCamelCase__					=       output_channel

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

						UpperCamelCase__					=       False







			def 				snake_case__				(							self      ,						snake_case      ,						snake_case=None     ):

						'''simple docstring'''


						UpperCamelCase__					=       z
						UpperCamelCase__					=       self.conv_in(snake_case     )

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

									def create_custom_forward(snake_case     ):
												def custom_forward(*snake_case     ):
															return module(*snake_case     )

												return custom_forward

									if is_torch_version(">="      ,						"1.11.0"     ):
												# middle
												UpperCamelCase__					=       torch.utils.checkpoint.checkpoint(
												    create_custom_forward(self.mid_block     )      ,						snake_case      ,						snake_case      ,						use_reentrant=snake_case     )
												UpperCamelCase__					=       sample.to(snake_case     )

												# up
												for up_block in self.up_blocks:
															UpperCamelCase__					=       torch.utils.checkpoint.checkpoint(
															    create_custom_forward(snake_case     )      ,						snake_case      ,						snake_case      ,						use_reentrant=snake_case     )
									else:
												# middle
												UpperCamelCase__					=       torch.utils.checkpoint.checkpoint(
												    create_custom_forward(self.mid_block     )      ,						snake_case      ,						snake_case     )
												UpperCamelCase__					=       sample.to(snake_case     )

												# up
												for up_block in self.up_blocks:
															UpperCamelCase__					=       torch.utils.checkpoint.checkpoint(create_custom_forward(snake_case     )      ,						snake_case      ,						snake_case     )
						else:
									# middle
									UpperCamelCase__					=       self.mid_block(snake_case      ,						snake_case     )
									UpperCamelCase__					=       sample.to(snake_case     )

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

        # post-process
						if latent_embeds is None:
									UpperCamelCase__					=       self.conv_norm_out(snake_case     )
						else:
									UpperCamelCase__					=       self.conv_norm_out(snake_case      ,						snake_case     )
						UpperCamelCase__					=       self.conv_act(snake_case     )
						UpperCamelCase__					=       self.conv_out(snake_case     )

						return sample







class        lowerCamelCase__	(							nn.Module      ):






			"""simple docstring"""






			def __init__(							self      ,						snake_case      ,						snake_case      ,						snake_case      ,						snake_case=None      ,						snake_case="random"      ,						snake_case=False      ,						snake_case=True     ):

						'''simple docstring'''


						super().__init__()
						UpperCamelCase__					=       n_e
						UpperCamelCase__					=       vq_embed_dim
						UpperCamelCase__					=       beta
						UpperCamelCase__					=       legacy

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

						UpperCamelCase__					=       remap
						if self.remap is not None:
									self.register_buffer("used"      ,						torch.tensor(np.load(self.remap     )     )     )
									UpperCamelCase__					=       self.used.shape[0]
									UpperCamelCase__					=       unknown_index  # "random" or "extra" or integer
									if self.unknown_index == "extra":
												UpperCamelCase__					=       self.re_embed
												UpperCamelCase__					=       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:
									UpperCamelCase__					=       n_e

						UpperCamelCase__					=       sane_index_shape




			def 				snake_case__				(							self      ,						snake_case     ):

						'''simple docstring'''


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




			def 				snake_case__				(							self      ,						snake_case     ):

						'''simple docstring'''


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




			def 				snake_case__				(							self      ,						snake_case     ):

						'''simple docstring'''


						UpperCamelCase__					=       z.permute(0      ,						2      ,						3      ,						1     ).contiguous()
						UpperCamelCase__					=       z.view(-1      ,						self.vq_embed_dim     )

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

						UpperCamelCase__					=       self.embedding(snake_case     ).view(z.shape     )
						UpperCamelCase__					=       None
						UpperCamelCase__					=       None

						# compute loss for embedding
						if not self.legacy:
									UpperCamelCase__					=       self.beta * torch.mean((z_q.detach() - z) ** 2     ) + torch.mean((z_q - z.detach()) ** 2     )
						else:
									UpperCamelCase__					=       torch.mean((z_q.detach() - z) ** 2     ) + self.beta * torch.mean((z_q - z.detach()) ** 2     )

						# preserve gradients
						UpperCamelCase__					=       z + (z_q - z).detach()

						# reshape back to match original input shape
						UpperCamelCase__					=       z_q.permute(0      ,						3      ,						1      ,						2     ).contiguous()

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

						if self.sane_index_shape:
									UpperCamelCase__					=       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      ,						snake_case      ,						snake_case     ):

						'''simple docstring'''


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

						# get quantized latent vectors
						UpperCamelCase__					=       self.embedding(snake_case     )

						if shape is not None:
									UpperCamelCase__					=       z_q.view(snake_case     )
									# reshape back to match original input shape
									UpperCamelCase__					=       z_q.permute(0      ,						3      ,						1      ,						2     ).contiguous()

						return z_q







class        lowerCamelCase__	(							UpperCAmelCase      ):






			"""simple docstring"""






			def __init__(							self      ,						snake_case      ,						snake_case=False     ):

						'''simple docstring'''


						UpperCamelCase__					=       parameters
						UpperCamelCase__,      UpperCamelCase__					=       torch.chunk(snake_case      ,						2      ,						dim=1     )
						UpperCamelCase__					=       torch.clamp(self.logvar      ,						-30.0      ,						20.0     )
						UpperCamelCase__					=       deterministic
						UpperCamelCase__					=       torch.exp(0.5 * self.logvar     )
						UpperCamelCase__					=       torch.exp(self.logvar     )
						if self.deterministic:
									UpperCamelCase__					=       UpperCamelCase__					=       torch.zeros_like(
									    self.mean      ,						device=self.parameters.device      ,						dtype=self.parameters.dtype     )




			def 				snake_case__				(							self      ,						snake_case = None     ):

						'''simple docstring'''


						UpperCamelCase__					=       randn_tensor(
						    self.mean.shape      ,						generator=snake_case      ,						device=self.parameters.device      ,						dtype=self.parameters.dtype     )
						UpperCamelCase__					=       self.mean + self.std * sample
						return x




			def 				snake_case__				(							self      ,						snake_case=None     ):

						'''simple docstring'''


						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      ,						snake_case      ,						snake_case=[1, 2, 3]     ):

						'''simple docstring'''


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







			def 				snake_case__				(							self     ):

						'''simple docstring'''


						return self.mean






def        UpperCamelCase_(				_A   :List[str]				,     _A   :Tuple				,     _A   :Any				,     _A   :Tuple				,     _A   :Optional[int]				,     _A   :str  )->		List[str]:
			if index == r:
						for j in range(_A  ):
									print(data[j]				,     end=" "  )
						print(" "  )
						return
			#  When no more elements are there to put in data[]
			if i >= n:
						return
			# current is included, put next at next location
			UpperCamelCase__					=       arr[i]
			combination_util(_A				,     _A				,     _A				,     index + 1				,     _A				,     i + 1  )
			# current is excluded, replace it with
			# next (Note that i+1 is passed, but
			# index is not changed)
			combination_util(_A				,     _A				,     _A				,     _A				,     _A				,     i + 1  )
			# The main function that prints all combinations
			# of size r in arr[] of size n. This function
			# mainly uses combinationUtil()
def        UpperCamelCase_(				_A   :Dict				,     _A   :Optional[Any]				,     _A   :Union[str, Any]  )->		Optional[int]:
			# A temporary array to store all combination one by one
			UpperCamelCase__					=       [0] * r
			# Print all combination using temporary array 'data[]'
			combination_util(_A				,     _A				,     _A				,     0				,     _A				,     0  )


if __name__ == "__main__":
						# Driver code to check the function above
						__UpperCamelCase    		=       [1_0, 2_0, 3_0, 4_0, 5_0]
						print_combination(arr, len(arr), 3)
						# This code is contributed by Ambuj sahu


