






"""simple docstring"""



from dataclasses import dataclass
from typing import Dict, Optional, Tuple, Union

import torch
import torch.nn as nn

from ..configuration_utils import ConfigMixin, register_to_config
from ..utils import BaseOutput, apply_forward_hook
from .attention_processor import AttentionProcessor, AttnProcessor
from .modeling_utils import ModelMixin
from .vae import Decoder, DecoderOutput, DiagonalGaussianDistribution, Encoder

@dataclass
class        a     (   a_	):
    UpperCAmelCase_ :     "DiagonalGaussianDistribution"


class        a     (   a_,				a_	):
    UpperCAmelCase_ :     List[Any]	     =True







    @register_to_config
    def __init__(			self							,		_lowerCamelCase = 3							,		_lowerCamelCase = 3							,		_lowerCamelCase = ("DownEncoderBlock2D",)							,		_lowerCamelCase = ("UpDecoderBlock2D",)							,		_lowerCamelCase = (6_4,)							,		_lowerCamelCase = 1							,		_lowerCamelCase = "silu"							,		_lowerCamelCase = 4							,		_lowerCamelCase = 3_2							,		_lowerCamelCase = 3_2							,		_lowerCamelCase = 0.1_8_2_1_5							,		):
      super().__init__()

      # pass init params to Encoder
      lowercase							    =       Encoder(
          in_channels=_lowerCamelCase							,		out_channels=_lowerCamelCase							,		down_block_types=_lowerCamelCase							,		block_out_channels=_lowerCamelCase							,		layers_per_block=_lowerCamelCase							,		act_fn=_lowerCamelCase							,		norm_num_groups=_lowerCamelCase							,		double_z=_lowerCamelCase							,		)

      # pass init params to Decoder
      lowercase							    =       Decoder(
          in_channels=_lowerCamelCase							,		out_channels=_lowerCamelCase							,		up_block_types=_lowerCamelCase							,		block_out_channels=_lowerCamelCase							,		layers_per_block=_lowerCamelCase							,		norm_num_groups=_lowerCamelCase							,		act_fn=_lowerCamelCase							,		)

      lowercase							    =       nn.Convad(2 * latent_channels							,		2 * latent_channels							,		1       )
      lowercase							    =       nn.Convad(_lowerCamelCase							,		_lowerCamelCase							,		1       )

      lowercase							    =       False
      lowercase							    =       False

      # only relevant if vae tiling is enabled
      lowercase							    =       self.config.sample_size
      lowercase							    =       (
          self.config.sample_size[0]
          if isinstance(self.config.sample_size							,		(list, tuple)       )
          else self.config.sample_size
      )
      lowercase							    =       int(sample_size / (2 ** (len(self.config.block_out_channels       ) - 1))       )
      lowercase							    =       0.2_5







    def 			UpperCamelCase_      (			self							,		_lowerCamelCase							,		_lowerCamelCase=False       ):
      if isinstance(_lowerCamelCase							,		(Encoder, Decoder)       ):
        lowercase							    =       value







    def 			UpperCamelCase_      (			self							,		_lowerCamelCase = True       ):
      lowercase							    =       use_tiling







    def 			UpperCamelCase_      (			self       ):
      self.enable_tiling(_lowerCamelCase       )







    def 			UpperCamelCase_      (			self       ):
      lowercase							    =       True







    def 			UpperCamelCase_      (			self       ):
      lowercase							    =       False







    @property
    # Copied from diffusers.models.unet_2d_condition.UNet2DConditionModel.attn_processors
    def 			UpperCamelCase_      (			self       ):
      lowercase							    =       {}

      def fn_recursive_add_processors(_lowerCamelCase							,		_lowerCamelCase							,		_lowerCamelCase       ):
        if hasattr(_lowerCamelCase							,		'set_processor'       ):
          lowercase							    =       module.processor

        for sub_name, child in module.named_children():
          fn_recursive_add_processors(F'{name}.{sub_name}'							,		_lowerCamelCase							,		_lowerCamelCase       )

        return processors

      for name, module in self.named_children():
        fn_recursive_add_processors(_lowerCamelCase							,		_lowerCamelCase							,		_lowerCamelCase       )

      return processors







    def 			UpperCamelCase_      (			self							,		_lowerCamelCase       ):
      lowercase							    =       len(self.attn_processors.keys()       )

      if isinstance(_lowerCamelCase							,		_lowerCamelCase       ) and len(_lowerCamelCase       ) != count:
        raise ValueError(
            F'A dict of processors was passed, but the number of processors {len(_lowerCamelCase       )} does not match the'
            F' number of attention layers: {count}. Please make sure to pass {count} processor classes.'       )

      def fn_recursive_attn_processor(_lowerCamelCase							,		_lowerCamelCase							,		_lowerCamelCase       ):
        if hasattr(_lowerCamelCase							,		'set_processor'       ):
          if not isinstance(_lowerCamelCase							,		_lowerCamelCase       ):
            module.set_processor(_lowerCamelCase       )
          else:
            module.set_processor(processor.pop(F'{name}.processor'       )       )

        for sub_name, child in module.named_children():
          fn_recursive_attn_processor(F'{name}.{sub_name}'							,		_lowerCamelCase							,		_lowerCamelCase       )

      for name, module in self.named_children():
        fn_recursive_attn_processor(_lowerCamelCase							,		_lowerCamelCase							,		_lowerCamelCase       )







    def 			UpperCamelCase_      (			self       ):
      self.set_attn_processor(AttnProcessor()       )







    @apply_forward_hook
    def 			UpperCamelCase_      (			self							,		_lowerCamelCase							,		_lowerCamelCase = True       ):
      if self.use_tiling and (x.shape[-1] > self.tile_sample_min_size or x.shape[-2] > self.tile_sample_min_size):
        return self.tiled_encode(_lowerCamelCase							,		return_dict=_lowerCamelCase       )

      if self.use_slicing and x.shape[0] > 1:
        lowercase							    =       [self.encoder(_lowerCamelCase       ) for x_slice in x.split(1       )]
        lowercase							    =       torch.cat(_lowerCamelCase       )
      else:
        lowercase							    =       self.encoder(_lowerCamelCase       )

      lowercase							    =       self.quant_conv(_lowerCamelCase       )
      lowercase							    =       DiagonalGaussianDistribution(_lowerCamelCase       )

      if not return_dict:
        return (posterior,)

      return AutoencoderKLOutput(latent_dist=_lowerCamelCase       )







    def 			UpperCamelCase_      (			self							,		_lowerCamelCase							,		_lowerCamelCase = True       ):
      if self.use_tiling and (z.shape[-1] > self.tile_latent_min_size or z.shape[-2] > self.tile_latent_min_size):
        return self.tiled_decode(_lowerCamelCase							,		return_dict=_lowerCamelCase       )

      lowercase							    =       self.post_quant_conv(_lowerCamelCase       )
      lowercase							    =       self.decoder(_lowerCamelCase       )

      if not return_dict:
        return (dec,)

      return DecoderOutput(sample=_lowerCamelCase       )







    @apply_forward_hook
    def 			UpperCamelCase_      (			self							,		_lowerCamelCase							,		_lowerCamelCase = True       ):
      if self.use_slicing and z.shape[0] > 1:
        lowercase							    =       [self._decode(_lowerCamelCase       ).sample for z_slice in z.split(1       )]
        lowercase							    =       torch.cat(_lowerCamelCase       )
      else:
        lowercase							    =       self._decode(_lowerCamelCase       ).sample

      if not return_dict:
        return (decoded,)

      return DecoderOutput(sample=_lowerCamelCase       )







    def 			UpperCamelCase_      (			self							,		_lowerCamelCase							,		_lowerCamelCase							,		_lowerCamelCase       ):
      lowercase							    =       min(a.shape[2]							,		b.shape[2]							,		_lowerCamelCase       )
      for y in range(_lowerCamelCase       ):
        lowercase							    =       a[:, :, -blend_extent + y, :] * (1 - y / blend_extent) + b[:, :, y, :] * (y / blend_extent)
      return b







    def 			UpperCamelCase_      (			self							,		_lowerCamelCase							,		_lowerCamelCase							,		_lowerCamelCase       ):
      lowercase							    =       min(a.shape[3]							,		b.shape[3]							,		_lowerCamelCase       )
      for x in range(_lowerCamelCase       ):
        lowercase							    =       a[:, :, :, -blend_extent + x] * (1 - x / blend_extent) + b[:, :, :, x] * (x / blend_extent)
      return b







    def 			UpperCamelCase_      (			self							,		_lowerCamelCase							,		_lowerCamelCase = True       ):
      lowercase							    =       int(self.tile_sample_min_size * (1 - self.tile_overlap_factor)       )
      lowercase							    =       int(self.tile_latent_min_size * self.tile_overlap_factor       )
      lowercase							    =       self.tile_latent_min_size - blend_extent

      # Split the image into 512x512 tiles and encode them separately.
      lowercase							    =       []
      for i in range(0							,		x.shape[2]							,		_lowerCamelCase       ):
        lowercase							    =       []
        for j in range(0							,		x.shape[3]							,		_lowerCamelCase       ):
          lowercase							    =       x[:, :, i : i + self.tile_sample_min_size, j : j + self.tile_sample_min_size]
          lowercase							    =       self.encoder(_lowerCamelCase       )
          lowercase							    =       self.quant_conv(_lowerCamelCase       )
          row.append(_lowerCamelCase       )
        rows.append(_lowerCamelCase       )
      lowercase							    =       []
      for i, row in enumerate(_lowerCamelCase       ):
        lowercase							    =       []
        for j, tile in enumerate(_lowerCamelCase       ):
          # blend the above tile and the left tile
          # to the current tile and add the current tile to the result row
          if i > 0:
            lowercase							    =       self.blend_v(rows[i - 1][j]							,		_lowerCamelCase							,		_lowerCamelCase       )
          if j > 0:
            lowercase							    =       self.blend_h(row[j - 1]							,		_lowerCamelCase							,		_lowerCamelCase       )
          result_row.append(tile[:, :, :row_limit, :row_limit]       )
        result_rows.append(torch.cat(_lowerCamelCase							,		dim=3       )       )

      lowercase							    =       torch.cat(_lowerCamelCase							,		dim=2       )
      lowercase							    =       DiagonalGaussianDistribution(_lowerCamelCase       )

      if not return_dict:
        return (posterior,)

      return AutoencoderKLOutput(latent_dist=_lowerCamelCase       )







    def 			UpperCamelCase_      (			self							,		_lowerCamelCase							,		_lowerCamelCase = True       ):
      lowercase							    =       int(self.tile_latent_min_size * (1 - self.tile_overlap_factor)       )
      lowercase							    =       int(self.tile_sample_min_size * self.tile_overlap_factor       )
      lowercase							    =       self.tile_sample_min_size - blend_extent

      # Split z into overlapping 64x64 tiles and decode them separately.
      # The tiles have an overlap to avoid seams between tiles.
      lowercase							    =       []
      for i in range(0							,		z.shape[2]							,		_lowerCamelCase       ):
        lowercase							    =       []
        for j in range(0							,		z.shape[3]							,		_lowerCamelCase       ):
          lowercase							    =       z[:, :, i : i + self.tile_latent_min_size, j : j + self.tile_latent_min_size]
          lowercase							    =       self.post_quant_conv(_lowerCamelCase       )
          lowercase							    =       self.decoder(_lowerCamelCase       )
          row.append(_lowerCamelCase       )
        rows.append(_lowerCamelCase       )
      lowercase							    =       []
      for i, row in enumerate(_lowerCamelCase       ):
        lowercase							    =       []
        for j, tile in enumerate(_lowerCamelCase       ):
          # blend the above tile and the left tile
          # to the current tile and add the current tile to the result row
          if i > 0:
            lowercase							    =       self.blend_v(rows[i - 1][j]							,		_lowerCamelCase							,		_lowerCamelCase       )
          if j > 0:
            lowercase							    =       self.blend_h(row[j - 1]							,		_lowerCamelCase							,		_lowerCamelCase       )
          result_row.append(tile[:, :, :row_limit, :row_limit]       )
        result_rows.append(torch.cat(_lowerCamelCase							,		dim=3       )       )

      lowercase							    =       torch.cat(_lowerCamelCase							,		dim=2       )
      if not return_dict:
        return (dec,)

      return DecoderOutput(sample=_lowerCamelCase       )







    def 			UpperCamelCase_      (			self							,		_lowerCamelCase							,		_lowerCamelCase = False							,		_lowerCamelCase = True							,		_lowerCamelCase = None							,		):
      lowercase							    =       sample
      lowercase							    =       self.encode(_lowerCamelCase       ).latent_dist
      if sample_posterior:
        lowercase							    =       posterior.sample(generator=_lowerCamelCase       )
      else:
        lowercase							    =       posterior.mode()
      lowercase							    =       self.decode(_lowerCamelCase       ).sample

      if not return_dict:
        return (dec,)

      return DecoderOutput(sample=_lowerCamelCase       )










"""simple docstring"""



# Author: OMKAR PATHAK, Nwachukwu Chidiebere

# Use a Python dictionary to construct the graph.
from __future__ import annotations

from pprint import pformat
from typing import Generic, TypeVar

_UpperCamelCase		:  Optional[Any]						=		TypeVar('T')

class        a     (   Generic[T]	):







    def __init__(			self							,		_lowerCamelCase = True       ):
      lowercase							    =       {}  # dictionary of lists
      lowercase							    =       directed







    def 			UpperCamelCase_      (			self							,		_lowerCamelCase							,		_lowerCamelCase       ):

      if not self.directed:  # For undirected graphs
        # if both source vertex and destination vertex are both present in the
        # adjacency list, add destination vertex to source vertex list of adjacent
        # vertices and add source vertex to destination vertex list of adjacent
        # vertices.
        if source_vertex in self.adj_list and destination_vertex in self.adj_list:
          self.adj_list[source_vertex].append(_lowerCamelCase       )
          self.adj_list[destination_vertex].append(_lowerCamelCase       )
        # if only source vertex is present in adjacency list, add destination vertex
        # to source vertex list of adjacent vertices, then create a new vertex with
        # destination vertex as key and assign a list containing the source vertex
        # as it's first adjacent vertex.
        elif source_vertex in self.adj_list:
          self.adj_list[source_vertex].append(_lowerCamelCase       )
          lowercase							    =       [source_vertex]
        # if only destination vertex is present in adjacency list, add source vertex
        # to destination vertex list of adjacent vertices, then create a new vertex
        # with source vertex as key and assign a list containing the source vertex
        # as it's first adjacent vertex.
        elif destination_vertex in self.adj_list:
          self.adj_list[destination_vertex].append(_lowerCamelCase       )
          lowercase							    =       [destination_vertex]
        # if both source vertex and destination vertex are not present in adjacency
        # list, create a new vertex with source vertex as key and assign a list
        # containing the destination vertex as it's first adjacent vertex also
        # create a new vertex with destination vertex as key and assign a list
        # containing the source vertex as it's first adjacent vertex.
        else:
          lowercase							    =       [destination_vertex]
          lowercase							    =       [source_vertex]
      else:  # For directed graphs
        # if both source vertex and destination vertex are present in adjacency
        # list, add destination vertex to source vertex list of adjacent vertices.
        if source_vertex in self.adj_list and destination_vertex in self.adj_list:
          self.adj_list[source_vertex].append(_lowerCamelCase       )
        # if only source vertex is present in adjacency list, add destination
        # vertex to source vertex list of adjacent vertices and create a new vertex
        # with destination vertex as key, which has no adjacent vertex
        elif source_vertex in self.adj_list:
          self.adj_list[source_vertex].append(_lowerCamelCase       )
          lowercase							    =       []
        # if only destination vertex is present in adjacency list, create a new
        # vertex with source vertex as key and assign a list containing destination
        # vertex as first adjacent vertex
        elif destination_vertex in self.adj_list:
          lowercase							    =       [destination_vertex]
        # if both source vertex and destination vertex are not present in adjacency
        # list, create a new vertex with source vertex as key and a list containing
        # destination vertex as it's first adjacent vertex. Then create a new vertex
        # with destination vertex as key, which has no adjacent vertex
        else:
          lowercase							    =       [destination_vertex]
          lowercase							    =       []

      return self







    def __repr__(			self       ):
      return pformat(self.adj_list       )


