/*
 *  test_rdv_param_setting.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_rdv_param_setting - test parameter setting on RDVs

Synopsis: (test_rdv_param_setting.sli) run -> dies if assertion fails

Description: 
Tests that parameters are set properly on RDVs and that exceptions are
raised if one tries to set unsuitable parameter values.

This test should be extended for every new RDV.

Author: Plesser
FirstVersion: 20140402
*/

(unittest) run
/unittest using

% /rngname /rdvname paramdict run_test
% leaves true if GetStatus returns what SetStatus sent in
% finally, it draws a few numbers to make sure things work
/run_test
{
  /params Set
  /rdvname Set
  rngdict exch get 12345 CreateRNG
  rdevdict rdvname get CreateRDV
  /rdv Set

  rdv params SetStatus

  % the remainder is only executed if SetStatus triggers no exception
  rdv 100 RandomArray ;   % just make sure it works

  % check that we have the desired parameters
  rdv GetStatus params SubsetQ
} def

% -------------------------------------------------------

% ensure that invalid parameter names lead to error

{
  /MT19937 /exponential << /foo 1.0 >> run_test
} fail_or_die

% -------------------------------------------------------

{
  /MT19937 /binomial << /p 0.5 /n 100 >> run_test
} assert_or_die

{
  /MT19937 /binomial << /p -0.5 >> run_test
} fail_or_die

{
  /MT19937 /binomial << /p 1.5 >> run_test
} fail_or_die

{
  /MT19937 /binomial << /n 0 >> run_test
} fail_or_die

{
  /MT19937 /binomial << /n -5 >> run_test
} fail_or_die

{
  /MT19937 /poisson << /n 1e19 cvi >> run_test
} fail_or_die

{
  /MT19937 /binomial_clipped << /min 0. /max -1. >> run_test
} fail_or_die

% -------------------------------------------------------

{
  /MT19937 /exponential << /lambda 1. >> run_test
} assert_or_die

{
  /MT19937 /exponential << /lambda 0. >> run_test
} fail_or_die

{
  /MT19937 /exponential << /lambda -1. >> run_test
} fail_or_die

{
  /MT19937 /exponential_clipped << /min 0. /max -1. >> run_test
} fail_or_die

% -------------------------------------------------------

{
  /MT19937 /gamma << /order 2.5 /scale 2. >> run_test
} assert_or_die

{
  /MT19937 /gamma << /order 0. >> run_test
} fail_or_die

{
  /MT19937 /gamma << /order -1. >> run_test
} fail_or_die

{
  /MT19937 /gamma << /scale 0. >> run_test
} fail_or_die

{
  /MT19937 /gamma << /scale -1. >> run_test
} fail_or_die

{
  /MT19937 /gamma_clipped << /min 0. /max -1. >> run_test
} fail_or_die

% -------------------------------------------------------

statusdict /have_gsl :: {

{
  /MT19937 /gsl_binomial << /p 0.5 /n 100 >> run_test
} fail_or_die

{
  /gsl_mt19937 /gsl_binomial << /p 0.5 /n 100 >> run_test
} assert_or_die

{
  /gsl_mt19937 /gsl_binomial << /p -0.5 >> run_test
} fail_or_die

{
  /gsl_mt19937 /gsl_binomial << /p 1.5 >> run_test
} fail_or_die

{
  /gsl_mt19937 /gsl_binomial << /n 0 >> run_test
} fail_or_die

{
  /gsl_mt19937 /gsl_binomial << /n -5 >> run_test
} fail_or_die

} if

% -------------------------------------------------------

{
  /MT19937 /normal << /mu 2.5 /sigma 2. >> run_test
} assert_or_die

{
  /MT19937 /normal << /sigma 0. >> run_test
} assert_or_die

{
  /MT19937 /normal << /sigma -1. >> run_test
} fail_or_die

{
  /MT19937 /normal_clipped << /min 0. /max -1. >> run_test
} fail_or_die

% -------------------------------------------------------

{
  /MT19937 /lognormal << /mu 2.5 /sigma 2. >> run_test
} assert_or_die

{
  /MT19937 /lognormal << /sigma 0. >> run_test
} assert_or_die

{
  /MT19937 /lognormal << /sigma -1. >> run_test
} fail_or_die

{
  /MT19937 /lognormal_clipped << /min 0. /max -1. >> run_test
} fail_or_die


% -------------------------------------------------------

{
  /MT19937 /poisson << /lambda 10. >> run_test
} assert_or_die

{
  /MT19937 /poisson << /lambda 0. >> run_test
} assert_or_die

{
  /MT19937 /poisson << /lambda -1. >> run_test
} fail_or_die

{
  /MT19937 /poisson << /lambda 1e19 >> run_test
} fail_or_die

{
  /MT19937 /poisson_clipped << /min 0. /max -1. >> run_test
} fail_or_die

% -------------------------------------------------------

{
  % choose uniformly from [1, 2, 3, ..., 10]
  /MT19937 /uniform_int << /low 1 /high 10 >> run_test
} assert_or_die

{
  % choose from [10] --- trivial, but must work
  /MT19937 /uniform_int << /low 10 /high 10 >> run_test
} assert_or_die

{
  % lower limit of number range higher than upper, must raise error
  /MT19937 /uniform_int << /low 11 /high 10 >> run_test
} fail_or_die

/*
 Compute the largest positive number representable by long type
 
 If long has N bits, this number is 2^(N-1) - 1. To avoid 
 overflow during the computation, we compute it as
 
 2^(N-1) - 1 = 2^(N-2) + [ 2^(N-2) - 1 ]
*/
/:LONG_MAX
  statusdict/architecture/long :: 8 mul   % N: bits in long type
  2 sub 2 exch pow cvi                    % 2^(N-2)
  dup 1 sub                               % stack: 2^(N-2) 2^(N-2)-1
  add                                     % 2^(N-1)-1
def

{
  % test with +- max value + 1  on both ends, must fail
  /MT19937 /uniform_int << /low :LONG_MAX neg cvi /high :LONG_MAX cvi >> run_test
} fail_or_die

{
  % test with max value + 1 at upper end, must fail
  /MT19937 /uniform_int << /low 0 /high :LONG_MAX cvi >> run_test
} fail_or_die

{
  % test with -(max value + 1) at lower end, must fail
  /MT19937 /uniform_int << /low :LONG_MAX neg cvi /high 0 >> run_test
} fail_or_die

{
  % test with non-extreme edge is +-1, must pass (largest allowed range)
  /MT19937 /uniform_int << /low 1 cvi /high :LONG_MAX cvi >> run_test
  /MT19937 /uniform_int << /low :LONG_MAX neg cvi /high -1 >> run_test
} pass_or_die 

% -------------------------------------------------------

{
  /MT19937 /uniform << /low -1. /high 10. >> run_test
} assert_or_die

{
  /MT19937 /uniform << /low 10. /high 10. >> run_test
} fail_or_die

{
  /MT19937 /uniform << /low 11. /high 10. >> run_test
} fail_or_die

% -------------------------------------------------------

% test that we can set parameters on construction
% this tests SLI functionality, so it suffices to test 
% this for one generator

{
  rngdict /MT19937 :: 12345 CreateRNG
  rdevdict /exponential :: << /lambda 10.5 >> CreateRDV
  dup /lambda get 10.5 eq
} assert_or_die

