|
1 | 1 | import numpy as np |
| 2 | +import torch |
2 | 3 |
|
3 | 4 | from pyGroupedTransforms import * |
| 5 | +from .NFFTtools import index_set_without_zeros |
| 6 | + |
| 7 | +import pykeops |
| 8 | +from pykeops.torch import LazyTensor |
| 9 | + |
4 | 10 |
|
5 | 11 | # All code that is linked to NFMTtools or to system = "mixed" is not tested yet.... |
6 | 12 |
|
@@ -266,24 +272,87 @@ def __init__( |
266 | 272 | bandwidths=s.bandwidths, X=np.copy(X[:, u], order="C") |
267 | 273 | ) |
268 | 274 | elif algorithm == "keops": |
269 | | - self.matrix = np.empty((0,0), dtype=object) |
| 275 | + self.matrix = np.empty((0,0), dtype=object) |
| 276 | + |
| 277 | + self.transforms = [ |
| 278 | + DeferredLinearOperator() |
| 279 | + for _ in range(len(self.settings)) |
| 280 | + ] |
| 281 | + |
| 282 | + D = X.shape[1] |
270 | 283 |
|
271 | | - self.transforms = [ |
272 | | - DeferredLinearOperator() |
273 | | - for _ in range(len(self.settings)) |
274 | | - ] |
| 284 | + freq_list = [] |
275 | 285 |
|
276 | | - for idx, s in enumerate(self.settings): |
| 286 | + for s in self.settings: |
277 | 287 |
|
278 | | - if len(s.bandwidths) == 0: |
279 | | - u = (0,) |
280 | | - else: |
281 | | - u = s.u |
| 288 | + if len(s.bandwidths) == 0: |
| 289 | + full = np.zeros((1, D), dtype=np.int32) |
| 290 | + |
| 291 | + |
| 292 | + else: |
| 293 | + local = index_set_without_zeros( |
| 294 | + np.array(s.bandwidths, dtype=np.int32) |
| 295 | + ).T |
| 296 | + |
| 297 | + full = np.zeros((local.shape[0], D), dtype=np.int32) |
| 298 | + |
| 299 | + for i, dim in enumerate(s.u): |
| 300 | + full[:, dim] = local[:, i] |
| 301 | + |
| 302 | + freq_list.append(full) |
| 303 | + |
| 304 | + freq = np.vstack(freq_list) |
| 305 | + |
| 306 | + X_torch = torch.tensor(X, dtype=torch.float64, device="cuda") |
| 307 | + I_torch = torch.tensor( |
| 308 | + freq, |
| 309 | + dtype=torch.float64, |
| 310 | + device="cuda" |
| 311 | + ) |
| 312 | + |
| 313 | + def trafo(fhat): |
| 314 | + X_i = LazyTensor(X_torch[:, None, :].contiguous()) |
| 315 | + K_j = LazyTensor(I_torch[None, :, :].contiguous()) |
| 316 | + phase_fwd = (X_i * K_j).sum(-1) |
| 317 | + two_pi_phase = -2 * torch.pi * phase_fwd |
| 318 | + kernel_fwd = two_pi_phase.cos() + 1j * two_pi_phase.sin() |
| 319 | + fhat_torch = torch.tensor(fhat, dtype=torch.complex128, device="cuda") |
| 320 | + fhat_j = LazyTensor(fhat_torch[None, :, None].contiguous()) |
| 321 | + |
| 322 | + try: |
| 323 | + result = (kernel_fwd * fhat_j).sum(dim=1) |
| 324 | + torch.cuda.synchronize() |
| 325 | + result = result.squeeze().cpu().numpy() |
| 326 | + return result |
| 327 | + except Exception as e: |
| 328 | + print("Error in KeOps trafo:", e) |
| 329 | + return None |
| 330 | + |
| 331 | + def adjoint(f): |
| 332 | + f_torch = torch.tensor(f, dtype=torch.complex128, device="cuda").contiguous() |
| 333 | + |
| 334 | + X_i = LazyTensor(X_torch[None, :, :].contiguous()) |
| 335 | + K_j = LazyTensor(I_torch[:, None, :].contiguous()) |
282 | 336 |
|
283 | | - self.transforms[idx] = s.mode.get_transform_keops( |
284 | | - bandwidths=s.bandwidths, |
285 | | - X=np.copy(X[:,u], order="C") |
286 | | - ) |
| 337 | + phase = (K_j * X_i).sum(-1) |
| 338 | + kernel = (-2*torch.pi*phase).cos() - 1j*(-2*torch.pi*phase).sin() |
| 339 | + |
| 340 | + f_i = LazyTensor(f_torch[None, :, None].contiguous()) |
| 341 | + |
| 342 | + try: |
| 343 | + result = (kernel * f_i).sum(dim=1) |
| 344 | + torch.cuda.synchronize() |
| 345 | + result = result.squeeze().cpu().numpy() |
| 346 | + |
| 347 | + return result |
| 348 | + except Exception as e: |
| 349 | + print("Error in KeOps adjoint:", e) |
| 350 | + return None |
| 351 | + |
| 352 | + self.transforms = [DeferredLinearOperator( |
| 353 | + dtype=np.complex128, shape=(X.shape[0], len(freq)), mfunc=trafo, rmfunc=adjoint |
| 354 | + )] |
| 355 | + |
287 | 356 | else: |
288 | 357 | self.transforms = [] |
289 | 358 | s1 = self.settings[0] |
@@ -363,14 +432,10 @@ def adjoint_worker(i): |
363 | 432 | adjoint_worker(i) |
364 | 433 |
|
365 | 434 | return fhat |
| 435 | + |
366 | 436 | elif self.algorithm == "keops": |
367 | | - fhat = GroupedCoefficients(self.settings) |
368 | | - |
369 | | - for i in range(len(self.transforms)): |
370 | | - adjoint_result = self.transforms[i].H @ other |
371 | | - fhat[self.settings[i].u] = adjoint_result |
372 | | - |
373 | | - return fhat |
| 437 | + return GroupedCoefficients(self.settings, self.transforms[0].H @ other) |
| 438 | + |
374 | 439 | elif self.algorithm == "direct": |
375 | 440 | return GroupedCoefficients( |
376 | 441 | self.settings, (self.matrix.conj()).T @ other |
@@ -403,15 +468,10 @@ def worker(i): |
403 | 468 | worker(i) |
404 | 469 |
|
405 | 470 | return sum(results) |
| 471 | + |
406 | 472 | elif self.algorithm == "keops": |
407 | | - results = [] |
408 | | - |
409 | | - for i in range(len(self.transforms)): |
410 | | - u = self.settings[i].u |
411 | | - result = self.transforms[i] @ other[u] |
412 | | - results.append(result) |
413 | | - |
414 | | - return sum(results) |
| 473 | + return self.transforms[0] @ other.data |
| 474 | + |
415 | 475 | elif self.algorithm == "direct": |
416 | 476 | return self.matrix @ other.data |
417 | 477 | else: |
|
0 commit comments