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

/* BeginDocumentation
   Name: testsuite::test_GetConnections - sli script to test if GetConnections works as expected

   Synopsis: (test_getConnections) run

   Description:

   This test generates 100 iaf_neurons and connects them with different synapses.

   SeeAlso: GetConnections

   FirstVersion: May 2012
   Author: Marc-Oliver Gewaltig
 */

/unittest (7488) require
/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_neuron 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] { /static_synapse Connect } ScanThread 
  [stdp_sources stdp_targets] { /stdp_synapse Connect } ScanThread 
} def

% first test: retrieve static connections
{
  << >> begin
    ResetKernel
    build_net

    /conns << /synapse_model /static_synapse >> GetConnections { cva } Map def
    /csrc conns { 0 get } Map def
    /ctgt conns { 1 get } Map def
    /cstp conns { 3 get } Map def  % synapse type
    /syn_id synapsedict /static_synapse get def
 
    csrc static_sources eq
    ctgt static_targets eq and
    cstp { syn_id eq and } Fold  % all synapses must have static type
  end
} assert_or_die

% second test: retrieve stdp connections
{
  << >> begin
    ResetKernel
    build_net

    /conns << /synapse_model /stdp_synapse >> GetConnections { cva } Map def
    /csrc conns { 0 get } Map def
    /ctgt conns { 1 get } Map def
    /cstp conns { 3 get } Map def  % synapse type
    /syn_id synapsedict /stdp_synapse get def

    csrc stdp_sources eq
    ctgt stdp_targets eq and
    cstp { syn_id eq and } Fold  % all synapses must have static type
  end
} assert_or_die

% third test: retrieve all connections --- static will come first
{
  << >> begin
    ResetKernel
    build_net

    /conns << >> GetConnections { cva } Map def
    /csrc conns { 0 get } Map def
    /ctgt conns { 1 get } Map def

    csrc static_sources stdp_sources join eq
    ctgt static_targets stdp_targets join eq and
  end
} assert_or_die

% 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 >> GetConnections { cva } Map def
    /csrc conns { 0 get } Map def
    /ctgt conns { 1 get } Map def

    csrc ssrc_all eq
    ctgt stgt_all eq and
  end
} assert_or_die

% 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 >> GetConnections { cva } Map def
    /csrc conns { 0 get } Map def
    /ctgt conns { 1 get } Map def

    csrc ssrc_all eq
    ctgt stgt_all eq and
  end
} assert_or_die

% 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 /target stgt_all >> GetConnections { cva } Map def
    /csrc conns { 0 get } Map def
    /ctgt conns { 1 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

% 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 /target stgt_all /synapse_model /static_synapse >> 
      GetConnections { cva } Map 
    def
    /csrc conns { 0 get } Map def
    /ctgt conns { 1 get } Map def

    csrc ssrc_static -2 Take eq
    ctgt stgt_static  2 Take eq and
  end
} assert_or_die

% eighth test: check static synapses on four threads
{
  << >> begin
    ResetKernel
    0 << /local_num_threads 4 >> SetStatus
    build_net

    % NB: relative ordering of data from threads is random under OpenMP  
    /conns << /synapse_model /static_synapse >> GetConnections { cva } Map 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 0 get 1000 mul exch 1 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

endusing