File size: 2,465 Bytes
165ee00
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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
65
66
67
68
# Author: Qiuyi

import torch
import torch.nn.functional as F
from sklearn.decomposition import PCA

def cube(n_samples, dim=2):
    return torch.rand([n_samples, dim])

def sphere(n_samples, dim=1):
    X = torch.randn([n_samples, dim+1])
    return F.normalize(X, dim=-1)

def torus(n_samples, R=2, r=1):
    u, v = (torch.rand([n_samples, 2]) * 2 * torch.pi).chunk(2, -1)
    x = (R + r * torch.cos(u)) * torch.cos(v)
    y = (R + r * torch.cos(u)) * torch.sin(v)
    z = r * torch.sin(u)
    return torch.cat([x, y, z], dim=-1)

def mobius_strip(n_samples):
    u, v = torch.rand([n_samples, 2]).chunk(2, -1)
    u *= 2 * torch.pi
    x = (1 + v/2 * torch.cos(u/2)) * torch.cos(u)
    y = (1 + v/2 * torch.cos(u/2)) * torch.sin(u)
    z = v/2 * torch.sin(u/2)
    return torch.cat([x, y, z], dim=-1)

def klein_bottle(n_samples, R=2, P=1, e=0.1):
    u, v = (torch.rand([n_samples, 2]) * 2 * torch.pi).chunk(2, -1)
    x = R * (torch.cos(u/2) * torch.cos(v) - torch.sin(u/2) * torch.sin(v*2))
    y = R * (torch.sin(u/2) * torch.cos(v) + torch.cos(u/2) * torch.sin(v*2))
    z = P * torch.cos(u) * (1 + e * torch.sin(v))
    w = P * torch.sin(u) * (1 + e * torch.sin(v))
    return torch.cat([x, y, z, w], dim=-1)


################################ Immersions ################################
# For nonlinearly embedding datasets into high dimensional ambient spaces. #
############################################################################

def polynomial_immersion(dataset, ambient_dim, weight=(1,1,0)):
    """
    The graph of a continous function is homeomorphic to its domain.
    Immersion is performed by polynomial function.
    """

    X = (dataset - dataset.mean(0)) / (dataset.std(0) * 2)
    XX = (X.unsqueeze(1) * X.unsqueeze(2)).flatten(1)
    XXX = (X.view(len(X), 1, 1, -1) \
           * X.view(len(X), 1, -1, 1) \
            * X.view(len(X), -1, 1, 1)).flatten(1)
    
    in_dim = dataset.size(-1)
    out_dim = ambient_dim - in_dim

    # 2nd order polynomial function Y = f(X)
    W1 = torch.randn(X.size(-1), out_dim) * weight[0]
    W2 = torch.randn(XX.size(-1), out_dim) * weight[1]
    W3 = torch.randn(XXX.size(-1), out_dim) * weight[2]
    Y = X @ W1 + XX @ W2 + XXX @ W3

    # rescaling
    D = torch.cat([dataset, Y], dim=-1) # graph of polynomial f
    D = torch.as_tensor(PCA(D.size(-1)).fit_transform(D), dtype=torch.float)
    s = torch.rand(D.size(-1)) * (1-0.5) + 0.5
    D = D / D.std(0).clip(3e-7) * s
    return D