Skip to content

Commit

Permalink
Merge pull request #55 from flatironinstitute/nemos
Browse files Browse the repository at this point in the history
converted to nemos
  • Loading branch information
BalzaniEdoardo authored Nov 7, 2023
2 parents 4bb837c + b2c771c commit 9a4616f
Show file tree
Hide file tree
Showing 21 changed files with 128 additions and 50 deletions.
75 changes: 75 additions & 0 deletions .github/workflows/deploy-pure-python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Build and upload to PyPI for pure python
on:
release:
types: [published]

jobs:
build:
name: Build and test package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# this is necessary for setuptools_scm to work properly with github
# actions, see https://github.com/pypa/setuptools_scm/issues/480 and
# https://stackoverflow.com/a/68959339
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Build package
run: |
pip install build
python -m build --outdir dist/ --sdist --wheel
- name: Check there's only one sdist and one whl file created
shell: bash
# because the following two tests will be weird otherwise. see
# https://askubuntu.com/a/454568 for why this is the right way to handle
# it. using [[ BOOLEAN ]] || EXPR is a compact way of writing IF NOT
# BOOLEAN THEN EXPR in bash
run: |
[[ $(find dist/ -type f -name "*whl" -printf x | wc -c) == 1 ]] || exit 1
[[ $(find dist/ -type f -name "*tar.gz" -printf x | wc -c) == 1 ]] || exit 1
- name: Check setuptools_scm version against git tag
shell: bash
run: |
# we use the error code of this comparison: =~ is bash's regex
# operator, so it checks whether the right side is contained in the
# left side. In particular, we succeed if the path of the source code
# ends in the most recent git tag, fail if it does not.
[[ "$(ls dist/*tar.gz)" =~ "-$(git describe --tags).tar.gz" ]]
- name: Check we can install from wheel
# note that this is how this works in bash (different shells might be
# slightly different). we've checked there's only one .whl file in an
# earlier step, so the bit in `$()` will expand to that single file,
# then we pass [dev] to get specify the optional dev dependencies, and
# we wrap the whole thing in quotes so bash doesn't try to interpret the
# square brackets but passes them directly to pip install
shell: bash
run: |
pip install "$(ls dist/*whl)[dev]"
- name: Run some tests
# modify the following as necessary to e.g., run notebooks
run: |
pytest
- uses: actions/upload-artifact@v3
with:
path: dist/*

publish:
name: Upload release to Test PyPI
needs: [build]
environment: pypi
runs-on: ubuntu-latest
permissions:
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
steps:
- uses: actions/download-artifact@v3
with:
name: artifact
path: dist
- name: Publish package to test pypi
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing

The `neurostatslib` package is designed to provide a robust set of statistical analysis tools for neuroscience research. While the repository is managed by a core team of data scientists at the Center for Computational Neuroscience of the Flatiron Institute, we warmly welcome contributions from external collaborators.
The `nemos` package is designed to provide a robust set of statistical analysis tools for neuroscience research. While the repository is managed by a core team of data scientists at the Center for Computational Neuroscience of the Flatiron Institute, we warmly welcome contributions from external collaborators.

## General Guidelines

Expand Down
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
![LOGO](CCN-logo-wText.png)

# neurostatslib
A toolbox of statistical analysis for neuroscience.
# nemos
NEural MOdelS, a statistical modeling framework for neuroscience.

## Disclaimer
This is an alpha version, the code is in active development and the API is subject to change.

## Setup

To install, clone this repo and install using `pip`:

``` sh
git clone [email protected]:flatironinstitute/generalized-linear-models.git
cd generalized-linear-models/
git clone [email protected]:flatironinstitute/nemos.git
cd nemos/
pip install -e .
```

Expand Down
10 changes: 5 additions & 5 deletions docs/developers_notes/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Introduction

Welcome to the Developer Notes of the `neurostatslib` project. These notes aim to provide detailed technical information about the various modules, classes, and functions that make up this library, as well as guidelines on how to write code that integrates nicely with our package. They are intended to help current and future developers understand the design decisions, structure, and functioning of the library, and to provide guidance on how to modify, extend, and maintain the codebase.
Welcome to the Developer Notes of the `nemos` project. These notes aim to provide detailed technical information about the various modules, classes, and functions that make up this library, as well as guidelines on how to write code that integrates nicely with our package. They are intended to help current and future developers understand the design decisions, structure, and functioning of the library, and to provide guidance on how to modify, extend, and maintain the codebase.

## Intended Audience

Expand All @@ -10,25 +10,25 @@ These notes are primarily intended for the following groups:

- **Future Developers**: These notes can help onboard new developers to the project, providing them with detailed explanations of the codebase and its underlying architecture.

- **Contributors**: If you wish to contribute to the `neurostatslib` project, the Developer Notes can provide a solid foundation of understanding, helping to ensure that your contributions align with the existing structure and design principles of the library.
- **Contributors**: If you wish to contribute to the `nemos` project, the Developer Notes can provide a solid foundation of understanding, helping to ensure that your contributions align with the existing structure and design principles of the library.

- **Advanced Users**: While the primary focus of these notes is on development, they might also be of interest to advanced users who want a deeper understanding of the library's functionality.

Please note that these notes assume a certain level of programming knowledge. Familiarity with Python, object-oriented programming, and the NumPy, Scipy and Jax libraries would be beneficial when reading these notes.

## Navigating the Developer Notes

The Developer Notes are divided into sections, each focusing on a different module or class within the `neurostatslib` library. Each section provides an overview of the class or module, explains its role and functionality within the library, and offers a comprehensive guide to its classes and functions. Typically, we will provide instructions on how to extend the existing modules. We generally advocate for the use of inheritance and encourage consistency with the existing codebase. In creating developer instructions, we follow the conventions outlined below:
The Developer Notes are divided into sections, each focusing on a different module or class within the `nemos` library. Each section provides an overview of the class or module, explains its role and functionality within the library, and offers a comprehensive guide to its classes and functions. Typically, we will provide instructions on how to extend the existing modules. We generally advocate for the use of inheritance and encourage consistency with the existing codebase. In creating developer instructions, we follow the conventions outlined below:

- **Must**: This denotes a requirement. Any method or function that fails to meet the requirement will not be merged.
- **Should**: This denotes a suggestion. Reasons should be provided if a suggestion is not followed.
- **May**: This denotes an option that, if implemented, could enhance the user/developer experience but can be overlooked if deemed unnecessary.

## Interact with us

If you're considering contributing to the library, first of all, welcome aboard! As a first step, we recommend that you read the [`CONTRIBUTING.md`](https://github.com/flatironinstitute/generalized-linear-models/blob/main/CONTRIBUTING.md) guidelines. These will help you understand how to interact with other contributors and how to submit your changes.
If you're considering contributing to the library, first of all, welcome aboard! As a first step, we recommend that you read the [`CONTRIBUTING.md`](https://github.com/flatironinstitute/nemos/blob/main/CONTRIBUTING.md) guidelines. These will help you understand how to interact with other contributors and how to submit your changes.

If you have any questions or need further clarification on any of the topics covered in these notes, please don't hesitate to reach out to us. You can do so via the [discussion](https://github.com/flatironinstitute/generalized-linear-models/discussions/landing) forum on GitHub.
If you have any questions or need further clarification on any of the topics covered in these notes, please don't hesitate to reach out to us. You can do so via the [discussion](https://github.com/flatironinstitute/nemos/discussions/landing) forum on GitHub.

We're looking forward to your contributions and to answering any queries you might have!

Expand Down
8 changes: 4 additions & 4 deletions docs/developers_notes/basis_module.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Introduction

The `neurostatslib.basis` module provides objects that allow users to construct and evaluate basis functions of various types. The classes are hierarchically organized as follows:
The `nemos.basis` module provides objects that allow users to construct and evaluate basis functions of various types. The classes are hierarchically organized as follows:

```
Abstract Class Basis
Expand Down Expand Up @@ -30,7 +30,7 @@ Abstract Class Basis

The super-class `Basis` provides two public methods, [`evaluate`](#the-public-method-evaluate) and [`evaluate_on_grid`](#the-public-method-evaluate_on_grid). These methods perform checks on both the input provided by the user and the output of the evaluation to ensure correctness, and are thus considered "safe". They both make use of the private abstract method `_evaluate` that is specific for each concrete class. See below for more details.

## The Class `neurostatslib.basis.Basis`
## The Class `nemos.basis.Basis`

### The Public Method `evaluate`

Expand All @@ -54,7 +54,7 @@ This method performs the following steps:

### Abstract Methods

The `neurostatslib.basis.Basis` class has the following abstract methods, which every concrete subclass must implement:
The `nemos.basis.Basis` class has the following abstract methods, which every concrete subclass must implement:

1. `_evaluate`: Evaluates a basis over some specified samples.
2. `_check_n_basis_min`: Checks the minimum number of basis functions required. This requirement can be specific to the type of basis.
Expand All @@ -65,7 +65,7 @@ The `neurostatslib.basis.Basis` class has the following abstract methods, which
To write a usable (i.e., concrete, non-abstract) basis object, you

- **Must** inherit the abstract superclass `Basis`
- **Must** define the `_evaluate` and `_check_n_basis_min` methods with the expected input/output format, see [Code References](../../reference/neurostatslib/basis/) for the specifics.
- **Must** define the `_evaluate` and `_check_n_basis_min` methods with the expected input/output format, see [Code References](../../reference/nemos/basis/) for the specifics.
- **Should not** overwrite the `evaluate` and `evaluate_on_grid` methods inherited from `Basis`.
- **May** inherit any number of abstract intermediate classes (e.g., `SplineBasis`).
- **May** reimplement the `_get_samples` method if your basis domain differs from `[0,1]`. However, we recommend mapping the specific basis domain to `[0,1]` whenever possible.
Expand Down
8 changes: 4 additions & 4 deletions docs/examples/plot_1D_basis_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@

import numpy as np
import matplotlib.pylab as plt
import neurostatslib as nsl
import nemos as nmo

# Initialize hyperparameters
order = 4
n_basis = 10

# Define the 1D basis function object
mspline_basis = nsl.basis.MSplineBasis(n_basis_funcs=n_basis, order=order)
mspline_basis = nmo.basis.MSplineBasis(n_basis_funcs=n_basis, order=order)

# %%
# Evaluating a Basis
Expand Down Expand Up @@ -63,12 +63,12 @@
# Other Basis Types
# -----------------
# Each basis type may necessitate specific hyperparameters for instantiation. For a comprehensive description,
# please refer to the [Code References](../../../reference/neurostatslib/basis). After instantiation, all classes
# please refer to the [Code References](../../../reference/nemos/basis). After instantiation, all classes
# share the same syntax for basis evaluation. The following is an example of how to instantiate and
# evaluate a log-spaced cosine raised function basis.

# Instantiate the basis noting that the `RaisedCosineBasisLog` does not require an `order` parameter
raised_cosine_log = nsl.basis.RaisedCosineBasisLog(n_basis_funcs=10)
raised_cosine_log = nmo.basis.RaisedCosineBasisLog(n_basis_funcs=10)

# Evaluate the raised cosine basis at the equi-spaced sample points
# (same method in all Basis elements)
Expand Down
12 changes: 6 additions & 6 deletions docs/examples/plot_ND_basis_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@

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

# Define 1D basis objects
a_basis = nsl.basis.MSplineBasis(n_basis_funcs=15, order=3)
b_basis = nsl.basis.RaisedCosineBasisLog(n_basis_funcs=14)
a_basis = nmo.basis.MSplineBasis(n_basis_funcs=15, order=3)
b_basis = nmo.basis.RaisedCosineBasisLog(n_basis_funcs=14)

# Define the 2D additive basis object
additive_basis = a_basis + b_basis
Expand Down Expand Up @@ -238,9 +238,9 @@
T = 10
n_basis = 8

a_basis = nsl.basis.RaisedCosineBasisLinear(n_basis_funcs=n_basis)
b_basis = nsl.basis.RaisedCosineBasisLinear(n_basis_funcs=n_basis)
c_basis = nsl.basis.RaisedCosineBasisLinear(n_basis_funcs=n_basis)
a_basis = nmo.basis.RaisedCosineBasisLinear(n_basis_funcs=n_basis)
b_basis = nmo.basis.RaisedCosineBasisLinear(n_basis_funcs=n_basis)
c_basis = nmo.basis.RaisedCosineBasisLinear(n_basis_funcs=n_basis)

prod_basis_3 = a_basis * b_basis * c_basis
samples = np.linspace(0, 1, T)
Expand Down
12 changes: 6 additions & 6 deletions docs/examples/plot_example_convolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import numpy as np
import matplotlib.pylab as plt
import matplotlib.patches as patches
import neurostatslib as nsl
import nemos as nmo

np.random.seed(10)
ws = 11
Expand Down Expand Up @@ -39,7 +39,7 @@


# create three filters
basis_obj = nsl.basis.RaisedCosineBasisLinear(n_basis_funcs=3)
basis_obj = nmo.basis.RaisedCosineBasisLinear(n_basis_funcs=3)
_, w = basis_obj.evaluate_on_grid(ws)

plt.plot(w)
Expand All @@ -48,7 +48,7 @@
# the function requires an iterable (one element per trial)
# and returns a list of convolutions

spk_conv = nsl.utils.convolve_1d_trials(w, [spk, np.zeros((20, 1))])
spk_conv = nmo.utils.convolve_1d_trials(w, [spk, np.zeros((20, 1))])
print(f"Shape of spk: {spk.shape}\nShape of w: {w.shape}")

# valid convolution should be of shape n_samples - ws + 1
Expand All @@ -72,9 +72,9 @@


# pad according to the causal direction of the filter, after squeeze, the dimension is (n_filters, n_samples)
spk_causal_utils = np.squeeze(nsl.utils.nan_pad_conv(spk_conv, ws, filter_type="causal")[0])
spk_anticausal_utils = np.squeeze(nsl.utils.nan_pad_conv(spk_conv, ws, filter_type="anti-causal")[0])
spk_acausal_utils = np.squeeze(nsl.utils.nan_pad_conv(spk_conv, ws, filter_type="acausal")[0])
spk_causal_utils = np.squeeze(nmo.utils.nan_pad_conv(spk_conv, ws, filter_type="causal")[0])
spk_anticausal_utils = np.squeeze(nmo.utils.nan_pad_conv(spk_conv, ws, filter_type="anti-causal")[0])
spk_acausal_utils = np.squeeze(nmo.utils.nan_pad_conv(spk_conv, ws, filter_type="acausal")[0])


# %%
Expand Down
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# neurostatslib
# nemos
A toolbox of statistical analysis for neuroscience.

## Disclaimer
Please note that this package is currently under development. While you can download and test the functionalities that are already present, it's important to be aware that the code stability and systematic testing cannot be guaranteed at this stage.

See our [README](https://github.com/flatironinstitute/generalized-linear-models/blob/main/README.md) for more info.
See our [README](https://github.com/flatironinstitute/nemos/blob/main/README.md) for more info.
4 changes: 2 additions & 2 deletions mkdocs.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
site_name: neurostatslib
repo_url: https://github.com/flatironinstitute/generalized-linear-models
site_name: nemos
repo_url: https://github.com/flatironinstitute/nemos

theme:
name: 'material' # The theme name, using the 'material' theme
Expand Down
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ requires = ["setuptools", "setuptools-scm"]
build-backend = "setuptools.build_meta"

[project]
name = "neurostatslib"
name = "nemos"
version = "0.1.0"
authors = [
{name = "Edoardo Balzani", email = "[email protected]"},
Expand Down Expand Up @@ -41,7 +41,7 @@ dependencies = [
# Configure package discovery for setuptools
[tool.setuptools.packages.find]
where = ["src"] # The directory where package modules are located
include = ["neurostatslib"] # The specific package(s) to include in the distribution
include = ["nemos"] # The specific package(s) to include in the distribution


# Define optional dependencies for the project
Expand Down Expand Up @@ -96,7 +96,7 @@ profile = "black"

# Configure pytest
[tool.pytest.ini_options]
addopts = "--cov=neurostatslib" # Additional options to pass to pytest, enabling coverage for the 'neurostatslib' package
addopts = "--cov=nemos" # Additional options to pass to pytest, enabling coverage for the 'nemos' package
testpaths = ["tests"] # Specify the directory where test files are located

[tool.coverage.report]
Expand Down
File renamed without changes.
6 changes: 3 additions & 3 deletions src/neurostatslib/basis.py → src/nemos/basis.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from numpy.typing import ArrayLike, NDArray
from scipy.interpolate import splev

from neurostatslib.utils import row_wise_kron
from .utils import row_wise_kron

__all__ = [
"MSplineBasis",
Expand Down Expand Up @@ -736,8 +736,8 @@ def _evaluate(self, sample_pts: NDArray) -> NDArray:
sample_pts : (number of samples,)
Spacing for basis functions, holding elements on interval [0,
1). A good default is
``nsl.sample_points.raised_cosine_log`` for log spacing (as used in
[2]_) or ``nsl.sample_points.raised_cosine_linear`` for linear
``nmo.sample_points.raised_cosine_log`` for log spacing (as used in
[2]_) or ``nmo.sample_points.raised_cosine_linear`` for linear
spacing.
Returns
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion tests/test_basis.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import pytest
import utils_testing

import neurostatslib.basis as basis
import nemos.basis as basis

# automatic define user accessible basis and check the methods

Expand Down
2 changes: 1 addition & 1 deletion tests/test_convolution_1d.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import numpy as np
import pytest

import neurostatslib.utils as utils
import nemos.utils as utils


class Test1DConvolution:
Expand Down
4 changes: 2 additions & 2 deletions tests/test_glm_runs.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import jax
import numpy as np

from neurostatslib.basis import MSplineBasis
from neurostatslib.glm import GLM
from nemos.basis import MSplineBasis
from nemos.glm import GLM


class DimensionMismatchError(Exception):
Expand Down
6 changes: 3 additions & 3 deletions tests/test_glm_synthetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
import matplotlib.pyplot as plt
import numpy as onp

import neurostatslib as nsl
from neurostatslib.basis import RaisedCosineBasisLinear
from neurostatslib.glm import GLM
import nemos as nmo
from nemos.basis import RaisedCosineBasisLinear
from nemos.glm import GLM


def test_set_up_glm():
Expand Down
Loading

0 comments on commit 9a4616f

Please sign in to comment.