


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						):
       ...





@overload
def 							_UpperCAmelCase    (UpperCamelCase__					:  torch.Tensor    ,							UpperCamelCase__					:  torch.Tensor    ,							UpperCamelCase__					:  torch.Tensor						):
       ...





def 							_UpperCAmelCase    (UpperCamelCase__					:  Union[str, Any]    ,							UpperCamelCase__					:  Dict    ,							UpperCamelCase__					:  List[str]						):
       _A				:	Union[str, Any]       =			aatype == rc.restype_order["G"]
       _A				:	List[Any]       =			rc.atom_order["CA"]
       _A				:	List[Any]       =			rc.atom_order["CB"]
       _A				:	Union[str, 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:
              _A				:	Dict       =			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]						):
       _A				:	Optional[int]       =			batched_gather(
           UpperCamelCase__    ,							batch["residx_atom37_to_atom14"]    ,							dim=-2    ,							no_batch_dims=len(atomaa.shape[:-2]						)    ,							)

       _A				:	List[Any]       =			atomaa_data * batch["atom37_atom_exists"][..., None]

       return atomaa_data





def 							_UpperCAmelCase    (UpperCamelCase__					:  Dict[str, torch.Tensor]						):
       _A				:	Dict       =			template_feats["template_aatype"]
       _A				:	Union[str, Any]       =			template_feats["template_torsion_angles_sin_cos"]
       _A				:	Optional[Any]       =			template_feats["template_alt_torsion_angles_sin_cos"]
       _A				:	Optional[int]       =			template_feats["template_torsion_angles_mask"]
       _A				:	Dict       =			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-20    ,							UpperCamelCase__					:  float = 1E8    ,							):
       _A				:	Dict       =			batch["template_pseudo_beta_mask"]
       _A				:	List[Any]       =			template_mask[..., None] * template_mask[..., None, :]

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

       _A				:	List[Any]       =			[dgram, template_mask_ad[..., None]]

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

       _A				:	Optional[Any]       =			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						)						)

       _A				:	Optional[Any]       =			[rc.atom_order[a] for a in ["N", "CA", "C"]]
       _A				:	int       =			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__    ,							)
       _A				:	Union[str, Any]       =			rigids.get_trans()[..., None, :, :]
       _A				:	str       =			rigids[..., None].invert_apply(UpperCamelCase__						)

       _A				:	Dict       =			torch.rsqrt(eps + torch.sum(rigid_vec**2    ,							dim=-1						)						)

       _A				:	Tuple       =			batch["template_all_atom_mask"]
       _A				:	List[str]       =			t_aa_masks[..., n] * t_aa_masks[..., ca] * t_aa_masks[..., c]
       _A				:	Union[str, Any]       =			template_mask[..., None] * template_mask[..., None, :]

       _A				:	Optional[Any]       =			inv_distance_scalar * template_mask_ad
       _A				:	int       =			rigid_vec * inv_distance_scalar[..., None]

       if not use_unit_vector:
              _A				:	List[str]       =			unit_vector * 0.0

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

       _A				:	Tuple       =			torch.cat(UpperCamelCase__    ,							dim=-1						)
       _A				:	Any       =			act * template_mask_ad[..., None]

       return act





def 							_UpperCAmelCase    (UpperCamelCase__					:  Dict[str, torch.Tensor]						):
       _A				:	torch.LongTensor       =			nn.functional.one_hot(batch["extra_msa"]    ,							23						)
       _A				:	Any       =			[
           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    ,							):
       # [*, N, 8, 4, 4]
       _A				:	Optional[int]       =			rrgdf[aatype, ...]

       # [*, N, 8] transformations, i.e.
       #   One [*, N, 8, 3, 3] rotation matrix and
       #   One [*, N, 8, 3]    translation matrix
       _A				:	List[str]       =			r.from_tensor_axa(UpperCamelCase__						)

       _A				:	Dict       =			alpha.new_zeros((*((1,) * len(alpha.shape[:-1]						)), 2)						)
       _A				:	Tuple       =			1

       # [*, N, 8, 2]
       _A				:	Optional[int]       =			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.

       _A				:	int       =			alpha.new_zeros(default_r.get_rots().get_rot_mats().shape						)
       _A				:	Tuple       =			1
       _A				:	Optional[Any]       =			alpha[..., 1]
       _A				:	str       =			-alpha[..., 0]
       _A				:	Optional[Any]       =			alpha

       _A				:	Tuple       =			default_r.compose(Rigid(Rotation(rot_mats=UpperCamelCase__						)    ,							UpperCamelCase__						)						)

       _A				:	Optional[int]       =			all_frames[..., 5]
       _A				:	Optional[Any]       =			all_frames[..., 6]
       _A				:	List[Any]       =			all_frames[..., 7]

       _A				:	str       =			all_frames[..., 4]
       _A				:	Tuple       =			chia_frame_to_bb.compose(UpperCamelCase__						)
       _A				:	Any       =			chia_frame_to_bb.compose(UpperCamelCase__						)
       _A				:	Any       =			chia_frame_to_bb.compose(UpperCamelCase__						)

       _A				:	Tuple       =			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    ,							)

       _A				:	str       =			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    ,							):
       # [*, N, 14]
       _A				:	List[Any]       =			group_idx[aatype, ...]

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

       # [*, N, 14, 8]
       _A				:	Any       =			r[..., None, :] * group_mask_one_hot

       # [*, N, 14]
       _A				:	Tuple       =			t_atoms_to_global.map_tensor_fn(lambda UpperCamelCase__						: torch.sum(UpperCamelCase__    ,							dim=-1						)						)

       # [*, N, 14, 1]
       _A				:	Union[str, Any]       =			atom_mask[aatype, ...].unsqueeze(-1						)

       # [*, N, 14, 3]
       _A				:	Any       =			lit_positions[aatype, ...]
       _A				:	int       =			t_atoms_to_global.apply(UpperCamelCase__						)
       _A				:	Union[str, Any]       =			pred_positions * atom_mask

       return pred_positions




def 							_UpperCAmelCase    (UpperCamelCase__					:  str						):
       _A				:	Tuple       =			str(UpperCamelCase__						).strip()
       if not bin_string:
              raise ValueError("Empty string was passed to the function"						)
       _A				:	Dict       =			bin_string[0] == "-"
       if is_negative:
              _A				:	Any       =			bin_string[1:]
       if not all(char in "01" for char in bin_string						):
              raise ValueError("Non-binary value was passed to the function"						)
       _A				:	Union[str, Any]       =			0
       for char in bin_string:
              _A				:	Union[str, Any]       =			2 * decimal_number + int(UpperCamelCase__						)
       return -decimal_number if is_negative else decimal_number


if __name__ == "__main__":
    from doctest import testmod

    testmod()
