






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					:		int	  =						Mapping[str, np.ndarray]
__UpperCamelCase					:		int	  =						Mapping[str, Any]  # Is a nested dict.
__UpperCamelCase					:		Any	  =						0.0_1


@dataclasses.dataclass(frozen=a_	)
class   __SCREAMING_SNAKE_CASE:
							_UpperCAmelCase     =       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'.
							_UpperCAmelCase     =       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.
							_UpperCAmelCase     =       42  # [num_res, num_atom_type]

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

							# Chain indices for multi-chain predictions
							_UpperCAmelCase     =       None

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

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

							# Chain corresponding to each parent
							_UpperCAmelCase     =       None


def      a_ (      _A  )			->			Protein:







				"""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      a_ (      _A      ,   _A = 0  )			->			List[str]:







				"""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      a_ (      _A      ,   _A  )			->			str:







				"""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      a_ (      _A  )			->			str:







				"""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      a_ (      _A  )			->			np.ndarray:







				"""simple docstring"""
				return residue_constants.STANDARD_ATOM_MASK[prot.aatype]


def      a_ (      _A      ,   _A      ,   _A = None      ,   _A = None      ,   _A = None      ,   _A = None      ,   _A = 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      ,   )












from __future__ import annotations
def      a_ (      _A  )			->			bool:







				"""simple docstring"""
				return len(set(_A  )  ) == len(_A  )


if __name__ == "__main__":
							import doctest

							doctest.testmod()




