Skip to content
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

[MRG+1] unify cell connectivity and drive connectivity #369

Merged
merged 22 commits into from Aug 18, 2021

Conversation

jasmainak
Copy link
Collaborator

@jasmainak jasmainak commented Jun 18, 2021

This is a very draft version, @cjayb do you have any objection to this kind of direction?

I think it will depend on some changes @ntolley is making in #348

@rythorpe
Copy link
Contributor

rythorpe commented Jul 7, 2021

Is this on the docket for our 0.2 release? I'm happy to work on this PR and keep the momentum of #383 going as I noticed there is a lot of unnecessary bulk involved in assigning drive connectivity.

@jasmainak
Copy link
Collaborator Author

I think it would be great to have! I'm always trying to motivate folks to keep the code in shape as we go rather than only add new features.

This was referenced Jul 14, 2021
@jasmainak
Copy link
Collaborator Author

@rythorpe this would be a good one to get your help on if you're interested. I can take care of #315

@rythorpe
Copy link
Contributor

Just rebased, but I'll work on this more throughout next week.

@rythorpe
Copy link
Contributor

I'm learning that _create_drive_conns() helped enforce legacy mode behavior by accepting target_populations as an argument and creating connectivity specifications for each target cell type independent of whether or not a real connection (i.e., as stored in net.connectivity) was created. By now relying on net.connectivity to determine which drive cells target which network cells in _instantiate_drives(), we've made it much more difficult to maintain legacy mode. I think I can work around it, but be prepared for some janky hacks.

hnn_core/network.py Outdated Show resolved Hide resolved
@jasmainak
Copy link
Collaborator Author

let's make it work first. I think some helper functions might be necessary but having the connectivity object unified across drives and cells will be really beneficial in terms of how we think about things!

@cjayb
Copy link
Collaborator

cjayb commented Jul 30, 2021

I think I can work around it, but be prepared for some janky hacks.

Do you need a workaround, or just a nuke? _legacy_mode was necessary to get all the gids to line up, but given all the other legacy-breaking changes in 0.2, it seems pointless to try to fix anything here. Consolidating on he new connectivity API is surely the only strategy that makes sense.

@rythorpe
Copy link
Contributor

I've got all the tests passing except for the following connectivity test in test_network.py. Is there systematic way to update this @ntolley without having to manually determine each correct connectivity index?

        # List of tuples with (arg, item, correct_indices)
        kwargs_good = [
            ('src_gids', 0, [30, 39]),
            ('src_gids', 'L2_pyramidal', [29]),
            ('src_gids', range(2), [30, 39]),
            ('src_gids', None, [4, 29, 30, 39]),
            ('target_gids', 35, [22, 34, 35, 37, 38, 40, 41, 42, 43, 44]),
            ('target_gids', range(2), [30, 39]),
            ('target_gids', 'L2_pyramidal',
             [22, 34, 35, 37, 38, 40, 41, 42, 43, 44]),
            ('target_gids', None,
             [22, 28, 30, 34, 35, 37, 38, 39, 40, 41, 42, 43, 44]),
            ('loc', 'soma', [30, 39]),
            ('loc', None, [30, 39]),
            ('receptor', 'gabaa', [30, 39]),
            ('receptor', None, [30, 39])]
        for arg, item, indices in kwargs_good:
            kwargs = kwargs_default.copy()
            kwargs[arg] = item
>           assert indices == pick_connection(**kwargs)
E           assert [30, 39] == [62, 71]
E             At index 0 diff: 30 != 62
E             Use -v to get the full diff

@ntolley
Copy link
Contributor

ntolley commented Aug 13, 2021

You're telling me you don't appreciate my mountain of hard coded tests? 😄

Yeah this is a pretty gross solution, I'll push some commits to this branch tomorrow with a more sensible test. I know it's not good practice to change tests to satisfy a PR, but it's worth it in this case.

@jasmainak
Copy link
Collaborator Author

jasmainak commented Aug 13, 2021 via email

@rythorpe
Copy link
Contributor

You're telling me you don't appreciate my mountain of hard coded tests? smile

Yeah this is a pretty gross solution, I'll push some commits to this branch tomorrow with a more sensible test. I know it's not good practice to change tests to satisfy a PR, but it's worth it in this case.

I've got to admit, I'm pretty sure my heart rate spiked the moment I saw this test fail. Sounds good, thanks Nick!

hnn_core/drives.py Outdated Show resolved Hide resolved
# 15 drive connections are added as follows: evdist1: 3 ampa + 3 nmda,
# evprox1: 4 ampa, evprox2: 4 ampa, and 1 extra zero-weighted ampa
# evdist1->L5_basket connection is added to comply with legacy_mode
assert len(net_default.connectivity) == n_conn + 15
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

could we do legacy_mode = False in all/most of our tests unless we are explicitly testing the legacy mode ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Mostly yes. Aside from the tests like this one that explicitly test against a hardcoded value, I've tried to write as many of my tests as possible to accommodate either scenario. That said, it's something we should probably dedicate a whole PR to (see #393).

location, receptor, weights, delays,
space_constant)
else:
src_gids = list(self.gid_ranges[name])
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Suggested change
src_gids = list(self.gid_ranges[name])

shouldn't need this, no? You can just provide name to add_connection ?

Copy link
Contributor

Choose a reason for hiding this comment

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

That only works for names in Network.cell_types. We could modify this validation step in add_connection()?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think we should ... it should allow cell_types as well as external_drives.keys()

@jasmainak
Copy link
Collaborator Author

jasmainak commented Aug 16, 2021

I think this looks great @rythorpe . One concern I have in my mind is if the net.connectivity is still easy to inspect since we have many drives and each connectivity element represents one target population and one receptor. So we end up having n_drives x n_target_populations x n_receptor connections. I guess nicer slicing and repr of this object could be future PRs

@jasmainak
Copy link
Collaborator Author

Oh, also you have flake8 errors. It would be good to bring the PR to MRG state. It looks pretty clean as such

@rythorpe
Copy link
Contributor

I think this looks great @rythorpe . One concern I have in my mind is if the net.connectivity is still easy to inspect since we have many drives and each connectivity element represents one target population and one receptor. So we end up having n_drives x n_target_populations x n_receptor connections. I guess nicer slicing and repr of this object could be future PRs

That's pretty much what we have now, although it is ominous given the sheer number of connections. What did you have in mind?

@codecov-commenter
Copy link

codecov-commenter commented Aug 16, 2021

Codecov Report

Merging #369 (c8c334e) into master (367a883) will increase coverage by 0.03%.
The diff coverage is 100.00%.

❗ Current head c8c334e differs from pull request most recent head 22f5906. Consider uploading reports for the commit 22f5906 to get more accurate results
Impacted file tree graph

@@            Coverage Diff             @@
##           master     #369      +/-   ##
==========================================
+ Coverage   90.26%   90.30%   +0.03%     
==========================================
  Files          17       17              
  Lines        3062     3054       -8     
==========================================
- Hits         2764     2758       -6     
+ Misses        298      296       -2     
Impacted Files Coverage Δ
hnn_core/drives.py 92.77% <100.00%> (+0.66%) ⬆️
hnn_core/network.py 91.70% <100.00%> (-0.30%) ⬇️
hnn_core/network_builder.py 94.23% <100.00%> (+0.09%) ⬆️
hnn_core/params.py 91.15% <100.00%> (+1.53%) ⬆️
hnn_core/parallel_backends.py 82.80% <0.00%> (-0.86%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 367a883...22f5906. Read the comment docs.

@jasmainak
Copy link
Collaborator Author

What did you have in mind?

I guess it's fine for now, we can always do:

net.connectivity[pick_connectivity(src_gids='L2_Pyramidal')]

maybe:

net.connectivity.pick(src_gids='L2_Pyramidal')

would have been cleaner but it would need us to define a new object etc., so not sure if it's worth the effort
?

@rythorpe rythorpe changed the title WIP: unify cell connectivity and drive connectivity [MRG] unify cell connectivity and drive connectivity Aug 16, 2021
@rythorpe
Copy link
Contributor

What did you have in mind?

I guess it's fine for now, we can always do:

net.connectivity[pick_connectivity(src_gids='L2_Pyramidal')]

maybe:

net.connectivity.pick(src_gids='L2_Pyramidal')

would have been cleaner but it would need us to define a new object etc., so not sure if it's worth the effort
?

I think this deserves it's own discussion/PR along with any renaming we do to pick_connection() as I now realize it is used in a lot of places and would blow up this PR.

@jasmainak
Copy link
Collaborator Author

yeah, agree that should be a different PR :)

@@ -40,6 +40,8 @@ Changelog

- Add :func:`~hnn_core.Network.pick_connection` to query the indices of specific connections in :attr:`~hnn_core.Network.connectivity`, by `Nick Tolley`_ in `#367 <https://github.com/jonescompneurolab/hnn-core/pull/367>`_

- Unify the codepath for instantiating drive and local network connectivity, by `Ryan Thorpe`_, `Mainak Jas`_, and `Nick Tolley`_ in `#369 <https://github.com/jonescompneurolab/hnn-core/pull/369>`_
Copy link
Collaborator Author

@jasmainak jasmainak Aug 17, 2021

Choose a reason for hiding this comment

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

You should think of "what affects the user" when updating this. User does not care about code path. They care about:

  • change in behavior (e.g., with 0 weights in param files, you now have empty connections?). That's a bug fix.
  • change in net.connectivity. It has more elements now and probably not in the same order. If someone hard coded net.connectivity[32] it would now break. So that's an API change.
  • change in drive['conns']. It no longer exists. If someone relied on it in their code, it would break now

Copy link
Contributor

Choose a reason for hiding this comment

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

What do you think of 3663826 @jasmainak?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Looks good!

@@ -389,7 +411,7 @@ def test_network():
# Test removing connections from net.connectivity
# Needs to be updated if number of drives change in preceeding tests
net.clear_connectivity()
assert len(net.connectivity) == 18
assert len(net.connectivity) == 50
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I am confused what's going on here. Isn't clear_connectivity going to remove all the connections? Then why do we still have 50 connections?

Copy link
Contributor

Choose a reason for hiding this comment

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

clear_connectivity clears local network connectivity, not the drive connectivity. Maybe we should update the name accordingly.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yeah updating the name sounds good. Either in this PR or another, as you feel like.

@jasmainak jasmainak changed the title [MRG] unify cell connectivity and drive connectivity [MRG+1] unify cell connectivity and drive connectivity Aug 17, 2021
@jasmainak
Copy link
Collaborator Author

It looks like I can't approve the pull request since I started it. So, I went back to "old ways" and edited the title. @ntolley or @cjayb feel free to merge once you are happy

rythorpe and others added 2 commits August 17, 2021 12:56
Co-authored-by: Mainak Jas <jasmainak@users.noreply.github.com>
@ntolley
Copy link
Contributor

ntolley commented Aug 18, 2021

Apologies for not keeping up too closely with the PR as it progressed, but I am definitely a fan of all the changes. Luckily for @rythorpe I really don't have nitpicks, it was so obvious that these redundant data structures needed to be merged and it's done super clean here.

Most of the issues I have are not with the PR, and have more to with general structure of net.connectivity which as mentioned before warrants some discussion on if this is the data structure we want to commit to. In any case great work!!

@ntolley ntolley merged commit 6fb132d into jonescompneurolab:master Aug 18, 2021
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.

None yet

5 participants