





from typing import Optional, Tuple, Union

import flax
import flax.linen as nn
import jax
import jax.numpy as jnp
from flax.core.frozen_dict import FrozenDict

from ..configuration_utils import ConfigMixin, flax_register_to_config
from ..utils import BaseOutput
from .embeddings_flax import FlaxTimestepEmbedding, FlaxTimesteps
from .modeling_flax_utils import FlaxModelMixin
from .unet_ad_blocks_flax import (
    FlaxCrossAttnDownBlockaD,
    FlaxDownBlockaD,
    FlaxUNetMidBlockaDCrossAttn,
)






@flax.struct.dataclass
class 						UpperCamelCase_  (  snake_case__							):
					_a      :						jnp.ndarray
					_a      :						jnp.ndarray






class 						UpperCamelCase_  (  nn.Module							):
					_a      :						int
					_a      :						Tuple[int]						    =					(1_6, 3_2, 9_6, 2_5_6)
					_a      :						jnp.dtype						    =					jnp.floataa



					def   __a     (		self     :     Optional[Any]						):
							lowerCamelCase_	:     Union[str, Any] 						=      nn.Conv(
							    self.block_out_channels[0]       ,      kernel_size=(3, 3)       ,      padding=((1, 1), (1, 1))       ,      dtype=self.dtype       ,      )

							lowerCamelCase_	:     Optional[Any] 						=      []
							for i in range(len(self.block_out_channels						) - 1						):
									lowerCamelCase_	:     List[str] 						=      self.block_out_channels[i]
									lowerCamelCase_	:     Optional[Any] 						=      self.block_out_channels[i + 1]
									lowerCamelCase_	:     List[str] 						=      nn.Conv(
									    lowerCamelCase       ,      kernel_size=(3, 3)       ,      padding=((1, 1), (1, 1))       ,      dtype=self.dtype       ,      )
									blocks.append(lowerCamelCase						)
									lowerCamelCase_	:     Optional[Any] 						=      nn.Conv(
									    lowerCamelCase       ,      kernel_size=(3, 3)       ,      strides=(2, 2)       ,      padding=((1, 1), (1, 1))       ,      dtype=self.dtype       ,      )
									blocks.append(lowerCamelCase						)
							lowerCamelCase_	:     Tuple 						=      blocks

							lowerCamelCase_	:     Tuple 						=      nn.Conv(
							    self.conditioning_embedding_channels       ,      kernel_size=(3, 3)       ,      padding=((1, 1), (1, 1))       ,      kernel_init=nn.initializers.zeros_init()       ,      bias_init=nn.initializers.zeros_init()       ,      dtype=self.dtype       ,      )





					def __call__(		self     :     List[str]       ,      lowerCamelCase     :     Any						):
							lowerCamelCase_	:     List[Any] 						=      self.conv_in(lowerCamelCase						)
							lowerCamelCase_	:     int 						=      nn.silu(lowerCamelCase						)

							for block in self.blocks:
									lowerCamelCase_	:     List[Any] 						=      block(lowerCamelCase						)
									lowerCamelCase_	:     Union[str, Any] 						=      nn.silu(lowerCamelCase						)

							lowerCamelCase_	:     int 						=      self.conv_out(lowerCamelCase						)

							return embedding






@flax_register_to_config
class 						UpperCamelCase_  (  nn.Module  ,     snake_case__  ,     snake_case__							):
					_a      :						int						    =					3_2
					_a      :						int						    =					4
					_a      :						Tuple[str]						    =					(
					    "CrossAttnDownBlock2D",
					    "CrossAttnDownBlock2D",
					    "CrossAttnDownBlock2D",
					    "DownBlock2D",
					)
					_a      :						Union[bool, Tuple[bool]]						    =					False
					_a      :						Tuple[int]						    =					(3_2_0, 6_4_0, 1_2_8_0, 1_2_8_0)
					_a      :						int						    =					2
					_a      :						Union[int, Tuple[int]]						    =					8
					_a      :						Optional[Union[int, Tuple[int]]]						    =					None
					_a      :						int						    =					1_2_8_0
					_a      :						float						    =					0.0
					_a      :						bool						    =					False
					_a      :						jnp.dtype						    =					jnp.floataa
					_a      :						bool						    =					True
					_a      :						int						    =					0
					_a      :						str						    =					"rgb"
					_a      :						Tuple[int]						    =					(1_6, 3_2, 9_6, 2_5_6)



					def   __a     (		self     :     str       ,      lowerCamelCase     :     jax.random.KeyArray						):
							# init input tensors
							lowerCamelCase_	:     str 						=      (1, self.in_channels, self.sample_size, self.sample_size)
							lowerCamelCase_	:     Optional[Any] 						=      jnp.zeros(lowerCamelCase       ,      dtype=jnp.floataa						)
							lowerCamelCase_	:     Optional[Any] 						=      jnp.ones((1,)       ,      dtype=jnp.intaa						)
							lowerCamelCase_	:     Dict 						=      jnp.zeros((1, 1, self.cross_attention_dim)       ,      dtype=jnp.floataa						)
							lowerCamelCase_	:     Dict 						=      (1, 3, self.sample_size * 8, self.sample_size * 8)
							lowerCamelCase_	:     int 						=      jnp.zeros(lowerCamelCase       ,      dtype=jnp.floataa						)

							lowerCamelCase_						,      lowerCamelCase_	:     Dict 						=      jax.random.split(lowerCamelCase						)
							lowerCamelCase_	:     Dict 						=      {'params': params_rng, 'dropout': dropout_rng}

							return self.init(lowerCamelCase       ,      lowerCamelCase       ,      lowerCamelCase       ,      lowerCamelCase       ,      lowerCamelCase						)["params"]



					def   __a     (		self     :     str						):
							lowerCamelCase_	:     List[str] 						=      self.block_out_channels
							lowerCamelCase_	:     Union[str, Any] 						=      block_out_channels[0] * 4

							# If `num_attention_heads` is not defined (which is the case for most models)
							# it will default to `attention_head_dim`. This looks weird upon first reading it and it is.
							# The reason for this behavior is to correct for incorrectly named variables that were introduced
							# when this library was created. The incorrect naming was only discovered much later in https://github.com/huggingface/diffusers/issues/2011#issuecomment-1547958131
							# Changing `attention_head_dim` to `num_attention_heads` for 40,000+ configurations is too backwards breaking
							# which is why we correct for the naming here.
							lowerCamelCase_	:     Tuple 						=      self.num_attention_heads or self.attention_head_dim

							# input
							lowerCamelCase_	:     Optional[Any] 						=      nn.Conv(
							    block_out_channels[0]       ,      kernel_size=(3, 3)       ,      strides=(1, 1)       ,      padding=((1, 1), (1, 1))       ,      dtype=self.dtype       ,      )

							# time
							lowerCamelCase_	:     Optional[int] 						=      FlaxTimesteps(
							    block_out_channels[0]       ,      flip_sin_to_cos=self.flip_sin_to_cos       ,      freq_shift=self.config.freq_shift						)
							lowerCamelCase_	:     Any 						=      FlaxTimestepEmbedding(lowerCamelCase       ,      dtype=self.dtype						)

							lowerCamelCase_	:     Optional[int] 						=      FlaxControlNetConditioningEmbedding(
							    conditioning_embedding_channels=block_out_channels[0]       ,      block_out_channels=self.conditioning_embedding_out_channels       ,      )

							lowerCamelCase_	:     str 						=      self.only_cross_attention
							if isinstance(lowerCamelCase       ,      lowerCamelCase						):
									lowerCamelCase_	:     str 						=      (only_cross_attention,) * len(self.down_block_types						)

							if isinstance(lowerCamelCase       ,      lowerCamelCase						):
									lowerCamelCase_	:     List[str] 						=      (num_attention_heads,) * len(self.down_block_types						)

							# down
							lowerCamelCase_	:     Optional[Any] 						=      []
							lowerCamelCase_	:     List[str] 						=      []

							lowerCamelCase_	:     int 						=      block_out_channels[0]

							lowerCamelCase_	:     Any 						=      nn.Conv(
							    lowerCamelCase       ,      kernel_size=(1, 1)       ,      padding='VALID'       ,      kernel_init=nn.initializers.zeros_init()       ,      bias_init=nn.initializers.zeros_init()       ,      dtype=self.dtype       ,      )
							controlnet_down_blocks.append(lowerCamelCase						)

							for i, down_block_type in enumerate(self.down_block_types						):
									lowerCamelCase_	:     Dict 						=      output_channel
									lowerCamelCase_	:     Optional[int] 						=      block_out_channels[i]
									lowerCamelCase_	:     str 						=      i == len(lowerCamelCase						) - 1

									if down_block_type == "CrossAttnDownBlock2D":
											lowerCamelCase_	:     int 						=      FlaxCrossAttnDownBlockaD(
											    in_channels=lowerCamelCase       ,      out_channels=lowerCamelCase       ,      dropout=self.dropout       ,      num_layers=self.layers_per_block       ,      num_attention_heads=num_attention_heads[i]       ,      add_downsample=not is_final_block       ,      use_linear_projection=self.use_linear_projection       ,      only_cross_attention=only_cross_attention[i]       ,      dtype=self.dtype       ,      )
									else:
											lowerCamelCase_	:     Dict 						=      FlaxDownBlockaD(
											    in_channels=lowerCamelCase       ,      out_channels=lowerCamelCase       ,      dropout=self.dropout       ,      num_layers=self.layers_per_block       ,      add_downsample=not is_final_block       ,      dtype=self.dtype       ,      )

									down_blocks.append(lowerCamelCase						)

									for _ in range(self.layers_per_block						):
											lowerCamelCase_	:     List[str] 						=      nn.Conv(
											    lowerCamelCase       ,      kernel_size=(1, 1)       ,      padding='VALID'       ,      kernel_init=nn.initializers.zeros_init()       ,      bias_init=nn.initializers.zeros_init()       ,      dtype=self.dtype       ,      )
											controlnet_down_blocks.append(lowerCamelCase						)

									if not is_final_block:
											lowerCamelCase_	:     Tuple 						=      nn.Conv(
											    lowerCamelCase       ,      kernel_size=(1, 1)       ,      padding='VALID'       ,      kernel_init=nn.initializers.zeros_init()       ,      bias_init=nn.initializers.zeros_init()       ,      dtype=self.dtype       ,      )
											controlnet_down_blocks.append(lowerCamelCase						)

							lowerCamelCase_	:     Optional[Any] 						=      down_blocks
							lowerCamelCase_	:     Optional[int] 						=      controlnet_down_blocks

							# mid
							lowerCamelCase_	:     Any 						=      block_out_channels[-1]
							lowerCamelCase_	:     Optional[int] 						=      FlaxUNetMidBlockaDCrossAttn(
							    in_channels=lowerCamelCase       ,      dropout=self.dropout       ,      num_attention_heads=num_attention_heads[-1]       ,      use_linear_projection=self.use_linear_projection       ,      dtype=self.dtype       ,      )

							lowerCamelCase_	:     Any 						=      nn.Conv(
							    lowerCamelCase       ,      kernel_size=(1, 1)       ,      padding='VALID'       ,      kernel_init=nn.initializers.zeros_init()       ,      bias_init=nn.initializers.zeros_init()       ,      dtype=self.dtype       ,      )





					def __call__(		self     :     List[Any]       ,      lowerCamelCase     :     str       ,      lowerCamelCase     :     Dict       ,      lowerCamelCase     :     List[str]       ,      lowerCamelCase     :     str       ,      lowerCamelCase     :     float = 1.0       ,      lowerCamelCase     :     bool = True       ,      lowerCamelCase     :     bool = False       ,      ):
							lowerCamelCase_	:     List[str] 						=      self.controlnet_conditioning_channel_order
							if channel_order == "bgr":
									lowerCamelCase_	:     Optional[Any] 						=      jnp.flip(lowerCamelCase       ,      axis=1						)

							# 1. time
							if not isinstance(lowerCamelCase       ,      jnp.ndarray						):
									lowerCamelCase_	:     List[Any] 						=      jnp.array([timesteps]       ,      dtype=jnp.intaa						)
							elif isinstance(lowerCamelCase       ,      jnp.ndarray						) and len(timesteps.shape						) == 0:
									lowerCamelCase_	:     Optional[Any] 						=      timesteps.astype(dtype=jnp.floataa						)
									lowerCamelCase_	:     str 						=      jnp.expand_dims(lowerCamelCase       ,      0						)

							lowerCamelCase_	:     Optional[Any] 						=      self.time_proj(lowerCamelCase						)
							lowerCamelCase_	:     List[Any] 						=      self.time_embedding(lowerCamelCase						)

							# 2. pre-process
							lowerCamelCase_	:     int 						=      jnp.transpose(lowerCamelCase       ,      (0, 2, 3, 1)						)
							lowerCamelCase_	:     Any 						=      self.conv_in(lowerCamelCase						)

							lowerCamelCase_	:     Optional[Any] 						=      jnp.transpose(lowerCamelCase       ,      (0, 2, 3, 1)						)
							lowerCamelCase_	:     Union[str, Any] 						=      self.controlnet_cond_embedding(lowerCamelCase						)
							sample += controlnet_cond

							# 3. down
							lowerCamelCase_	:     Tuple 						=      (sample,)
							for down_block in self.down_blocks:
									if isinstance(lowerCamelCase       ,      lowerCamelCase						):
											lowerCamelCase_						,      lowerCamelCase_	:     List[str] 						=      down_block(lowerCamelCase       ,      lowerCamelCase       ,      lowerCamelCase       ,      deterministic=not train						)
									else:
											lowerCamelCase_						,      lowerCamelCase_	:     Union[str, Any] 						=      down_block(lowerCamelCase       ,      lowerCamelCase       ,      deterministic=not train						)
									down_block_res_samples += res_samples

							# 4. mid
							lowerCamelCase_	:     Any 						=      self.mid_block(lowerCamelCase       ,      lowerCamelCase       ,      lowerCamelCase       ,      deterministic=not train						)

							# 5. contronet blocks
							lowerCamelCase_	:     Tuple 						=      ()
							for down_block_res_sample, controlnet_block in zip(lowerCamelCase       ,      self.controlnet_down_blocks						):
									lowerCamelCase_	:     Any 						=      controlnet_block(lowerCamelCase						)
									controlnet_down_block_res_samples += (down_block_res_sample,)

							lowerCamelCase_	:     Tuple 						=      controlnet_down_block_res_samples

							lowerCamelCase_	:     Tuple 						=      self.controlnet_mid_block(lowerCamelCase						)

							# 6. scaling
							lowerCamelCase_	:     List[str] 						=      [sample * conditioning_scale for sample in down_block_res_samples]
							mid_block_res_sample *= conditioning_scale

							if not return_dict:
									return (down_block_res_samples, mid_block_res_sample)

							return FlaxControlNetOutput(
							    down_block_res_samples=lowerCamelCase       ,      mid_block_res_sample=lowerCamelCase						)







_lowercase		:  Any			       =[0, 2, 4, 6, 8]
_lowercase		:  List[Any]			       =[1, 3, 5, 7, 9]


def 		_SCREAMING_SNAKE_CASE     ( lowerCAmelCase__							,lowerCAmelCase__							,lowerCAmelCase__							,lowerCAmelCase__						):
		if remaining_length == 0:
				if digits[0] == 0 or digits[-1] == 0:
						return 0

				for i in range(length // 2 - 1							,-1							,-1						):
						remainder += digits[i] + digits[length - i - 1]

						if remainder % 2 == 0:
								return 0

						remainder //= 10

				return 1

		if remaining_length == 1:
				if remainder % 2 == 0:
						return 0

				lowerCamelCase_	:     Dict 						=      0
				for digit in range(10						):
						lowerCamelCase_	:     List[Any] 						=      digit
						result += reversible_numbers(
						    0							,(remainder + 2 * digit) // 10							,lowerCAmelCase__							,lowerCAmelCase__						)
				return result

		lowerCamelCase_	:     List[str] 						=      0
		for digita in range(10						):
				lowerCamelCase_	:     Tuple 						=      digita

				if (remainder + digita) % 2 == 0:
						lowerCamelCase_	:     Dict 						=      ODD_DIGITS
				else:
						lowerCamelCase_	:     str 						=      EVEN_DIGITS

				for digita in other_parity_digits:
						lowerCamelCase_	:     Optional[int] 						=      digita
						result += reversible_numbers(
						    remaining_length - 2							,(remainder + digita + digita) // 10							,lowerCAmelCase__							,lowerCAmelCase__							,)
		return result


def 		_SCREAMING_SNAKE_CASE     ( lowerCAmelCase__ = 9						):
		lowerCamelCase_	:     int 						=      0
		for length in range(1							,max_power + 1						):
				result += reversible_numbers(lowerCAmelCase__							,0							,[0] * length							,lowerCAmelCase__						)
		return result


if __name__ == "__main__":
		print(F'''{solution() = }''')
