Skip to content

no limit on number of ion mechanisms#3089

Merged
nrnhines merged 28 commits into
masterfrom
hines/ions-unlimited
Oct 1, 2024
Merged

no limit on number of ion mechanisms#3089
nrnhines merged 28 commits into
masterfrom
hines/ions-unlimited

Conversation

@nrnhines

@nrnhines nrnhines commented Sep 23, 2024

Copy link
Copy Markdown
Member

PR 3055 extended the allowed number of ion mechanisms from 31 to max_ions = 256; by replacing

static long *chk_conc_, *ion_bit_, ...

with

static std::vector<std::bitset<max_ions>> chk_conc_, ion_bit_;

This PR extension to #3081 makes the underlying alogorithm more understandable by using:

static std::map<int, std::set<int>> mechtype2ionconctype;
static void add_mechtype2ionconctype(int mechtype, int iontype, int i) {...}
static bool mech_uses_ionconctype(int mechtype, int iontype, int i) {...}

Also, with the map of sets, the number of ions allowed in this context in now essentially unlimited. I.e., INT_MAX/2 or more than 1 billion.

@azure-pipelines

Copy link
Copy Markdown

✔️ aea6299 -> Azure artifacts URL

@pramodk

pramodk commented Sep 24, 2024

Copy link
Copy Markdown
Member

@nrnhines : gitlab ci can be ignored. As it’s going into branch, it can be merged.

@azure-pipelines

Copy link
Copy Markdown

✔️ a9de3d7 -> Azure artifacts URL

@bbpbuildbot

This comment has been minimized.

Base automatically changed from hines/ions to master September 30, 2024 21:54
@sonarqubecloud

Copy link
Copy Markdown

@nrnhines nrnhines requested a review from 1uc September 30, 2024 23:35
@azure-pipelines

Copy link
Copy Markdown

✔️ b608ddd -> Azure artifacts URL

@codecov

codecov Bot commented Oct 1, 2024

Copy link
Copy Markdown

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 66.89%. Comparing base (95cc05b) to head (b608ddd).
Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3089      +/-   ##
==========================================
- Coverage   66.90%   66.89%   -0.01%     
==========================================
  Files         572      572              
  Lines      106671   106662       -9     
==========================================
- Hits        71364    71355       -9     
  Misses      35307    35307              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@1uc 1uc left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This seems to solve the problem without a hard coded upper limit (that's less than 2^31).

It's very common in NEURON to have maps mech_type -> f(mech_type) and this follows that convention. In this case it might be easier to store inverse map, i.e. for each ionconc_type save the ids of the mechanisms that write to it.

In pseudo code it might look something like this:

static std::map<int, std::set<int>> ionconctype2writers;

const S& register_ion_write_access(int mechtype, int iontype, int side) {
    auto& writers = ionconctype2writers[ionconctype];
    writers.insert(mechtype);

    return writers;
}

void nrn_check_conc_write(Prop* pmech, Prop* pion, int side) {
    auto & writers = register_ion_write_access(pmech->_type, pion->_type, side);
    // ...
    if(ii && flag) {
        // ...
        for (p = pion->next; p; p = p->next) {
            // ...
            if(writers.count(mechtype) == 1) {
    // ...
}

If you want you can then also short circuit the following loop:

for (p = pion->next; p; p = p->next)

whenever writers.size() == 1.

@nrnhines

nrnhines commented Oct 1, 2024

Copy link
Copy Markdown
Member Author

@1uc

might be easier to store inverse map

I was wondering about that. And the inverse seems conceptually better. But let me know if the following tips the scales in the direction I chose (perhaps I should have added a comment.)

I expect a very large number of ions and a very small number of mechanisms (most often 1) that write to those ions. So is there a memory/performance benefit to map(mech_that_write) -> set(ionconc_written_by_that_mech) over the inverse?
I.e., Is it better to have one large set or a large number of sets of size 1.

@1uc

1uc commented Oct 1, 2024

Copy link
Copy Markdown
Collaborator

@nrnhines That seems like a good justification.

Let's count the number of large searches in the case where one mechanism sets all ions:

  • In the forwards variation we do: One large search to insert the ionconctype into the set (during add_mechtype2ionconctype) and again for the .count (during mech_uses_ionconctype). Two in total.
  • In the reverse search we do: One large search to insert the ionconctype into the outer map.

In the reverse approach we can replace the std::map with a hashmap, i.e. std::unordered_map for which insert/access is amortized constant time. Then there's no expensive search at all (under the assumption that the std::sets are tiny).

Edit: I'd like to expand a bit. In the forward variation, if the outer map is large then we pay the cost for searching it once per mechanism registered at that node; and for every hit we need to also do a .count. Even if we replace the std::map with an std::unordered_map it's 10s or 100s of searches instead of just the one.

I suspect both approaches suffer if the std::sets are (very) large. This is because the operation we do on the outer map are amortized constant time, while the operations on the std::set is O(log(n)) (where n is the size of that std::set). If I read your comment correctly, then we expect there to be many very small std::sets in the reverse approach; and very few, but quite large std::sets in the forward approach.

@nrnhines

nrnhines commented Oct 1, 2024

Copy link
Copy Markdown
Member Author

@1uc

I'd like to expand a bit.

I'm going to go ahead and merge this. I think it is very likely there is a meta-reason not to waste anymore time on this.
In practice, I suspect there will not be any mod files at all in the use case of large numbers of ion types. But all the ions and model components that use them will be entirely in the RxD world. Ultimately, I believe, there will be other PRs that deal with large numbers of receptors and cascades within RxD and that world will represent those concepts in a much more memory/performant representation that does not even use the notion of many distinct ion types.

@nrnhines nrnhines merged commit 3fcec76 into master Oct 1, 2024
@nrnhines nrnhines deleted the hines/ions-unlimited branch October 1, 2024 14:37
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.

5 participants