





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


A       :   Dict					= Mapping[str, np.ndarray]
A       :   Optional[int]					= Mapping[str, Any]  # Is a nested dict.
A       :   Optional[Any]					= 0.01


@dataclasses.dataclass(frozen=SCREAMING_SNAKE_CASE       )
class     A     :
			'''simple docstring'''




			__lowerCamelCase      :			np.ndarray  # [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      :			np.ndarray  # [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      :			np.ndarray  # [num_res, num_atom_type]

			# Residue index as used in PDB. It is not necessarily continuous or 0-indexed.
			__lowerCamelCase      :			np.ndarray  # [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      :			np.ndarray  # [num_res, num_atom_type]

			# Chain indices for multi-chain predictions
			__lowerCamelCase      :			Optional[np.ndarray]							     =       None

			# Optional remark about the protein. Included as a comment in output PDB
			# files
			__lowerCamelCase      :			Optional[str]							     =       None

			# Templates used to generate this protein (prediction-only)
			__lowerCamelCase      :			Optional[Sequence[str]]							     =       None

			# Chain corresponding to each parent
			__lowerCamelCase      :			Optional[Sequence[int]]							     =       None







def   __lowerCamelCase   (				__a  :str       )						->							Protein:






		"""simple docstring"""

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

		A__     =  ["N", "CA", "C"]
		A__     =  None
		A__     =  None
		A__     =  None
		for g in groups:
				if "[PRIMARY]" == g[0]:
						A__     =  g[1][0].strip()
						for i in range(len(__a       )       ):
								if seq[i] not in residue_constants.restypes:
										A__     =  """X"""  # FIXME: strings are immutable
						A__     =  np.array(
						    [residue_constants.restype_order.get(__a       ,	residue_constants.restype_num       ) for res_symbol in seq]       )
				elif "[TERTIARY]" == g[0]:
						A__     =  []
						for axis in range(3       ):
								tertiary.append(list(map(__a       ,	g[1][axis].split()       )       )       )
						A__     =  np.array(__a       )
						A__     =  np.zeros((len(tertiary[0]       ) // 3, residue_constants.atom_type_num, 3)       ).astype(np.floataa       )
						for i, atom in enumerate(__a       ):
								A__     =  np.transpose(tertiary_np[:, i::3]       )
						atom_positions *= PICO_TO_ANGSTROM
				elif "[MASK]" == g[0]:
						A__     =  np.array(list(map({"""-""": 0, """+""": 1}.get       ,	g[1][0].strip()       )       )       )
						A__     =  np.zeros(
						    (
						        len(__a       ),
						        residue_constants.atom_type_num,
						    )       ).astype(np.floataa       )
						for i, atom in enumerate(__a       ):
								A__     =  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  :Protein       ,	__a  :int = 0       )						->							List[str]:






		"""simple docstring"""

		A__     =  []

		A__     =  prot.remark
		if remark is not None:
				pdb_headers.append(F'REMARK {remark}'       )

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

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

		pdb_headers.append(F'PARENT {" ".join(__a       )}'       )

		return pdb_headers







def   __lowerCamelCase   (				__a  :Protein       ,	__a  :str       )						->							str:






		"""simple docstring"""

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

		A__     =  prot.remark
		if remark is not None:
				out_pdb_lines.append(F'REMARK {remark}'       )

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

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

		def make_parent_line(__a  :Sequence[str]       ) -> str:
				return F'PARENT {" ".join(__a       )}'

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

		A__     =  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       ):
								A__     =  parents_per_chain[chain_counter]
						else:
								A__     =  ["""N/A"""]

						out_pdb_lines.append(make_parent_line(__a       )       )

		return "\n".join(__a       )







def   __lowerCamelCase   (				__a  :Protein       )						->							str:






		"""simple docstring"""

		A__     =  residue_constants.restypes + ["""X"""]

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

		A__     =  residue_constants.atom_types

		A__     =  []

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

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

		A__     =  get_pdb_headers(__a       )
		if len(__a       ) > 0:
				pdb_lines.extend(__a       )

		A__     =  aatype.shape[0]
		A__     =  1
		A__     =  0
		A__     =  string.ascii_uppercase
		A__     =  None
		# Add all atom sites.
		for i in range(__a       ):
				A__     =  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

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

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

						# PDB is a columnar format, every space matters here!
						A__     =  (
						    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

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

				if should_terminate:
						# Close the chain.
						A__     =  """TER"""
						A__     =  (
						    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  :Protein       )						->							np.ndarray:






		"""simple docstring"""

		return residue_constants.STANDARD_ATOM_MASK[prot.aatype]







def   __lowerCamelCase   (				__a  :FeatureDict       ,	__a  :ModelOutput       ,	__a  :Optional[np.ndarray] = None       ,	__a  :Optional[np.ndarray] = None       ,	__a  :Optional[str] = None       ,	__a  :Optional[Sequence[str]] = None       ,	__a  :Optional[Sequence[int]] = None       ,	)						->							Protein:






		"""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   (				__a  :str       )						->							bool:






		"""simple docstring"""

		A__     =  0
		for ch in input_str:
				A__     =  ord(__a       )
				A__     =  pow(2       ,	__a       )

				# If we already turned on bit for current character's unicode
				if bitmap >> ch_unicode & 1 == 1:
						return False
				bitmap |= ch_bit_index_on
		return True


if __name__ == "__main__":
					import doctest

					doctest.testmod()



