/*
* connection_manager.h
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef CONNECTION_MANAGER_H
#define CONNECTION_MANAGER_H
#include <vector>
#include <limits>
#include "nest.h"
#include "model.h"
#include "dictutils.h"
#include "connector.h"
#include "nest_time.h"
#include "nest_timeconverter.h"
#include "arraydatum.h"
#include "sparsetable.h"
namespace nest
{
class Network;
class ConnectorModel;
/**
* Manages the available connection prototypes and connections. It provides
* the interface to establish and modify connections between nodes.
*/
class ConnectionManager
{
struct syn_id_connector
{
index syn_id;
Connector* connector;
};
typedef std::vector< syn_id_connector > tVConnector;
typedef google::sparsetable< tVConnector > tVVConnector;
typedef std::vector< tVVConnector > tVVVConnector;
public:
ConnectionManager(Network& net);
~ConnectionManager();
void init(Dictionary*);
void reset();
/**
* Register a synapse type. This is called by Network::register_synapse_prototype.
* Returns an id, which is needed to unregister the prototype later.
*/
index register_synapse_prototype(ConnectorModel * cf);
/**
* Checks, whether connections of the given type were created
*/
bool synapse_prototype_in_use(index syn_id);
/**
* Unregister a previously registered synapse prototype.
*/
void unregister_synapse_prototype(index syn_id);
/**
* Try, if it is possible to unregister synapse prototype.
* Throw exception, if not possible.
*/
void try_unregister_synapse_prototype(index syn_id);
/**
* Add ConnectionManager specific stuff to the root status dictionary
*/
void get_status(DictionaryDatum& d) const;
// aka SetDefaults for synapse models
void set_prototype_status(index syn_id, const DictionaryDatum& d);
// aka GetDefaults for synapse models
DictionaryDatum get_prototype_status(index syn_id) const;
// aka conndatum GetStatus
DictionaryDatum get_synapse_status(index gid, index syn_id, port p, thread tid);
// aka conndatum SetStatus
void set_synapse_status(index gid, index syn_id, port p, thread tid, const DictionaryDatum& d);
DictionaryDatum get_connector_status(const Node& node, index syn_id);
DictionaryDatum get_connector_status(index gid, index syn_id);
void set_connector_status(Node& node, index syn_id, thread tid, const DictionaryDatum& d);
ArrayDatum find_connections(DictionaryDatum params);
void find_connections(ArrayDatum& connectome, thread t, index source, int syn_vec_index, index syn_id, DictionaryDatum params);
/**
* Return connections between pairs of neurons.
* The params dictionary can have the following entries:
* 'source' a token array with GIDs of source neurons.
* 'target' a token array with GIDs of target neuron.
* If either of these does not exist, all neuron are used for the respective entry.
* 'synapse_model' name of the synapse model, or all synapse models are searched.
* The function then iterates all entries in source and collects the connection IDs to all neurons in target.
* get_connections will eventually replace find_connections.
*/
ArrayDatum get_connections(DictionaryDatum params) const;
void get_connections(ArrayDatum& connectome, TokenArray const *source, TokenArray const *target, size_t syn_id) const;
/**
* Return connections between source and any neuron on thread t.
*/
void get_connections(ArrayDatum& connectome, index source, thread t, index syn_id) const;
// aka CopyModel for synapse models
index copy_synapse_prototype(index old_id, std::string new_name);
bool has_user_prototypes() const;
bool get_user_set_delay_extrema() const;
const Time get_min_delay() const;
const Time get_max_delay() const;
/**
* Count the number of connections in all connectors and update the
* global counter num_connections_ in ConnectionManager and the
* local counters in the prototype objects.
* @note This function must be const, because it is called by const
* functions like get_num_connections() and get_status(). The number
* of connections is stored in a mutable variable num_connections_.
*/
void count_connections() const;
/**
* Make sure that the connection counters are up-to-date and return
* the total number of connections in the network.
*/
size_t get_num_connections() const;
/**
* Connect is used to establish a connection between a sender and
* receiving node.
* \param s A reference to the sending Node.
* \param r A reference to the receiving Node.
* \param t The thread of the target node.
* \param syn The synapse model to use.
* \returns The receiver port number for the new connection
*/
void connect(Node& s, Node& r, index s_gid, thread tid, index syn);
void connect(Node& s, Node& r, index s_gid, thread tid, double_t w, double_t d, index syn);
void connect(Node& s, Node& r, index s_gid, thread tid, DictionaryDatum& p, index syn);
/**
* Experimental bulk connector. See documentation in network.h
*/
bool connect(ArrayDatum &d);
void send(thread t, index sgid, Event& e);
/**
* Resize the structures for the Connector objects if necessary.
* This function should be called after number of threads, min_delay, max_delay,
* and time representation have been changed in the scheduler.
* The TimeConverter is used to convert times from the old to the new representation.
* It is also forwarding the calibration
* request to all ConnectorModel objects.
*/
void calibrate(const TimeConverter &);
private:
std::vector<ConnectorModel*> pristine_prototypes_; //!< The list of clean synapse prototypes
std::vector<ConnectorModel*> prototypes_; //!< The list of available synapse prototypes
Network& net_; //!< The reference to the network
Dictionary* synapsedict_; //!< The synapsedict (owned by the network)
/**
* A 3-dim structure to hold the Connector objects which in turn hold the connection
* information.
* - First dim: A std::vector for each local thread
* - Second dim: A std::vector for each node on each thread
* - Third dim: A std::vector for each synapse prototype, holding the Connector objects
*/
tVVVConnector connections_;
mutable size_t num_connections_; //!< The global counter for the number of synapses
mutable bool num_conn_changed_since_counted_; //!< Did the number of synapses change since counting?
void init_();
void delete_connections_();
void clear_prototypes_();
index validate_connector(thread tid, index gid, index syn_id);
/**
* Return pointer to protoype for given synapse id.
* @throws UnknownSynapseType
*/
const ConnectorModel& get_synapse_prototype(index syn_id) const;
/**
* Asserts validity of synapse index, otherwise throws exception.
* @throws UnknownSynapseType
*/
void assert_valid_syn_id(index syn_id) const;
/**
* For a given thread, source gid and synapse id, return the correct
* index (syn_vec_index) into the connection store, so that one can
* access the corresponding connector using
* \code
connections_[tid][gid][syn_vec_index].
\endcode
* @returns the index of the Connector or -1 if it does not exist.
*/
int get_syn_vec_index(thread tid, index gid, index syn_id) const;
};
inline
const ConnectorModel& ConnectionManager::get_synapse_prototype(index syn_id) const
{
assert_valid_syn_id(syn_id);
return *(prototypes_[syn_id]);
}
inline
void ConnectionManager::assert_valid_syn_id(index syn_id) const
{
if (syn_id >= prototypes_.size() || prototypes_[syn_id] == 0)
throw UnknownSynapseType(syn_id);
}
inline
bool ConnectionManager::has_user_prototypes() const
{
return prototypes_.size() > pristine_prototypes_.size();
}
inline
int ConnectionManager::get_syn_vec_index(thread tid, index gid, index syn_id) const
{
if (static_cast<size_t>(tid) >= connections_.size() || gid >= connections_[tid].size() || connections_[tid][gid].size() == 0)
return -1;
index syn_vec_index = 0;
while ( syn_vec_index < connections_[tid][gid].size() && connections_[tid][gid][syn_vec_index].syn_id != syn_id )
syn_vec_index++;
if (syn_vec_index == connections_[tid][gid].size())
return -1;
return syn_vec_index;
}
} // namespace
#endif /* #ifndef CONNECTION_MANAGER_H */