Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 21 additions & 98 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');

- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: true

Expand Down Expand Up @@ -60,118 +60,41 @@ jobs:
Build-mac:
runs-on: macos-latest
steps:
- name: Export GitHub Actions cache environment variables
uses: actions/github-script@v7
with:
script: |
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');

- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: true

- name: Install system-wide build tools
shell: bash
# Install
# mono: NuGet requires a dotnet runtime
# ninja: Build system
# llvm: Just for clang-tidy. Need to add to path.
# Just add clang-tidy to path, not all of LLVM clang.
run: |
brew install mono ninja llvm
ln -s $(brew --prefix llvm)/bin/clang-tidy /usr/local/bin/clang-tidy
brew install autoconf autoconf-archive automake libtool
- name: Install dependencies
run: brew install meson ninja fftw armadillo googletest google-benchmark pybind11

- name: Setup VCPKG
shell: bash
run: |
cd ${{ github.workspace }}
git clone https://github.com/microsoft/vcpkg
${{ github.workspace }}/vcpkg/bootstrap-vcpkg.sh
- name: Meson setup
run: meson setup builddir --buildtype=release

- name: Add NuGet sources
shell: bash
env:
gh_packages_secret: ${{ secrets.GH_PACKAGES_TOKEN }}
if: ${{ env.gh_packages_secret != '' }}
run: |
mono `${{ env.VCPKG_EXE }} fetch nuget | tail -n 1` \
sources add \
-Source "${{ env.FEED_URL }}" \
-StorePasswordInClearText \
-Name GitHubPackages \
-UserName "${{ env.USERNAME }}" \
-Password "${{ secrets.GH_PACKAGES_TOKEN }}"
mono `${{ env.VCPKG_EXE }} fetch nuget | tail -n 1` \
setapikey "${{ secrets.GH_PACKAGES_TOKEN }}" \
-Source "${{ env.FEED_URL }}"
- name: Build
run: meson compile -C builddir

- name: CMake configure
shell: bash
run: cmake --preset clang

- name: CMake build
shell: bash
run: cmake --build --preset clang-release

- name: CTest
shell: bash
run: ctest --output-on-failure --test-dir build/clang/test/
- name: Test
run: meson test -C builddir --print-errorlogs

Build-linux:
runs-on: ubuntu-24.04
steps:
- name: Export GitHub Actions cache environment variables
uses: actions/github-script@v7
with:
script: |
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');

- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: true

- name: Install system dependencies
shell: bash
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y mono-devel ninja-build pkg-config cmake clang clang-tidy

- name: Setup VCPKG
shell: bash
run: |
cd ${{ github.workspace }}
git clone https://github.com/microsoft/vcpkg
${{ github.workspace }}/vcpkg/bootstrap-vcpkg.sh
sudo apt-get install -y meson ninja-build pkg-config clang \
libfftw3-dev libarmadillo-dev libgtest-dev libbenchmark-dev \
pybind11-dev

- name: Add NuGet sources
shell: bash
env:
gh_packages_secret: ${{ secrets.GH_PACKAGES_TOKEN }}
if: ${{ env.gh_packages_secret != '' }}
run: |
# Use nuget via mono (since mono is not pre-installed on ubuntu, and vcpkg fetches the Windows nuget binary)
mono `${{ env.VCPKG_EXE }} fetch nuget | tail -n 1` \
sources add \
-Source "${{ env.FEED_URL }}" \
-StorePasswordInClearText \
-Name GitHubPackages \
-UserName "${{ env.USERNAME }}" \
-Password "${{ secrets.GH_PACKAGES_TOKEN }}"
mono `${{ env.VCPKG_EXE }} fetch nuget | tail -n 1` \
setapikey "${{ secrets.GH_PACKAGES_TOKEN }}" \
-Source "${{ env.FEED_URL }}"
- name: Meson setup
run: CC=clang CXX=clang++ meson setup builddir --buildtype=release

- name: CMake configure
shell: bash
run: cmake --preset clang

- name: CMake build
shell: bash
run: cmake --build --preset clang-release
- name: Build
run: meson compile -C builddir

- name: CTest
shell: bash
run: ctest --output-on-failure --test-dir build/clang/test/
- name: Test
run: meson test -C builddir --print-errorlogs
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ __pycache__/

# Distribution / packaging
.Python
build/
build*/
develop-eggs/
dist/
downloads/
Expand Down
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
{}
{
"C_Cpp.default.configurationProvider": "mesonbuild.mesonbuild",
}
9 changes: 9 additions & 0 deletions benchmark/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
benchmark_dep = dependency('benchmark')
armadillo_dep = dependency('armadillo')

executable('bench_fftconv',
'bench_fftconv.cpp',
'bench_hilbert.cpp',
include_directories : fftconv_inc,
dependencies : [fftw3_dep, fftw3f_dep, benchmark_dep, armadillo_dep],
)
9 changes: 3 additions & 6 deletions include/fftconv/fftconv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@
#include <complex>
#include <fftconv/aligned_vector.hpp>
#include <fftconv/fftw.hpp>
#include <memory>
#include <span>
#include <type_traits>
#include <unordered_map>

// NOLINTBEGIN(*-reinterpret-cast, *-const-cast, *-pointer-arithmetic)

Expand Down Expand Up @@ -386,13 +384,12 @@ struct FFTConvEngine : public fftw::cache_mixin<FFTConvEngine<T, PlannerFlag>> {

const size_t fft_size = buf.real.size();
const size_t step_size = fft_size - (k.size() - 1);
const T fct = static_cast<T>(1. / fft_size);

// forward fft of kernel and save to complex2
internal::copy_to_padded_buffer<T>(k, buf.real);
forward.execute_dft_r2c(buf.real_ptr(), buf.cx2_ptr());

const auto fct = static_cast<T>(1. / fft_size);

if constexpr (Mode == ConvMode::Full) {
assert(a.size() + k.size() - 1 == out.size());

Expand Down Expand Up @@ -450,7 +447,7 @@ struct FFTConvEngine : public fftw::cache_mixin<FFTConvEngine<T, PlannerFlag>> {
// * Cache fftw_plan
// * Reuse buffers (no malloc on second call to the same convolution size)
// https://en.wikipedia.org/w/index.php?title=Convolution#Fast_convolution_algorithms
template <Floating T, ConvMode Mode = ConvMode::Same,
template <Floating T, ConvMode Mode = ConvMode::Full,
int PlannerFlag = FFTW_ESTIMATE>
void convolve_fftw(const std::span<const T> input,
const std::span<const T> kernel, std::span<T> output) {
Expand All @@ -471,7 +468,7 @@ For "Same" mode, output_size == input_size
2. convolve with kernel using fft of length N.
3. add blocks together
*/
template <Floating T, ConvMode Mode = ConvMode::Same,
template <Floating T, ConvMode Mode = ConvMode::Full,
int PlannerFlag = FFTW_ESTIMATE>
void oaconvolve_fftw(std::span<const T> input, std::span<const T> kernel,
std::span<T> output) {
Expand Down
16 changes: 9 additions & 7 deletions include/fftconv/fftw.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ A C++ FFTW wrapper
#include <complex>
#include <cstdlib>
#include <fftw3.h>
#include <span>
#include <memory>
#include <span>
#include <type_traits>
#include <unordered_map>

Expand All @@ -20,7 +20,8 @@ A C++ FFTW wrapper
#include <arm_neon.h>
#endif

// NOLINTBEGIN(*-pointer-arithmetic, *-macro-usage, *-const-cast)
// NOLINTBEGIN(*-pointer-arithmetic, *-macro-usage, *-const-cast,
// *-math-missing-parenthesis)

namespace fftw {

Expand All @@ -31,8 +32,10 @@ struct WisdomSetup {
explicit WisdomSetup(bool threadSafe) {
static bool callSetup = true;
if (threadSafe && callSetup) {
#if defined FFTW_HAVE_THREADS
fftw_make_planner_thread_safe();
fftwf_make_planner_thread_safe();
#endif
callSetup = false;
}
fftw_import_wisdom_from_filename(".fftw_wisdom");
Expand Down Expand Up @@ -625,7 +628,7 @@ Helper functions
out[i] += in[i] * fct
*/
template <typename T>
inline void normalize_add(T *out, T *in, size_t len, T fct) {
inline void normalize_add(T *out, const T *in, size_t len, T fct) {
for (size_t i = 0; i < len; ++i) {
out[i] += in[i] * fct;
}
Expand All @@ -637,9 +640,7 @@ out[i] += in[i] * fct
template <typename T>
inline void normalize_add(std::span<T> out, std::span<const T> in, T fct) {
const auto len = std::min(out.size(), in.size());
for (size_t i = 0; i < len; ++i) {
out[i] += in[i] * fct;
}
normalize_add<T>(out.data(), in.data(), len, fct);
}

/**
Expand Down Expand Up @@ -925,4 +926,5 @@ void scale_imag_and_magnitude(T const *real, T const *imag, T fct, size_t n,

} // namespace fftw

// NOLINTEND(*-pointer-arithmetic, *-macro-usage, *-const-cast)
// NOLINTEND(*-pointer-arithmetic, *-macro-usage, *-const-cast,
// *-math-missing-parenthesis)
17 changes: 9 additions & 8 deletions include/fftconv/hilbert.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
#include <fftconv/fftw.hpp>
#include <span>

// NOLINTBEGIN(*-pointer-arithmetic, *-magic-numbers)
// NOLINTBEGIN(*-pointer-arithmetic, *-magic-numbers,
// *-math-missing-parenthesis)

namespace fftconv {

Expand All @@ -15,19 +16,19 @@ Uses FFTW's r2c transform
*/
template <fftw::Floating T>
void hilbert(const std::span<const T> x, const std::span<T> env) {
const auto n = x.size();
const size_t n = x.size();
assert(n > 0);
assert(x.size() == env.size());

fftw::EngineR2C1D<T> &engine = fftw::EngineR2C1D<T>::get(n);
fftw::R2CBuffer<T> &buf = engine.buf;

if (isSIMDAligned<64>(x.data())) {
if (isSIMDAligned<32>(x.data())) {
// Avoid a copy
engine.forward(x.data(), buf.out);
} else {
// Copy input to real buffer
for (int i = 0; i < n; ++i) {
for (size_t i = 0; i < n; ++i) {
buf.in[i] = x[i];
}

Expand All @@ -36,8 +37,8 @@ void hilbert(const std::span<const T> x, const std::span<T> env) {
}

// Multiply by 1j (skip DC and Nyquist)
const auto cx_size = n / 2 + 1;
for (auto i = 0; i < cx_size; ++i) {
const size_t cx_size = n / 2 + 1;
for (size_t i = 0; i < cx_size; ++i) {
// Skip DC (0 Hz) and Nyquist (n/2 Hz when n is even)
if (i == 0 || (n % 2 == 0 && i == cx_size - 1)) {
buf.out[i][0] = 0.0;
Expand All @@ -56,7 +57,7 @@ void hilbert(const std::span<const T> x, const std::span<T> env) {
// Take the abs of the analytic signal
const T fct = static_cast<T>(1. / n);

for (auto i = 0; i < n; ++i) {
for (size_t i = 0; i < n; ++i) {
const auto real = x[i];
const auto imag = buf.in[i] * fct;
env[i] = std::sqrt(real * real + imag * imag);
Expand Down Expand Up @@ -182,4 +183,4 @@ void hilbert(const std::span<const T> x, const std::span<T> env) {

} // namespace fftconv

// NOLINTEND(*-pointer-arithmetic, *-magic-numbers)
// NOLINTEND(*-pointer-arithmetic, *-magic-numbers, *-math-missing-parenthesis)
13 changes: 13 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
project('fftconv', 'c', 'cpp',
version : '0.5.1',
default_options : ['cpp_std=c++20', 'warning_level=2'],
)

fftconv_inc = include_directories('include')

fftw3_dep = dependency('fftw3')
fftw3f_dep = dependency('fftw3f')

subdir('test')
subdir('benchmark')
subdir('py')
18 changes: 18 additions & 0 deletions py/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
py = import('python').find_installation(pure: false)
pybind11_dep = dependency('pybind11')

py.extension_module(
'_pyfftconv',
'main.cpp',
include_directories: fftconv_inc,
dependencies: [fftw3_dep, fftw3f_dep, pybind11_dep],
install: true,
subdir: 'pyfftconv',
)

py.install_sources(
'pyfftconv/__init__.py',
'pyfftconv/__init__.pyi',
'pyfftconv/_pyfftconv.pyi',
subdir: 'pyfftconv',
)
21 changes: 2 additions & 19 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[build-system]
requires = ["scikit-build-core>=0.10", "pybind11"]
build-backend = "scikit_build_core.build"
requires = ["meson-python", "pybind11"]
build-backend = "mesonpy"

[project]
name = "pyfftconv"
Expand All @@ -16,20 +16,3 @@ classifiers = [

[project.urls]
homepage = "https://github.com/kwsp/fftconv"

[tool.scikit-build]
minimum-version = "build-system.requires"
logging.level = "INFO"

cmake.version = ">=3.20"
cmake.args = [
"--preset=clang",
"-GNinja", # -GNinja overrides the "Ninja Multi-Config" defined in the preset
]
cmake.build-type = "Release"
cmake.source-dir = "."

build.verbose = true
build.targets = ["_pyfftconv"]

wheel.packages = ["py/pyfftconv"]
Loading
Loading