



import glob
import os
from typing import Dict, List, Union

import torch

from diffusers.utils import is_safetensors_available


if is_safetensors_available():
	import safetensors.torch

from huggingface_hub import snapshot_download

from diffusers import DiffusionPipeline, __version__
from diffusers.schedulers.scheduling_utils import SCHEDULER_CONFIG_NAME
from diffusers.utils import CONFIG_NAME, DIFFUSERS_CACHE, ONNX_WEIGHTS_NAME, WEIGHTS_NAME


class  _lowercase				(a_ ):
				'''simple docstring'''







				def __init__(	self      ):

									'''simple docstring'''


									self.register_to_config()
									super().__init__()

				def  _lowerCamelCase   (	self       ,	snake_case__       ,	snake_case__      ):

									'''simple docstring'''


									if dicta == dicta:
														return True
									else:
														UpperCamelCase_					,      UpperCamelCase_											=				self._remove_meta_keys(snake_case__      )
														UpperCamelCase_					,      UpperCamelCase_											=				self._remove_meta_keys(snake_case__      )
														if configa == configa:
																			print(F"""Warning !: Mismatch in keys {meta_keysa} and {meta_keysa}."""      )
																			return True
									return False

				def  _lowerCamelCase   (	self       ,	snake_case__      ):

									'''simple docstring'''


									UpperCamelCase_											=				[]
									UpperCamelCase_											=				config_dict.copy()
									for key in config_dict.keys():
														if key.startswith("_"      ):
																			temp_dict.pop(snake_case__      )
																			meta_keys.append(snake_case__      )
									return (temp_dict, meta_keys)

				@torch.no_grad()
				def  _lowerCamelCase   (	self       ,	snake_case__       ,	**snake_case__      ):

									'''simple docstring'''


									UpperCamelCase_											=				kwargs.pop("cache_dir"       ,	snake_case__      )
									UpperCamelCase_											=				kwargs.pop("resume_download"       ,	snake_case__      )
									UpperCamelCase_											=				kwargs.pop("force_download"       ,	snake_case__      )
									UpperCamelCase_											=				kwargs.pop("proxies"       ,	snake_case__      )
									UpperCamelCase_											=				kwargs.pop("local_files_only"       ,	snake_case__      )
									UpperCamelCase_											=				kwargs.pop("use_auth_token"       ,	snake_case__      )
									UpperCamelCase_											=				kwargs.pop("revision"       ,	snake_case__      )
									UpperCamelCase_											=				kwargs.pop("torch_dtype"       ,	snake_case__      )
									UpperCamelCase_											=				kwargs.pop("device_map"       ,	snake_case__      )

									UpperCamelCase_											=				kwargs.pop("alpha"       ,	0.5      )
									UpperCamelCase_											=				kwargs.pop("interp"       ,	snake_case__      )

									print("Received list"       ,	snake_case__      )
									print(F"""Combining with alpha={alpha}, interpolation mode={interp}"""      )

									UpperCamelCase_											=				len(snake_case__      )
									# Ignore result from model_index_json comparision of the two checkpoints
									UpperCamelCase_											=				kwargs.pop("force"       ,	snake_case__      )

									# If less than 2 checkpoints, nothing to merge. If more than 3, not supported for now.
									if checkpoint_count > 3 or checkpoint_count < 2:
														raise ValueError(
														    "Received incorrect number of checkpoints to merge. Ensure that either 2 or 3 checkpoints are being"
														    " passed."      )

									print("Received the right number of checkpoints"      )
									# chkpt0, chkpt1 = pretrained_model_name_or_path_list[0:2]
									# chkpt2 = pretrained_model_name_or_path_list[2] if checkpoint_count == 3 else None

									# Validate that the checkpoints can be merged
									# Step 1: Load the model config and compare the checkpoints. We'll compare the model_index.json first while ignoring the keys starting with '_'
									UpperCamelCase_											=				[]
									for pretrained_model_name_or_path in pretrained_model_name_or_path_list:
														UpperCamelCase_											=				DiffusionPipeline.load_config(
														    snake_case__       ,	cache_dir=snake_case__       ,	resume_download=snake_case__       ,	force_download=snake_case__       ,	proxies=snake_case__       ,	local_files_only=snake_case__       ,	use_auth_token=snake_case__       ,	revision=snake_case__       ,	)
														config_dicts.append(snake_case__      )

									UpperCamelCase_											=				True
									for idx in range(1       ,	len(snake_case__      )      ):
														comparison_result &= self._compare_model_configs(config_dicts[idx - 1]       ,	config_dicts[idx]      )
														if not force and comparison_result is False:
																			raise ValueError("Incompatible checkpoints. Please check model_index.json for the models."      )
																			print(config_dicts[0]       ,	config_dicts[1]      )
									print("Compatible model_index.json files found"      )
									# Step 2: Basic Validation has succeeded. Let's download the models and save them into our local files.
									UpperCamelCase_											=				[]
									for pretrained_model_name_or_path, config_dict in zip(snake_case__       ,	snake_case__      ):
														UpperCamelCase_											=				[k for k in config_dict.keys() if not k.startswith("_"      )]
														UpperCamelCase_											=				[os.path.join(snake_case__       ,	"*"      ) for k in folder_names]
														allow_patterns += [
														    WEIGHTS_NAME,
														    SCHEDULER_CONFIG_NAME,
														    CONFIG_NAME,
														    ONNX_WEIGHTS_NAME,
														    DiffusionPipeline.config_name,
														]
														UpperCamelCase_											=				config_dict.get("_class_name"      )
														UpperCamelCase_											=				{"diffusers": __version__, "pipeline_class": requested_pipeline_class}

														UpperCamelCase_											=				(
														    pretrained_model_name_or_path
														    if os.path.isdir(snake_case__      )
														    else snapshot_download(
														        snake_case__       ,	cache_dir=snake_case__       ,	resume_download=snake_case__       ,	proxies=snake_case__       ,	local_files_only=snake_case__       ,	use_auth_token=snake_case__       ,	revision=snake_case__       ,	allow_patterns=snake_case__       ,	user_agent=snake_case__       ,	)
														)
														print("Cached Folder"       ,	snake_case__      )
														cached_folders.append(snake_case__      )

									# Step 3:-
									# Load the first checkpoint as a diffusion pipeline and modify its module state_dict in place
									UpperCamelCase_											=				DiffusionPipeline.from_pretrained(
									    cached_folders[0]       ,	torch_dtype=snake_case__       ,	device_map=snake_case__      )
									final_pipe.to(self.device      )

									UpperCamelCase_											=				None
									if len(snake_case__      ) > 2:
														UpperCamelCase_											=				os.path.join(cached_folders[2]      )

									if interp == "sigmoid":
														UpperCamelCase_											=				CheckpointMergerPipeline.sigmoid
									elif interp == "inv_sigmoid":
														UpperCamelCase_											=				CheckpointMergerPipeline.inv_sigmoid
									elif interp == "add_diff":
														UpperCamelCase_											=				CheckpointMergerPipeline.add_difference
									else:
														UpperCamelCase_											=				CheckpointMergerPipeline.weighted_sum

									# Find each module's state dict.
									for attr in final_pipe.config.keys():
														if not attr.startswith("_"      ):
																			UpperCamelCase_											=				os.path.join(cached_folders[1]       ,	snake_case__      )
																			if os.path.exists(snake_case__      ):
																								UpperCamelCase_											=				[
																								    *glob.glob(os.path.join(snake_case__       ,	"*.safetensors"      )      ),
																								    *glob.glob(os.path.join(snake_case__       ,	"*.bin"      )      ),
																								]
																								UpperCamelCase_											=				files[0] if len(snake_case__      ) > 0 else None
																			if len(snake_case__      ) < 3:
																								UpperCamelCase_											=				None
																			else:
																								UpperCamelCase_											=				os.path.join(cached_folders[2]       ,	snake_case__      )
																								if os.path.exists(snake_case__      ):
																													UpperCamelCase_											=				[
																													    *glob.glob(os.path.join(snake_case__       ,	"*.safetensors"      )      ),
																													    *glob.glob(os.path.join(snake_case__       ,	"*.bin"      )      ),
																													]
																													UpperCamelCase_											=				files[0] if len(snake_case__      ) > 0 else None
                # For an attr if both checkpoint_path_1 and 2 are None, ignore.
                # If atleast one is present, deal with it according to interp method, of course only if the state_dict keys match.
																			if checkpoint_path_a is None and checkpoint_path_a is None:
																								print(F"""Skipping {attr}: not present in 2nd or 3d model"""      )
																								continue
																			try:
																								UpperCamelCase_											=				getattr(snake_case__       ,	snake_case__      )
																								if isinstance(snake_case__       ,	snake_case__      ):  # ignore requires_safety_checker boolean
																													continue
																								UpperCamelCase_											=				getattr(snake_case__       ,	"state_dict"      )
																								UpperCamelCase_											=				theta_a()

																								UpperCamelCase_											=				getattr(snake_case__       ,	"load_state_dict"      )
																								UpperCamelCase_											=				(
																								    safetensors.torch.load_file(snake_case__      )
																								    if (is_safetensors_available() and checkpoint_path_a.endswith(".safetensors"      ))
																								    else torch.load(snake_case__       ,	map_location="cpu"      )
																								)
																								UpperCamelCase_											=				None
																								if checkpoint_path_a:
																													UpperCamelCase_											=				(
																													    safetensors.torch.load_file(snake_case__      )
																													    if (is_safetensors_available() and checkpoint_path_a.endswith(".safetensors"      ))
																													    else torch.load(snake_case__       ,	map_location="cpu"      )
																													)

																								if not theta_a.keys() == theta_a.keys():
																													print(F"""Skipping {attr}: key mismatch"""      )
																													continue
																								if theta_a and not theta_a.keys() == theta_a.keys():
																													print(F"""Skipping {attr}:y mismatch"""      )
																			except Exception as e:
																								print(F"""Skipping {attr} do to an unexpected error: {str(snake_case__      )}"""      )
																								continue
																			print(F"""MERGING {attr}"""      )

																			for key in theta_a.keys():
																								if theta_a:
																													UpperCamelCase_											=				theta_func(theta_a[key]       ,	theta_a[key]       ,	theta_a[key]       ,	snake_case__      )
																								else:
																													UpperCamelCase_											=				theta_func(theta_a[key]       ,	theta_a[key]       ,	snake_case__       ,	snake_case__      )

																			del theta_a
																			del theta_a
																			update_theta_a(snake_case__      )

																			del theta_a
									return final_pipe

				@staticmethod
				def  _lowerCamelCase   (	snake_case__       ,	snake_case__       ,	snake_case__       ,	snake_case__      ):

									'''simple docstring'''


									return ((1 - alpha) * thetaa) + (alpha * thetaa)

				@staticmethod
				def  _lowerCamelCase   (	snake_case__       ,	snake_case__       ,	snake_case__       ,	snake_case__      ):

									'''simple docstring'''


									UpperCamelCase_											=				alpha * alpha * (3 - (2 * alpha))
									return thetaa + ((thetaa - thetaa) * alpha)

				@staticmethod
				def  _lowerCamelCase   (	snake_case__       ,	snake_case__       ,	snake_case__       ,	snake_case__      ):

									'''simple docstring'''


									import math

									UpperCamelCase_											=				0.5 - math.sin(math.asin(1.0 - 2.0 * alpha      ) / 3.0      )
									return thetaa + ((thetaa - thetaa) * alpha)

				@staticmethod
				def  _lowerCamelCase   (	snake_case__       ,	snake_case__       ,	snake_case__       ,	snake_case__      ):

									'''simple docstring'''


									return thetaa + (thetaa - thetaa) * (1.0 - alpha)





from typing import List, Optional, Tuple, Union

from . import logging
from .import_utils import is_torch_available, is_torch_version


if is_torch_available():
	import torch

UpperCAmelCase				:							Any								=logging.get_logger(__name__)  # pylint: disable=invalid-name

try:
	from torch._dynamo import allow_in_graph as maybe_allow_in_graph
except (ImportError, ModuleNotFoundError):



	def 				_lowerCAmelCase      (cls):
						return cls



def 				_lowerCAmelCase      (_lowerCAmelCase				,		_lowerCAmelCase = None				,		_lowerCAmelCase = None				,		_lowerCAmelCase = None				,		_lowerCAmelCase = None				,		):
					UpperCamelCase_											=				device
					UpperCamelCase_											=				shape[0]

					UpperCamelCase_											=				layout or torch.strided
					UpperCamelCase_											=				device or torch.device("cpu")

					if generator is not None:
										UpperCamelCase_											=				generator.device.type if not isinstance(_lowerCAmelCase				,		_lowerCAmelCase) else generator[0].device.type
										if gen_device_type != device.type and gen_device_type == "cpu":
															UpperCamelCase_											=				"cpu"
															if device != "mps":
																				logger.info(
																				    f"""The passed generator was created on 'cpu' even though a tensor on {device} was expected."""
																				    f""" Tensors will be created on 'cpu' and then moved to {device}. Note that one can probably"""
																				    f""" slighly speed up this function by passing a generator that was created on the {device} device.""")
										elif gen_device_type != device.type and gen_device_type == "cuda":
															raise ValueError(f"""Cannot generate a {device} tensor from a generator of type {gen_device_type}.""")

					if isinstance(_lowerCAmelCase				,		_lowerCAmelCase):
										UpperCamelCase_											=				(1,) + shape[1:]
										UpperCamelCase_											=				[
										    torch.randn(_lowerCAmelCase				,		generator=generator[i]				,		device=_lowerCAmelCase				,		dtype=_lowerCAmelCase				,		layout=_lowerCAmelCase)
										    for i in range(_lowerCAmelCase)
										]
										UpperCamelCase_											=				torch.cat(_lowerCAmelCase				,		dim=0).to(_lowerCAmelCase)
					else:
										UpperCamelCase_											=				torch.randn(_lowerCAmelCase				,		generator=_lowerCAmelCase				,		device=_lowerCAmelCase				,		dtype=_lowerCAmelCase				,		layout=_lowerCAmelCase).to(_lowerCAmelCase)

					return latents






def 				_lowerCAmelCase      (_lowerCAmelCase):
					if is_torch_version("<"				,		"2.0.0") or not hasattr(_lowerCAmelCase				,		"_dynamo"):
										return False
					return isinstance(_lowerCAmelCase				,		torch._dynamo.eval_frame.OptimizedModule)
