




from typing import Dict, Tuple, overload

import torch
import torch.types
from torch import nn

from . import residue_constants as rc
from .rigid_utils import Rigid, Rotation
from .tensor_utils import batched_gather




@overload
def 							_UpperCAmelCase     (UpperCamelCase_       :       torch.Tensor					,			UpperCamelCase_       :       torch.Tensor					,			UpperCamelCase_       :       None				):
				'''simple docstring'''
				...




@overload
def 							_UpperCAmelCase     (UpperCamelCase_       :       torch.Tensor					,			UpperCamelCase_       :       torch.Tensor					,			UpperCamelCase_       :       torch.Tensor				):
				'''simple docstring'''
				...




def 							_UpperCAmelCase     (UpperCamelCase_       :       str					,			UpperCamelCase_       :       Optional[Any]					,			UpperCamelCase_       :       str				):
				'''simple docstring'''
				_lowerCAmelCase			:			Tuple        =					aatype == rc.restype_order["""G"""]
				_lowerCAmelCase			:			Optional[int]        =					rc.atom_order["""CA"""]
				_lowerCAmelCase			:			List[Any]        =					rc.atom_order["""CB"""]
				_lowerCAmelCase			:			Any        =					torch.where(
				    is_gly[..., None].expand(*((-1,) * len(is_gly.shape				))					,			3				)					,			all_atom_positions[..., ca_idx, :]					,			all_atom_positions[..., cb_idx, :]					,			)

				if all_atom_masks is not None:
								_lowerCAmelCase			:			Union[str, Any]        =					torch.where(
								    UpperCamelCase_					,			all_atom_masks[..., ca_idx]					,			all_atom_masks[..., cb_idx]					,			)
								return pseudo_beta, pseudo_beta_mask
				else:
								return pseudo_beta




def 							_UpperCAmelCase     (UpperCamelCase_       :       torch.Tensor					,			UpperCamelCase_       :       Dict[str, torch.Tensor]				):
				'''simple docstring'''
				_lowerCAmelCase			:			Any        =					batched_gather(
				    UpperCamelCase_					,			batch["""residx_atom37_to_atom14"""]					,			dim=-2					,			no_batch_dims=len(atomaa.shape[:-2]				)					,			)

				_lowerCAmelCase			:			str        =					atomaa_data * batch["""atom37_atom_exists"""][..., None]

				return atomaa_data




def 							_UpperCAmelCase     (UpperCamelCase_       :       Dict[str, torch.Tensor]				):
				'''simple docstring'''
				_lowerCAmelCase			:			List[str]        =					template_feats["""template_aatype"""]
				_lowerCAmelCase			:			int        =					template_feats["""template_torsion_angles_sin_cos"""]
				_lowerCAmelCase			:			Union[str, Any]        =					template_feats["""template_alt_torsion_angles_sin_cos"""]
				_lowerCAmelCase			:			Any        =					template_feats["""template_torsion_angles_mask"""]
				_lowerCAmelCase			:			Any        =					torch.cat(
				    [
				        nn.functional.one_hot(UpperCamelCase_					,			22				),
				        torsion_angles_sin_cos.reshape(*torsion_angles_sin_cos.shape[:-2]					,			14				),
				        alt_torsion_angles_sin_cos.reshape(*alt_torsion_angles_sin_cos.shape[:-2]					,			14				),
				        torsion_angles_mask,
				    ]					,			dim=-1					,			)

				return template_angle_feat




def 							_UpperCAmelCase     (UpperCamelCase_       :       Dict[str, torch.Tensor]					,			UpperCamelCase_       :       torch.types.Number					,			UpperCamelCase_       :       torch.types.Number					,			UpperCamelCase_       :       int					,			UpperCamelCase_       :       bool = False					,			UpperCamelCase_       :       float = 1E-2_0					,			UpperCamelCase_       :       float = 1E8					,			):
				'''simple docstring'''
				_lowerCAmelCase			:			int        =					batch["""template_pseudo_beta_mask"""]
				_lowerCAmelCase			:			int        =					template_mask[..., None] * template_mask[..., None, :]

				# Compute distogram (this seems to differ slightly from Alg. 5)
				_lowerCAmelCase			:			List[Any]        =					batch["""template_pseudo_beta"""]
				_lowerCAmelCase			:			int        =					torch.sum((tpb[..., None, :] - tpb[..., None, :, :]) ** 2					,			dim=-1					,			keepdim=UpperCamelCase_				)
				_lowerCAmelCase			:			Optional[int]        =					torch.linspace(UpperCamelCase_					,			UpperCamelCase_					,			UpperCamelCase_					,			device=tpb.device				) ** 2
				_lowerCAmelCase			:			Optional[int]        =					torch.cat([lower[1:], lower.new_tensor([inf]				)]					,			dim=-1				)
				_lowerCAmelCase			:			Union[str, Any]        =					((dgram > lower) * (dgram < upper)).type(dgram.dtype				)

				_lowerCAmelCase			:			Tuple        =					[dgram, template_mask_ad[..., None]]

				_lowerCAmelCase			:			torch.LongTensor        =					nn.functional.one_hot(
				    batch["""template_aatype"""]					,			rc.restype_num + 2					,			)

				_lowerCAmelCase			:			int        =					batch["""template_aatype"""].shape[-1]
				to_concat.append(aatype_one_hot[..., None, :, :].expand(*aatype_one_hot.shape[:-2]					,			UpperCamelCase_					,			-1					,			-1				)				)
				to_concat.append(aatype_one_hot[..., None, :].expand(*aatype_one_hot.shape[:-2]					,			-1					,			UpperCamelCase_					,			-1				)				)

				_lowerCAmelCase    ,			_lowerCAmelCase    ,			_lowerCAmelCase			:			Dict        =					[rc.atom_order[a] for a in ["""N""", """CA""", """C"""]]
				_lowerCAmelCase			:			Union[str, Any]        =					Rigid.make_transform_from_reference(
				    n_xyz=batch["""template_all_atom_positions"""][..., n, :]					,			ca_xyz=batch["""template_all_atom_positions"""][..., ca, :]					,			c_xyz=batch["""template_all_atom_positions"""][..., c, :]					,			eps=UpperCamelCase_					,			)
				_lowerCAmelCase			:			str        =					rigids.get_trans()[..., None, :, :]
				_lowerCAmelCase			:			Optional[Any]        =					rigids[..., None].invert_apply(UpperCamelCase_				)

				_lowerCAmelCase			:			Optional[int]        =					torch.rsqrt(eps + torch.sum(rigid_vec**2					,			dim=-1				)				)

				_lowerCAmelCase			:			Optional[int]        =					batch["""template_all_atom_mask"""]
				_lowerCAmelCase			:			Optional[Any]        =					t_aa_masks[..., n] * t_aa_masks[..., ca] * t_aa_masks[..., c]
				_lowerCAmelCase			:			Any        =					template_mask[..., None] * template_mask[..., None, :]

				_lowerCAmelCase			:			int        =					inv_distance_scalar * template_mask_ad
				_lowerCAmelCase			:			List[str]        =					rigid_vec * inv_distance_scalar[..., None]

				if not use_unit_vector:
								_lowerCAmelCase			:			Tuple        =					unit_vector * 0.0

				to_concat.extend(torch.unbind(unit_vector[..., None, :]					,			dim=-1				)				)
				to_concat.append(template_mask_ad[..., None]				)

				_lowerCAmelCase			:			Any        =					torch.cat(UpperCamelCase_					,			dim=-1				)
				_lowerCAmelCase			:			List[Any]        =					act * template_mask_ad[..., None]

				return act




def 							_UpperCAmelCase     (UpperCamelCase_       :       Dict[str, torch.Tensor]				):
				'''simple docstring'''
				_lowerCAmelCase			:			torch.LongTensor        =					nn.functional.one_hot(batch["""extra_msa"""]					,			23				)
				_lowerCAmelCase			:			Dict        =					[
				    msa_ahot,
				    batch["""extra_has_deletion"""].unsqueeze(-1				),
				    batch["""extra_deletion_value"""].unsqueeze(-1				),
				]
				return torch.cat(UpperCamelCase_					,			dim=-1				)




def 							_UpperCAmelCase     (UpperCamelCase_       :       Rigid					,			UpperCamelCase_       :       torch.Tensor					,			UpperCamelCase_       :       torch.Tensor					,			UpperCamelCase_       :       torch.Tensor					,			):
				'''simple docstring'''
				# [*, N, 8, 4, 4]
				_lowerCAmelCase			:			Tuple        =					rrgdf[aatype, ...]

				# [*, N, 8] transformations, i.e.
				#   One [*, N, 8, 3, 3] rotation matrix and
				#   One [*, N, 8, 3]    translation matrix
				_lowerCAmelCase			:			Tuple        =					r.from_tensor_axa(UpperCamelCase_				)

				_lowerCAmelCase			:			Dict        =					alpha.new_zeros((*((1,) * len(alpha.shape[:-1]				)), 2)				)
				_lowerCAmelCase			:			Optional[int]        =					1

				# [*, N, 8, 2]
				_lowerCAmelCase			:			Union[str, Any]        =					torch.cat([bb_rot.expand(*alpha.shape[:-2]					,			-1					,			-1				), alpha]					,			dim=-2				)

				# [*, N, 8, 3, 3]
				# Produces rotation matrices of the form:
				# [
				#   [1, 0  , 0  ],
				#   [0, a_2,-a_1],
				#   [0, a_1, a_2]
				# ]
				# This follows the original code rather than the supplement, which uses
				# different indices.

				_lowerCAmelCase			:			int        =					alpha.new_zeros(default_r.get_rots().get_rot_mats().shape				)
				_lowerCAmelCase			:			List[Any]        =					1
				_lowerCAmelCase			:			Dict        =					alpha[..., 1]
				_lowerCAmelCase			:			Dict        =					-alpha[..., 0]
				_lowerCAmelCase			:			str        =					alpha

				_lowerCAmelCase			:			List[Any]        =					default_r.compose(Rigid(Rotation(rot_mats=UpperCamelCase_				)					,			UpperCamelCase_				)				)

				_lowerCAmelCase			:			Optional[int]        =					all_frames[..., 5]
				_lowerCAmelCase			:			Union[str, Any]        =					all_frames[..., 6]
				_lowerCAmelCase			:			str        =					all_frames[..., 7]

				_lowerCAmelCase			:			str        =					all_frames[..., 4]
				_lowerCAmelCase			:			Optional[int]        =					chia_frame_to_bb.compose(UpperCamelCase_				)
				_lowerCAmelCase			:			List[Any]        =					chia_frame_to_bb.compose(UpperCamelCase_				)
				_lowerCAmelCase			:			Optional[Any]        =					chia_frame_to_bb.compose(UpperCamelCase_				)

				_lowerCAmelCase			:			Optional[int]        =					Rigid.cat(
				    [
				        all_frames[..., :5],
				        chia_frame_to_bb.unsqueeze(-1				),
				        chia_frame_to_bb.unsqueeze(-1				),
				        chia_frame_to_bb.unsqueeze(-1				),
				    ]					,			dim=-1					,			)

				_lowerCAmelCase			:			Union[str, Any]        =					r[..., None].compose(UpperCamelCase_				)

				return all_frames_to_global





def 							_UpperCAmelCase     (UpperCamelCase_       :       Rigid					,			UpperCamelCase_       :       torch.Tensor					,			UpperCamelCase_       :       torch.Tensor					,			UpperCamelCase_       :       torch.Tensor					,			UpperCamelCase_       :       torch.Tensor					,			UpperCamelCase_       :       torch.Tensor					,			):
				'''simple docstring'''
				# [*, N, 14]
				_lowerCAmelCase			:			Optional[int]        =					group_idx[aatype, ...]

				# [*, N, 14, 8]
				_lowerCAmelCase			:			torch.LongTensor        =					nn.functional.one_hot(
				    UpperCamelCase_					,			num_classes=default_frames.shape[-3]					,			)

				# [*, N, 14, 8]
				_lowerCAmelCase			:			Dict        =					r[..., None, :] * group_mask_one_hot

				# [*, N, 14]
				_lowerCAmelCase			:			List[str]        =					t_atoms_to_global.map_tensor_fn(lambda UpperCamelCase_				: torch.sum(UpperCamelCase_					,			dim=-1				)				)

				# [*, N, 14, 1]
				_lowerCAmelCase			:			List[str]        =					atom_mask[aatype, ...].unsqueeze(-1				)

				# [*, N, 14, 3]
				_lowerCAmelCase			:			Dict        =					lit_positions[aatype, ...]
				_lowerCAmelCase			:			str        =					t_atoms_to_global.apply(UpperCamelCase_				)
				_lowerCAmelCase			:			Optional[int]        =					pred_positions * atom_mask

				return pred_positions




from __future__ import annotations

SCREAMING_SNAKE_CASE_						=					'Alexander Joslin'

def 							__SCREAMING_SNAKE_CASE							( lowerCAmelCase:     int       )      ->				int:

				if number <= 0:
								_UpperCAmelCase				:						Optional[Any]       						=			F'n must be greater than 0. Got n = {number}'
								raise ValueError(lowerCAmelCase       )

				_UpperCAmelCase				:						Dict       						=			[number + 1] * (number + 1)

				# starting position
				_UpperCAmelCase				:						Dict       						=			0
				for i in range(1     ,					lowerCAmelCase       ):
								_UpperCAmelCase				:						int       						=			min(table[i + 1]     ,					table[i] + 1       )
								# check if out of bounds
								if i * 2 <= number:
												_UpperCAmelCase				:						int       						=			min(table[i * 2]     ,					table[i] + 1       )
								# check if out of bounds
								if i * 3 <= number:
												_UpperCAmelCase				:						int       						=			min(table[i * 3]     ,					table[i] + 1       )
				return table[number]


if __name__ == "__main__":
					import doctest

					doctest.testmod()


