
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,
    FlaxCrossAttnUpBlockaD,
    FlaxDownBlockaD,
    FlaxUNetMidBlockaDCrossAttn,
    FlaxUpBlockaD,
)



@flax.struct.dataclass
class    a_ (			_a    ):
			a	:			jnp.ndarray







@flax_register_to_config
class    a_ (			nn.Module					,			_a					,			_a    ):
			a	:			int					   =							3_2
			a	:			int					   =							4
			a	:			int					   =							4
			a	:			Tuple[str]					   =							(
			    "CrossAttnDownBlock2D",
			    "CrossAttnDownBlock2D",
			    "CrossAttnDownBlock2D",
			    "DownBlock2D",
			)
			a	:			Tuple[str]					   =							("UpBlock2D", "CrossAttnUpBlock2D", "CrossAttnUpBlock2D", "CrossAttnUpBlock2D")
			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	:			bool					   =							False






			def    UpperCamelCase_				(      self				,			__UpperCamelCase  ):
									# init input tensors
									_lowercase					       =					(1, self.in_channels, self.sample_size, self.sample_size)
									_lowercase					       =					jnp.zeros(__UpperCamelCase				,			dtype=jnp.floataa  )
									_lowercase					       =					jnp.ones((1,)				,			dtype=jnp.intaa  )
									_lowercase					       =					jnp.zeros((1, 1, self.cross_attention_dim)				,			dtype=jnp.floataa  )

									_lowercase       ,						_lowercase					       =					jax.random.split(__UpperCamelCase  )
									_lowercase					       =					{"""params""": params_rng, """dropout""": dropout_rng}

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






			def    UpperCamelCase_				(      self  ):
									_lowercase					       =					self.block_out_channels
									_lowercase					       =					block_out_channels[0] * 4

									if self.num_attention_heads is not None:
															raise ValueError(
															    """At the moment it is not possible to define the number of attention heads via `num_attention_heads` because of a naming issue as described in https://github.com/huggingface/diffusers/issues/2011#issuecomment-1547958131. Passing `num_attention_heads` will only be supported in diffusers v0.19."""  )

									# 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.
									_lowercase					       =					self.num_attention_heads or self.attention_head_dim

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

									# time
									_lowercase					       =					FlaxTimesteps(
									    block_out_channels[0]				,			flip_sin_to_cos=self.flip_sin_to_cos				,			freq_shift=self.config.freq_shift  )
									_lowercase					       =					FlaxTimestepEmbedding(__UpperCamelCase				,			dtype=self.dtype  )

									_lowercase					       =					self.only_cross_attention
									if isinstance(__UpperCamelCase				,			__UpperCamelCase  ):
															_lowercase					       =					(only_cross_attention,) * len(self.down_block_types  )

									if isinstance(__UpperCamelCase				,			__UpperCamelCase  ):
															_lowercase					       =					(num_attention_heads,) * len(self.down_block_types  )

									# down
									_lowercase					       =					[]
									_lowercase					       =					block_out_channels[0]
									for i, down_block_type in enumerate(self.down_block_types  ):
															_lowercase					       =					output_channel
															_lowercase					       =					block_out_channels[i]
															_lowercase					       =					i == len(__UpperCamelCase  ) - 1

															if down_block_type == "CrossAttnDownBlock2D":
																					_lowercase					       =					FlaxCrossAttnDownBlockaD(
																					    in_channels=__UpperCamelCase				,			out_channels=__UpperCamelCase				,			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]				,			use_memory_efficient_attention=self.use_memory_efficient_attention				,			dtype=self.dtype				,			)
															else:
																					_lowercase					       =					FlaxDownBlockaD(
																					    in_channels=__UpperCamelCase				,			out_channels=__UpperCamelCase				,			dropout=self.dropout				,			num_layers=self.layers_per_block				,			add_downsample=not is_final_block				,			dtype=self.dtype				,			)

															down_blocks.append(__UpperCamelCase  )
									_lowercase					       =					down_blocks

									# mid
									_lowercase					       =					FlaxUNetMidBlockaDCrossAttn(
									    in_channels=block_out_channels[-1]				,			dropout=self.dropout				,			num_attention_heads=num_attention_heads[-1]				,			use_linear_projection=self.use_linear_projection				,			use_memory_efficient_attention=self.use_memory_efficient_attention				,			dtype=self.dtype				,			)

									# up
									_lowercase					       =					[]
									_lowercase					       =					list(reversed(__UpperCamelCase  )  )
									_lowercase					       =					list(reversed(__UpperCamelCase  )  )
									_lowercase					       =					list(reversed(__UpperCamelCase  )  )
									_lowercase					       =					reversed_block_out_channels[0]
									for i, up_block_type in enumerate(self.up_block_types  ):
															_lowercase					       =					output_channel
															_lowercase					       =					reversed_block_out_channels[i]
															_lowercase					       =					reversed_block_out_channels[min(i + 1				,			len(__UpperCamelCase  ) - 1  )]

															_lowercase					       =					i == len(__UpperCamelCase  ) - 1

															if up_block_type == "CrossAttnUpBlock2D":
																					_lowercase					       =					FlaxCrossAttnUpBlockaD(
																					    in_channels=__UpperCamelCase				,			out_channels=__UpperCamelCase				,			prev_output_channel=__UpperCamelCase				,			num_layers=self.layers_per_block + 1				,			num_attention_heads=reversed_num_attention_heads[i]				,			add_upsample=not is_final_block				,			dropout=self.dropout				,			use_linear_projection=self.use_linear_projection				,			only_cross_attention=only_cross_attention[i]				,			use_memory_efficient_attention=self.use_memory_efficient_attention				,			dtype=self.dtype				,			)
															else:
																					_lowercase					       =					FlaxUpBlockaD(
																					    in_channels=__UpperCamelCase				,			out_channels=__UpperCamelCase				,			prev_output_channel=__UpperCamelCase				,			num_layers=self.layers_per_block + 1				,			add_upsample=not is_final_block				,			dropout=self.dropout				,			dtype=self.dtype				,			)

															up_blocks.append(__UpperCamelCase  )
															_lowercase					       =					output_channel
									_lowercase					       =					up_blocks

									# out
									_lowercase					       =					nn.GroupNorm(num_groups=32				,			epsilon=1E-5  )
									_lowercase					       =					nn.Conv(
									    self.out_channels				,			kernel_size=(3, 3)				,			strides=(1, 1)				,			padding=((1, 1), (1, 1))				,			dtype=self.dtype				,			)






			def __call__(      self				,			__UpperCamelCase				,			__UpperCamelCase				,			__UpperCamelCase				,			__UpperCamelCase=None				,			__UpperCamelCase=None				,			__UpperCamelCase = True				,			__UpperCamelCase = False				,			):
									# 1. time
									if not isinstance(__UpperCamelCase				,			jnp.ndarray  ):
															_lowercase					       =					jnp.array([timesteps]				,			dtype=jnp.intaa  )
									elif isinstance(__UpperCamelCase				,			jnp.ndarray  ) and len(timesteps.shape  ) == 0:
															_lowercase					       =					timesteps.astype(dtype=jnp.floataa  )
															_lowercase					       =					jnp.expand_dims(__UpperCamelCase				,			0  )

									_lowercase					       =					self.time_proj(__UpperCamelCase  )
									_lowercase					       =					self.time_embedding(__UpperCamelCase  )

									# 2. pre-process
									_lowercase					       =					jnp.transpose(__UpperCamelCase				,			(0, 2, 3, 1)  )
									_lowercase					       =					self.conv_in(__UpperCamelCase  )

									# 3. down
									_lowercase					       =					(sample,)
									for down_block in self.down_blocks:
															if isinstance(__UpperCamelCase				,			__UpperCamelCase  ):
																					_lowercase       ,						_lowercase					       =					down_block(__UpperCamelCase				,			__UpperCamelCase				,			__UpperCamelCase				,			deterministic=not train  )
															else:
																					_lowercase       ,						_lowercase					       =					down_block(__UpperCamelCase				,			__UpperCamelCase				,			deterministic=not train  )
															down_block_res_samples += res_samples

									if down_block_additional_residuals is not None:
															_lowercase					       =					()

															for down_block_res_sample, down_block_additional_residual in zip(
															    __UpperCamelCase				,			__UpperCamelCase  ):
																					down_block_res_sample += down_block_additional_residual
																					new_down_block_res_samples += (down_block_res_sample,)

															_lowercase					       =					new_down_block_res_samples

									# 4. mid
									_lowercase					       =					self.mid_block(__UpperCamelCase				,			__UpperCamelCase				,			__UpperCamelCase				,			deterministic=not train  )

									if mid_block_additional_residual is not None:
															sample += mid_block_additional_residual

									# 5. up
									for up_block in self.up_blocks:
															_lowercase					       =					down_block_res_samples[-(self.layers_per_block + 1) :]
															_lowercase					       =					down_block_res_samples[: -(self.layers_per_block + 1)]
															if isinstance(__UpperCamelCase				,			__UpperCamelCase  ):
																					_lowercase					       =					up_block(
																					    __UpperCamelCase				,			temb=__UpperCamelCase				,			encoder_hidden_states=__UpperCamelCase				,			res_hidden_states_tuple=__UpperCamelCase				,			deterministic=not train				,			)
															else:
																					_lowercase					       =					up_block(__UpperCamelCase				,			temb=__UpperCamelCase				,			res_hidden_states_tuple=__UpperCamelCase				,			deterministic=not train  )

        # 6. post-process
									_lowercase					       =					self.conv_norm_out(__UpperCamelCase  )
									_lowercase					       =					nn.silu(__UpperCamelCase  )
									_lowercase					       =					self.conv_out(__UpperCamelCase  )
									_lowercase					       =					jnp.transpose(__UpperCamelCase				,			(0, 3, 1, 2)  )

									if not return_dict:
															return (sample,)

									return FlaxUNetaDConditionOutput(sample=__UpperCamelCase  )

from __future__ import annotations




def 	UpperCamelCase__  (     SCREAMING_SNAKE_CASE_	:	float		,   SCREAMING_SNAKE_CASE_	:	float		,   SCREAMING_SNAKE_CASE_	:	float		,   )  ->     tuple:
						if (electron_conc, hole_conc, intrinsic_conc).count(0       ) != 1:
												raise ValueError("""You cannot supply more or less than 2 values"""       )
						elif electron_conc < 0:
												raise ValueError("""Electron concentration cannot be negative in a semiconductor"""       )
						elif hole_conc < 0:
												raise ValueError("""Hole concentration cannot be negative in a semiconductor"""       )
						elif intrinsic_conc < 0:
												raise ValueError(
												    """Intrinsic concentration cannot be negative in a semiconductor"""       )
						elif electron_conc == 0:
												return (
												    "electron_conc",
												    intrinsic_conc**2 / hole_conc,
												)
						elif hole_conc == 0:
												return (
												    "hole_conc",
												    intrinsic_conc**2 / electron_conc,
												)
						elif intrinsic_conc == 0:
												return (
												    "intrinsic_conc",
												    (electron_conc * hole_conc) ** 0.5,
												)
						else:
												return (-1, -1)


if __name__ == "__main__":
		import doctest

		doctest.testmod()