Skip to content

Commit e8ead6f

Browse files
committed
include hfft
1 parent f31e883 commit e8ead6f

File tree

6 files changed

+150
-67
lines changed

6 files changed

+150
-67
lines changed

Diff for: CHANGES.rst

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22
:code:`mkl_fft` changelog
33
=========================
44

5-
1.3.14 (04/10/2025)
5+
[dev] (MM/DD/YY)
6+
==================
7+
8+
scipy interface :code:`mkl_fft.interfaces.scipy_fft` now includes Hermitian FFT functions:
9+
:code:`hfft`, :code:`ihfft`, :code:`hfftn`, :code:`ihfftn`, :code:`hfft2`, and :code:`ihfft2`
10+
11+
1.3.14 (04/11/2025)
612
===================
713

814
resolves gh-152 by adding an explicit :code:`mkl-service` dependency to :code:`mkl-fft` when building the wheel

Diff for: mkl_fft/_fft_utils.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
import numpy as np
2828

29-
__all__ = ["_check_norm", "_compute_fwd_scale"]
29+
__all__ = ["_check_norm", "_compute_fwd_scale", "_swap_direction"]
3030

3131

3232
def _check_norm(norm):
@@ -49,3 +49,15 @@ def _compute_fwd_scale(norm, n, shape):
4949
return fsc
5050
else: # norm == "ortho"
5151
return np.sqrt(fsc)
52+
53+
54+
def _swap_direction(norm):
55+
_check_norm(norm)
56+
_swap_direction_map = {
57+
"backward": "forward",
58+
None: "forward",
59+
"ortho": "ortho",
60+
"forward": "backward",
61+
}
62+
63+
return _swap_direction_map[norm]

Diff for: mkl_fft/_numpy_fft.py

+2-16
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
import numpy as np
7777

7878
from . import _pydfti as mkl_fft # pylint: disable=no-name-in-module
79-
from ._fft_utils import _check_norm, _compute_fwd_scale
79+
from ._fft_utils import _compute_fwd_scale, _swap_direction
8080
from ._float_utils import _downcast_float128_array
8181

8282

@@ -124,18 +124,6 @@ def _cook_nd_args(a, s=None, axes=None, invreal=False):
124124
return s, axes
125125

126126

127-
def _swap_direction(norm):
128-
_check_norm(norm)
129-
_swap_direction_map = {
130-
"backward": "forward",
131-
None: "forward",
132-
"ortho": "ortho",
133-
"forward": "backward",
134-
}
135-
136-
return _swap_direction_map[norm]
137-
138-
139127
def trycall(func, args, kwrds):
140128
try:
141129
res = func(*args, **kwrds)
@@ -604,7 +592,7 @@ def hfft(a, n=None, axis=-1, norm=None):
604592

605593
norm = _swap_direction(norm)
606594
x = _downcast_float128_array(a)
607-
x = np.array(x, copy=True, dtype=complex)
595+
x = np.array(x, copy=True)
608596
np.conjugate(x, out=x)
609597
fsc = _compute_fwd_scale(norm, n, 2 * (x.shape[axis] - 1))
610598

@@ -671,10 +659,8 @@ def ihfft(a, n=None, axis=-1, norm=None):
671659
672660
"""
673661

674-
# The copy may be required for multithreading.
675662
norm = _swap_direction(norm)
676663
x = _downcast_float128_array(a)
677-
x = np.array(x, copy=True, dtype=float)
678664
fsc = _compute_fwd_scale(norm, n, x.shape[axis])
679665

680666
output = trycall(

Diff for: mkl_fft/_scipy_fft.py

+93-13
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
import numpy as np
3434

3535
from . import _pydfti as mkl_fft # pylint: disable=no-name-in-module
36-
from ._fft_utils import _compute_fwd_scale
36+
from ._fft_utils import _compute_fwd_scale, _swap_direction
3737
from ._float_utils import _supported_array_or_not_implemented
3838

3939
__doc__ = """
@@ -125,6 +125,12 @@ def set_workers(n_workers):
125125
"irfft2",
126126
"rfftn",
127127
"irfftn",
128+
"hfft",
129+
"ihfft",
130+
"hfft2",
131+
"ihfft2",
132+
"hfftn",
133+
"ihfftn",
128134
"get_workers",
129135
"set_workers",
130136
"DftiBackend",
@@ -231,7 +237,7 @@ def _validate_input(a):
231237

232238

233239
def fft(
234-
a, n=None, axis=-1, norm=None, overwrite_x=False, workers=None, plan=None
240+
a, n=None, axis=-1, norm=None, overwrite_x=False, workers=None, *, plan=None
235241
):
236242
_check_plan(plan)
237243
x = _validate_input(a)
@@ -244,7 +250,7 @@ def fft(
244250

245251

246252
def ifft(
247-
a, n=None, axis=-1, norm=None, overwrite_x=False, workers=None, plan=None
253+
a, n=None, axis=-1, norm=None, overwrite_x=False, workers=None, *, plan=None
248254
):
249255
_check_plan(plan)
250256
x = _validate_input(a)
@@ -263,6 +269,7 @@ def fft2(
263269
norm=None,
264270
overwrite_x=False,
265271
workers=None,
272+
*,
266273
plan=None,
267274
):
268275

@@ -284,6 +291,7 @@ def ifft2(
284291
norm=None,
285292
overwrite_x=False,
286293
workers=None,
294+
*,
287295
plan=None,
288296
):
289297

@@ -299,7 +307,14 @@ def ifft2(
299307

300308

301309
def fftn(
302-
a, s=None, axes=None, norm=None, overwrite_x=False, workers=None, plan=None
310+
a,
311+
s=None,
312+
axes=None,
313+
norm=None,
314+
overwrite_x=False,
315+
workers=None,
316+
*,
317+
plan=None,
303318
):
304319
_check_plan(plan)
305320
x = _validate_input(a)
@@ -312,7 +327,14 @@ def fftn(
312327

313328

314329
def ifftn(
315-
a, s=None, axes=None, norm=None, overwrite_x=False, workers=None, plan=None
330+
a,
331+
s=None,
332+
axes=None,
333+
norm=None,
334+
overwrite_x=False,
335+
workers=None,
336+
*,
337+
plan=None,
316338
):
317339
_check_plan(plan)
318340
x = _validate_input(a)
@@ -324,7 +346,7 @@ def ifftn(
324346
)
325347

326348

327-
def rfft(a, n=None, axis=-1, norm=None, workers=None, plan=None):
349+
def rfft(a, n=None, axis=-1, norm=None, workers=None, *, plan=None):
328350
_check_plan(plan)
329351
x = _validate_input(a)
330352
fsc = _compute_fwd_scale(norm, n, x.shape[axis])
@@ -333,7 +355,7 @@ def rfft(a, n=None, axis=-1, norm=None, workers=None, plan=None):
333355
return mkl_fft.rfft(x, n=n, axis=axis, fwd_scale=fsc)
334356

335357

336-
def irfft(a, n=None, axis=-1, norm=None, workers=None, plan=None):
358+
def irfft(a, n=None, axis=-1, norm=None, workers=None, *, plan=None):
337359
_check_plan(plan)
338360
x = _validate_input(a)
339361
fsc = _compute_fwd_scale(norm, n, 2 * (x.shape[axis] - 1))
@@ -342,17 +364,15 @@ def irfft(a, n=None, axis=-1, norm=None, workers=None, plan=None):
342364
return mkl_fft.irfft(x, n=n, axis=axis, fwd_scale=fsc)
343365

344366

345-
def rfft2(a, s=None, axes=(-2, -1), norm=None, workers=None, plan=None):
346-
367+
def rfft2(a, s=None, axes=(-2, -1), norm=None, workers=None, *, plan=None):
347368
return rfftn(a, s=s, axes=axes, norm=norm, workers=workers, plan=plan)
348369

349370

350-
def irfft2(a, s=None, axes=(-2, -1), norm=None, workers=None, plan=None):
351-
371+
def irfft2(a, s=None, axes=(-2, -1), norm=None, workers=None, *, plan=None):
352372
return irfftn(a, s=s, axes=axes, norm=norm, workers=workers, plan=plan)
353373

354374

355-
def rfftn(a, s=None, axes=None, norm=None, workers=None, plan=None):
375+
def rfftn(a, s=None, axes=None, norm=None, workers=None, *, plan=None):
356376
_check_plan(plan)
357377
x = _validate_input(a)
358378
s, axes = _cook_nd_args(x, s, axes)
@@ -362,11 +382,71 @@ def rfftn(a, s=None, axes=None, norm=None, workers=None, plan=None):
362382
return mkl_fft.rfftn(x, s, axes, fwd_scale=fsc)
363383

364384

365-
def irfftn(a, s=None, axes=None, norm=None, workers=None, plan=None):
385+
def irfftn(a, s=None, axes=None, norm=None, workers=None, *, plan=None):
386+
_check_plan(plan)
387+
x = _validate_input(a)
388+
s, axes = _cook_nd_args(x, s, axes, invreal=True)
389+
fsc = _compute_fwd_scale(norm, s, x.shape)
390+
391+
with Workers(workers):
392+
return mkl_fft.irfftn(x, s, axes, fwd_scale=fsc)
393+
394+
395+
def hfft(a, n=None, axis=-1, norm=None, workers=None, *, plan=None):
396+
_check_plan(plan)
397+
x = _validate_input(a)
398+
norm = _swap_direction(norm)
399+
x = np.array(x, copy=True)
400+
np.conjugate(x, out=x)
401+
fsc = _compute_fwd_scale(norm, n, 2 * (x.shape[axis] - 1))
402+
403+
with Workers(workers):
404+
return mkl_fft.irfft(x, n=n, axis=axis, fwd_scale=fsc)
405+
406+
407+
def ihfft(a, n=None, axis=-1, norm=None, workers=None, *, plan=None):
408+
_check_plan(plan)
409+
x = _validate_input(a)
410+
norm = _swap_direction(norm)
411+
fsc = _compute_fwd_scale(norm, n, x.shape[axis])
412+
413+
with Workers(workers):
414+
result = mkl_fft.rfft(x, n=n, axis=axis, fwd_scale=fsc)
415+
416+
np.conjugate(result, out=result)
417+
return result
418+
419+
420+
def hfft2(a, s=None, axes=(-2, -1), norm=None, workers=None, *, plan=None):
421+
return hfftn(a, s=s, axes=axes, norm=norm, workers=workers, plan=plan)
422+
423+
424+
def ihfft2(a, s=None, axes=(-2, -1), norm=None, workers=None, *, plan=None):
425+
return ihfftn(a, s=s, axes=axes, norm=norm, workers=workers, plan=plan)
426+
427+
428+
def hfftn(a, s=None, axes=None, norm=None, workers=None, *, plan=None):
366429
_check_plan(plan)
367430
x = _validate_input(a)
431+
norm = _swap_direction(norm)
432+
x = np.array(x, copy=True)
433+
np.conjugate(x, out=x)
368434
s, axes = _cook_nd_args(x, s, axes, invreal=True)
369435
fsc = _compute_fwd_scale(norm, s, x.shape)
370436

371437
with Workers(workers):
372438
return mkl_fft.irfftn(x, s, axes, fwd_scale=fsc)
439+
440+
441+
def ihfftn(a, s=None, axes=None, norm=None, workers=None, *, plan=None):
442+
_check_plan(plan)
443+
x = _validate_input(a)
444+
norm = _swap_direction(norm)
445+
s, axes = _cook_nd_args(x, s, axes)
446+
fsc = _compute_fwd_scale(norm, s, x.shape)
447+
448+
with Workers(workers):
449+
result = mkl_fft.rfftn(x, s, axes, fwd_scale=fsc)
450+
451+
np.conjugate(result, out=result)
452+
return result

0 commit comments

Comments
 (0)