/*
* archiving_node.cpp
*
* 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/>.
*
*/
/**
* \file archiving_node.cpp
* Implementation of archiving_node to record and manage spike history
* \author Moritz Helias, Abigail Morrison
* \date april 2006
*/
#include "archiving_node.h"
#include "dictutils.h"
namespace nest {
//member functions for Archiving_Node
nest::Archiving_Node::Archiving_Node() :
n_incoming_(0),
Kminus_(0.0),
triplet_Kminus_(0.0),
tau_minus_(20.0),
tau_minus_triplet_(110.0),
last_spike_(-1.0)
{}
nest::Archiving_Node::Archiving_Node(const Archiving_Node& n)
:Node(n),
n_incoming_(n.n_incoming_),
Kminus_(n.Kminus_),
triplet_Kminus_(n.triplet_Kminus_),
tau_minus_(n.tau_minus_),
tau_minus_triplet_(n.tau_minus_triplet_),
last_spike_(n.last_spike_)
{}
void Archiving_Node::register_stdp_connection(double_t t_first_read)
{
// Mark all entries in the deque, which we will not read in future as read by this input
// input, so that we savely increment the incoming number of
// connections afterwards without leaving spikes in the history.
// For details see bug #218. MH 08-04-22
for ( std::deque<histentry>::iterator runner = history_.begin();
runner != history_.end() && runner->t_ <= t_first_read;
runner++)
(runner->access_counter_)++;
n_incoming_++;
}
void Archiving_Node::unregister_stdp_connection(double_t t_last_read)
{
// Mark all entries in the deque we have read as unread
// so that we can savely decrement the incoming number of
// connections afterwards without loosing entries, which
// are still needed. For details see bug #218. MH 08-04-22
for ( std::deque<histentry>::iterator runner = history_.begin();
runner != history_.end() && runner->t_ <= t_last_read;
runner++)
(runner->access_counter_)--;
n_incoming_--;
}
double_t nest::Archiving_Node::get_K_value(double_t t)
{
if (history_.empty()) return Kminus_;
int i = history_.size() - 1;
while (i >= 0)
{
if (t > history_[i].t_)
return (history_[i].Kminus_*std::exp((history_[i].t_ - t)/tau_minus_));
i--;
}
return 0;
}
void nest::Archiving_Node::get_K_values(double_t t, double_t& K_value, double_t& triplet_K_value)
{
// case when the neuron has not yet spiked
if (history_.empty()) {
triplet_K_value = triplet_Kminus_;
K_value = Kminus_;
return;
}
// case
int i = history_.size() - 1;
while (i >= 0)
{
if (t > history_[i].t_) {
triplet_K_value = (history_[i].triplet_Kminus_*std::exp((history_[i].t_ - t)/tau_minus_triplet_));
K_value = (history_[i].Kminus_*std::exp((history_[i].t_ - t)/tau_minus_));
return;
}
i--;
}
// we only get here if t< time of all spikes in history)
// return 0.0 for both K values
triplet_K_value = 0.0;
K_value = 0.0;
}
void nest::Archiving_Node::get_history(double_t t1, double_t t2,
std::deque<histentry>::iterator* start,
std::deque<histentry>::iterator* finish)
{
*finish = history_.end();
if (history_.empty())
{
*start = *finish;
return;
}
else
{
std::deque<histentry>::iterator runner = history_.begin();
while ((runner != history_.end()) && (runner->t_ <= t1)) runner++;
*start = runner;
while ((runner != history_.end()) && (runner->t_ <= t2))
{
(runner->access_counter_)++;
runner++;
}
*finish = runner;
}
}
void nest::Archiving_Node::set_spiketime(Time const & t_sp)
{
if (n_incoming_)
{
// prune all spikes from history which are no longer needed
// except the penultimate one. we might still need it.
while (history_.size() > 1)
{
if (history_.front().access_counter_ >= n_incoming_)
history_.pop_front();
else
break;
}
// update spiking history
Kminus_ = Kminus_ * std::exp((last_spike_ - t_sp.get_ms())/tau_minus_) + 1.0;
triplet_Kminus_ = triplet_Kminus_ * std::exp((last_spike_ - t_sp.get_ms())/tau_minus_triplet_) + 1.0;
last_spike_ = t_sp.get_ms();
history_.push_back( histentry( last_spike_, Kminus_, triplet_Kminus_,0) );
}
else
{
last_spike_ = t_sp.get_ms();
}
}
void nest::Archiving_Node::get_status(DictionaryDatum & d) const
{
def<double>(d, names::t_spike, get_spiketime_ms());
def<double>(d, names::tau_minus, tau_minus_);
def<double>(d, names::tau_minus_triplet, tau_minus_triplet_);
#ifdef DEBUG_ARCHIVER
def<int>(d, names::archiver_length, history_.size());
#endif
}
void nest::Archiving_Node::set_status(const DictionaryDatum & d)
{
// We need to preserve values in case invalid values are set
double_t new_tau_minus = tau_minus_;
double_t new_tau_minus_triplet = tau_minus_triplet_;
updateValue<double_t>(d, names::tau_minus, new_tau_minus);
updateValue<double_t>(d, names::tau_minus_triplet, new_tau_minus_triplet);
if ( new_tau_minus <= 0 || new_tau_minus_triplet <= 0 )
throw BadProperty("All time constants must be strictly positive.");
tau_minus_ = new_tau_minus;
tau_minus_triplet_ = new_tau_minus_triplet;
// check, if to clear spike history and K_minus
bool clear = false;
updateValue<bool>(d, names::clear, clear);
if ( clear )
clear_history();
}
void nest::Archiving_Node::clear_history()
{
last_spike_ = -1.0;
Kminus_ = 0.0;
triplet_Kminus_ = 0.0;
history_.clear();
}
} // of namespace nest