




import dataclasses
import re
import string
from typing import Any, Dict, Iterator, List, Mapping, Optional, Sequence, Tuple

import numpy as np

from . import residue_constants


lowercase__				:     List[Any] 		=						Mapping[str, np.ndarray]
lowercase__				:     Any 		=						Mapping[str, Any]  # Is a nested dict.
lowercase__				:     int 		=						0.01
@dataclasses.dataclass(frozen=UpperCAmelCase__			)
class 		UpperCAmelCase   :







						'''simple docstring'''





						lowerCAmelCase_     		=   42  # [num_res, num_atom_type, 3]

						# Amino-acid type for each residue represented as an integer between 0 and
						# 20, where 20 is 'X'.
						lowerCAmelCase_     		=   42  # [num_res]

						# Binary float mask to indicate presence of a particular atom. 1.0 if an atom
						# is present and 0.0 if not. This should be used for loss masking.
						lowerCAmelCase_     		=   42  # [num_res, num_atom_type]

						# Residue index as used in PDB. It is not necessarily continuous or 0-indexed.
						lowerCAmelCase_     		=   42  # [num_res]

						# B-factors, or temperature factors, of each residue (in sq. angstroms units),
						# representing the displacement of the residue from its ground truth mean
						# value.
						lowerCAmelCase_     		=   42  # [num_res, num_atom_type]

						# Chain indices for multi-chain predictions
						lowerCAmelCase_     		=   None

						# Optional remark about the protein. Included as a comment in output PDB
						# files
						lowerCAmelCase_     		=   None

						# Templates used to generate this protein (prediction-only)
						lowerCAmelCase_     		=   None

						# Chain corresponding to each parent
						lowerCAmelCase_     		=   None







def 						lowerCamelCase__    (		_A							):







	'''simple docstring'''





	snake_case_		    =     R"(\[[A-Z]+\]\n)"
	snake_case_		    =     [tag.strip() for tag in re.split(_A     ,	_A							) if len(_A							) > 0]
	snake_case_		    =     zip(tags[0::2]     ,	[l.split("\n"							) for l in tags[1::2]]							)

	snake_case_		    =     ["N", "CA", "C"]
	snake_case_		    =     None
	snake_case_		    =     None
	snake_case_		    =     None
	for g in groups:
		if "[PRIMARY]" == g[0]:
			snake_case_		    =     g[1][0].strip()
			for i in range(len(_A							)							):
				if seq[i] not in residue_constants.restypes:
					snake_case_		    =     "X"  # FIXME: strings are immutable
			snake_case_		    =     np.array(
			    [residue_constants.restype_order.get(_A     ,	residue_constants.restype_num							) for res_symbol in seq]							)
		elif "[TERTIARY]" == g[0]:
			snake_case_		    =     []
			for axis in range(3							):
				tertiary.append(list(map(_A     ,	g[1][axis].split()							)							)							)
			snake_case_		    =     np.array(_A							)
			snake_case_		    =     np.zeros((len(tertiary[0]							) // 3, residue_constants.atom_type_num, 3)							).astype(np.floataa							)
			for i, atom in enumerate(_A							):
				snake_case_		    =     np.transpose(tertiary_np[:, i::3]							)
			atom_positions *= PICO_TO_ANGSTROM
		elif "[MASK]" == g[0]:
			snake_case_		    =     np.array(list(map({"-": 0, "+": 1}.get     ,	g[1][0].strip()							)							)							)
			snake_case_		    =     np.zeros(
			    (
			        len(_A							),
			        residue_constants.atom_type_num,
			    )							).astype(np.floataa							)
			for i, atom in enumerate(_A							):
				snake_case_		    =     1
			atom_mask *= mask[..., None]

	assert aatype is not None

	return Protein(
	    atom_positions=_A     ,	atom_mask=_A     ,	aatype=_A     ,	residue_index=np.arange(len(_A							)							)     ,	b_factors=_A     ,	)


def 						lowerCamelCase__    (		_A     ,	_A = 0							):







	'''simple docstring'''





	snake_case_		    =     []

	snake_case_		    =     prot.remark
	if remark is not None:
		pdb_headers.append(f"REMARK {remark}"							)

	snake_case_		    =     prot.parents
	snake_case_		    =     prot.parents_chain_index
	if parents is not None and parents_chain_index is not None:
		snake_case_		    =     [p for i, p in zip(_A     ,	_A							) if i == chain_id]

	if parents is None or len(_A							) == 0:
		snake_case_		    =     ["N/A"]

	pdb_headers.append(f"PARENT {' '.join(_A							)}"							)

	return pdb_headers


def 						lowerCamelCase__    (		_A     ,	_A							):







	'''simple docstring'''





	snake_case_		    =     []
	snake_case_		    =     pdb_str.split("\n"							)

	snake_case_		    =     prot.remark
	if remark is not None:
		out_pdb_lines.append(f"REMARK {remark}"							)

	snake_case_		    =     42
	if prot.parents is not None and len(prot.parents							) > 0:
		snake_case_		    =     []
		if prot.parents_chain_index is not None:
			snake_case_		    =     {}
			for p, i in zip(prot.parents     ,	prot.parents_chain_index							):
				parent_dict.setdefault(str(_A							)     ,	[]							)
				parent_dict[str(_A							)].append(_A							)

			snake_case_		    =     max([int(_A							) for chain_idx in parent_dict]							)
			for i in range(max_idx + 1							):
				snake_case_		    =     parent_dict.get(str(_A							)     ,	["N/A"]							)
				parents_per_chain.append(_A							)
		else:
			parents_per_chain.append(list(prot.parents							)							)
	else:
		snake_case_		    =     [["N/A"]]

	def make_parent_line(_A							) -> str:
		return f"PARENT {' '.join(_A							)}"

	out_pdb_lines.append(make_parent_line(parents_per_chain[0]							)							)

	snake_case_		    =     0
	for i, l in enumerate(_A							):
		if "PARENT" not in l and "REMARK" not in l:
			out_pdb_lines.append(_A							)
		if "TER" in l and "END" not in lines[i + 1]:
			chain_counter += 1
			if not chain_counter >= len(_A							):
				snake_case_		    =     parents_per_chain[chain_counter]
			else:
				snake_case_		    =     ["N/A"]

			out_pdb_lines.append(make_parent_line(_A							)							)

	return "\n".join(_A							)


def 						lowerCamelCase__    (		_A							):







	'''simple docstring'''





	snake_case_		    =     residue_constants.restypes + ["X"]

	def res_atoa(_A							) -> str:
		return residue_constants.restype_atoa.get(restypes[r]     ,	"UNK"							)

	snake_case_		    =     residue_constants.atom_types

	snake_case_		    =     []

	snake_case_		    =     prot.atom_mask
	snake_case_		    =     prot.aatype
	snake_case_		    =     prot.atom_positions
	snake_case_		    =     prot.residue_index.astype(np.intaa							)
	snake_case_		    =     prot.b_factors
	snake_case_		    =     prot.chain_index

	if np.any(aatype > residue_constants.restype_num							):
		raise ValueError("Invalid aatypes."							)

	snake_case_		    =     get_pdb_headers(_A							)
	if len(_A							) > 0:
		pdb_lines.extend(_A							)

	snake_case_		    =     aatype.shape[0]
	snake_case_		    =     1
	snake_case_		    =     0
	snake_case_		    =     string.ascii_uppercase
	snake_case_		    =     None
	# Add all atom sites.
	for i in range(_A							):
		snake_case_		    =     res_atoa(aatype[i]							)
		for atom_name, pos, mask, b_factor in zip(_A     ,	atom_positions[i]     ,	atom_mask[i]     ,	b_factors[i]							):
			if mask < 0.5:
				continue

			snake_case_		    =     "ATOM"
			snake_case_		    =     atom_name if len(_A							) == 4 else f" {atom_name}"
			snake_case_		    =     ""
			snake_case_		    =     ""
			snake_case_		    =     1.00
			snake_case_		    =     atom_name[0]  # Protein supports only C, N, O, S, this works.
			snake_case_		    =     ""

			snake_case_		    =     "A"
			if chain_index is not None:
				snake_case_		    =     chain_tags[chain_index[i]]

			# PDB is a columnar format, every space matters here!
			snake_case_		    =     (
			    f"{record_type:<6}{atom_index:>5} {name:<4}{alt_loc:>1}"
			    f"{res_name_a:>3} {chain_tag:>1}"
			    f"{residue_index[i]:>4}{insertion_code:>1}   "
			    f"{pos[0]:>8.3f}{pos[1]:>8.3f}{pos[2]:>8.3f}"
			    f"{occupancy:>6.2f}{b_factor:>6.2f}          "
			    f"{element:>2}{charge:>2}"
			)
			pdb_lines.append(_A							)
			atom_index += 1

		snake_case_		    =     i == n - 1
		if chain_index is not None:
			if i != n - 1 and chain_index[i + 1] != prev_chain_index:
				snake_case_		    =     True
				snake_case_		    =     chain_index[i + 1]

		if should_terminate:
			# Close the chain.
			snake_case_		    =     "TER"
			snake_case_		    =     (
			    f"{chain_end:<6}{atom_index:>5}      {res_atoa(aatype[i]							):>3} {chain_tag:>1}{residue_index[i]:>4}"
			)
			pdb_lines.append(_A							)
			atom_index += 1

			if i != n - 1:
				# "prev" is a misnomer here. This happens at the beginning of
				# each new chain.
				pdb_lines.extend(get_pdb_headers(_A     ,	_A							)							)

	pdb_lines.append("END"							)
	pdb_lines.append(""							)
	return "\n".join(_A							)


def 						lowerCamelCase__    (		_A							):







	'''simple docstring'''





	return residue_constants.STANDARD_ATOM_MASK[prot.aatype]






def 						lowerCamelCase__    (		_A     ,	_A     ,	_A = None     ,	_A = None     ,	_A = None     ,	_A = None     ,	_A = None     ,	):







	'''simple docstring'''





	return Protein(
	    aatype=features["aatype"]     ,	atom_positions=result["final_atom_positions"]     ,	atom_mask=result["final_atom_mask"]     ,	residue_index=features["residue_index"] + 1     ,	b_factors=b_factors if b_factors is not None else np.zeros_like(result["final_atom_mask"]							)     ,	chain_index=_A     ,	remark=_A     ,	parents=_A     ,	parents_chain_index=_A     ,	)






def 						lowerCamelCase__    (		):







	'''simple docstring'''





	snake_case_		    =     []
	snake_case_		    =     1

	while len(_A							) < 1E6:
		constant.append(str(_A							)							)
		i += 1

	snake_case_		    =     "".join(_A							)

	return (
	    int(constant[0]							)
	    * int(constant[9]							)
	    * int(constant[99]							)
	    * int(constant[999]							)
	    * int(constant[9999]							)
	    * int(constant[99999]							)
	    * int(constant[999999]							)
	)


if __name__ == "__main__":
		print(solution())
