/*
 *  test_symmetric_connections_mpi.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_symmetric_connections_mpi - Tests that the functionality to create
symmetric connections works properly when running across MPI processes.

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

Description: 
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 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
*/

(unittest) run
/unittest using

M_ERROR setverbosity

/:swap_first_two  % swap first two elements in an array
{
  arrayload /n Set n -2 roll exch n 2 roll n arraystore
} def

[1 2 4]
{
  ResetKernel

  /iaf_psc_alpha 10 Create pop

  /set1 1 5 cvgidcollection def
  /set2 6 10 cvgidcollection def

    set1 set2 
    << /rule /one_to_one 
       /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 .>
       /alpha <. 1.2 2.2 3.2 4.2 5.2 .> >>
    Connect

    << /source [1 5] Range >> GetConnections /fwd Set
    << /source [6 10] Range >> GetConnections /bck Set

    [ fwd bck ]
    {
      {
        [ /source /target /weight /delay /alpha ]
        {
          exch dup rolld get 
        } Map 
        exch pop
      } Map
    } Map
    % On the stack, we now have a list with two elements. The first
    % contains the properties of all local forward connections, 
    % the second the properties of all backward connections.
    % At the driver level, we must
    %   - collect all forward and all backward connections
    %   - ensure that there are five connections in each direction
    %   - ensure that connections are symmetric
  }
{
  {
    % combine forward and backward arrays, respectively, across all ranks
    % the stack then contains an array with one element per NMPI, each
    % of which contains one forward and one backward connection array 
    [ [] [] ] exch { 2 arraystore { join } MapThread } Fold
    
    % swap source and target in each backward array, then convert array to
    % string and sort forward and backward arrays
    { 2 eq 
        { { :swap_first_two pcvs } Map } 
        { { pcvs } Map } 
      ifelse 
      Sort 
    } MapIndexed 
  } Map
  /results Set
  
  % now check across all NMPI values that forward and backward are equal
  true results { { eq } MapThread true exch { and } Fold and } Fold
   
  % compare that the strings obtained for all NMPI values are equal
  results First /ref Set
  true results Rest { ref eq and } Fold
  and
}
distributed_collect_assert_or_die

endusing
