Visualization

manify.utils.visualization

Manify visualization utilities.

hyperboloid_to_poincare(X)

Convert hyperboloid coordinates to Poincaré ball coordinates.

Parameters:
  • X (Float[Tensor, 'n_points n_dim']) –

    Input coordinates in the hyperboloid model.

Returns:
  • poincare_coords( Float[Tensor, 'n_points n_dim-1'] ) –

    Coordinates in the Poincaré ball model.

Source code in manify/utils/visualization.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def hyperboloid_to_poincare(X: Float[torch.Tensor, "n_points n_dim"]) -> Float[torch.Tensor, "n_points n_dim-1"]:
    """Convert hyperboloid coordinates to Poincaré ball coordinates.

    Args:
        X: Input coordinates in the hyperboloid model.

    Returns:
        poincare_coords: Coordinates in the Poincaré ball model.
    """
    # Spatial components: all columns except the first
    x_space = X[:, 1:]

    # Time-like component: first column, reshaped for broadcasting
    x_time = X[:, 0:1]

    # Convert to Poincaré ball coordinates
    poincare_coords = x_space / (1 + x_time)

    return poincare_coords

spherical_to_polar(X)

Convert spherical coordinates to polar coordinates.

Parameters:
  • X (Float[Tensor, 'n_points n_dim']) –

    Input coordinates in spherical form.

Returns:
  • polar_coords( Float[Tensor, 'n_points n_dim-1'] ) –

    Coordinates in polar form.

Source code in manify/utils/visualization.py
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def spherical_to_polar(X: Float[torch.Tensor, "n_points n_dim"]) -> Float[torch.Tensor, "n_points n_dim-1"]:
    """Convert spherical coordinates to polar coordinates.

    Args:
        X: Input coordinates in spherical form.

    Returns:
        polar_coords: Coordinates in polar form.
    """
    # Radius computation
    r = torch.norm(X, dim=1, keepdim=True)

    # Prepare output tensor
    out = torch.zeros_like(X)
    out[:, 0] = r.squeeze()  # Set the radius

    # Compute angles
    for i in range(1, X.size(1)):
        if i == X.size(1) - 1:
            # Last angle, use atan2 for full 360 degree
            out[:, i] = torch.atan2(X[:, i - 1], X[:, i - 2])
        else:
            # Compute angle from the higher dimension 'hypotenuse'
            hypotenuse = torch.norm(X[:, i:], dim=1, keepdim=True)
            # Prevent division by zero
            safe_hypotenuse = torch.where(hypotenuse > 0, hypotenuse, torch.tensor(1.0).to(X.device))
            # Ensure acos receives values within [-1, 1] and preserve dimensions
            angle = torch.acos(torch.clamp(X[:, i : i + 1] / safe_hypotenuse, -1, 1))
            out[:, i] = angle.squeeze()

    return out[:, 1:]

S2_to_polar(X)

Convert S^2 (2-sphere) coordinates to polar coordinates.

Parameters:
  • X (Float[Tensor, 'n_points 3']) –

    Input coordinates on the 2-sphere.

Returns:
  • polar_coords( Float[Tensor, 'n_points 2'] ) –

    Coordinates in polar form (elevation, azimuth).

Source code in manify/utils/visualization.py
67
68
69
70
71
72
73
74
75
76
def S2_to_polar(X: Float[torch.Tensor, "n_points 3"]) -> Float[torch.Tensor, "n_points 2"]:
    """Convert S^2 (2-sphere) coordinates to polar coordinates.

    Args:
        X: Input coordinates on the 2-sphere.

    Returns:
        polar_coords: Coordinates in polar form (elevation, azimuth).
    """
    return torch.stack([torch.acos(X[:, 2]), torch.atan2(X[:, 1], X[:, 0])], dim=1)