/*
 *  ticket-941.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 <http://www.gnu.org/licenses/>.
 *
 */

/* BeginDocumentation

Name: testsuite::ticket-941 Ensure that GetConnections works correctly with multiple synapse models

Synopsis: (ticket-941) run -> NEST exits if test fails

Description:
This ticket ensures that GetConnections returns correct results when neurons are connected
with different synapse models.

Author: Hans Ekkehard Plesser, 2014-11-30
 */

(unittest) run
/unittest using

M_ERROR setverbosity

/*
  We connect connect two parrot neurons to each other using
  different synpase types. We use a different delay for each 
  pn1 -> pn2 connection so that we can detect actually
  existing connections by spike delays, thus cross-checking output
  from GetConnection.
  
  To test actually existing connections, we drive the first
  parrot neuron with a spike generator and record from the second.
 */
 
 % Helper function
 % sgid num_expected content_expect -> bool
 % content_expect is [sgid tgid thrd synid] 
 /:check_get_conn
 {
   /expected Set
   /n_expected Set
   /sgid Set
   
   << /source [ sgid ] >> GetConnections
   dup length n_expected eq
   {
     true exch { cva 4 Take expected eq and } Fold
   }
   {
     ;   pop dup of GetConnections result 
     false
   }
   ifelse
 }
 def
 
 % Set up basic network ----------------------------------------------------
 
 0 << /resolution 0.1 >> SetStatus
 
 /sg /spike_generator << /spike_times [ 1.0 ] >> Create def
 /pn1 /parrot_neuron Create def
 /pn2 /parrot_neuron Create def
 /sd /spike_detector << /record_to [ /memory ] /withtime true >> Create def
 
 [sg] [pn1] << /rule /one_to_one >> << /model /static_synapse >> Connect
 [pn2] [sd] << /rule /one_to_one >> << /model /static_synapse >> Connect
 
 % check that we have precisely two connections
 { 0 /num_connections get 2 eq } assert_or_die 
 
 % check they are the right connections; do not test port, it may change with implementation
 { 
   sg  1 [sg  pn1 0 synapsedict/static_synapse :: ] :check_get_conn
   pn2 1 [pn2 sd  0 synapsedict/static_synapse :: ] :check_get_conn
   and
 } assert_or_die
 
 % Add one synapse between pn1 and pn2 --------------------------------------
 
 [pn1] [pn2] << /rule /one_to_one >> << /model /static_synapse /delay 1.0 >> Connect
 
 % check that we now have precisely three connections
 { 0 /num_connections get 3 eq } assert_or_die
 
 % check that GetConnections reports correct outgoing connection from pn1
 { 
   pn1 1 [pn1 pn2 0 synapsedict/static_synapse :: ] :check_get_conn
 } assert_or_die
 
 % Add another synapse of same type between pn1 and pn2 ---------------------
 
 [pn1] [pn2] << /rule /one_to_one >> << /model /static_synapse /delay 2.0 >> Connect
 
 % check that we now have precisely four connections
 { 0 /num_connections get 4 eq } assert_or_die
 
 % check that GetConnections reports correct outgoing connection from pn1
 { 
   pn1 2 [pn1 pn2 0 synapsedict/static_synapse :: ] :check_get_conn
 } assert_or_die
 
 % Add synapse with different type  between pn1 and pn2 -----------------------
 
 [pn1] [pn2] << /rule /one_to_one >> << /model /static_synapse_hom_w /delay 3.0 >> Connect
 
 % check that we now have precisely five connections
 { 0 /num_connections get 5 eq } assert_or_die
 
 % Simulate: we should see three spikes, 1 ms apart
 % We do this before testing GetConnections, since it is only the latter that fails 
 {
   10 Simulate
   sd [/events /times] get cva [ 3. 4. 5. ] eq
 } assert_or_die
 
 % check that GetConnections reports correct outgoing connection from sg
 % NB: This test RELIES on the fact that SYNPASES ARE RETURNED IN ORDER OF CREATION
 %     This assumption may fail in future versions of NEST. Then, this test needs
 %     to be generalized to handle arbitrary order
 { 
   << /source [pn1] >> GetConnections { cva 4 Take } Map
   dup ==
   
   [ [pn1 pn2 0 synapsedict/static_synapse :: ]
     [pn1 pn2 0 synapsedict/static_synapse :: ]
     [pn1 pn2 0 synapsedict/static_synapse_hom_w :: ]
   ] eq
 } assert_or_die  
 
endusing
 
 