Skip to content

Update code#27

Merged
chaoming0625 merged 6 commits intomainfrom
update
Feb 19, 2025
Merged

Update code#27
chaoming0625 merged 6 commits intomainfrom
update

Conversation

@chaoming0625
Copy link
Copy Markdown
Collaborator

@chaoming0625 chaoming0625 commented Feb 19, 2025

This pull request includes a significant refactor of the braincell package, mainly focusing on replacing the usage of the bst module with the brainstate module across various files. Additionally, it includes improvements to the Container and TreeNode classes in braincell/_misc.py.

Module replacement:

Class improvements:

Documentation:

  • README.md: Removed outdated comments about the braincell package.

Summary by Sourcery

Refactors the braincell package to use the brainstate module instead of bst, enhances the Container and TreeNode classes, and updates documentation.

Enhancements:

  • Improve the Container and TreeNode classes in braincell/_misc.py with detailed docstrings and additional methods for better type checking and element management.
  • Update the documentation in braincell/_base.py to provide a more comprehensive overview of the module's purpose, class hierarchy, and usage.

Documentation:

  • Remove outdated comments about the braincell package in README.md.

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Feb 19, 2025

Reviewer's Guide by Sourcery

This pull request refactors the braincell package by replacing the bst module with brainstate, improving class documentation and structure, and updating method names for consistency. The changes enhance code readability, maintainability, and extensibility.

Updated class diagram for HHTypedNeuron

classDiagram
    class HHTypedNeuron {
        -size: brainstate.typing.Size
        -name: Optional[str]
        -ion_channels: Dict[str, IonChannel]
        +__init__(size: brainstate.typing.Size, name: Optional[str], **ion_channels)
        +pop_size: Tuple[int, ...]
        +n_compartment: int
        +current(*args, **kwargs)
        +pre_integral(*args, **kwargs)
        +compute_derivative(*args, **kwargs)
        +post_integral(*args, **kwargs)
        +init_state(batch_size=None)
        +reset_state(batch_size=None)
        +add(**elements)
    }
    HHTypedNeuron ..> IonChannel : contains
    HHTypedNeuron --|> brainstate.nn.Dynamics
    HHTypedNeuron --|> Container
    HHTypedNeuron --|> DiffEqModule
    note for HHTypedNeuron "Base class for Hodgkin-Huxley type neuron models"
Loading

Updated class diagram for IonChannel

classDiagram
    class IonChannel {
        -size: brainstate.typing.Size
        -name: Optional[str]
        +__init__(size: brainstate.typing.Size, name: Optional[str])
        +varshape
        +current(*args, **kwargs)
        +pre_integral(*args, **kwargs)
        +compute_derivative(*args, **kwargs)
        +post_integral(*args, **kwargs)
        +reset_state(*args, **kwargs)
        +init_state(*args, **kwargs)
    }
    IonChannel --|> brainstate.graph.Node
    IonChannel --|> TreeNode
    IonChannel --|> DiffEqModule
    note for IonChannel "Base class for ion channel modeling"
Loading

Updated class diagram for Ion

classDiagram
    class Ion {
        -channels: Dict[str, Channel]
        -_external_currents: Dict[str, Callable]
        +__init__(size: brainstate.typing.Size, name: Optional[str], **channels)
        +external_currents
        +pre_integral(V)
        +compute_derivative(V)
        +post_integral(V)
        +current(V, include_external: bool = False)
        +init_state(V, batch_size: int = None)
        +reset_state(V, batch_size: int = None)
        +register_external_current(key: str, fun: Callable)
        +pack_info() IonInfo
        +add(**elements)
    }
    Ion --|> IonChannel
    Ion --|> Container
    Ion ..> Channel : contains
    note for Ion "Base class for modeling the Ion dynamics"
Loading

Updated class diagram for MixIons

classDiagram
    class MixIons {
        -ions: Tuple[Ion]
        -_ion_types: Tuple[Type[Ion]]
        -channels: Dict[str, Channel]
        +__init__(*ions, name: Optional[str] = None, **channels)
        +ion_types
        +pre_integral(V)
        +compute_derivative(V)
        +post_integral(V)
        +current(V)
        +init_state(V, batch_size: int = None)
        +reset_state(V, batch_size=None)
        +add(**elements)
        -_check_hierarchy(ions, leaf)
        -_get_ion(ion)
    }
    MixIons --|> IonChannel
    MixIons --|> Container
    MixIons ..> Channel : contains
    note for MixIons "Mixing Ions"
Loading

Updated class diagram for Channel

classDiagram
    class Channel {

    }
    Channel --|> IonChannel
    note for Channel "Base class for modeling channel dynamics."
Loading

Updated class diagram for PotassiumChannel

classDiagram
    class PotassiumChannel {

    }
    PotassiumChannel --|> Channel
    note for PotassiumChannel "Base class for potassium channel dynamics."
Loading

Updated class diagram for SodiumChannel

classDiagram
    class SodiumChannel {

    }
    SodiumChannel --|> Channel
    note for SodiumChannel "Base class for sodium channel dynamics."
Loading

File-Level Changes

Change Details Files
Replaced the bst module with the brainstate module for state management and context handling.
  • Updated imports to use brainstate instead of bst.
  • Replaced bst.graph.Node with brainstate.graph.Node.
  • Replaced bst.typing.Size with brainstate.typing.Size.
  • Replaced bst.State with brainstate.State.
  • Replaced bst.init.param with brainstate.init.param.
  • Replaced bst.mixin.JointTypes with brainstate.mixin.JointTypes.
  • Replaced bst.mixin.Mixin with brainstate.mixin.Mixin.
  • Replaced bst.augment.vmap with brainstate.augment.vmap.
  • Replaced bst.environ.context with brainstate.environ.context.
  • Replaced bst.StateTraceStack with brainstate.StateTraceStack.
  • Replaced bst.compile.for_loop with brainstate.compile.for_loop.
  • Replaced bst.compile.jit with brainstate.compile.jit.
  • Replaced bst.random.uniform with brainstate.random.uniform.
braincell/_base.py
braincell/channel/potassium.py
braincell/channel/calcium.py
braincell/channel/sodium.py
braincell/channel/hyperpolarization_activated.py
braincell/channel/potassium_calcium.py
braincell/_misc.py
braincell/ion/calcium.py
braincell/ion/sodium.py
examples/thalamus_single_compartment_neurons.py
examples/fitting_a_hh_neuron/main.py
braincell/channel/leaky.py
braincell/_integrators.py
braincell/neuron/multi_compartment.py
braincell/neuron/single_compartment.py
braincell/ion/potassium.py
examples/calcium_activation_functions.py
examples/hh_neuron.py
examples/simple_dendrite_model_fitting_by_adam.py
examples/simple_dendrite_model.py
braincell/_protocol.py
examples/golgi_model/golgi.py
Improved the Container and TreeNode classes with enhanced functionality and documentation.
  • Added detailed docstrings to the Container and TreeNode classes.
  • Implemented custom attribute and item access methods in the Container class.
  • Added type checking for child elements in the Container class.
  • Implemented methods to validate the compatibility between root and leaf nodes in the TreeNode class.
braincell/_misc.py
Enhanced the base classes for neuron and ion channel modeling with detailed documentation and improved structure.
  • Added comprehensive docstrings to the HHTypedNeuron, IonChannel, Ion, MixIons, and Channel classes.
  • Improved the structure and organization of the base classes for better clarity and extensibility.
  • Added type hints and annotations for improved code readability and maintainability.
  • Refactored methods for initializing and managing ion channels within neuron models.
braincell/_base.py
braincell/channel/potassium.py
braincell/channel/calcium.py
braincell/channel/sodium.py
Updated method names to add instead of add_elem.
  • Replaced all instances of add_elem with add.
braincell/_base.py
braincell/ion/calcium.py
braincell/ion/potassium.py
examples/thalamus_single_compartment_neurons.py
Removed outdated comments about the braincell package.
  • Removed outdated comments.
README.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!
  • Generate a plan of action for an issue: Comment @sourcery-ai plan on
    an issue to generate a plan of action for it.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@chaoming0625 chaoming0625 merged commit bc10045 into main Feb 19, 2025
@chaoming0625 chaoming0625 deleted the update branch February 19, 2025 04:13
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey @chaoming0625 - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider adding a brief migration guide or deprecation warnings for users who are upgrading from bst to brainstate.
  • The documentation strings are very detailed, but consider adding some simple examples to the docstrings to improve usability.
Here's what I looked at during the review
  • 🟡 General issues: 1 issue found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 2 issues found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread braincell/_base.py
channel.reset_state(self.V.value, batch_size=batch_size)

def add_elem(self, **elements):
def add(self, **elements):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: Renaming 'add_elem' to 'add' improves clarity.

Ensure that all external references to this method are updated accordingly and that its behavior remains consistent.

Suggested implementation:

    result = self.add(**new_elements)
# Usage example: creating a new ion channel via add
channel = neuron_group.add(channel_param=value)

Review other parts of your codebase for references to the old add_elem method and update them to use add.

self.phi = brainstate.init.param(phi, self.varshape, allow_none=False)
self.g_max = brainstate.init.param(g_max, self.varshape, allow_none=False)

def init_state(self, V, Na: IonInfo, batch_size=None):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

issue (complexity): Consider refactoring the repetitive DiffEqState initialization and derivative calculations in the INa_Rsg subclass into helper functions or loops to reduce code duplication.

To reduce the complexity and duplication in the `INa_Rsg` subclass (without changing behavior), consider refactoring the repeated DiffEqState initialization and derivative calls into helper functions or loops.

For example, in the `init_state` method you can use a dictionary of state names and their initializers:

```python
def init_state(self, V, Na: IonInfo, batch_size=None):
    init_funcs = {
        "C1": u.math.ones,
        "C2": u.math.ones,
        "C3": u.math.ones,
        "C4": u.math.ones,
        "C5": u.math.ones,
        "I1": u.math.ones,
        "I2": u.math.ones,
        "I3": u.math.ones,
        "I4": u.math.ones,
        "I5": u.math.ones,
        "I6": u.math.ones,
        "O":  u.math.zeros,
        "B":  u.math.zeros,
    }
    for name, init_func in init_funcs.items():
        setattr(self, name, DiffEqState(bst.init.param(init_func, self.varshape, batch_size)))
    self.normalize_states([getattr(self, key) for key in init_funcs])

Likewise, you can capture common derivative patterns into helper functions. For instance, if a derivative has the form

  (A.value * f_A(V) + B.value * f_B(V) − state.value * (f_C(V) + f_D(V))) / u.ms

you could factor it out (you’ll need to adapt this for each unique state):

def calc_derivative(self, state, contributions, losses, dt=u.ms):
    num = sum(func(V) * val for val, func in contributions) - state.value * sum(func(V) for func in losses)
    state.derivative = num / dt

def compute_derivative(self, V, Na: IonInfo):
    # Example for C1: (I1 * bi1(V) + C2 * b01(V) - C1 * (fi1(V) + f01(V))) / u.ms
    self.calc_derivative(
        self.C1,
        contributions=[(self.I1.value, self.bi1), (self.C2.value, self.b01)],
        losses=[self.fi1, self.f01]
    )
    # Similar refactoring can be applied for other states
    # ...

These small refactoring steps abstract the repetitive patterns while keeping functionality intact.

Comment thread braincell/_integrators.py
# k1: first derivative step
assert len(tableau.A[0]) == 0, f'The first row of A must be empty. Got {tableau.A[0]}'
with bst.environ.context(t=t + tableau.C[0] * dt), bst.StateTraceStack() as trace:
with brainstate.environ.context(t=t + tableau.C[0] * dt), brainstate.StateTraceStack() as trace:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

issue (complexity): Consider creating a context manager to encapsulate the combined contexts and reduce nesting.

You can reduce the nesting by extracting the repeated context‐combinations into a helper/context manager. For example, you might define

from contextlib import contextmanager

@contextmanager
def env_context_trace(t, *, ms=False):
    time_val = t * u.ms if ms else t
    with brainstate.environ.context(t=time_val), brainstate.StateTraceStack() as trace:
        yield trace

Then, in the integration routines (e.g. in _general_rk_step and _diffrax_solve), replace

with brainstate.environ.context(t=t + tableau.C[0] * dt), brainstate.StateTraceStack() as trace:
    ...

with

with env_context_trace(t + tableau.C[0] * dt, ms=False) as trace:
    ...

This refactoring keeps the functionality unchanged while reducing cognitive load by flattening the nesting.

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.

1 participant