Skip to content

Fourier #300

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 51 commits into
base: development
Choose a base branch
from
Open

Fourier #300

wants to merge 51 commits into from

Conversation

BalzaniEdoardo
Copy link
Collaborator

Add a Fourier basis.

This PR adds a Fourier basis. The API is as follows:

import nemos as nmo
import numpy as np
import matplotlib.pyplot as plt

# this configuration exclude the 0 frequency creating 2*n_frequencies bases.
bas = nmo.basis.FourierEval(n_frequencies=5)
out = bas.compute_features(np.linspace(0, 1, 200))

plt.figure()
plt.title("No 0 frequency")
plt.plot(out)
plt.show()

# this configuration exclude the 0 frequency creating 2*n_frequencies bases + 1.
bas = nmo.basis.FourierEval(n_frequencies=5, include_constant=True)
out = bas.compute_features(np.linspace(0, 1, 200))

plt.figure()
plt.title("Include 0 frequency")
plt.plot(out)
plt.show()

@BalzaniEdoardo BalzaniEdoardo marked this pull request as draft January 23, 2025 21:44
@billbrod billbrod mentioned this pull request Jan 28, 2025
@BalzaniEdoardo BalzaniEdoardo marked this pull request as ready for review June 3, 2025 14:03
@BalzaniEdoardo BalzaniEdoardo marked this pull request as draft June 3, 2025 16:17
@BalzaniEdoardo BalzaniEdoardo marked this pull request as ready for review June 18, 2025 19:11
Copy link
Member

@billbrod billbrod left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some minor requested changes about the docstrings and tests.

  • Looks like a lot of minor changes in the basis tests -- is that to make sure that the window size is big enough for the Fourier Conv basis?
  • Also some line-wrapping -- did the version of black change or something?
  • I think we should add tests that check the relationship with FFT.

- 🔵 Conv

* - **Fourier Basis**
- .. plot:: scripts/basis_figs.py plot_fourier_basis
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this image looks like a mess -- is there a more informative way to plot it?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think plotting fewer frequencies would help

n_frequencies :
The number of frequencies for the Fourier basis.
include_constant:
Include the constant term, which corresponds to 0 frequency. Default is False.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Include the constant term, which corresponds to 0 frequency. Default is False.
Include the constant term, which corresponds to 0 frequency.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't describe defaults in docstring -- it's already in signature

self,
n_frequencies: int,
include_constant: bool = False,
phase_sign: int = 1,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not described in docstring


@property
def phase_sign(self):
"""Read-only phase sign property."""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""Read-only phase sign property."""

doesn't add anything.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(so either remove, or make it more descriptive and add some for the other properties as well)

By default, ``phase_sign = 1``, which corresponds to the standard orthonormal Fourier basis.
Setting ``phase_sign = -1`` inverts the sign of the phase angle and aligns the basis
with the Discrete Fourier Transform (DFT) convention. With such convention the convolution
with this basis yields the FFT time evolution.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"FFT time evolution"? is that the right word?

And do we have a test for this?

\text{phase_sign} \cdot \sin(2\pi k x), & \text{otherwise}
\end{cases}

By default, ``phase_sign = -1``, which aligns the basis with the Discrete Fourier Transform (DFT)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove "default" and should probably be identical to the description in FourierEval

\text{phase_sign} \cdot \sin(2\pi k x), & \text{otherwise}
\end{cases}

By default, ``phase_sign = 1``, which corresponds to the standard orthonormal Fourier basis.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove "default"

conv_kwargs:
Additional keyword arguments passed to :func:`nemos.convolve.create_convolutional_predictor`;
These arguments are used to change the default behavior of the convolution.
For example, changing the ``predictor_causality``, which by default is set to ``"causal"``.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again, remove default

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and should probably have an example of how to do this in doctest

@@ -2607,6 +2670,106 @@ def test_samples_range_matches_compute_features_requirements(
basis_obj.compute_features(np.linspace(*sample_range, 100))


class TestFourierBasis(BasisFuncsTesting):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should test window size is too small for Nyquist

Comment on lines +152 to +153
trans_bas_b.n_frequencies = 3
assert bas_b.n_frequencies == 5
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's going on here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as in, why does it the transformer basis have more frequencies than the non-transformer one?

Copy link
Collaborator

@sjvenditto sjvenditto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking great! I have a few comments on missing test cases, and I think the Fourier basis docstring could use a little more information

- 🔵 Conv

* - **Fourier Basis**
- .. plot:: scripts/basis_figs.py plot_fourier_basis
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think plotting fewer frequencies would help

n_frequencies: int,
include_constant: bool = False,
phase_sign: int = 1,
label: Optional[str] = "RaisedCosineBasisLinear",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
label: Optional[str] = "RaisedCosineBasisLinear",
label: Optional[str] = "Fourier",

HistoryConv,
IdentityEval,
TransformerBasis,
)
from nemos.basis._basis import (
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests test_expected_output_eval_on_grid,test_expected_output_compute_features, test_expected_output_split_by_feature are missing cases for Fourier

basis.CyclicBSplineConv: "'mylabel': CyclicBSplineConv(n_basis_funcs=5, window_size=11, order=4)",
basis.MSplineConv: "'mylabel': MSplineConv(n_basis_funcs=5, window_size=11, order=4)",
basis.OrthExponentialConv: "'mylabel': OrthExponentialConv(n_basis_funcs=5, window_size=11)",
basis.HistoryConv: "'mylabel': HistoryConv(window_size=11)",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no expected output here for Fourier



class FourierBasis(Basis, AtomicBasisMixin, abc.ABC):
"""Fourier Basis.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this give a little more of a description? The other basis functions have more than this

@BalzaniEdoardo
Copy link
Collaborator Author

  • of minor changes in the b

Just some minor requested changes about the docstrings and tests.

* Looks like a lot of minor changes in the basis tests -- is that to make sure that the window size is big enough for the Fourier Conv basis?

Yes, the window size in many of the tests was too small for the nyqst check of the basis, so I had to make sure that the check passed.

* Also some line-wrapping -- did the version of black change or something?

Yes, black was upgraded. I am calling tox -e fix with no changes in the configurations.

* I think we should add tests that check the relationship with FFT.

I will, good call

@BalzaniEdoardo
Copy link
Collaborator Author

  • Add a public property frequencies that returns the frequency value.
  • Setter will change the n_frequencies and checks for integers values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants