From 4bac15ebaa156741c708d2a50cd2c0ced011faf5 Mon Sep 17 00:00:00 2001 From: Hans Ekkehard Plesser Date: Mon, 18 Mar 2024 13:26:18 +0100 Subject: [PATCH 1/4] Correctly support SLI-creation of Parameter from double --- lib/sli/nest-init.sli | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sli/nest-init.sli b/lib/sli/nest-init.sli index 1e25b9e0c1..925eb24f03 100644 --- a/lib/sli/nest-init.sli +++ b/lib/sli/nest-init.sli @@ -413,7 +413,7 @@ def /CreateParameter trie [/dictionarytype] /CreateParameter_D load addtotrie -[/doubletype] /CreateParameter_D load addtotrie +[/doubletype] { /val Set << /constant << /value val >> >> CreateParameter_D } addtotrie def /GetValue [/parametertype] From def56141fa2edb9a66e2f192356e7bf9414394c8 Mon Sep 17 00:00:00 2001 From: Hans Ekkehard Plesser Date: Mon, 18 Mar 2024 13:27:12 +0100 Subject: [PATCH 2/4] Correctly handle random parameters appearing in the denominator Co-authored-by: Jannik Grundler --- pynest/nest/lib/hl_api_types.py | 3 +- .../pytests/test_regression_issue-3156.py | 85 +++++++++++++++++++ 2 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 testsuite/pytests/test_regression_issue-3156.py diff --git a/pynest/nest/lib/hl_api_types.py b/pynest/nest/lib/hl_api_types.py index 00118855f5..fe6900a311 100644 --- a/pynest/nest/lib/hl_api_types.py +++ b/pynest/nest/lib/hl_api_types.py @@ -1077,8 +1077,7 @@ def __truediv__(self, rhs): return self._binop("div", rhs) def __rtruediv__(self, lhs): - rhs_inv = CreateParameter("constant", {"value": 1 / float(self.GetValue())}) - return rhs_inv._binop("mul", lhs) + return self**-1 * lhs def __pow__(self, exponent): try: diff --git a/testsuite/pytests/test_regression_issue-3156.py b/testsuite/pytests/test_regression_issue-3156.py new file mode 100644 index 0000000000..52ebbf1521 --- /dev/null +++ b/testsuite/pytests/test_regression_issue-3156.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +# +# test_regression_issue-3156.py +# +# 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 . + +import operator as ops + +import nest +import pytest + +""" +Tests to ensure that random parameters can be used with all operators that support parameters. + +We expect that each parameter value drawn will differ from all others. +""" + + +@pytest.fixture(autouse=True) +def reset(): + nest.ResetKernel() + + +num_neurons = 10 +operators = [ops.add, ops.sub, ops.mul, ops.truediv, ops.pow, ops.mod] + + +@pytest.mark.parametrize("lhs", [1, 2, 2.0]) +@pytest.mark.parametrize("op", operators) +def test_params_random_denominator(lhs, op): + num_neurons = 10 + try: + n = nest.Create("iaf_psc_alpha", num_neurons, {"V_m": op(lhs, nest.random.uniform(1, 2))}) + except TypeError: + pass # operation not supported for parameter + else: + assert len(set(n.V_m)) == num_neurons + + +@pytest.mark.parametrize("op", operators) +@pytest.mark.parametrize("rhs", [1, 2, 2.0]) +def test_params_random_numerator(op, rhs): + num_neurons = 10 + + try: + n = nest.Create("iaf_psc_alpha", num_neurons, {"V_m": op(nest.random.uniform(1, 2), rhs)}) + except TypeError: + pass # operation not supported for parameter + else: + assert len(set(n.V_m)) == num_neurons + + +def test_random_numer_and_denom(): + """ + For random parameters in numerator and denominator, we make the denominator uniform + on the set {-1, +1}. We expect then that there must be at least one positive and at + least one negative result. + """ + num_neurons = 10 + try: + n = nest.Create( + "iaf_psc_alpha", num_neurons, {"V_m": nest.random.uniform(1, 2) / (1.0 - 2.0 * nest.random.uniform_int(2))} + ) + except TypeError: + pass + else: + V_m = n.V_m + assert len(set(n.V_m)) == num_neurons + assert sum(V < 0 for V in V_m) > 0 + assert sum(V >= 0 for V in V_m) > 0 From f5f10859dfc9af1651e55479ac7f2e2201fc8663 Mon Sep 17 00:00:00 2001 From: Hans Ekkehard Plesser Date: Mon, 18 Mar 2024 15:30:41 +0100 Subject: [PATCH 3/4] Increase number of neurons in test to reduce probability of unwanted corner case. --- testsuite/pytests/test_regression_issue-3156.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/testsuite/pytests/test_regression_issue-3156.py b/testsuite/pytests/test_regression_issue-3156.py index 52ebbf1521..d90312d3a9 100644 --- a/testsuite/pytests/test_regression_issue-3156.py +++ b/testsuite/pytests/test_regression_issue-3156.py @@ -68,10 +68,11 @@ def test_params_random_numerator(op, rhs): def test_random_numer_and_denom(): """ For random parameters in numerator and denominator, we make the denominator uniform - on the set {-1, +1}. We expect then that there must be at least one positive and at - least one negative result. + on the set {-1, +1}. For 50 neurons we then have at least one positive and at least + one negative result with p = 2 * 2^-50 ≈ 2e-15. """ - num_neurons = 10 + + num_neurons = 50 try: n = nest.Create( "iaf_psc_alpha", num_neurons, {"V_m": nest.random.uniform(1, 2) / (1.0 - 2.0 * nest.random.uniform_int(2))} From f1fffbf0fa9356821e50c1ceaf7508ff4a1fbe0d Mon Sep 17 00:00:00 2001 From: Hans Ekkehard Plesser Date: Tue, 19 Mar 2024 13:59:46 +0100 Subject: [PATCH 4/4] Fixed documentation --- testsuite/pytests/test_regression_issue-3156.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testsuite/pytests/test_regression_issue-3156.py b/testsuite/pytests/test_regression_issue-3156.py index d90312d3a9..7bf9b6c952 100644 --- a/testsuite/pytests/test_regression_issue-3156.py +++ b/testsuite/pytests/test_regression_issue-3156.py @@ -68,8 +68,8 @@ def test_params_random_numerator(op, rhs): def test_random_numer_and_denom(): """ For random parameters in numerator and denominator, we make the denominator uniform - on the set {-1, +1}. For 50 neurons we then have at least one positive and at least - one negative result with p = 2 * 2^-50 ≈ 2e-15. + on the set {-1, +1}. For 50 neurons, the probability that the denominator has the same + sign (either positive or negative) is 2 * 2^-50 ≈ 2e-15. """ num_neurons = 50