




'''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


_lowercase  =			Mapping[str, np.ndarray]
_lowercase  =			Mapping[str, Any]  # Is a nested dict.
_lowercase  =			0.01
@dataclasses.dataclass(frozen=UpperCAmelCase__						)
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 						lowerCamelCase__   (				a							):
						__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							):
						__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							):
						__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							):
						__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							):
						return residue_constants.STANDARD_ATOM_MASK[prot.aatype]






def 						lowerCamelCase__   (				a    ,	a    ,	a = None    ,	a = None    ,	a = None    ,	a = None    ,	a = None    ,	):
						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    ,	)







'''simple docstring'''


def 						lowerCamelCase__   (				a							):
						if number < 0:
												raise ValueError('number must not be negative'							)
						return number & (number - 1) == 0


if __name__ == "__main__":
	import doctest

	doctest.testmod()

