diff --git a/examples/nest/gap_junction/inhibitory_network.py b/examples/nest/gap_junction/inhibitory_network.py index bc5be7e5fa..9df95a454c 100644 --- a/examples/nest/gap_junction/inhibitory_network.py +++ b/examples/nest/gap_junction/inhibitory_network.py @@ -114,9 +114,9 @@ [random.sample(neurons, 2) for _ in range(n_connection)]) # Connect sources -> targets and targets -> sources with -# one call to nest.Connect using the "symmetric" flag +# one call to nest.Connect using the "make_symmetric" flag nest.Connect(connections[0], connections[1], - {'rule': 'one_to_one', 'symmetric': True}, + {'rule': 'one_to_one', 'make_symmetric': True}, {'model': 'gap_junction', 'weight': gap_weight}) nest.Simulate(simtime) diff --git a/examples/nest/gap_junction/two_neurons.py b/examples/nest/gap_junction/two_neurons.py index 4ea44628ec..ab5cdc5d50 100644 --- a/examples/nest/gap_junction/two_neurons.py +++ b/examples/nest/gap_junction/two_neurons.py @@ -58,7 +58,7 @@ Use 'all_to_all' to connect neurons. This is equivalent to: nest.Connect([neuron[0]],[neuron[1]], - {'rule': 'one_to_one', 'symmetric': True}, + {'rule': 'one_to_one', 'make_symmetric': True}, {'model': 'gap_junction', 'weight': 0.5}) """ diff --git a/models/modelsmodule.cpp b/models/modelsmodule.cpp index f9fb965987..a986eb3f66 100644 --- a/models/modelsmodule.cpp +++ b/models/modelsmodule.cpp @@ -414,7 +414,7 @@ ModelsModule::init( SLIInterpreter* ) kernel() .model_manager .register_secondary_connection_model< GapJunction< TargetIdentifierPtrRport > >( - "gap_junction", false ); + "gap_junction", /*has_delay=*/false, /*requires_symmetric=*/true ); /* BeginDocumentation diff --git a/nestkernel/conn_builder.cpp b/nestkernel/conn_builder.cpp index d855ab0e67..6d4290c540 100644 --- a/nestkernel/conn_builder.cpp +++ b/nestkernel/conn_builder.cpp @@ -56,7 +56,7 @@ nest::ConnBuilder::ConnBuilder( const GIDCollection& sources, , targets_( &targets ) , autapses_( true ) , multapses_( true ) - , symmetric_( false ) + , make_symmetric_( false ) , exceptions_raised_( kernel().vp_manager.get_num_threads() ) , synapse_model_( kernel().model_manager.get_synapsedict()->lookup( "static_synapse" ) ) @@ -70,7 +70,7 @@ nest::ConnBuilder::ConnBuilder( const GIDCollection& sources, // - rule-specific params are handled by subclass c'tor updateValue< bool >( conn_spec, names::autapses, autapses_ ); updateValue< bool >( conn_spec, names::multapses, multapses_ ); - updateValue< bool >( conn_spec, names::symmetric, symmetric_ ); + updateValue< bool >( conn_spec, names::make_symmetric, make_symmetric_ ); // read out synapse-related parameters ---------------------- if ( !syn_spec->known( names::model ) ) @@ -208,9 +208,9 @@ nest::ConnBuilder::ConnBuilder( const GIDCollection& sources, } } - // If symmetric_ is requested call reset on all parameters in order + // If make_symmetric_ is requested call reset on all parameters in order // to check if all parameters support symmetric connections - if ( symmetric_ ) + if ( make_symmetric_ ) { if ( weight_ ) { @@ -382,13 +382,25 @@ nest::ConnBuilder::change_connected_synaptic_elements( index sgid, void nest::ConnBuilder::connect() { - if ( symmetric_ && not supports_symmetric() ) + if ( kernel().model_manager.connector_requires_symmetric( synapse_model_ ) + and not( is_symmetric() or make_symmetric_ ) ) + { + throw BadProperty( + "Connections with this synapse model can only be created as " + "one-to-one connections with \"make_symmetric\" set to true " + "or as all-to-all connections with equal source and target " + "populations and default or scalar parameters." ); + } + + if ( make_symmetric_ && not supports_symmetric() ) + { throw NotImplemented( "This connection rule does not support symmetric connections." ); + } if ( pre_synaptic_element_name != "" && post_synaptic_element_name != "" ) { - if ( symmetric_ ) + if ( make_symmetric_ ) throw NotImplemented( "Symmetric connections are not supported in combination with " "structural plasticity." ); @@ -397,7 +409,7 @@ nest::ConnBuilder::connect() else { connect_(); - if ( symmetric_ ) + if ( make_symmetric_ ) { // call reset on all parameters if ( weight_ ) @@ -580,6 +592,27 @@ nest::ConnBuilder::set_post_synaptic_element_name( std::string name ) post_synaptic_element_name = name; } +bool +nest::ConnBuilder::all_parameters_scalar_() const +{ + bool all_scalar = true; + if ( weight_ ) + { + all_scalar = all_scalar && weight_->is_scalar(); + } + if ( delay_ ) + { + all_scalar = all_scalar && delay_->is_scalar(); + } + for ( ConnParameterMap::const_iterator it = synapse_params_.begin(); + it != synapse_params_.end(); + ++it ) + { + all_scalar = all_scalar && it->second->is_scalar(); + } + return all_scalar; +} + bool nest::ConnBuilder::loop_over_targets_() const { diff --git a/nestkernel/conn_builder.h b/nestkernel/conn_builder.h index cb209891c8..9577aa04b7 100644 --- a/nestkernel/conn_builder.h +++ b/nestkernel/conn_builder.h @@ -103,6 +103,8 @@ class ConnBuilder void set_pre_synaptic_element_name( std::string name ); void set_post_synaptic_element_name( std::string name ); + bool all_parameters_scalar_() const; + int change_connected_synaptic_elements( index, index, const int, int ); virtual bool @@ -111,6 +113,12 @@ class ConnBuilder return false; } + virtual bool + is_symmetric() const + { + return false; + } + protected: //! Implements the actual connection algorithm virtual void connect_() = 0; @@ -168,7 +176,7 @@ class ConnBuilder bool autapses_; bool multapses_; - bool symmetric_; + bool make_symmetric_; //! buffer for exceptions raised in threads std::vector< lockPTR< WrappedThreadException > > exceptions_raised_; @@ -258,6 +266,12 @@ class AllToAllBuilder : public ConnBuilder { } + bool + is_symmetric() const + { + return *sources_ == *targets_ && all_parameters_scalar_(); + } + protected: void connect_(); void sp_connect_(); diff --git a/nestkernel/conn_parameter.h b/nestkernel/conn_parameter.h index 6a38e3a036..dcfcb6f419 100644 --- a/nestkernel/conn_parameter.h +++ b/nestkernel/conn_parameter.h @@ -83,6 +83,12 @@ class ConnParameter } virtual bool is_array() const = 0; + virtual bool + is_scalar() const + { + return false; + } + virtual void reset() const { @@ -148,6 +154,13 @@ class ScalarDoubleParameter : public ConnParameter { } + bool + is_scalar() const + { + return true; + } + + private: double value_; }; @@ -188,6 +201,12 @@ class ScalarIntegerParameter : public ConnParameter { } + bool + is_scalar() const + { + return true; + } + private: long value_; }; diff --git a/nestkernel/connector_model.cpp b/nestkernel/connector_model.cpp index 258026399d..ebd03825c2 100644 --- a/nestkernel/connector_model.cpp +++ b/nestkernel/connector_model.cpp @@ -27,11 +27,13 @@ namespace nest ConnectorModel::ConnectorModel( const std::string name, bool is_primary, - bool has_delay ) + bool has_delay, + bool requires_symmetric ) : name_( name ) , default_delay_needs_check_( true ) , is_primary_( is_primary ) , has_delay_( has_delay ) + , requires_symmetric_( requires_symmetric ) { } @@ -41,6 +43,7 @@ ConnectorModel::ConnectorModel( const ConnectorModel& cm, , default_delay_needs_check_( true ) , is_primary_( cm.is_primary_ ) , has_delay_( cm.has_delay_ ) + , requires_symmetric_( cm.requires_symmetric_ ) { } diff --git a/nestkernel/connector_model.h b/nestkernel/connector_model.h index 2b7518f851..99170f4ee6 100644 --- a/nestkernel/connector_model.h +++ b/nestkernel/connector_model.h @@ -97,7 +97,10 @@ class ConnectorModel { public: - ConnectorModel( const std::string, bool is_primary, bool has_delay ); + ConnectorModel( const std::string, + bool is_primary, + bool has_delay, + bool requires_symmetric ); ConnectorModel( const ConnectorModel&, const std::string ); virtual ~ConnectorModel() { @@ -171,6 +174,12 @@ class ConnectorModel return has_delay_; } + bool + requires_symmetric() const + { + return requires_symmetric_; + } + protected: std::string name_; //! Flag indicating, that the default delay must be checked @@ -178,6 +187,8 @@ class ConnectorModel //! indicates, whether this ConnectorModel belongs to a primary connection bool is_primary_; bool has_delay_; //!< indicates, that ConnectorModel has a delay + bool requires_symmetric_; + //!< indicates, that ConnectorModel requires symmetric connections }; // ConnectorModel @@ -196,8 +207,9 @@ class GenericConnectorModel : public ConnectorModel public: GenericConnectorModel( const std::string name, bool is_primary, - bool has_delay ) - : ConnectorModel( name, is_primary, has_delay ) + bool has_delay, + bool requires_symmetric ) + : ConnectorModel( name, is_primary, has_delay, requires_symmetric ) , receptor_type_( 0 ) { } @@ -289,10 +301,13 @@ class GenericSecondaryConnectorModel typename ConnectionT::EventType* pev_; public: - GenericSecondaryConnectorModel( const std::string name, bool has_delay ) + GenericSecondaryConnectorModel( const std::string name, + bool has_delay, + bool requires_symmetric ) : GenericConnectorModel< ConnectionT >( name, /*is _primary=*/false, - has_delay ) + has_delay, + requires_symmetric ) , pev_( 0 ) { pev_ = new typename ConnectionT::EventType(); diff --git a/nestkernel/connector_model_impl.h b/nestkernel/connector_model_impl.h index 2bb57734d6..4aaf032b8e 100644 --- a/nestkernel/connector_model_impl.h +++ b/nestkernel/connector_model_impl.h @@ -141,6 +141,8 @@ GenericConnectorModel< ConnectionT >::get_status( DictionaryDatum& d ) const ( *d )[ names::receptor_type ] = receptor_type_; ( *d )[ "synapsemodel" ] = LiteralDatum( name_ ); + ( *d )[ "requires_symmetric" ] = requires_symmetric_; + ( *d )[ "has_delay" ] = has_delay_; } template < typename ConnectionT > diff --git a/nestkernel/model_manager.cpp b/nestkernel/model_manager.cpp index 6df9a7e795..01900a0b62 100644 --- a/nestkernel/model_manager.cpp +++ b/nestkernel/model_manager.cpp @@ -424,6 +424,14 @@ ModelManager::get_connector_defaults( synindex syn_id ) const return dict; } +bool +ModelManager::connector_requires_symmetric( synindex syn_id ) const +{ + assert_valid_syn_id( syn_id ); + + return prototypes_[ 0 ][ syn_id ]->requires_symmetric(); +} + void ModelManager::clear_models_( bool called_from_destructor ) { diff --git a/nestkernel/model_manager.h b/nestkernel/model_manager.h index 824977d57f..710b28fab0 100644 --- a/nestkernel/model_manager.h +++ b/nestkernel/model_manager.h @@ -180,11 +180,13 @@ class ModelManager : public ManagerInterface * @return an ID for the synapse prototype. */ template < class ConnectionT > - void register_connection_model( const std::string& name ); + void register_connection_model( const std::string& name, + bool requires_symmetric = false ); template < class ConnectionT > void register_secondary_connection_model( const std::string& name, - bool has_delay = true ); + bool has_delay = true, + bool requires_symmetric = false ); /** * @return The model id of a given model name @@ -197,6 +199,12 @@ class ModelManager : public ManagerInterface Model* get_model( index ) const; DictionaryDatum get_connector_defaults( synindex syn_id ) const; + + /** + * Checks, whether synapse type requires symmetric connections + */ + bool connector_requires_symmetric( synindex syn_id ) const; + void set_connector_defaults( synindex syn_id, const DictionaryDatum& d ); /** diff --git a/nestkernel/model_manager_impl.h b/nestkernel/model_manager_impl.h index 57e02562a9..50697d73be 100644 --- a/nestkernel/model_manager_impl.h +++ b/nestkernel/model_manager_impl.h @@ -80,16 +80,20 @@ ModelManager::register_preconf_node_model( const Name& name, template < class ConnectionT > void -ModelManager::register_connection_model( const std::string& name ) +ModelManager::register_connection_model( const std::string& name, + bool requires_symmetric ) { ConnectorModel* cf = new GenericConnectorModel< ConnectionT >( - name, /*is_primary=*/true, /*has_delay=*/true ); + name, /*is_primary=*/true, /*has_delay=*/true, requires_symmetric ); register_connection_model_( cf ); if ( not ends_with( name, "_hpc" ) ) { cf = new GenericConnectorModel< ConnectionLabel< ConnectionT > >( - name + "_lbl", /*is_primary=*/true, /*has_delay=*/true ); + name + "_lbl", + /*is_primary=*/true, + /*has_delay=*/true, + requires_symmetric ); register_connection_model_( cf ); } } @@ -100,10 +104,11 @@ ModelManager::register_connection_model( const std::string& name ) template < class ConnectionT > void ModelManager::register_secondary_connection_model( const std::string& name, - bool has_delay ) + bool has_delay, + bool requires_symmetric ) { - ConnectorModel* cm = - new GenericSecondaryConnectorModel< ConnectionT >( name, has_delay ); + ConnectorModel* cm = new GenericSecondaryConnectorModel< ConnectionT >( + name, has_delay, requires_symmetric ); synindex synid = register_connection_model_( cm ); @@ -119,7 +124,7 @@ ModelManager::register_secondary_connection_model( const std::string& name, // create labeled secondary event connection model cm = new GenericSecondaryConnectorModel< ConnectionLabel< ConnectionT > >( - name + "_lbl", has_delay ); + name + "_lbl", has_delay, requires_symmetric ); synid = register_connection_model_( cm ); diff --git a/nestkernel/nest_names.cpp b/nestkernel/nest_names.cpp index 29a223ec13..c3791f940a 100644 --- a/nestkernel/nest_names.cpp +++ b/nestkernel/nest_names.cpp @@ -187,6 +187,7 @@ const Name linear( "linear" ); const Name local( "local" ); const Name local_id( "local_id" ); +const Name make_symmetric( "make_symmetric" ); const Name MAXERR( "MAXERR" ); const Name mean( "mean" ); const Name memory( "memory" ); @@ -202,7 +203,6 @@ const Name N_channels( "N_channels" ); const Name n_events( "n_events" ); const Name n_proc( "n_proc" ); const Name n_receptors( "n_receptors" ); -const Name needs_prelim_update( "needs_prelim_update" ); const Name neuron( "neuron" ); const Name node_uses_wfr( "node_uses_wfr" ); const Name noise( "noise" ); @@ -281,7 +281,6 @@ const Name structural_plasticity_update_interval( const Name structure( "structure" ); const Name supports_precise_spikes( "supports_precise_spikes" ); const Name success( "success" ); -const Name symmetric( "symmetric" ); const Name synapse( "synapse" ); const Name synapse_label( "synapse_label" ); const Name synapse_model( "synapse_model" ); diff --git a/nestkernel/nest_names.h b/nestkernel/nest_names.h index d513f9770b..2ab26fe6bd 100644 --- a/nestkernel/nest_names.h +++ b/nestkernel/nest_names.h @@ -248,6 +248,7 @@ extern const Name linear; //!< Parameter for MSP growth curves extern const Name local; //!< Node parameter extern const Name local_id; //!< Node +extern const Name make_symmetric; //!< Connectivity-related extern const Name MAXERR; //!< Largest permissible error for adaptive stepsize //!< (Brette & Gerstner 2005) extern const Name mean; //!< Miscellaneous parameters @@ -266,12 +267,11 @@ extern const Name N_channels; //!< Specific to correlomatrix_detector extern const Name n_events; //!< Recorder parameter extern const Name n_proc; //!< Number of component processes of ppd_sup_/gamma_sup_generator -extern const Name n_receptors; //!< number of receptor ports -extern const Name needs_prelim_update; //!< Node parameter -extern const Name neuron; //!< Node type -extern const Name node_uses_wfr; //!< Node parameter -extern const Name noise; //!< Specific to iaf_chs_2008 neuron -extern const Name ns; //!< Number of release sites (property arrays) +extern const Name n_receptors; //!< number of receptor ports +extern const Name neuron; //!< Node type +extern const Name node_uses_wfr; //!< Node parameter +extern const Name noise; //!< Specific to iaf_chs_2008 neuron +extern const Name ns; //!< Number of release sites (property arrays) extern const Name offset; //!< Miscellaneous parameters extern const Name offsets; //!< Recorder parameter @@ -358,7 +358,6 @@ extern const Name structure; //!< Node type extern const Name success; extern const Name supports_precise_spikes; //!< true if model supports precise //!< spikes -extern const Name symmetric; //!< Connectivity-related extern const Name synapse; //!< Node type extern const Name synapse_label; //!< Label id of synapses with labels extern const Name synapse_model; //!< Connection parameters diff --git a/pynest/nest/tests/test_connect_one_to_one.py b/pynest/nest/tests/test_connect_one_to_one.py index f0bc4b2ee7..bb2268ccde 100644 --- a/pynest/nest/tests/test_connect_one_to_one.py +++ b/pynest/nest/tests/test_connect_one_to_one.py @@ -50,7 +50,7 @@ def testConnectivity(self): def testSymmetricFlag(self): conn_dict_symmetric = self.conn_dict.copy() - conn_dict_symmetric['symmetric'] = True + conn_dict_symmetric['make_symmetric'] = True self.setUpNetwork(conn_dict_symmetric) M1 = hf.get_connectivity_matrix(self.pop1, self.pop2) M2 = hf.get_connectivity_matrix(self.pop2, self.pop1) diff --git a/pynest/nest/tests/test_labeled_synapses.py b/pynest/nest/tests/test_labeled_synapses.py index f6ed484c80..06dd184332 100644 --- a/pynest/nest/tests/test_labeled_synapses.py +++ b/pynest/nest/tests/test_labeled_synapses.py @@ -55,9 +55,12 @@ def test_SetLabelToSynapseOnConnect(self): for syn in labeled_synapse_models: a = self.default_network() + # see if symmetric connections are required + symm = nest.GetDefaults(syn, 'requires_symmetric') + # set a label during connection - nest.Connect(a, a, {"rule": "one_to_one"}, { - "model": syn, "synapse_label": 123}) + nest.Connect(a, a, {"rule": "one_to_one", "make_symmetric": symm}, + {"model": syn, "synapse_label": 123}) c = nest.GetConnections(a, a) self.assertTrue( all([ @@ -74,8 +77,12 @@ def test_SetLabelToSynapseSetStatus(self): for syn in labeled_synapse_models: a = self.default_network() + # see if symmetric connections are required + symm = nest.GetDefaults(syn, 'requires_symmetric') + # set no label during connection - nest.Connect(a, a, {"rule": "one_to_one"}, {"model": syn}) + nest.Connect(a, a, {"rule": "one_to_one", "make_symmetric": symm}, + {"model": syn}) c = nest.GetConnections(a, a) # still unlabeled self.assertTrue( @@ -102,9 +109,13 @@ def test_SetLabelToSynapseSetDefaults(self): for syn in labeled_synapse_models: a = self.default_network() + # see if symmetric connections are required + symm = nest.GetDefaults(syn, 'requires_symmetric') + # set a label during SetDefaults nest.SetDefaults(syn, {'synapse_label': 123}) - nest.Connect(a, a, {"rule": "one_to_one"}, {"model": syn}) + nest.Connect(a, a, {"rule": "one_to_one", "make_symmetric": symm}, + {"model": syn}) c = nest.GetConnections(a, a) self.assertTrue( all([ @@ -121,12 +132,15 @@ def test_GetLabeledSynapses(self): for syn in labeled_synapse_models: a = self.default_network() + # see if symmetric connections are required + symm = nest.GetDefaults(syn, 'requires_symmetric') + # some more connections nest.Connect(a, a, {"rule": "one_to_one"}, {"model": "static_synapse"}) # set a label during connection - nest.Connect(a, a, {"rule": "one_to_one"}, { - "model": syn, "synapse_label": 123}) + nest.Connect(a, a, {"rule": "one_to_one", "make_symmetric": symm}, + {"model": syn, "synapse_label": 123}) c = nest.GetConnections(a, a, synapse_label=123) self.assertTrue( all([ @@ -142,17 +156,22 @@ def test_SetLabelToNotLabeledSynapse(self): for syn in labeled_synapse_models: a = self.default_network() + # see if symmetric connections are required + symm = nest.GetDefaults(syn, 'requires_symmetric') + # try set a label during SetDefaults with self.assertRaises(nest.NESTError): nest.SetDefaults(syn, {'synapse_label': 123}) # try set on connect with self.assertRaises(nest.NESTError): - nest.Connect(a, a, {"rule": "one_to_one"}, { - "model": syn, "synapse_label": 123}) + nest.Connect(a, a, {"rule": "one_to_one", + "make_symmetric": symm}, + {"model": syn, "synapse_label": 123}) # plain connection - nest.Connect(a, a, {"rule": "one_to_one"}, {"model": syn}) + nest.Connect(a, a, {"rule": "one_to_one", "make_symmetric": symm}, + {"model": syn}) # try set on SetStatus c = nest.GetConnections(a, a) with self.assertRaises(nest.NESTError): diff --git a/testsuite/mpitests/test_gap_junctions_mpi.sli b/testsuite/mpitests/test_gap_junctions_mpi.sli index 2bb8a63797..e9beb6fe9f 100644 --- a/testsuite/mpitests/test_gap_junctions_mpi.sli +++ b/testsuite/mpitests/test_gap_junctions_mpi.sli @@ -79,14 +79,20 @@ if /withtime true >> Create def - neuron1 neuron2 << /weight 10.0 >> /gap_junction Connect - neuron2 neuron1 << /weight 10.0 >> /gap_junction Connect + [neuron1] [neuron2] + << /rule /one_to_one /make_symmetric true >> + << /model /gap_junction /weight 10.0 >> + Connect - neuron1 neuron3 << /weight 8.0 >> /gap_junction Connect - neuron3 neuron1 << /weight 8.0 >> /gap_junction Connect + [neuron1] [neuron3] + << /rule /one_to_one /make_symmetric true >> + << /model /gap_junction /weight 8.0 >> + Connect - neuron1 neuron4 << /weight 12.0 >> /gap_junction Connect - neuron4 neuron1 << /weight 12.0 >> /gap_junction Connect + [neuron1] [neuron4] + << /rule /one_to_one /make_symmetric true >> + << /model /gap_junction /weight 12.0 >> + Connect neuron1 sd Connect neuron2 sd Connect diff --git a/testsuite/mpitests/test_symmetric_connections_mpi.sli b/testsuite/mpitests/test_symmetric_connections_mpi.sli index f6db7cfec6..87d805f4ce 100644 --- a/testsuite/mpitests/test_symmetric_connections_mpi.sli +++ b/testsuite/mpitests/test_symmetric_connections_mpi.sli @@ -32,7 +32,7 @@ This test ensures that the functionality to create symmetric connections works properly when running on several MPI processes. In more detail the test ensures that -- the symmetric flag works properly with one-to-one connection rule +- the make_symmetric flag works properly with one-to-one connection rule Author: Hans Ekkehard Plesser, 2016-05-03 based on serial test by Jan Hahne, 2016-04-22 */ @@ -58,7 +58,7 @@ M_ERROR setverbosity set1 set2 << /rule /one_to_one - /symmetric true >> + /make_symmetric true >> << /model /stdp_synapse /weight <. 1.0 2.0 3.0 4.0 5.0 .> /delay <. 1.5 2.5 3.5 4.5 5.5 .> diff --git a/testsuite/unittests/test_gap_junction.sli b/testsuite/unittests/test_gap_junction.sli index 3a42630d56..9954fc130d 100644 --- a/testsuite/unittests/test_gap_junction.sli +++ b/testsuite/unittests/test_gap_junction.sli @@ -61,49 +61,77 @@ M_ERROR setverbosity % Check that accurate gap-junction connections can be created { setup - neuron_gap neuron_gap /gap_junction Connect + [neuron_gap] [neuron_gap] + << /rule /one_to_one /make_symmetric true >> + << /model /gap_junction >> + Connect } pass_or_die { setup - neuron_gap neuron_gap << /weight 2.0 >> /gap_junction Connect + [neuron_gap] [neuron_gap] + << /rule /one_to_one /make_symmetric true >> + << /model /gap_junction /weight 2.0 >> + Connect } pass_or_die { setup - [neuron_gap] [neuron_gap] << /rule /all_to_all >> << /weight 2.0 >> Connect + [neuron_gap] [neuron_gap] + << /rule /all_to_all >> + << /model /gap_junction >> + Connect } pass_or_die % Check that delay cannot be set for gap-junction connections { setup - neuron_gap neuron_gap 2.0 2.0 /gap_junction Connect + [neuron_gap] [neuron_gap] + << /rule /one_to_one /make_symmetric true >> + << /model /gap_junction /delay 2.0 >> + Connect } fail_or_die { setup - neuron_gap neuron_gap << /delay 2.0 >> /gap_junction Connect + [neuron_gap] [neuron_gap] + << /rule /all_to_all >> + << /model /gap_junction /delay 2.0 >> + Connect } fail_or_die +% Check that illegal gap-junction connections cannot be created { setup - [neuron_gap] [neuron_gap] << /rule /all_to_all >> << /delay 2.0 >> /gap_junction Connect + [neuron_no_gap] [neuron_no_gap] + << /rule /one_to_one /make_symmetric true >> + << /model /gap_junction >> + Connect } fail_or_die -% Check that illegal gap-junction connections cannot be created { setup - neuron_no_gap neuron_no_gap << /weight 2.0 >> /gap_junction Connect + [neuron_no_gap] [neuron_gap] + << /rule /one_to_one /make_symmetric true >> + << /model /gap_junction >> + Connect } fail_or_die { setup - neuron_no_gap neuron_gap << /weight 2.0 >> /gap_junction Connect + [neuron_gap] [neuron_no_gap] + << /rule /one_to_one /make_symmetric true >> + << /model /gap_junction >> + Connect } fail_or_die +% Check that non-symmetric gap-junction connections cannot be created { setup - neuron_gap neuron_no_gap << /weight 2.0 >> /gap_junction Connect + [neuron_gap] [neuron_gap] + << /rule /one_to_one /make_symmetric false >> + << /model /gap_junction /weight 2.0 >> + Connect } fail_or_die % Check that gap-junction connections contribute to the min_delay with wfr_comm_interval @@ -117,7 +145,10 @@ M_ERROR setverbosity 0 /min_delay get /old_min Set % ... then create a gap-junction connection - neuron_gap neuron_gap /gap_junction Connect + [neuron_gap] [neuron_gap] + << /rule /one_to_one /make_symmetric true >> + << /model /gap_junction >> + Connect 0 /max_delay get /new_max Set 0 /min_delay get /new_min Set @@ -151,7 +182,10 @@ M_ERROR setverbosity 0 /min_delay get /old_min Set % ... then create a gap-junction connection - neuron_gap neuron_gap /gap_junction Connect + [neuron_gap] [neuron_gap] + << /rule /one_to_one /make_symmetric true >> + << /model /gap_junction >> + Connect 0 /max_delay get /new_max Set 0 /min_delay get /new_min Set diff --git a/testsuite/unittests/test_hh_psc_alpha_gap.sli b/testsuite/unittests/test_hh_psc_alpha_gap.sli index 026f9eb1c0..33d77a66a1 100644 --- a/testsuite/unittests/test_hh_psc_alpha_gap.sli +++ b/testsuite/unittests/test_hh_psc_alpha_gap.sli @@ -85,8 +85,10 @@ neuron1 /voltmeter Create /vm Set vm << /withtime true /time_in_steps true /interval h >> SetStatus -neuron1 neuron2 << /weight 20.0 >> /gap_junction Connect -neuron2 neuron1 << /weight 20.0 >> /gap_junction Connect +[neuron1] [neuron2] +<< /rule /one_to_one /make_symmetric true >> +<< /model /gap_junction /weight 20.0 >> Connect + vm neuron2 1.0 h Connect diff --git a/testsuite/unittests/test_symmetric_connections.sli b/testsuite/unittests/test_symmetric_connections.sli index 5fdbf8ad1e..c14d034838 100644 --- a/testsuite/unittests/test_symmetric_connections.sli +++ b/testsuite/unittests/test_symmetric_connections.sli @@ -29,14 +29,17 @@ Synopsis: (test_symmetric_connections) run -> NEST exits if test fails Description: This test ensures that the functionality to create symmetric connections -works properly. +via flag "make_symmetric" works properly. It also ensures that the +built-in property "requires_symmetric" for synapse models works properly. In more detail the test ensures that -- the symmetric flag works properly with one-to-one connection rule -- the usage of the symmetric flag with any other connections throws +- the "make_symmetric" flag works properly with one-to-one connection rule +- the usage of the "make_symmetric" flag with any other connections throws an NotImplemented exception +- synapse models that "require_symmetric" cannot be created without + "make_symmetric" except for suitable uniform all-to-all connections -Author: Jan Hahne, 2016-04-22 +Author: Jan Hahne, 2016-04-22, updated 2016-11-02 */ (unittest) run @@ -54,35 +57,35 @@ M_ERROR setverbosity /set2 6 10 cvgidcollection def } def -% Check that symmetric flag cannot be used with other connection rules than one_to_one +% Check that make_symmetric flag cannot be used with other connection rules than one_to_one { setup - set1 set2 << /rule /all_to_all /symmetric true >> /static_synapse Connect + set1 set2 << /rule /all_to_all /make_symmetric true >> /static_synapse Connect } fail_or_die { setup - set1 set2 << /rule /fixed_indegree /indegree 3 /symmetric true >> /static_synapse Connect + set1 set2 << /rule /fixed_indegree /indegree 3 /make_symmetric true >> /static_synapse Connect } fail_or_die { setup - set1 set2 << /rule /fixed_outdegree /outdegree 3 /symmetric true >> /static_synapse Connect + set1 set2 << /rule /fixed_outdegree /outdegree 3 /make_symmetric true >> /static_synapse Connect } fail_or_die { setup - set1 set2 << /rule /fixed_total_number /N 3 /symmetric true >> /static_synapse Connect + set1 set2 << /rule /fixed_total_number /N 3 /make_symmetric true >> /static_synapse Connect } fail_or_die -% Check that symmetric flag works properly for basic one_to_one connections +% Check that make_symmetric flag works properly for basic one_to_one connections { setup - set1 set2 << /rule /one_to_one /symmetric true >> /static_synapse Connect + set1 set2 << /rule /one_to_one /make_symmetric true >> /static_synapse Connect << /source [1 5] Range >> GetConnections /fwd Set << /source [6 10] Range >> GetConnections /bck Set @@ -98,12 +101,12 @@ fail_or_die true exch { and } Fold } assert_or_die -% Check that symmetric flag cannot be used with random parameters +% Check that make_symmetric flag cannot be used with random parameters { setup set1 set2 << /rule /one_to_one - /symmetric true >> + /make_symmetric true >> << /model /stdp_synapse /weight << /distribution /uniform >> >> Connect @@ -114,20 +117,20 @@ fail_or_die setup set1 set2 << /rule /one_to_one - /symmetric true >> + /make_symmetric true >> << /model /stdp_synapse /alpha << /distribution /uniform >> >> Connect } fail_or_die -% Check that symmetric flag works properly for one_to_one connections +% Check that make_symmetric flag works properly for one_to_one connections % containing array-parameters { setup set1 set2 << /rule /one_to_one - /symmetric true >> + /make_symmetric true >> << /model /stdp_synapse /weight <. 1.0 2.0 3.0 4.0 5.0 .> /delay <. 1.5 2.5 3.5 4.5 5.5 .> @@ -149,4 +152,91 @@ fail_or_die true exch { and } Fold } assert_or_die + +% The now following tests need the synapse model +% gap_junction (which has require_make_symmetric=true) and +% ergo the model hh_psc_alpha_gap, so +% this test should only run if we have GSL +statusdict/have_gsl :: not +{ + exit_test_gracefully +} +if + +/setup2 +{ + ResetKernel + + /hh_psc_alpha_gap 4 Create + + /set1 1 2 cvgidcollection def + /set2 3 4 cvgidcollection def +} def + +% Check that connections that require_symmetric cannot be created without make_symmetric=true +{ + setup2 + set1 set2 << /rule /one_to_one /make_symmetric false >> /gap_junction Connect +} +fail_or_die + +{ + setup2 + set1 set2 << /rule /fixed_indegree /indegree 3 /make_symmetric false >> /gap_junction Connect +} +fail_or_die + +{ + setup2 + set1 set2 << /rule /fixed_outdegree /outdegree 3 /make_symmetric false >> /gap_junction Connect +} +fail_or_die + +{ + setup2 + set1 set2 << /rule /fixed_total_number /N 3 /make_symmetric false >> /gap_junction Connect +} +fail_or_die + +% Check that all-to-all connection can only be created with scalar parameters and +% sources == targets. These connections are inherently symmetric. +{ + setup2 + set1 set2 << /rule /all_to_all /make_symmetric false >> /gap_junction Connect +} +fail_or_die + +{ + setup2 + set1 set1 + << /rule /all_to_all /make_symmetric false >> + << /model /gap_junction /weight <. 1.0 2.0 3.0 4.0 .> >> + Connect +} +fail_or_die + +{ + setup2 + set1 set1 + << /rule /all_to_all /make_symmetric false >> + << /model /gap_junction /weight << /distribution /uniform >> >> + Connect +} +fail_or_die + +{ + setup2 + set1 set1 << /rule /all_to_all /make_symmetric false >> /gap_junction Connect +} +pass_or_die + +{ + setup2 + set1 set1 + << /rule /all_to_all /make_symmetric false >> + << /model /gap_junction /weight 2.0 >> + Connect +} +pass_or_die + endusing