





'''simple docstring'''






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


__UpperCamelCase					    =	Mapping[str, np.ndarray]
__UpperCamelCase					    =	Mapping[str, Any]  # Is a nested dict.
__UpperCamelCase					    =	0.01




@dataclasses.dataclass(frozen=__lowercase		)
class  _A :
		lowercase__:   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'.
		lowercase__:   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.
		lowercase__:   np.ndarray  # [num_res, num_atom_type]

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

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

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

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

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







def 					_a						(       _lowerCamelCase ) ->				Protein:



			"""simple docstring"""


			__snake_case					:      List[str]							      =     R"""(\[[A-Z]+\]\n)"""
			__snake_case					:      List[str]							      =     [tag.strip() for tag in re.split(_lowerCamelCase    ,	_lowerCamelCase ) if len(_lowerCamelCase ) > 0]
			__snake_case					:      Iterator[Tuple[str, List[str]]]							      =     zip(tags[0::2]    ,	[l.split("""\n""" ) for l in tags[1::2]] )

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

			assert aatype is not None

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







def 					_a						(       _lowerCamelCase    ,	_lowerCamelCase = 0 ) ->				List[str]:



			"""simple docstring"""


			__snake_case					:      List[str]							      =     []

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

			__snake_case					:      Optional[int]							      =     prot.parents
			__snake_case					:      Optional[int]							      =     prot.parents_chain_index
			if parents is not None and parents_chain_index is not None:
						__snake_case					:      Any							      =     [p for i, p in zip(_lowerCamelCase    ,	_lowerCamelCase ) if i == chain_id]

			if parents is None or len(_lowerCamelCase ) == 0:
						__snake_case					:      str							      =     ["""N/A"""]

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

			return pdb_headers







def 					_a						(       _lowerCamelCase    ,	_lowerCamelCase ) ->				str:



			"""simple docstring"""


			__snake_case					:      List[str]							      =     []
			__snake_case					:      int							      =     pdb_str.split("""\n""" )

			__snake_case					:      Union[str, Any]							      =     prot.remark
			if remark is not None:
						out_pdb_lines.append(F'''REMARK {remark}''' )

			__snake_case					:      List[List[str]]
			if prot.parents is not None and len(prot.parents ) > 0:
						__snake_case					:      Union[str, Any]							      =     []
						if prot.parents_chain_index is not None:
									__snake_case					:      Dict[str, List[str]]							      =     {}
									for p, i in zip(prot.parents    ,	prot.parents_chain_index ):
												parent_dict.setdefault(str(_lowerCamelCase )    ,	[] )
												parent_dict[str(_lowerCamelCase )].append(_lowerCamelCase )

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

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

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

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

									out_pdb_lines.append(make_parent_line(_lowerCamelCase ) )

			return "\n".join(_lowerCamelCase )







def 					_a						(       _lowerCamelCase ) ->				str:



			"""simple docstring"""


			__snake_case					:      Optional[int]							      =     residue_constants.restypes + ["""X"""]

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

			__snake_case					:      Union[str, Any]							      =     residue_constants.atom_types

			__snake_case					:      List[str]							      =     []

			__snake_case					:      int							      =     prot.atom_mask
			__snake_case					:      Optional[int]							      =     prot.aatype
			__snake_case					:      List[str]							      =     prot.atom_positions
			__snake_case					:      str							      =     prot.residue_index.astype(np.intaa )
			__snake_case					:      Optional[int]							      =     prot.b_factors
			__snake_case					:      str							      =     prot.chain_index

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

			__snake_case					:      Optional[int]							      =     get_pdb_headers(_lowerCamelCase )
			if len(_lowerCamelCase ) > 0:
						pdb_lines.extend(_lowerCamelCase )

			__snake_case					:      Dict							      =     aatype.shape[0]
			__snake_case					:      Optional[int]							      =     1
			__snake_case					:      List[str]							      =     0
			__snake_case					:      Optional[Any]							      =     string.ascii_uppercase
			__snake_case					:      Tuple							      =     None
			# Add all atom sites.
			for i in range(_lowerCamelCase ):
						__snake_case					:      Optional[Any]							      =     res_atoa(aatype[i] )
						for atom_name, pos, mask, b_factor in zip(_lowerCamelCase    ,	atom_positions[i]    ,	atom_mask[i]    ,	b_factors[i] ):
									if mask < 0.5:
												continue

									__snake_case					:      int							      =     """ATOM"""
									__snake_case					:      int							      =     atom_name if len(_lowerCamelCase ) == 4 else F''' {atom_name}'''
									__snake_case					:      List[str]							      =     """"""
									__snake_case					:      Optional[Any]							      =     """"""
									__snake_case					:      Any							      =     1.00
									__snake_case					:      Optional[Any]							      =     atom_name[0]  # Protein supports only C, N, O, S, this works.
									__snake_case					:      List[Any]							      =     """"""

									__snake_case					:      Tuple							      =     """A"""
									if chain_index is not None:
												__snake_case					:      Optional[int]							      =     chain_tags[chain_index[i]]

									# PDB is a columnar format, every space matters here!
									__snake_case					:      Optional[int]							      =     (
									    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(_lowerCamelCase )
									atom_index += 1

						__snake_case					:      List[str]							      =     i == n - 1
						if chain_index is not None:
									if i != n - 1 and chain_index[i + 1] != prev_chain_index:
												__snake_case					:      Optional[Any]							      =     True
												__snake_case					:      Union[str, Any]							      =     chain_index[i + 1]

						if should_terminate:
									# Close the chain.
									__snake_case					:      Optional[Any]							      =     """TER"""
									__snake_case					:      List[str]							      =     (
									    F'''{chain_end:<6}{atom_index:>5}      {res_atoa(aatype[i] ):>3} {chain_tag:>1}{residue_index[i]:>4}'''
									)
									pdb_lines.append(_lowerCamelCase )
									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(_lowerCamelCase    ,	_lowerCamelCase ) )

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







def 					_a						(       _lowerCamelCase ) ->				np.ndarray:



			"""simple docstring"""


			return residue_constants.STANDARD_ATOM_MASK[prot.aatype]







def 					_a						(       _lowerCamelCase    ,	_lowerCamelCase    ,	_lowerCamelCase = None    ,	_lowerCamelCase = None    ,	_lowerCamelCase = None    ,	_lowerCamelCase = None    ,	_lowerCamelCase = 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=_lowerCamelCase    ,	remark=_lowerCamelCase    ,	parents=_lowerCamelCase    ,	parents_chain_index=_lowerCamelCase    ,	)









'''simple docstring'''






def 					_a						(       _lowerCamelCase ) ->				int:



			"""simple docstring"""


			if not isinstance(_lowerCamelCase    ,	_lowerCamelCase ):
						raise TypeError("""only integers accepted as input""" )
			else:
						__snake_case					:      List[Any]							      =     str(abs(_lowerCamelCase ) )
						__snake_case					:      Union[str, Any]							      =     [list(_lowerCamelCase ) for char in range(len(_lowerCamelCase ) )]
						for index in range(len(_lowerCamelCase ) ):
									num_transpositions[index].pop(_lowerCamelCase )
						return max(
						    int("""""".join(list(_lowerCamelCase ) ) ) for transposition in num_transpositions )


if __name__ == "__main__":
	__import__("doctest").testmod()


