nystrom-ncut 0.1.5__py3-none-any.whl → 0.1.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -128,9 +128,9 @@ class DistanceRealization(OnlineNystromSubsampleFit):
128
128
  features: torch.Tensor,
129
129
  precomputed_sampled_indices: torch.Tensor = None,
130
130
  ) -> torch.Tensor:
131
- V, L = OnlineNystromSubsampleFit.fit_transform(self, features, precomputed_sampled_indices)
132
- return V * (L ** 0.5)
131
+ V = OnlineNystromSubsampleFit.fit_transform(self, features, precomputed_sampled_indices)
132
+ return V * (self.eigenvalues_ ** 0.5)
133
133
 
134
134
  def transform(self, features: torch.Tensor = None) -> torch.Tensor:
135
- V, L = OnlineNystromSubsampleFit.transform(self, features)
136
- return V * (L ** 0.5)
135
+ V = OnlineNystromSubsampleFit.transform(self, features)
136
+ return V * (self.eigenvalues_ ** 0.5)
@@ -20,7 +20,7 @@ EigSolverOptions = Literal["svd_lowrank", "lobpcg", "svd", "eigh"]
20
20
 
21
21
 
22
22
  class OnlineKernel:
23
- def fit(self, features: torch.Tensor) -> None: # [n x d]
23
+ def fit(self, features: torch.Tensor) -> "OnlineKernel": # [n x d]
24
24
  raise NotImplementedError()
25
25
 
26
26
  def update(self, features: torch.Tensor) -> torch.Tensor: # [m x d] -> [m x n]
@@ -47,7 +47,6 @@ class OnlineNystrom:
47
47
  self.n_components: int = n_components
48
48
  self.kernel: OnlineKernel = kernel
49
49
  self.eig_solver: EigSolverOptions = eig_solver
50
- self.inverse_approximation_dim: int = None
51
50
 
52
51
  self.chunk_size = chunk_size
53
52
 
@@ -61,13 +60,13 @@ class OnlineNystrom:
61
60
  # Updated matrices
62
61
  self.S: torch.Tensor = None # [n x n]
63
62
  self.transform_matrix: torch.Tensor = None # [n x n_components]
64
- self.LS: torch.Tensor = None # [n]
63
+ self.eigenvalues_: torch.Tensor = None # [n]
65
64
 
66
- def _update_to_kernel(self) -> Tuple[torch.Tensor, torch.Tensor]:
65
+ def _update_to_kernel(self, d: int) -> Tuple[torch.Tensor, torch.Tensor]:
67
66
  self.A = self.S = self.kernel.transform()
68
67
  U, L = solve_eig(
69
68
  self.A,
70
- num_eig=self.inverse_approximation_dim,
69
+ num_eig=d + 1, # d * (d + 3) // 2 + 1,
71
70
  eig_solver=self.eig_solver,
72
71
  ) # [n x (? + 1)], [? + 1]
73
72
  self.Ahinv_UL = U * (L ** -0.5) # [n x (? + 1)]
@@ -75,57 +74,57 @@ class OnlineNystrom:
75
74
  self.Ahinv = self.Ahinv_UL @ self.Ahinv_VT # [n x n]
76
75
  return U, L
77
76
 
78
- def fit(self, features: torch.Tensor):
77
+ def fit(self, features: torch.Tensor) -> "OnlineNystrom":
79
78
  OnlineNystrom.fit_transform(self, features)
80
79
  return self
81
80
 
82
- def fit_transform(self, features: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
81
+ def fit_transform(self, features: torch.Tensor) -> torch.Tensor:
83
82
  self.anchor_features = features
84
83
 
85
84
  self.kernel.fit(self.anchor_features)
86
- self.inverse_approximation_dim = max(self.n_components, features.shape[-1] + 1)
87
- U, L = self._update_to_kernel() # [n x (? + 1)], [? + 1]
85
+ U, L = self._update_to_kernel(features.shape[-1]) # [n x (d + 1)], [d + 1]
88
86
 
89
87
  self.transform_matrix = (U / L)[:, :self.n_components] # [n x n_components]
90
- self.LS = L[:self.n_components] # [n_components]
91
- return U[:, :self.n_components], L[:self.n_components] # [n x n_components], [n_components]
88
+ self.eigenvalues_ = L[:self.n_components] # [n_components]
89
+ return U[:, :self.n_components] # [n x n_components]
92
90
 
93
- def update(self, features: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
91
+ def update(self, features: torch.Tensor) -> torch.Tensor:
92
+ d = features.shape[-1]
94
93
  n_chunks = ceildiv(len(features), self.chunk_size)
95
94
  if n_chunks > 1:
96
95
  """ Chunked version """
97
96
  chunks = torch.chunk(features, n_chunks, dim=0)
98
97
  for chunk in chunks:
99
98
  self.kernel.update(chunk)
100
- self._update_to_kernel()
99
+ self._update_to_kernel(d)
101
100
 
102
- compressed_BBT = torch.zeros((self.inverse_approximation_dim, self.inverse_approximation_dim)) # [(? + 1) x (? + 1))]
103
- for i, chunk in enumerate(chunks):
104
- _B = self.kernel.transform(chunk).mT # [n x _m]
105
- _compressed_B = self.Ahinv_VT @ _B # [(? + 1) x _m]
106
- compressed_BBT = compressed_BBT + _compressed_B @ _compressed_B.mT # [(? + 1) x (? + 1)]
107
- self.S = self.S + self.Ahinv_UL @ compressed_BBT @ self.Ahinv_UL.mT # [n x n]
108
- US, self.LS = solve_eig(self.S, self.n_components, self.eig_solver) # [n x n_components], [n_components]
109
- self.transform_matrix = self.Ahinv @ US * (self.LS ** -0.5) # [n x n_components]
101
+ compressed_BBT = 0.0 # [(? + 1) x (? + 1))]
102
+ for chunk in chunks:
103
+ _B = self.kernel.transform(chunk).mT # [n x _m]
104
+ _compressed_B = self.Ahinv_VT @ _B # [(? + 1) x _m]
105
+ compressed_BBT = compressed_BBT + _compressed_B @ _compressed_B.mT # [(? + 1) x (? + 1)]
106
+ self.S = self.S + self.Ahinv_UL @ compressed_BBT @ self.Ahinv_UL.mT # [n x n]
107
+ US, self.eigenvalues_ = solve_eig(self.S, self.n_components, self.eig_solver) # [n x n_components], [n_components]
108
+ self.transform_matrix = self.Ahinv @ US * (self.eigenvalues_ ** -0.5) # [n x n_components]
110
109
 
111
110
  VS = []
112
111
  for chunk in chunks:
113
- VS.append(self.kernel.transform(chunk) @ self.transform_matrix) # [_m x n_components]
112
+ VS.append(self.kernel.transform(chunk) @ self.transform_matrix) # [_m x n_components]
114
113
  VS = torch.cat(VS, dim=0)
115
- return VS, self.LS # [m x n_components], [n_components]
114
+ return VS # [m x n_components]
116
115
  else:
117
116
  """ Unchunked version """
118
- B = self.kernel.update(features).mT # [n x m]
119
- self._update_to_kernel()
120
- compressed_B = self.Ahinv_VT @ B # [indirect_pca_dim x m]
117
+ B = self.kernel.update(features).mT # [n x m]
118
+ self._update_to_kernel(d)
119
+ compressed_B = self.Ahinv_VT @ B # [indirect_pca_dim x m]
121
120
 
122
- self.S = self.S + self.Ahinv_UL @ (compressed_B @ compressed_B.mT) @ self.Ahinv_UL.mT # [n x n]
123
- US, self.LS = solve_eig(self.S, self.n_components, self.eig_solver) # [n x n_components], [n_components]
124
- self.transform_matrix = self.Ahinv @ US * (self.LS ** -0.5) # [n x n_components]
121
+ self.S = self.S + self.Ahinv_UL @ (compressed_B @ compressed_B.mT) @ self.Ahinv_UL.mT # [n x n]
122
+ US, self.eigenvalues_ = solve_eig(self.S, self.n_components, self.eig_solver) # [n x n_components], [n_components]
123
+ self.transform_matrix = self.Ahinv @ US * (self.eigenvalues_ ** -0.5) # [n x n_components]
125
124
 
126
- return B.mT @ self.transform_matrix, self.LS # [m x n_components], [n_components]
125
+ return B.mT @ self.transform_matrix # [m x n_components]
127
126
 
128
- def transform(self, features: torch.Tensor = None) -> Tuple[torch.Tensor, torch.Tensor]:
127
+ def transform(self, features: torch.Tensor = None) -> torch.Tensor:
129
128
  if features is None:
130
129
  VS = self.A @ self.transform_matrix # [n x n_components]
131
130
  else:
@@ -135,12 +134,12 @@ class OnlineNystrom:
135
134
  chunks = torch.chunk(features, n_chunks, dim=0)
136
135
  VS = []
137
136
  for chunk in chunks:
138
- VS.append(self.kernel.transform(chunk) @ self.transform_matrix) # [_m x n_components]
137
+ VS.append(self.kernel.transform(chunk) @ self.transform_matrix) # [_m x n_components]
139
138
  VS = torch.cat(VS, dim=0)
140
139
  else:
141
140
  """ Unchunked version """
142
- VS = self.kernel.transform(features) @ self.transform_matrix # [m x n_components]
143
- return VS, self.LS # [m x n_components], [n_components]
141
+ VS = self.kernel.transform(features) @ self.transform_matrix # [m x n_components]
142
+ return VS # [m x n_components]
144
143
 
145
144
 
146
145
  class OnlineNystromSubsampleFit(OnlineNystrom):
@@ -192,7 +191,7 @@ class OnlineNystromSubsampleFit(OnlineNystrom):
192
191
  if _n_not_sampled > 0:
193
192
  unsampled_indices = torch.full((_n,), True, device=features.device).scatter_(0, self.anchor_indices, False)
194
193
  unsampled_features = features[unsampled_indices]
195
- V_unsampled, _ = OnlineNystrom.update(self, unsampled_features)
194
+ V_unsampled = OnlineNystrom.update(self, unsampled_features)
196
195
  else:
197
196
  unsampled_indices = V_unsampled = None
198
197
  return unsampled_indices, V_unsampled
@@ -201,7 +200,7 @@ class OnlineNystromSubsampleFit(OnlineNystrom):
201
200
  self,
202
201
  features: torch.Tensor,
203
202
  precomputed_sampled_indices: torch.Tensor = None,
204
- ):
203
+ ) -> "OnlineNystromSubsampleFit":
205
204
  """Fit Nystrom Normalized Cut on the input features.
206
205
  Args:
207
206
  features (torch.Tensor): input features, shape (n_samples, n_features)
@@ -217,7 +216,7 @@ class OnlineNystromSubsampleFit(OnlineNystrom):
217
216
  self,
218
217
  features: torch.Tensor,
219
218
  precomputed_sampled_indices: torch.Tensor = None,
220
- ) -> Tuple[torch.Tensor, torch.Tensor]:
219
+ ) -> torch.Tensor:
221
220
  """
222
221
  Args:
223
222
  features (torch.Tensor): input features, shape (n_samples, n_features)
@@ -229,7 +228,7 @@ class OnlineNystromSubsampleFit(OnlineNystrom):
229
228
  (torch.Tensor): eigen_values, sorted in descending order, shape (num_eig,)
230
229
  """
231
230
  unsampled_indices, V_unsampled = OnlineNystromSubsampleFit._fit_helper(self, features, precomputed_sampled_indices)
232
- V_sampled, L = OnlineNystrom.transform(self)
231
+ V_sampled = OnlineNystrom.transform(self)
233
232
 
234
233
  if unsampled_indices is not None:
235
234
  V = torch.zeros((len(unsampled_indices), self.n_components), device=features.device)
@@ -237,7 +236,7 @@ class OnlineNystromSubsampleFit(OnlineNystrom):
237
236
  V[unsampled_indices] = V_unsampled
238
237
  else:
239
238
  V = V_sampled
240
- return V, L
239
+ return V
241
240
 
242
241
 
243
242
  def solve_eig(
@@ -179,14 +179,13 @@ def _rgb_with_dimensionality_reduction(
179
179
  )
180
180
 
181
181
  _inp = features[subgraph_indices].numpy(force=True)
182
- _subgraph_embed = reduction(
182
+ _subgraph_embed = torch.tensor(reduction(
183
183
  n_components=reduction_dim,
184
184
  metric=disttype,
185
185
  random_state=seed,
186
186
  **reduction_kwargs
187
- ).fit_transform(_inp)
187
+ ).fit_transform(_inp), device=features.device, dtype=features.dtype)
188
188
 
189
- _subgraph_embed = torch.tensor(_subgraph_embed, dtype=torch.float32)
190
189
  rgb = rgb_func(extrapolate_knn(
191
190
  features[subgraph_indices],
192
191
  _subgraph_embed,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: nystrom_ncut
3
- Version: 0.1.5
3
+ Version: 0.1.7
4
4
  Summary: Normalized Cut and Nyström Approximation
5
5
  Author-email: Huzheng Yang <huze.yann@gmail.com>, Wentinn Liao <wentinn.liao@gmail.com>
6
6
  Project-URL: Documentation, https://github.com/JophiArcana/Nystrom-NCUT/
@@ -3,13 +3,13 @@ nystrom_ncut/__init__.py,sha256=HifrTcqX2-hYjBDe6xIThHvuIBYMPBA3EzjR8-qPMUM,512
3
3
  nystrom_ncut/common.py,sha256=_PGJoImSk_Fb_5Ri-e_IsFoCcSfbGS8CxYUUHVoNM50,2036
4
4
  nystrom_ncut/distance_utils.py,sha256=p-pYdpRrJsIhzxM_IxUqja7N8okngx52WGXD9pu_Aec,3129
5
5
  nystrom_ncut/sampling_utils.py,sha256=oMmhFcd_N_D15Ht7F0rCGPSgLeitJszAKMD3ICKwHNU,3105
6
- nystrom_ncut/visualize_utils.py,sha256=RsQVjPhxoIdxDOQ2PI7ifFDuEL23YXpZBdJ0wjjafek,22970
6
+ nystrom_ncut/visualize_utils.py,sha256=_J6YjWUsBe0VqW6KXsQx_iPmRCcO-ie0g6t5mD289UI,22957
7
7
  nystrom_ncut/nystrom/__init__.py,sha256=4EpxD3Cmc8Fif4vo8DG-6FpTfCnNanD5zCZxK3WrMwQ,121
8
- nystrom_ncut/nystrom/distance_realization.py,sha256=YaKEzuiiJfS6tdOTuJ4Ce1jqOWIfrVGb8ilvhzKeW9w,5789
8
+ nystrom_ncut/nystrom/distance_realization.py,sha256=InajllGtRVnLVlZoipZNbHFTGHaTs3zxizKe3kI2Los,5815
9
9
  nystrom_ncut/nystrom/normalized_cut.py,sha256=N-M5wkTo59vpbBfIx8evkSQBxlo4j80qCtuoifxQa_A,7578
10
- nystrom_ncut/nystrom/nystrom_utils.py,sha256=Wq364xlxBhr74lqyCkPWLBxq5YSt2zr-DSfYUHpYfgE,12989
11
- nystrom_ncut-0.1.5.dist-info/LICENSE,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
12
- nystrom_ncut-0.1.5.dist-info/METADATA,sha256=7gO_GxpjbitbEBB9juaha7W4e7SWs-hYqgkYfaGmuIg,6058
13
- nystrom_ncut-0.1.5.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
14
- nystrom_ncut-0.1.5.dist-info/top_level.txt,sha256=gM8IWWHYysIRTCvCTcdS4RShOyl9pxpylgSwPUZR2XM,22
15
- nystrom_ncut-0.1.5.dist-info/RECORD,,
10
+ nystrom_ncut/nystrom/nystrom_utils.py,sha256=UVs1tC7vnVq2mWSTpcrP4C19x9wDJ77ACht0EltOO2E,12698
11
+ nystrom_ncut-0.1.7.dist-info/LICENSE,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
12
+ nystrom_ncut-0.1.7.dist-info/METADATA,sha256=eb0Q6bwCKC4c5bcuJI_PnIaPW5qFYGSgwbPeuWI7EUk,6058
13
+ nystrom_ncut-0.1.7.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
14
+ nystrom_ncut-0.1.7.dist-info/top_level.txt,sha256=gM8IWWHYysIRTCvCTcdS4RShOyl9pxpylgSwPUZR2XM,22
15
+ nystrom_ncut-0.1.7.dist-info/RECORD,,