Skip to content

Commit c73da22

Browse files
committed
feat: NFCT equivalent using KeOps
1 parent e6abf47 commit c73da22

1 file changed

Lines changed: 103 additions & 37 deletions

File tree

src/pyGroupedTransforms/GroupedTransform.py

Lines changed: 103 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,20 @@ def __init__(
288288
if len(s.bandwidths) == 0:
289289
full = np.zeros((1, D), dtype=np.int32)
290290

291+
elif self.system == "cos":
291292

292-
else:
293+
local = np.atleast_2d(
294+
s.mode.index_set_without_zeros(
295+
np.array(s.bandwidths, dtype=np.int32)
296+
)
297+
).T
298+
299+
full = np.zeros((local.shape[0], D), dtype=np.int32)
300+
301+
for i, dim in enumerate(s.u):
302+
full[:, dim] = local[:, i]
303+
304+
else:
293305
local = index_set_without_zeros(
294306
np.array(s.bandwidths, dtype=np.int32)
295307
).T
@@ -309,48 +321,102 @@ def __init__(
309321
dtype=torch.float64,
310322
device="cuda"
311323
)
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-
324+
325+
def trafo(fhat):
326+
if self.system == "cos" or self.system == "cheb":
327+
mult = np.sqrt(2.0) ** np.count_nonzero(freq, axis=1)
328+
mult_torch = torch.tensor(mult, dtype=torch.float64, device="cuda")
329+
330+
kernel = 1.0
331+
for i in range(D):
332+
Xi = LazyTensor(X_torch[:, None, i:i+1].contiguous())
333+
Ki = LazyTensor(I_torch[None, :, i:i+1].contiguous())
334+
kernel = kernel * (2 * torch.pi * Xi * Ki).cos()
335+
336+
fhat_torch = (
337+
torch.as_tensor(fhat, dtype=torch.float64, device="cuda")
338+
* mult_torch
339+
)
340+
fhat_j = LazyTensor(fhat_torch[None, :, None].contiguous())
341+
342+
try:
343+
result = (kernel * fhat_j).sum(dim=1)
344+
torch.cuda.synchronize()
345+
return result.squeeze().cpu().numpy()
346+
except Exception as e:
347+
print("Error in KeOps trafo:", e)
348+
return None
349+
else:
350+
X_i = LazyTensor(X_torch[:, None, :].contiguous())
351+
K_j = LazyTensor(I_torch[None, :, :].contiguous())
352+
353+
phase_fwd = (X_i * K_j).sum(-1)
354+
two_pi_phase = -2 * torch.pi * phase_fwd
355+
kernel = two_pi_phase.cos() + 1j * two_pi_phase.sin()
356+
357+
fhat_torch = torch.tensor(fhat, dtype=torch.complex128, device="cuda")
358+
fhat_j = LazyTensor(fhat_torch[None, :, None].contiguous())
359+
360+
try:
361+
result = (kernel * fhat_j).sum(dim=1)
362+
torch.cuda.synchronize()
363+
result = result.squeeze().cpu().numpy()
364+
return result
365+
except Exception as e:
366+
print("Error in KeOps trafo:", e)
367+
return None
368+
331369
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())
370+
if self.system == "cos" or self.system == "cheb":
371+
mult = np.sqrt(2.0) ** np.count_nonzero(freq, axis=1)
372+
mult_torch = torch.tensor(mult, dtype=torch.float64, device="cuda")
373+
374+
f_torch = (
375+
torch.as_tensor(f, dtype=torch.float64, device="cuda")
376+
* mult_torch
377+
).contiguous()
378+
379+
kernel = 1.0
380+
for i in range(D):
381+
Ki = LazyTensor(I_torch[:, None, i:i+1].contiguous())
382+
Xi = LazyTensor(X_torch[None, :, i:i+1].contiguous())
383+
kernel = kernel * (2 * torch.pi * Xi * Ki).cos()
384+
385+
f_i = LazyTensor(f_torch[None, :, None].contiguous())
386+
387+
try:
388+
result = (kernel * f_i).sum(dim=1)
389+
torch.cuda.synchronize()
390+
result = result.squeeze().cpu().numpy()
391+
return result
392+
except Exception as e:
393+
print("Error in KeOps adjoint:", e)
394+
return None
395+
else:
396+
f_torch = torch.tensor(f, dtype=torch.complex128, device="cuda").contiguous()
336397

337-
phase = (K_j * X_i).sum(-1)
338-
kernel = (-2*torch.pi*phase).cos() - 1j*(-2*torch.pi*phase).sin()
398+
X_i = LazyTensor(X_torch[None, :, :].contiguous())
399+
K_j = LazyTensor(I_torch[:, None, :].contiguous())
339400

340-
f_i = LazyTensor(f_torch[None, :, None].contiguous())
401+
phase = (K_j * X_i).sum(-1)
402+
two_pi_phase = 2 * torch.pi * phase
403+
kernel = two_pi_phase.cos() + 1j * two_pi_phase.sin()
341404

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
405+
f_i = LazyTensor(f_torch[None, :, None].contiguous())
406+
407+
try:
408+
result = (kernel * f_i).sum(dim=1)
409+
torch.cuda.synchronize()
410+
result = result.squeeze().cpu().numpy()
411+
412+
return result
413+
except Exception as e:
414+
print("Error in KeOps adjoint:", e)
415+
return None
351416

417+
keops_dtype = np.float64 if self.system == "cos" else np.complex128
352418
self.transforms = [DeferredLinearOperator(
353-
dtype=np.complex128, shape=(X.shape[0], len(freq)), mfunc=trafo, rmfunc=adjoint
419+
dtype=keops_dtype, shape=(X.shape[0], len(freq)), mfunc=trafo, rmfunc=adjoint
354420
)]
355421

356422
else:

0 commit comments

Comments
 (0)