From 7975a0ec9d1daab561ed0a35b135baee4e6f1a7a Mon Sep 17 00:00:00 2001 From: Nicolai Haug Date: Wed, 3 May 2023 16:15:56 +0200 Subject: [PATCH 1/6] Port test_GetConnections from sli-2-py --- ...test_getconnections_multiple_syn_models.py | 126 +++++++++ testsuite/unittests/test_GetConnections.sli | 258 ------------------ 2 files changed, 126 insertions(+), 258 deletions(-) create mode 100644 testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py delete mode 100644 testsuite/unittests/test_GetConnections.sli diff --git a/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py b/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py new file mode 100644 index 0000000000..dd7e6bac7d --- /dev/null +++ b/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py @@ -0,0 +1,126 @@ +# -*- coding: utf-8 -*- +# +# test_getconnections_multiple_syn_models.py +# +# This file is part of NEST. +# +# Copyright (C) 2004 The NEST Initiative +# +# NEST is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# NEST is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with NEST. If not, see . + +""" +Test `GetConnections` in the context of more than one synapse model. + +The test constructs a network where the connections are modeled by two +synapse models. A subset of the neurons have one of the synapse models, +and some also have both. +""" + +import numpy.testing as nptest +import pandas as pd +import pytest + +import nest + + +@pytest.fixture(autouse=True) +def reset_kernel(): + nest.ResetKernel() + + +@pytest.fixture() +def network(): + """ + Fixture for building network. + + Builds the following network: + - Create 100 neurons + - 1, 3, ..., 99 are sources + - 2, 4, ..., 100 are targets + - Connect 1, 3, ..., 69 -> 2, 4, ..., 70 with `static_synapse` + - Connect 31, 33, ..., 99 -> 32, 34, ..., 100 with `stdp_synapse` + """ + + nest.Create("iaf_psc_alpha", 100) + static_sources = nest.NodeCollection(list(range(1, 70, 2))) + static_targets = nest.NodeCollection(list(range(2, 71, 2))) + stdp_sources = nest.NodeCollection(list(range(31, 100, 2))) + stdp_targets = nest.NodeCollection(list(range(32, 101, 2))) + + nest.Connect(static_sources, static_targets, "one_to_one", "static_synapse") + nest.Connect(stdp_sources, stdp_targets, "one_to_one", "stdp_synapse") + + d = { + "static_sources": static_sources, + "static_targets": static_targets, + "stdp_sources": stdp_sources, + "stdp_targets": stdp_targets, + } + return d + + +def test_retrieve_correct_proportion_of_synapse_model(network): + """ + Verify that the expected distribution of synapse models is retrieved. + + We expect: + - 15 connections with `static_synapse` only. + - 20 connections with `static_synapse` and `stdp_synapse`. + - 15 connections with `stdp_synapse` only. + """ + + expected_num_static_only = 15 + expected_num_stdp_only = 15 + expected_num_static_stdp = 20 + + syn_collection = nest.GetConnections() + df = pd.DataFrame.from_dict(syn_collection.get()) + + # Remove entries with duplicate sources (i.e., no static + stdp connections) + df_no_dup = df.drop_duplicates(subset=["source"], keep=False) + actual_num_static_only = len( + df_no_dup.loc[df_no_dup["synapse_model"] == "static_synapse"].index + ) + actual_num_stdp_only = len( + df_no_dup.loc[df_no_dup["synapse_model"] == "stdp_synapse"].index + ) + + # Obtain entries with duplicate sources only (i.e., only static + stdp connections) + df_only_dup = df[df.duplicated(subset=["source"], keep=False)] + # Must divide by 2 since sources are listed twice (once per synapse model) + actual_num_static_stdp = len(df_only_dup) / 2 + + assert actual_num_static_only == expected_num_static_only + assert actual_num_stdp_only == expected_num_stdp_only + assert actual_num_static_stdp == expected_num_static_stdp + + +@pytest.mark.parametrize("syn_model", ["static", "stdp"]) +def test_retrieve_correct_sources_and_targets(network, syn_model): + """ + Verify that the expected sources and targets are retrieved. + """ + + expected_sources = network[f"{syn_model}_sources"].tolist() + expected_targets = network[f"{syn_model}_targets"].tolist() + + syn_collection = nest.GetConnections() + df = pd.DataFrame.from_dict(syn_collection.get()) + + condition = df["synapse_model"] == f"{syn_model}_synapse" + actual_sources = df["source"].loc[condition].to_numpy() + actual_targets = df["target"].loc[condition].to_numpy() + + nptest.assert_array_equal(actual_sources, expected_sources) + nptest.assert_array_equal(actual_targets, expected_targets) diff --git a/testsuite/unittests/test_GetConnections.sli b/testsuite/unittests/test_GetConnections.sli deleted file mode 100644 index 6a9dfb8a98..0000000000 --- a/testsuite/unittests/test_GetConnections.sli +++ /dev/null @@ -1,258 +0,0 @@ -/* - * test_GetConnections.sli - * - * This file is part of NEST. - * - * Copyright (C) 2004 The NEST Initiative - * - * NEST is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * NEST is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with NEST. If not, see . - * - */ - -% SLI2PY: Check for overlap with conn tests in Python, port what is missing -% SLI2PY: Note, see if net can be built once and then multiple tests applied -% SLI2PYComplexity: Low - -/** @BeginDocumentation - Name: testsuite::test_GetConnections - sli script to test if GetConnections works as expected - - Synopsis: (test_getConnections) run - - Description: - - This test generates 100 iaf_psc_alpha neurons and connects them - with different synapses. It then retrieves the parameters of those - connections and checks them against a known good reference. - - SeeAlso: GetConnections - - FirstVersion: May 2012 - Author: Marc-Oliver Gewaltig - */ - -(unittest) run -/unittest using - -% Create the following network: -% - 100 neurons -% - 1, 3, ..., 99 are sources -% - 2, 4, ..., 100 are targets -% - Connect 1, 3, ..., 69 -> 2, 4, ..., 70 with static_synapse -% - Connect 31, ..., 99 -> 32, ..., 100 with stdp_synapse -% - Then: -% 15 connections with static only -% 20 connections with static + stdp -% 15 connections with stdp only -/build_net -{ - % create 100 neurons, connect (2n-1) -> 2n for n=1..50 - /iaf_psc_alpha 100 Create ; - /static_sources [ 1 69 2 ] Range def - /static_targets static_sources 1 add def - /stdp_sources [ 31 99 2 ] Range def - /stdp_targets stdp_sources 1 add def - static_sources static_targets /one_to_one /static_synapse Connect - stdp_sources stdp_targets /one_to_one /stdp_synapse Connect -} def - -% first test: retrieve static connections -{ - << >> begin - ResetKernel - build_net - - /conns << /synapse_model /static_synapse >> GetConnections GetStatus def - /csrc conns { /source get } Map def - /ctgt conns { /target get } Map def - /cstp conns { /synapse_model get } Map def - - csrc static_sources eq - ctgt static_targets eq and - cstp { /static_synapse eq and } Fold - end -} assert_or_die - -(FIRST TEST PASSED) == - - -% second test: retrieve stdp connections -{ - << >> begin - ResetKernel - build_net - - /conns << /synapse_model /stdp_synapse >> GetConnections GetStatus def - /csrc conns { /source get } Map def - /ctgt conns { /target get } Map def - /cstp conns { /synapse_model get } Map def - - csrc stdp_sources eq - ctgt stdp_targets eq and - cstp { /stdp_synapse eq and } Fold - end -} assert_or_die - -(SECOND TEST PASSED) == - - -% third test: retrieve all connections --- static will come first -{ - << >> begin - ResetKernel - build_net - - /conns << >> GetConnections GetStatus def - /csrc conns { /source get } Map def - /ctgt conns { /target get } Map def - - csrc static_sources stdp_sources join eq - ctgt static_targets stdp_targets join eq and - end -} assert_or_die - -(THIRD TEST PASSED) == - - -% fourth test: retrieve connections for some sources -{ - << >> begin - ResetKernel - build_net - - /ssrc_static static_sources 3 Take def - /stgt_static static_targets 3 Take def - /ssrc_stdp stdp_sources -3 Take def % take final three to avoid - /stgt_stdp stdp_targets -3 Take def % those with static+stdp - /ssrc_all ssrc_static ssrc_stdp join def - /stgt_all stgt_static stgt_stdp join def - /conns << /source ssrc_all cvnodecollection >> GetConnections GetStatus def - /csrc conns { /source get } Map def - /ctgt conns { /target get } Map def - - csrc ssrc_all eq - ctgt stgt_all eq and - end -} assert_or_die - -(FOURTH TEST PASSED) == - - -% fifth test: retrieve connections for some targets -{ - << >> begin - ResetKernel - build_net - - /ssrc_static static_sources 3 Take def - /stgt_static static_targets 3 Take def - /ssrc_stdp stdp_sources -3 Take def % take final three to avoid - /stgt_stdp stdp_targets -3 Take def % those with static+stdp - /ssrc_all ssrc_static ssrc_stdp join def - /stgt_all stgt_static stgt_stdp join def - /conns << /target stgt_all cvnodecollection >> GetConnections GetStatus def - /csrc conns { /source get } Map def - /ctgt conns { /target get } Map def - - csrc ssrc_all eq - ctgt stgt_all eq and - end -} assert_or_die - -(FIFTH TEST PASSED) == - - -% sixth test: retrieve connections for specific sources and targets -{ - << >> begin - ResetKernel - build_net - - % set up so that for each synapse type, last two srcs match first two tgts - /ssrc_static static_sources [1 3] Take def - /stgt_static static_targets [2 4] Take def - /ssrc_stdp stdp_sources [-4 -2] Take def % take final three to avoid - /stgt_stdp stdp_targets [-3 -1] Take def % those with static+stdp - /ssrc_all ssrc_static ssrc_stdp join def - /stgt_all stgt_static stgt_stdp join def - /conns << /source ssrc_all cvnodecollection /target stgt_all cvnodecollection >> GetConnections GetStatus def - /csrc conns { /source get } Map def - /ctgt conns { /target get } Map def - - csrc ssrc_static -2 Take ssrc_stdp -2 Take join eq - ctgt stgt_static 2 Take stgt_stdp 2 Take join eq and - end -} assert_or_die - -(SIXTH TEST PASSED) == - - -% seventh test: same as sixth, but select static synapses -{ - << >> begin - ResetKernel - build_net - - % set up so that for each synapse type, last two srcs match first two tgts - /ssrc_static static_sources [1 3] Take def - /stgt_static static_targets [2 4] Take def - /ssrc_stdp stdp_sources [-4 -2] Take def % take final three to avoid - /stgt_stdp stdp_targets [-3 -1] Take def % those with static+stdp - /ssrc_all ssrc_static ssrc_stdp join def - /stgt_all stgt_static stgt_stdp join def - /conns - << /source ssrc_all cvnodecollection /target stgt_all cvnodecollection /synapse_model /static_synapse >> - GetConnections GetStatus - def - /csrc conns { /source get } Map def - /ctgt conns { /target get } Map def - - csrc ssrc_static -2 Take eq - ctgt stgt_static 2 Take eq and - end -} assert_or_die - -(SEVENTH TEST PASSED) == - - -% eighth test: check static synapses on four threads -skip_if_not_threaded - -{ - << >> begin - ResetKernel - << /local_num_threads 4 >> SetKernelStatus - build_net - - % NB: relative ordering of data from threads is random under OpenMP - /conns << /synapse_model /static_synapse >> GetConnections GetStatus def - - % SLI Sort can only sort numbers or strings. - % To sort source-target pairs, we convert them to large numbers - /conns_as_nums - conns - { dup /source get 1000 mul exch /target get add } Map - def - /expect_as_nums - [ static_sources static_targets ] - { exch 1000 mul add } MapThread - def - - conns_as_nums Sort expect_as_nums Sort eq -end -} assert_or_die - -(EIGHT TEST PASSED) == - - -endusing From 9e62b3bbd19f209d91fb3443d80a543dd55f505d Mon Sep 17 00:00:00 2001 From: Nicolai Haug Date: Wed, 3 May 2023 16:26:14 +0200 Subject: [PATCH 2/6] Take len of dataframe index instead --- .../sli2py_connect/test_getconnections_multiple_syn_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py b/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py index dd7e6bac7d..2850d3929f 100644 --- a/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py +++ b/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py @@ -99,7 +99,7 @@ def test_retrieve_correct_proportion_of_synapse_model(network): # Obtain entries with duplicate sources only (i.e., only static + stdp connections) df_only_dup = df[df.duplicated(subset=["source"], keep=False)] # Must divide by 2 since sources are listed twice (once per synapse model) - actual_num_static_stdp = len(df_only_dup) / 2 + actual_num_static_stdp = len(df_only_dup.index) / 2 assert actual_num_static_only == expected_num_static_only assert actual_num_stdp_only == expected_num_stdp_only From fdcff3c8d204ee557b00bf9a3e3c1137194ee54f Mon Sep 17 00:00:00 2001 From: Nicolai Haug Date: Tue, 27 Jun 2023 22:18:48 +0200 Subject: [PATCH 3/6] Black formatting --- .../test_getconnections_multiple_syn_models.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py b/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py index 2850d3929f..2f2f09d792 100644 --- a/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py +++ b/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py @@ -89,12 +89,8 @@ def test_retrieve_correct_proportion_of_synapse_model(network): # Remove entries with duplicate sources (i.e., no static + stdp connections) df_no_dup = df.drop_duplicates(subset=["source"], keep=False) - actual_num_static_only = len( - df_no_dup.loc[df_no_dup["synapse_model"] == "static_synapse"].index - ) - actual_num_stdp_only = len( - df_no_dup.loc[df_no_dup["synapse_model"] == "stdp_synapse"].index - ) + actual_num_static_only = len(df_no_dup.loc[df_no_dup["synapse_model"] == "static_synapse"].index) + actual_num_stdp_only = len(df_no_dup.loc[df_no_dup["synapse_model"] == "stdp_synapse"].index) # Obtain entries with duplicate sources only (i.e., only static + stdp connections) df_only_dup = df[df.duplicated(subset=["source"], keep=False)] From 50e5dbba3a6ae9a51a8ad0d434685c73ada94fcd Mon Sep 17 00:00:00 2001 From: Nicolai Haug Date: Wed, 30 Aug 2023 12:56:24 +0200 Subject: [PATCH 4/6] WIP: port more similar to SLI version [skip ci] --- ...test_getconnections_multiple_syn_models.py | 59 +++++++++++++++---- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py b/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py index 2f2f09d792..a8d41e4bba 100644 --- a/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py +++ b/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py @@ -34,12 +34,7 @@ import nest -@pytest.fixture(autouse=True) -def reset_kernel(): - nest.ResetKernel() - - -@pytest.fixture() +@pytest.fixture(scope="module") def network(): """ Fixture for building network. @@ -61,13 +56,51 @@ def network(): nest.Connect(static_sources, static_targets, "one_to_one", "static_synapse") nest.Connect(stdp_sources, stdp_targets, "one_to_one", "stdp_synapse") - d = { - "static_sources": static_sources, - "static_targets": static_targets, - "stdp_sources": stdp_sources, - "stdp_targets": stdp_targets, + return { + "static_synapse": {"sources": static_sources, "targets": static_targets}, + "stdp_synapse": {"sources": stdp_sources, "targets": stdp_targets}, } - return d + + +@pytest.mark.parametrize("syn_model", ["static_synapse", "stdp_synapse"]) +def test_retrieve_correct_sources_and_targets(network, syn_model): + """ + Verify that the expected sources and targets are retrieved. + """ + + conns = nest.GetConnections(synapse_model=syn_model) + actual_sources = conns.get("source") + actual_targets = conns.get("target") + + expected_sources = network[f"{syn_model}"]["sources"].tolist() + expected_targets = network[f"{syn_model}"]["targets"].tolist() + + nptest.assert_array_equal(actual_sources, expected_sources) + nptest.assert_array_equal(actual_targets, expected_targets) + + +def test_retrieve_all_connections(network): + """ + Test retrieval of all connections. + + Note that ``static_synapse`` connections will come first. + """ + + conns = nest.GetConnections() + + actual_sources = conns.get("source") + actual_targets = conns.get("target") + + expected_static_sources = network["static_synapse"]["sources"].tolist() + expected_stdp_sources = network["stdp_synapse"]["sources"].tolist() + expected_all_sources = expected_static_sources + expected_stdp_sources + + expected_static_targets = network["static_synapse"]["targets"].tolist() + expected_stdp_targets = network["stdp_synapse"]["targets"].tolist() + expected_all_targets = expected_static_targets + expected_stdp_targets + + nptest.assert_array_equal(actual_sources, expected_all_sources) + nptest.assert_array_equal(actual_targets, expected_all_targets) def test_retrieve_correct_proportion_of_synapse_model(network): @@ -102,6 +135,7 @@ def test_retrieve_correct_proportion_of_synapse_model(network): assert actual_num_static_stdp == expected_num_static_stdp +''' @pytest.mark.parametrize("syn_model", ["static", "stdp"]) def test_retrieve_correct_sources_and_targets(network, syn_model): """ @@ -120,3 +154,4 @@ def test_retrieve_correct_sources_and_targets(network, syn_model): nptest.assert_array_equal(actual_sources, expected_sources) nptest.assert_array_equal(actual_targets, expected_targets) +''' From d17331912a1feecc7e54ee0bb0e971a19cd1722f Mon Sep 17 00:00:00 2001 From: Nicolai Haug Date: Thu, 31 Aug 2023 11:48:33 +0200 Subject: [PATCH 5/6] wip [skip ci] --- ...test_getconnections_multiple_syn_models.py | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py b/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py index a8d41e4bba..6be799e956 100644 --- a/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py +++ b/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py @@ -20,7 +20,7 @@ # along with NEST. If not, see . """ -Test `GetConnections` in the context of more than one synapse model. +Test ``GetConnections`` in the context of more than one synapse model. The test constructs a network where the connections are modeled by two synapse models. A subset of the neurons have one of the synapse models, @@ -103,6 +103,51 @@ def test_retrieve_all_connections(network): nptest.assert_array_equal(actual_targets, expected_all_targets) +@pytest.mark.parametrize() +def test_retrieve_connections_for_some_sources(network): + """ + Test + + Cannot add NodeCollection to a sliced composite + """ + + # Take first 3 static sources and targets + src_static = network["static_synapse"]["sources"][:3].tolist() + tgt_static = network["static_synapse"]["targets"][:3].tolist() + + # Take final 3 stpd sources and targes to avoid those with static+stdp + src_stdp = network["stdp_synapse"]["sources"][-3:].tolist() + tgt_stpd = network["stdp_synapse"]["targets"][-3:].tolist() + + src_all = src_static + src_stdp + # tgt_all = tgt_static + tgt_stpd + print(src_all) + + conns = nest.GetConnections(source=nest.NodeCollection(src_all)) + + actual_sources = conns.get("source") + print(actual_sources) + + nptest.assert_array_equal(actual_sources, src_all) + + # nptest.assert_array_equal(actual_targets, expected_all_targets) + + """ + /ssrc_static static_sources 3 Take def + /stgt_static static_targets 3 Take def + /ssrc_stdp stdp_sources -3 Take def % take final three to avoid + /stgt_stdp stdp_targets -3 Take def % those with static+stdp + /ssrc_all ssrc_static ssrc_stdp join def + /stgt_all stgt_static stgt_stdp join def + /conns << /source ssrc_all cvnodecollection >> GetConnections GetStatus def + /csrc conns { /source get } Map def + /ctgt conns { /target get } Map def + + csrc ssrc_all eq + ctgt stgt_all eq and + """ + + def test_retrieve_correct_proportion_of_synapse_model(network): """ Verify that the expected distribution of synapse models is retrieved. From 3ee4f9a3979ac8dca02d7929d9b9571d82ce9e02 Mon Sep 17 00:00:00 2001 From: Nicolai Haug Date: Thu, 31 Aug 2023 12:41:27 +0200 Subject: [PATCH 6/6] Port more one-to-one with sli version --- ...test_getconnections_multiple_syn_models.py | 162 ++++++++++-------- 1 file changed, 88 insertions(+), 74 deletions(-) diff --git a/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py b/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py index 6be799e956..c15cbfca01 100644 --- a/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py +++ b/testsuite/pytests/sli2py_connect/test_getconnections_multiple_syn_models.py @@ -34,12 +34,11 @@ import nest -@pytest.fixture(scope="module") -def network(): +def build_net(num_threads=1): """ - Fixture for building network. + Build network with specified number of threads. - Builds the following network: + The following network is built: - Create 100 neurons - 1, 3, ..., 99 are sources - 2, 4, ..., 100 are targets @@ -47,6 +46,10 @@ def network(): - Connect 31, 33, ..., 99 -> 32, 34, ..., 100 with `stdp_synapse` """ + nest.ResetKernel() + + nest.local_num_threads = num_threads + nest.Create("iaf_psc_alpha", 100) static_sources = nest.NodeCollection(list(range(1, 70, 2))) static_targets = nest.NodeCollection(list(range(2, 71, 2))) @@ -62,8 +65,18 @@ def network(): } +@pytest.fixture(scope="module") +def nodes(): + """ + Fixture that returns the nodes of the network built on a single thread. + """ + + nodes = build_net(num_threads=1) + return nodes + + @pytest.mark.parametrize("syn_model", ["static_synapse", "stdp_synapse"]) -def test_retrieve_correct_sources_and_targets(network, syn_model): +def test_retrieve_correct_sources_and_targets(nodes, syn_model): """ Verify that the expected sources and targets are retrieved. """ @@ -72,14 +85,14 @@ def test_retrieve_correct_sources_and_targets(network, syn_model): actual_sources = conns.get("source") actual_targets = conns.get("target") - expected_sources = network[f"{syn_model}"]["sources"].tolist() - expected_targets = network[f"{syn_model}"]["targets"].tolist() + expected_sources = nodes[f"{syn_model}"]["sources"].tolist() + expected_targets = nodes[f"{syn_model}"]["targets"].tolist() nptest.assert_array_equal(actual_sources, expected_sources) nptest.assert_array_equal(actual_targets, expected_targets) -def test_retrieve_all_connections(network): +def test_retrieve_all_connections(nodes): """ Test retrieval of all connections. @@ -91,112 +104,113 @@ def test_retrieve_all_connections(network): actual_sources = conns.get("source") actual_targets = conns.get("target") - expected_static_sources = network["static_synapse"]["sources"].tolist() - expected_stdp_sources = network["stdp_synapse"]["sources"].tolist() + expected_static_sources = nodes["static_synapse"]["sources"].tolist() + expected_stdp_sources = nodes["stdp_synapse"]["sources"].tolist() expected_all_sources = expected_static_sources + expected_stdp_sources - expected_static_targets = network["static_synapse"]["targets"].tolist() - expected_stdp_targets = network["stdp_synapse"]["targets"].tolist() + expected_static_targets = nodes["static_synapse"]["targets"].tolist() + expected_stdp_targets = nodes["stdp_synapse"]["targets"].tolist() expected_all_targets = expected_static_targets + expected_stdp_targets nptest.assert_array_equal(actual_sources, expected_all_sources) nptest.assert_array_equal(actual_targets, expected_all_targets) -@pytest.mark.parametrize() -def test_retrieve_connections_for_some_sources(network): +@pytest.mark.parametrize( + ("source_filter", "target_filter"), + [(True, False), (False, True), (True, True)], +) +def test_retrieve_connections_with_sliced_node_collections(nodes, source_filter, target_filter): """ - Test + Test retrieval of connections for a subset of sources and targets. - Cannot add NodeCollection to a sliced composite + The test ensures that retrieval of a subset of connections works when + filtering by source and/or target nodes. + + .. note:: + + The source and target ``NodeCollection``s returned by the fixture are + first converted to lists of node ids. The source and target lists are + then concatenated and a new ``NodeCollection`` with the sliced node ids + is created if the nodes will be used as filter. We have to convert to + lists first because it is not possible to add a ``NodeCollection`` to + a sliced composite. """ # Take first 3 static sources and targets - src_static = network["static_synapse"]["sources"][:3].tolist() - tgt_static = network["static_synapse"]["targets"][:3].tolist() + src_static = nodes["static_synapse"]["sources"][:3].tolist() + tgt_static = nodes["static_synapse"]["targets"][:3].tolist() # Take final 3 stpd sources and targes to avoid those with static+stdp - src_stdp = network["stdp_synapse"]["sources"][-3:].tolist() - tgt_stpd = network["stdp_synapse"]["targets"][-3:].tolist() + src_stdp = nodes["stdp_synapse"]["sources"][-3:].tolist() + tgt_stpd = nodes["stdp_synapse"]["targets"][-3:].tolist() src_all = src_static + src_stdp - # tgt_all = tgt_static + tgt_stpd - print(src_all) + tgt_all = tgt_static + tgt_stpd + + sources = nest.NodeCollection(src_all) if source_filter else None + targets = nest.NodeCollection(tgt_all) if target_filter else None - conns = nest.GetConnections(source=nest.NodeCollection(src_all)) + conns = nest.GetConnections(source=sources, target=targets) actual_sources = conns.get("source") - print(actual_sources) + actual_targets = conns.get("target") nptest.assert_array_equal(actual_sources, src_all) + nptest.assert_array_equal(actual_targets, tgt_all) - # nptest.assert_array_equal(actual_targets, expected_all_targets) +def test_retrieve_connections_with_nodes_and_synapse(nodes): """ - /ssrc_static static_sources 3 Take def - /stgt_static static_targets 3 Take def - /ssrc_stdp stdp_sources -3 Take def % take final three to avoid - /stgt_stdp stdp_targets -3 Take def % those with static+stdp - /ssrc_all ssrc_static ssrc_stdp join def - /stgt_all stgt_static stgt_stdp join def - /conns << /source ssrc_all cvnodecollection >> GetConnections GetStatus def - /csrc conns { /source get } Map def - /ctgt conns { /target get } Map def - - csrc ssrc_all eq - ctgt stgt_all eq and - """ - + Test retrieval of connections with node subset and synapse model. -def test_retrieve_correct_proportion_of_synapse_model(network): + The test ensures that retrieval of a subset of connections works when + filtering by nodes and synapse model. """ - Verify that the expected distribution of synapse models is retrieved. - We expect: - - 15 connections with `static_synapse` only. - - 20 connections with `static_synapse` and `stdp_synapse`. - - 15 connections with `stdp_synapse` only. - """ + # Take first 3 static sources and targets + src_static = nodes["static_synapse"]["sources"][:3].tolist() + tgt_static = nodes["static_synapse"]["targets"][:3].tolist() - expected_num_static_only = 15 - expected_num_stdp_only = 15 - expected_num_static_stdp = 20 + # Take final 3 stpd sources and targes to avoid those with static+stdp + src_stdp = nodes["stdp_synapse"]["sources"][-3:].tolist() + tgt_stpd = nodes["stdp_synapse"]["targets"][-3:].tolist() - syn_collection = nest.GetConnections() - df = pd.DataFrame.from_dict(syn_collection.get()) + src_all = src_static + src_stdp + tgt_all = tgt_static + tgt_stpd - # Remove entries with duplicate sources (i.e., no static + stdp connections) - df_no_dup = df.drop_duplicates(subset=["source"], keep=False) - actual_num_static_only = len(df_no_dup.loc[df_no_dup["synapse_model"] == "static_synapse"].index) - actual_num_stdp_only = len(df_no_dup.loc[df_no_dup["synapse_model"] == "stdp_synapse"].index) + conns = nest.GetConnections( + source=nest.NodeCollection(src_all), target=nest.NodeCollection(tgt_all), synapse_model="static_synapse" + ) - # Obtain entries with duplicate sources only (i.e., only static + stdp connections) - df_only_dup = df[df.duplicated(subset=["source"], keep=False)] - # Must divide by 2 since sources are listed twice (once per synapse model) - actual_num_static_stdp = len(df_only_dup.index) / 2 + actual_sources = conns.get("source") + actual_targets = conns.get("target") - assert actual_num_static_only == expected_num_static_only - assert actual_num_stdp_only == expected_num_stdp_only - assert actual_num_static_stdp == expected_num_static_stdp + nptest.assert_array_equal(actual_sources, src_static) + nptest.assert_array_equal(actual_targets, tgt_static) -''' -@pytest.mark.parametrize("syn_model", ["static", "stdp"]) -def test_retrieve_correct_sources_and_targets(network, syn_model): +@pytest.mark.skipif_missing_threads +@pytest.mark.parametrize("syn_model", ["static_synapse", "stdp_synapse"]) +def test_retrieve_connections_multithreaded(syn_model): """ - Verify that the expected sources and targets are retrieved. + Test multithreaded retrieval of connections filtered by synapse model. + + The relative ordering of connection data from threads is random under + OpenMP. Hence, the retrieved connections must be sorted before comparing + with expectation. """ - expected_sources = network[f"{syn_model}_sources"].tolist() - expected_targets = network[f"{syn_model}_targets"].tolist() + nodes = build_net(num_threads=4) - syn_collection = nest.GetConnections() - df = pd.DataFrame.from_dict(syn_collection.get()) + syn_collection = nest.GetConnections(synapse_model=syn_model) + actual_connections = pd.DataFrame.from_dict(syn_collection.get(["source", "target"])) + actual_connections.sort_values(by=["source", "target"], ignore_index=True, inplace=True) + actual_sources = actual_connections["source"] + actual_targets = actual_connections["target"] - condition = df["synapse_model"] == f"{syn_model}_synapse" - actual_sources = df["source"].loc[condition].to_numpy() - actual_targets = df["target"].loc[condition].to_numpy() + expected_sources = nodes[f"{syn_model}"]["sources"].tolist() + expected_targets = nodes[f"{syn_model}"]["targets"].tolist() nptest.assert_array_equal(actual_sources, expected_sources) nptest.assert_array_equal(actual_targets, expected_targets) -'''