


import argparse
import pathlib
from pathlib import Path
from tempfile import TemporaryDirectory

import esm as esm_module
import torch
from esm.esmfold.va.misc import batch_encode_sequences as esmfold_encode_sequences
from esm.esmfold.va.pretrained import esmfold_va

from transformers.models.esm.configuration_esm import EsmConfig, EsmFoldConfig
from transformers.models.esm.modeling_esm import (
    EsmForMaskedLM,
    EsmForSequenceClassification,
    EsmIntermediate,
    EsmLayer,
    EsmOutput,
    EsmSelfAttention,
    EsmSelfOutput,
)
from transformers.models.esm.modeling_esmfold import EsmForProteinFolding
from transformers.models.esm.tokenization_esm import EsmTokenizer
from transformers.utils import logging


logging.set_verbosity_info()
A_    :					Optional[int]             =logging.get_logger(__name__)

A_    :					Tuple             =[
    (
        """protein1""",
        """MNGTEGPNFYVPFSNATGVVRSPFEYPQYYLAEPWQFSMLAAYMFLLIVLGFPINFLTLYVTVQHKKLRTPLNYILLNLAVADLFMVLGGFTSTLYTSLHGYFVFGPTGCNLEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFGENHAIMGVAFTWVMALACAAPPLAGWSRYIPEGLQCSCGIDYYTLKPEVNNESFVIYMFVVHFTIPMIIIFFCYGQLVFTVKEAAAQQQESATTQKAEKEVTRMVIIMVIAFLICWVPYASVAFYIFTHQGSNFGPIFMTIPAFFAKSAAIYNPVIYIMMNKQFRNCMLTTICCGKNPLGDDEASATVSKTETSQVAPA""",
    ),
    ("""protein2""", """MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLA"""),
    ("""protein3""", """MKTVRQERLKSI<mask>RILERSKEPVSGAQLAEELS<mask>SRQVIVQDIAYLRSLGYN<mask>VATPRGYVLAGG"""),
    ("""protein4""", """MKTVRQERLKSI<mask>RILERSKEPVSGAQLAEELS<mask>SRQVIVQDIAYLRSLGYN<mask>VATPRGYVLA"""),
]

A_    :					Optional[int]             ={
    """esm1b_t33_650M_UR50S""": esm_module.pretrained.esm1b_t33_650M_UR50S,
    """esm1v_t33_650M_UR90S_1""": esm_module.pretrained.esm1v_t33_650M_UR90S_1,
    """esm1v_t33_650M_UR90S_2""": esm_module.pretrained.esm1v_t33_650M_UR90S_2,
    """esm1v_t33_650M_UR90S_3""": esm_module.pretrained.esm1v_t33_650M_UR90S_3,
    """esm1v_t33_650M_UR90S_4""": esm_module.pretrained.esm1v_t33_650M_UR90S_4,
    """esm1v_t33_650M_UR90S_5""": esm_module.pretrained.esm1v_t33_650M_UR90S_5,
    """esm2_t48_15B_UR50D""": esm_module.pretrained.esm2_t48_15B_UR50D,
    """esm2_t36_3B_UR50D""": esm_module.pretrained.esm2_t36_3B_UR50D,
    """esm2_t33_650M_UR50D""": esm_module.pretrained.esm2_t33_650M_UR50D,
    """esm2_t30_150M_UR50D""": esm_module.pretrained.esm2_t30_150M_UR50D,
    """esm2_t12_35M_UR50D""": esm_module.pretrained.esm2_t12_35M_UR50D,
    """esm2_t6_8M_UR50D""": esm_module.pretrained.esm2_t6_8M_UR50D,
    """esmfold_v1""": esmfold_va,
}

A_    :					str             =list("""ARNDCQEGHILKMFPSTWYV""")

A_    :					int             =restypes + ["""X"""]
A_    :					Optional[Any]             =restypes_with_x + ["""<pad>""", """<mask>""", """<cls>""", """<sep>""", """<eos>"""]




def   lowerCamelCase_       (					):



						"""simple docstring"""




						with TemporaryDirectory() as tempdir:
												a_					=		"""\n""".join(UpperCAmelCase__      )
												a_					=		Path(UpperCAmelCase__      ) / """vocab.txt"""
												vocab_file.write_text(UpperCAmelCase__      )
												a_					=		EsmTokenizer(vocab_file=str(UpperCAmelCase__      )      )
						a_					=		0  # Overlaps with 'A' but that seems to be what they want
						return hf_tokenizer




def   lowerCamelCase_       (					UpperCAmelCase__       ,    UpperCAmelCase__      ):



						"""simple docstring"""




						a_					=		our_module.load_state_dict(original_module.state_dict()      )
						if status.missing_keys:
												raise ValueError(F"Missing keys: {status.missing_keys}"      )
						if status.unexpected_keys:
												raise ValueError(F"Unexpected keys: {status.unexpected_keys}"      )




def   lowerCamelCase_       (					UpperCAmelCase__       ,    UpperCAmelCase__       ,    UpperCAmelCase__       ,    UpperCAmelCase__       ,    UpperCAmelCase__      ):



						"""simple docstring"""




						if model.startswith("""esmfold"""      ):
												a_					=		MODEL_MAPPING[model]()
						else:
												a_			,   a_					=		MODEL_MAPPING[model]()
						esm.eval()  # disable dropout

						if model.startswith("""esmfold"""      ):
												a_					=		esm.esm.embed_dim
												a_					=		esm.esm.num_layers
												a_					=		esm.esm.attention_heads
												a_					=		4 * embed_dim
												a_					=		esm.esm.token_dropout
												a_					=		False  # This code path does not exist in ESM-2
												a_					=		"""rotary"""
												a_					=		True
												a_					=		EsmFoldConfig()
												for key, val in esm.cfg.items():
																		if hasattr(UpperCAmelCase__       ,    UpperCAmelCase__      ) and key != "trunk":
																								setattr(UpperCAmelCase__       ,    UpperCAmelCase__       ,    UpperCAmelCase__      )
												for key, val in esm.cfg.trunk.items():
																		if hasattr(esmfold_config.trunk       ,    UpperCAmelCase__      ) and key != "structure_module":
																								setattr(esmfold_config.trunk       ,    UpperCAmelCase__       ,    UpperCAmelCase__      )
												for key, val in esm.cfg.trunk.structure_module.items():
																		if hasattr(esmfold_config.trunk.structure_module       ,    UpperCAmelCase__      ):
																								setattr(esmfold_config.trunk.structure_module       ,    UpperCAmelCase__       ,    UpperCAmelCase__      )
						elif hasattr(UpperCAmelCase__       ,    """args"""      ):
												# Indicates an ESM-1b or ESM-1v model
												a_					=		esm.args.embed_dim
												a_					=		esm.args.layers
												a_					=		esm.args.attention_heads
												a_					=		esm.args.ffn_embed_dim
												a_					=		esm.args.token_dropout
												a_					=		True if esm.emb_layer_norm_before else False
												a_					=		"""absolute"""
												a_					=		False
												a_					=		None
						else:
												# Indicates an ESM-2 model
												a_					=		esm.embed_dim
												a_					=		esm.num_layers
												a_					=		esm.attention_heads
												a_					=		4 * embed_dim  # This is hardcoded in ESM-2
												a_					=		esm.token_dropout
												a_					=		False  # This code path does not exist in ESM-2
												a_					=		"""rotary"""
												a_					=		False
												a_					=		None

						if is_folding_model:
												a_					=		esm.esm.alphabet
						a_					=		tuple(alphabet.all_toks      )
						a_					=		alphabet.mask_idx
						a_					=		alphabet.padding_idx

						if is_folding_model:
												a_					=		esm.esm
						else:
												a_					=		esm

						a_					=		EsmConfig(
						    vocab_size=original_esm_model.embed_tokens.num_embeddings       ,    mask_token_id=UpperCAmelCase__       ,    hidden_size=UpperCAmelCase__       ,    num_hidden_layers=UpperCAmelCase__       ,    num_attention_heads=UpperCAmelCase__       ,    intermediate_size=UpperCAmelCase__       ,    max_position_embeddings=1_026       ,    layer_norm_eps=1e-5       ,    attention_probs_dropout_prob=0.0       ,    hidden_dropout_prob=0.0       ,    pad_token_id=UpperCAmelCase__       ,    emb_layer_norm_before=UpperCAmelCase__       ,    token_dropout=UpperCAmelCase__       ,    position_embedding_type=UpperCAmelCase__       ,    is_folding_model=UpperCAmelCase__       ,    esmfold_config=UpperCAmelCase__       ,    vocab_list=UpperCAmelCase__       ,    )
						if classification_head:
												a_					=		esm.classification_heads["""mnli"""].out_proj.weight.shape[0]
						print("""Our ESM config:"""       ,    UpperCAmelCase__      )

						if model.startswith("""esmfold"""      ):
												a_					=		EsmForProteinFolding
						elif classification_head:
												a_					=		EsmForSequenceClassification
						else:
												a_					=		EsmForMaskedLM
						a_					=		model_class(UpperCAmelCase__      )
						model.eval()

						# Now let's copy all the weights.
						# Embeddings
						a_					=		original_esm_model.embed_tokens.weight
						if position_embedding_type == "absolute":
												a_					=		original_esm_model.embed_positions.weight

						if config.emb_layer_norm_before:
												a_					=		original_esm_model.emb_layer_norm_before.weight
												a_					=		original_esm_model.emb_layer_norm_before.bias

						a_					=		original_esm_model.emb_layer_norm_after.weight
						a_					=		original_esm_model.emb_layer_norm_after.bias

						for i in range(config.num_hidden_layers      ):
												# Encoder: start of layer
												a_					=		model.esm.encoder.layer[i]
												# esm_layer: TransformerSentenceEncoderLayer = original_esm_model.layers[i]
												a_					=		original_esm_model.layers[i]

												# self attention
												a_					=		layer.attention.self
												assert (
												    esm_layer.self_attn.k_proj.weight.data.shape
												    == esm_layer.self_attn.q_proj.weight.data.shape
												    == esm_layer.self_attn.v_proj.weight.data.shape
												    == torch.Size((config.hidden_size, config.hidden_size)      )
												)

												a_					=		esm_layer.self_attn.q_proj.weight
												a_					=		esm_layer.self_attn.q_proj.bias
												a_					=		esm_layer.self_attn.k_proj.weight
												a_					=		esm_layer.self_attn.k_proj.bias
												a_					=		esm_layer.self_attn.v_proj.weight
												a_					=		esm_layer.self_attn.v_proj.bias

												if getattr(esm_layer.self_attn       ,    """rot_emb"""       ,    UpperCAmelCase__      ) is not None:
																		# Matt: Although inv_freq is not a trainable weight, it is computed at model init and cached.
																		# During the training of ESM-2 the model was converted to float16 precision, which also converts
																		# the inv_freq tensor, and the loss of precision remains even if the model is loaded later as float32.
																		# If we recompute inv_freq without this loss of precision then we will get subtly different rotary
																		# embeddings, which are enough to cause significant discrepancies in model outputs. To avoid this,
																		# we make sure the new model copies the data from the old inv_freq.
																		a_					=		esm_layer.self_attn.rot_emb.inv_freq

												# LayerNorm changes for pre-activation
												a_					=		esm_layer.self_attn_layer_norm.weight
												a_					=		esm_layer.self_attn_layer_norm.bias
												a_					=		esm_layer.final_layer_norm.weight
												a_					=		esm_layer.final_layer_norm.bias

												# self-attention output
												a_					=		layer.attention.output
												assert self_output.dense.weight.shape == esm_layer.self_attn.out_proj.weight.shape
												a_					=		esm_layer.self_attn.out_proj.weight
												a_					=		esm_layer.self_attn.out_proj.bias

												# intermediate
												a_					=		layer.intermediate
												assert intermediate.dense.weight.shape == esm_layer.fca.weight.shape
												a_					=		esm_layer.fca.weight
												a_					=		esm_layer.fca.bias

												# output
												a_					=		layer.output
												assert bert_output.dense.weight.shape == esm_layer.fca.weight.shape
												a_					=		esm_layer.fca.weight
												a_					=		esm_layer.fca.bias
												# end of layer

						if is_folding_model:
												a_					=		esm.esm_s_combine.data
												a_					=		esm.afa_to_esm.data
												transfer_and_check_weights(esm.embedding       ,    model.embedding      )
												transfer_and_check_weights(esm.esm_s_mlp       ,    model.esm_s_mlp      )
												transfer_and_check_weights(esm.trunk       ,    model.trunk      )
												transfer_and_check_weights(esm.distogram_head       ,    model.distogram_head      )
												transfer_and_check_weights(esm.ptm_head       ,    model.ptm_head      )
												transfer_and_check_weights(esm.lm_head       ,    model.lm_head      )
												transfer_and_check_weights(esm.lddt_head       ,    model.lddt_head      )

						elif classification_head:
												a_					=		esm.esm.classification_heads["""mnli"""].dense.weight
												a_					=		esm.classification_heads["""mnli"""].dense.bias
												a_					=		esm.classification_heads["""mnli"""].out_proj.weight
												a_					=		esm.classification_heads["""mnli"""].out_proj.bias
						else:
												# LM Head
												a_					=		esm.lm_head.dense.weight
												a_					=		esm.lm_head.dense.bias
												a_					=		esm.lm_head.layer_norm.weight
												a_					=		esm.lm_head.layer_norm.bias
												a_					=		esm.lm_head.weight
												a_					=		esm.lm_head.bias

						# Contact prediction head
						transfer_and_check_weights(esm.contact_head       ,    model.esm.contact_head      )

						# Prepare data (first 2 sequences from ESMStructuralSplitDataset superfamily / 4)
						if is_folding_model:
												# Folding models aren't trained on masked inputs and don't like mask tokens.
												a_					=		SAMPLE_DATA[:2]
						else:
												a_					=		SAMPLE_DATA

						if is_folding_model:
												a_					=		get_esmfold_tokenizer()
												a_					=		hf_tokenizer(
												    [row[1] for row in sample_data]       ,    return_tensors="""pt"""       ,    padding=UpperCAmelCase__       ,    add_special_tokens=UpperCAmelCase__      )
												a_			,   a_			,   a_			,   a_			,   a_					=		esmfold_encode_sequences([row[1] for row in sample_data]      )
												a_					=		torch.all(hf_tokens["""input_ids"""] == esmfold_aas      ) and torch.all(
												    hf_tokens["""attention_mask"""] == esmfold_mask      )
						else:
												# Let's check that we get the same results.
												a_					=		alphabet.get_batch_converter()
												a_			,   a_			,   a_					=		batch_converter(UpperCAmelCase__      )
												# Prepare tokenizer and make sure it matches
												with TemporaryDirectory() as tempdir:
																		a_					=		"""\n""".join(alphabet.all_toks      )
																		a_					=		Path(UpperCAmelCase__      ) / """vocab.txt"""
																		vocab_file.write_text(UpperCAmelCase__      )
																		a_					=		EsmTokenizer(vocab_file=str(UpperCAmelCase__      )      )

												a_					=		hf_tokenizer([row[1] for row in sample_data]       ,    return_tensors="""pt"""       ,    padding=UpperCAmelCase__      )
												a_					=		torch.all(hf_tokens["""input_ids"""] == batch_tokens      )

						print("""Do both models tokenizers output the same tokens?"""       ,    """🔥""" if success else """💩"""      )
						if not success:
												raise Exception("""Tokenization does not match!"""      )

						with torch.no_grad():
												if is_folding_model:
																		# Let's test the model in parts
																		# ESMFold always converts the ESM stem to float16, which requires float16 ops
																		# that don't exist on CPU. Therefore, to test it we need to run it on GPU. However,
																		# ESMFold is what we in the community call a "big boy" and so we desperately avoid putting both the
																		# original and the converted model on the GPU at the same time.
																		a_					=		esm.cuda().infer([row[1] for row in sample_data]      )
																		a_					=		model.cuda()(
																		    input_ids=hf_tokens["""input_ids"""].cuda()       ,    attention_mask=hf_tokens["""attention_mask"""].cuda()      )
												else:
																		a_					=		model(**UpperCAmelCase__       ,    output_hidden_states=UpperCAmelCase__      )
																		a_					=		our_output["""logits"""]
																		if classification_head:
																								a_					=		esm.model.classification_heads["""mnli"""](esm.extract_features(UpperCAmelCase__      )      )
																		else:
																								a_					=		esm(hf_tokens["""input_ids"""]       ,    repr_layers=list(range(999      )      )      )
																								a_					=		their_output["""logits"""]

												if is_folding_model:
																		a_					=		torch.max(torch.abs(our_output["""positions"""] - their_output["""positions"""]      )      ).item()
																		a_					=		torch.allclose(our_output["""positions"""]       ,    their_output["""positions"""]       ,    atol=1e-5      )
												else:
																		a_					=		torch.max(torch.abs(our_output - their_output      )      ).item()
																		a_					=		torch.allclose(UpperCAmelCase__       ,    UpperCAmelCase__       ,    atol=1e-5      )

												print(F"max_absolute_diff = {max_absolute_diff}"      )  # ~ 1e-5
												print("""Do both models output the same tensors?"""       ,    """🔥""" if success else """💩"""      )

												if not success:
																		raise Exception("""Something went wRoNg"""      )

												if not is_folding_model:
																		# Let's check contact prediction too
																		a_					=		model.predict_contacts(hf_tokens["""input_ids"""]       ,    hf_tokens["""attention_mask"""]      )
																		a_					=		esm.predict_contacts(hf_tokens["""input_ids"""]      )
																		a_					=		torch.max(torch.abs(our_output - their_output      )      ).item()
																		a_					=		torch.allclose(UpperCAmelCase__       ,    UpperCAmelCase__       ,    atol=1e-5      )

																		print("""Contact prediction testing:"""      )
																		print(F"max_absolute_diff = {max_absolute_diff}"      )  # ~ 1e-5
																		print("""Do both models output the same tensors?"""       ,    """🔥""" if success else """💩"""      )

																		if not success:
																								raise Exception("""Something went wRoNg"""      )

												pathlib.Path(UpperCAmelCase__      ).mkdir(parents=UpperCAmelCase__       ,    exist_ok=UpperCAmelCase__      )
												print(F"Saving model to {pytorch_dump_folder_path}"      )
												model.save_pretrained(UpperCAmelCase__      )

												del esm  # Free up some memory before continuing

						print(F"Saving tokenizer to {pytorch_dump_folder_path}"      )
						hf_tokenizer.save_pretrained(UpperCAmelCase__      )

						if push_to_repo:
												model.push_to_hub(repo_id=UpperCAmelCase__       ,    use_auth_token=UpperCAmelCase__      )
												hf_tokenizer.push_to_hub(repo_id=UpperCAmelCase__       ,    use_auth_token=UpperCAmelCase__      )


if __name__ == "__main__":
	A_    :					int             =argparse.ArgumentParser()
	# Required parameters
	parser.add_argument(
	    """--pytorch_dump_folder_path""", type=str, required=True, help="""Path to the output PyTorch model."""
	)
	parser.add_argument(
	    """--classification_head""", action="""store_true""", help="""Whether to convert a final classification head."""
	)
	parser.add_argument("""--model""", default=None, type=str, required=True, help="""Name of model to convert.""")
	parser.add_argument("""--push_to_repo""", type=str, help="""Repo to upload to (including username!).""")
	parser.add_argument("""--auth_token""", type=str, help="""HuggingFace auth token.""")
	A_    :					Dict             =parser.parse_args()
	convert_esm_checkpoint_to_pytorch(
	    args.model, args.pytorch_dump_folder_path, args.classification_head, args.push_to_repo, args.auth_token
	)



from collections.abc import Callable
from math import log
from os import name, system
from random import gauss, seed
from typing import TypeVar




def   lowerCamelCase_       (					UpperCAmelCase__       ,    UpperCAmelCase__       ,    UpperCAmelCase__      ):



						"""simple docstring"""




						seed(1      )
						return [gauss(UpperCAmelCase__       ,    UpperCAmelCase__      ) for _ in range(UpperCAmelCase__      )]




def   lowerCamelCase_       (					UpperCAmelCase__       ,    UpperCAmelCase__      ):



						"""simple docstring"""




						return [k for k in range(UpperCAmelCase__      ) for _ in range(instance_count[k]      )]




def   lowerCamelCase_       (					UpperCAmelCase__       ,    UpperCAmelCase__      ):



						"""simple docstring"""




						return sum(UpperCAmelCase__      ) / instance_count




def   lowerCamelCase_       (					UpperCAmelCase__       ,    UpperCAmelCase__      ):



						"""simple docstring"""




						return instance_count / total_count




def   lowerCamelCase_       (					UpperCAmelCase__       ,    UpperCAmelCase__       ,    UpperCAmelCase__      ):



						"""simple docstring"""




						a_					=		[]  # An empty list to store all squared differences
						# iterate over number of elements in items
						for i in range(len(UpperCAmelCase__      )      ):
												# for loop iterates over number of elements in inner layer of items
												for j in range(len(items[i]      )      ):
																		# appending squared differences to 'squared_diff' list
																		squared_diff.append((items[i][j] - means[i]) ** 2      )

    # one divided by (the number of all instances - number of classes) multiplied by
    # sum of all squared differences
						a_					=		len(UpperCAmelCase__      )  # Number of classes in dataset
						return 1 / (total_count - n_classes) * sum(UpperCAmelCase__      )




def   lowerCamelCase_       (					UpperCAmelCase__       ,    UpperCAmelCase__       ,    UpperCAmelCase__       ,    UpperCAmelCase__      ):



						"""simple docstring"""




						a_					=		[]
						# for loop iterates over number of elements in list
						for i in range(len(UpperCAmelCase__      )      ):
												# for loop iterates over number of inner items of each element
												for j in range(len(x_items[i]      )      ):
																		a_					=		[]  # to store all discriminant values of each item as a list
																		# for loop iterates over number of classes we have in our dataset
																		for k in range(len(UpperCAmelCase__      )      ):
																								# appending values of discriminants for each class to 'temp' list
																								temp.append(
																								    x_items[i][j] * (means[k] / variance)
																								    - (means[k] ** 2 / (2 * variance))
																								    + log(probabilities[k]      )      )
																		# appending discriminant values of each item to 'results' list
																		results.append(UpperCAmelCase__      )

						return [result.index(max(UpperCAmelCase__      )      ) for result in results]




def   lowerCamelCase_       (					UpperCAmelCase__       ,    UpperCAmelCase__      ):



						"""simple docstring"""




						a_					=		sum(1 for i, j in zip(UpperCAmelCase__       ,    UpperCAmelCase__      ) if i == j      )
						# percentage of accuracy equals to number of correct predictions divided by number
						# of all data and multiplied by 100
						return (correct / len(UpperCAmelCase__      )) * 100


A_    :					Dict             =TypeVar("""num""")




def   lowerCamelCase_       (					UpperCAmelCase__       ,    UpperCAmelCase__       ,    UpperCAmelCase__       ,    UpperCAmelCase__ = lambda UpperCAmelCase__      : True       ,    UpperCAmelCase__ = None       ,    ):



						"""simple docstring"""




						while True:
												try:
																		a_					=		input_type(input(UpperCAmelCase__      ).strip() or default      )
																		if condition(UpperCAmelCase__      ):
																								return user_input
																		else:
																								print(F"{user_input}: {err_msg}"      )
																								continue
												except ValueError:
																		print(
																		    F"{user_input}: Incorrect input type, expected {input_type.__name__!r}"      )




def   lowerCamelCase_       (					):



						"""simple docstring"""




						while True:
												print(""" Linear Discriminant Analysis """.center(50       ,    """*"""      )      )
												print("""*""" * 50       ,    """\n"""      )
												print("""First of all we should specify the number of classes that"""      )
												print("""we want to generate as training dataset"""      )
												# Trying to get number of classes
												a_					=		valid_input(
												    input_type=UpperCAmelCase__       ,    condition=lambda UpperCAmelCase__      : x > 0       ,    input_msg="""Enter the number of classes (Data Groupings): """       ,    err_msg="""Number of classes should be positive!"""       ,    )

												print("""-""" * 100      )

												# Trying to get the value of standard deviation
												a_					=		valid_input(
												    input_type=UpperCAmelCase__       ,    condition=lambda UpperCAmelCase__      : x >= 0       ,    input_msg=(
												        """Enter the value of standard deviation"""
												        """(Default value is 1.0 for all classes): """
												    )       ,    err_msg="""Standard deviation should not be negative!"""       ,    default="""1.0"""       ,    )

												print("""-""" * 100      )

												# Trying to get number of instances in classes and theirs means to generate
												# dataset
												a_					=		[]  # An empty list to store instance counts of classes in dataset
												for i in range(UpperCAmelCase__      ):
																		a_					=		valid_input(
																		    input_type=UpperCAmelCase__       ,    condition=lambda UpperCAmelCase__      : x > 0       ,    input_msg=(F"Enter The number of instances for class_{i+1}: ")       ,    err_msg="""Number of instances should be positive!"""       ,    )
																		counts.append(UpperCAmelCase__      )
												print("""-""" * 100      )

												# An empty list to store values of user-entered means of classes
												a_					=		[]
												for a in range(UpperCAmelCase__      ):
																		a_					=		valid_input(
																		    input_type=UpperCAmelCase__       ,    input_msg=(F"Enter the value of mean for class_{a+1}: ")       ,    err_msg="""This is an invalid value."""       ,    )
																		user_means.append(UpperCAmelCase__      )
												print("""-""" * 100      )

												print("""Standard deviation: """       ,    UpperCAmelCase__      )
												# print out the number of instances in classes in separated line
												for i, count in enumerate(UpperCAmelCase__       ,    1      ):
																		print(F"Number of instances in class_{i} is: {count}"      )
												print("""-""" * 100      )

												# print out mean values of classes separated line
												for i, user_mean in enumerate(UpperCAmelCase__       ,    1      ):
																		print(F"Mean of class_{i} is: {user_mean}"      )
												print("""-""" * 100      )

												# Generating training dataset drawn from gaussian distribution
												a_					=		[
												    gaussian_distribution(user_means[j]       ,    UpperCAmelCase__       ,    counts[j]      )
												    for j in range(UpperCAmelCase__      )
												]
												print("""Generated Normal Distribution: \n"""       ,    UpperCAmelCase__      )
												print("""-""" * 100      )

												# Generating Ys to detecting corresponding classes
												a_					=		y_generator(UpperCAmelCase__       ,    UpperCAmelCase__      )
												print("""Generated Corresponding Ys: \n"""       ,    UpperCAmelCase__      )
												print("""-""" * 100      )

												# Calculating the value of actual mean for each class
												a_					=		[calculate_mean(counts[k]       ,    x[k]      ) for k in range(UpperCAmelCase__      )]
												# for loop iterates over number of elements in 'actual_means' list and print
												# out them in separated line
												for i, actual_mean in enumerate(UpperCAmelCase__       ,    1      ):
																		print(F"Actual(Real) mean of class_{i} is: {actual_mean}"      )
												print("""-""" * 100      )

												# Calculating the value of probabilities for each class
												a_					=		[
												    calculate_probabilities(counts[i]       ,    sum(UpperCAmelCase__      )      ) for i in range(UpperCAmelCase__      )
												]

												# for loop iterates over number of elements in 'probabilities' list and print
												# out them in separated line
												for i, probability in enumerate(UpperCAmelCase__       ,    1      ):
																		print(F"Probability of class_{i} is: {probability}"      )
												print("""-""" * 100      )

												# Calculating the values of variance for each class
												a_					=		calculate_variance(UpperCAmelCase__       ,    UpperCAmelCase__       ,    sum(UpperCAmelCase__      )      )
												print("""Variance: """       ,    UpperCAmelCase__      )
												print("""-""" * 100      )

												# Predicting Y values
												# storing predicted Y values in 'pre_indexes' variable
												a_					=		predict_y_values(UpperCAmelCase__       ,    UpperCAmelCase__       ,    UpperCAmelCase__       ,    UpperCAmelCase__      )
												print("""-""" * 100      )

												# Calculating Accuracy of the model
												print(F"Accuracy: {accuracy(UpperCAmelCase__       ,    UpperCAmelCase__      )}"      )
												print("""-""" * 100      )
												print(""" DONE """.center(100       ,    """+"""      )      )

												if input("""Press any key to restart or 'q' for quit: """      ).strip().lower() == "q":
																		print("""\n""" + """GoodBye!""".center(100       ,    """-"""      ) + """\n"""      )
																		break
												system("""cls""" if name == """nt""" else """clear"""      )  # noqa: S605


if __name__ == "__main__":
	main()