From 3be85217085933466ae8a192e6a50e4cb57b2644 Mon Sep 17 00:00:00 2001 From: Martin Bubel Date: Sat, 28 Jun 2025 21:05:11 +0200 Subject: [PATCH 1/7] modernize package setup --- pyproject.toml | 55 ++++++++++++++++++++ pytest.ini | 3 ++ setup.py | 134 +------------------------------------------------ 3 files changed, 60 insertions(+), 132 deletions(-) create mode 100644 pyproject.toml create mode 100644 pytest.ini diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..6c289b9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,55 @@ +[project] +name = "paramz" +dynamic = ["version", "readme"] +authors = [ + {name = "Max Zwiessele", email = "ibinbei@gmail.com"}, +] +description = "The Parameterization Framework" +license = {text = "BSD 3-clause"} +keywords = ["machine-learning", "gaussian-processes", "kernels"] +classifiers = [ + "License :: OSI Approved :: BSD License", + "Natural Language :: English", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX :: Linux", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Topic :: Scientific/Engineering :: Artificial Intelligence", +] + +dependencies = [ + "numpy>=1.7", + "scipy", + "six", + "decorator>=4.0.10", +] + +[project.optional-dependencies] +docs = ["sphinx"] +notebook = [ + "jupyter_client >= 4.0.6", + "ipywidgets >= 4.0.3", + "ipykernel >= 4.1.0", + "notebook >= 4.0.5", +] +optimization = ["climin"] + +[project.urls] +Homepage = "https://github.com/sods/paramz" + +[tool.setuptools] +packages = ["paramz", "paramz.core", "paramz.optimization", "paramz.examples", "paramz.tests"] + +[tool.setuptools.dynamic] +version = {attr = "paramz.__version__.__version__"} +readme = {file = ["README.rst"]} + +[build-system] +requires = ["setuptools>=42", "wheel"] +build-backend = "setuptools.build_meta" \ No newline at end of file diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..84d9897 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +testpaths = paramz/tests +python_files = *_tests.py \ No newline at end of file diff --git a/setup.py b/setup.py index 255972d..5b7436d 100644 --- a/setup.py +++ b/setup.py @@ -1,137 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -#=============================================================================== -# Copyright (c) 2015, Max Zwiessele -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of paramax nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#=============================================================================== - -from __future__ import print_function -import os from setuptools import setup -import codecs - -def read(fname): - with codecs.open(fname, 'r', 'latin') as f: - return f.read() - -#def read_to_rst(fname): -# try: -# import pypandoc -# rstname = "{}.{}".format(os.path.splitext(fname)[0], 'rst') -# pypandoc.convert(read(fname), 'rst', format='md', outputfile=rstname) -# with open(rstname, 'r') as f: -# rststr = f.read() -# return rststr -# #return read(rstname) -# except ImportError: -# return read(fname) - -desc = read('README.rst') - -version_dummy = {} -exec(read('paramz/__version__.py'), version_dummy) -__version__ = version_dummy['__version__'] -del version_dummy - -#Mac OS X Clang doesn't support OpenMP at the current time. -#This detects if we are building on a Mac -# def ismac(): -# return sys.platform[:6] == 'darwin' -# -# if ismac(): -# compile_flags = [ '-O3', ] -# link_args = [] -# else: -# compile_flags = [ '-fopenmp', '-O3', ] -# link_args = ['-lgomp'] - -# ext_mods = [Extension(name='GPy.kern._src.stationary_cython', -# sources=['GPy/kern/_src/stationary_cython.c', -# 'GPy/kern/_src/stationary_utils.c'], -# include_dirs=[np.get_include(),'.'], -# extra_compile_args=compile_flags, -# extra_link_args = link_args), -# Extension(name='GPy.util.choleskies_cython', -# sources=['GPy/util/choleskies_cython.c'], -# include_dirs=[np.get_include(),'.'], -# extra_link_args = link_args, -# extra_compile_args=compile_flags), -# Extension(name='GPy.util.linalg_cython', -# sources=['GPy/util/linalg_cython.c'], -# include_dirs=[np.get_include(),'.'], -# extra_compile_args=compile_flags), -# Extension(name='GPy.kern._src.coregionalize_cython', -# sources=['GPy/kern/_src/coregionalize_cython.c'], -# include_dirs=[np.get_include(),'.'], -# extra_compile_args=compile_flags)] -setup(name = 'paramz', - version = __version__, - author = 'Max Zwiessele', - author_email = "ibinbei@gmail.com", - description = ("The Parameterization Framework"), - license = "BSD 3-clause", - keywords = "machine-learning gaussian-processes kernels", - url = "https://github.com/sods/paramz", - #ext_modules = ext_mods, - packages = ["paramz", - "paramz.core", - "paramz.optimization", - "paramz.examples", - "paramz.tests" - ], - #package_dir={'GPy': 'GPy'}, - #package_data = {'GPy': ['defaults.cfg', 'installation.cfg', - # 'util/data_resources.json', - # 'util/football_teams.json', - # ]}, - #include_package_data = True, - py_modules = ['paramz.__init__'], - test_suite = 'paramz.tests', - long_description=desc, - install_requires=['numpy>=1.7', 'scipy', 'six', 'decorator>=4.0.10'], - extras_require = {'docs':['sphinx'], - 'notebook':['jupyter_client >= 4.0.6', - 'ipywidgets >= 4.0.3', - 'ipykernel >= 4.1.0', - 'notebook >= 4.0.5', - ], - 'optimization':['climin'], - }, - classifiers=['License :: OSI Approved :: BSD License', - 'Natural Language :: English', - 'Operating System :: MacOS :: MacOS X', - 'Operating System :: Microsoft :: Windows', - 'Operating System :: POSIX :: Linux', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Topic :: Scientific/Engineering :: Artificial Intelligence'] - ) +if __name__ == "__main__": + setup() \ No newline at end of file From 593e9bb150538db484e118cc0f35d52f60e6e3d4 Mon Sep 17 00:00:00 2001 From: Martin Bubel Date: Sat, 28 Jun 2025 21:04:56 +0200 Subject: [PATCH 2/7] update deprecated assertregexp call --- paramz/tests/parameterized_tests.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/paramz/tests/parameterized_tests.py b/paramz/tests/parameterized_tests.py index 825750e..2baf26f 100644 --- a/paramz/tests/parameterized_tests.py +++ b/paramz/tests/parameterized_tests.py @@ -131,8 +131,8 @@ def test_num_params(self): self.assertEqual(self.test1.add.rbf.num_params, 2) def test_index_operations(self): - self.assertRaisesRegexp(AttributeError, "An index operation with the name constraints was already taken", self.test1.add_index_operation, 'constraints', None) - self.assertRaisesRegexp(AttributeError, "No index operation with the name", self.test1.remove_index_operation, 'not_an_index_operation') + self.assertRaisesRegex(AttributeError, "An index operation with the name constraints was already taken", self.test1.add_index_operation, 'constraints', None) + self.assertRaisesRegex(AttributeError, "No index operation with the name", self.test1.remove_index_operation, 'not_an_index_operation') def test_names(self): self.assertSequenceEqual(self.test1.parameter_names(adjust_for_printing=True), self.test1.parameter_names(adjust_for_printing=False)) @@ -182,7 +182,7 @@ def max_recursion(): from builtins import RecursionError as RE except: RE = RuntimeError - self.assertRaisesRegexp(RE, "aximum recursion depth", max_recursion) + self.assertRaisesRegex(RE, "aximum recursion depth", max_recursion) # Recursion limit not reached if kernels are named individually: sys.setrecursionlimit(1000) p = Parameterized('add') @@ -239,7 +239,7 @@ def test_remove_parameter_param_array_grad_array(self): self.assertListEqual(self.test1.kern.param_array.tolist(), val[:2].tolist()) def test_add_parameter_already_in_hirarchy(self): - self.assertRaisesRegexp(HierarchyError, "You cannot add a parameter twice into the hierarchy", self.test1.link_parameter, self.white.parameters[0]) + self.assertRaisesRegex(HierarchyError, "You cannot add a parameter twice into the hierarchy", self.test1.link_parameter, self.white.parameters[0]) def test_default_constraints(self): self.assertIs(self.rbf.variance.constraints._param_index_ops, self.rbf.constraints._param_index_ops) From 6f32003237a2cd02ae7aa0bc37d6d60449a2261a Mon Sep 17 00:00:00 2001 From: Martin Bubel Date: Sun, 29 Jun 2025 17:43:27 +0200 Subject: [PATCH 3/7] restore numpy.1.2.6 compatibility --- paramz/core/indexable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paramz/core/indexable.py b/paramz/core/indexable.py index b648422..c39dfd7 100644 --- a/paramz/core/indexable.py +++ b/paramz/core/indexable.py @@ -158,7 +158,7 @@ def _raveled_index_for(self, param): """ from ..param import ParamConcatenation if isinstance(param, ParamConcatenation): - return np.hstack((self._raveled_index_for(p) for p in param.params)) + return np.hstack([self._raveled_index_for(p) for p in param.params]) return param._raveled_index() + self._offset_for(param) def _raveled_index_for_transformed(self, param): From dd0c2b2ff6a87a75b53dc6362826a17f0bd0ea3e Mon Sep 17 00:00:00 2001 From: Martin Bubel Date: Sun, 29 Jun 2025 18:03:51 +0200 Subject: [PATCH 4/7] Refactor numerical operations to remove unnecessary float conversions in model and test files --- paramz/model.py | 12 ++++++------ paramz/tests/model_tests.py | 8 ++++---- paramz/tests/parameterized_tests.py | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/paramz/model.py b/paramz/model.py index 1c9a7e1..8970b61 100644 --- a/paramz/model.py +++ b/paramz/model.py @@ -370,9 +370,9 @@ def _checkgrad(self, target_param=None, verbose=False, step=1e-6, tolerance=1e-3 for xind in zip(transformed_index): xx = x.copy() xx[xind] += step - f1 = float(self._objective(xx)) + f1 = self._objective(xx) xx[xind] -= 2.*step - f2 = float(self._objective(xx)) + f2 = self._objective(xx) #Avoid divide by zero, if any of the values are above 1e-15, otherwise both values are essentiall #the same if f1 > 1e-15 or f1 < -1e-15 or f2 > 1e-15 or f2 < -1e-15: @@ -396,11 +396,11 @@ def _checkgrad(self, target_param=None, verbose=False, step=1e-6, tolerance=1e-3 if df_unstable: # pragma: no cover formatted_name = "\033[94m {0} \033[0m".format(names[xind]) - r = '%.6f' % float(ratio) - d = '%.6f' % float(difference) + r = '%.6f' % ratio + d = '%.6f' % difference g = '%.6f' % gradient[xind] - ng = '%.6f' % float(numerical_gradient) - df = '%1.e' % float(df_ratio) + ng = '%.6f' % numerical_gradient + df = '%1.e' % df_ratio grad_string = "{0:<{c0}}|{1:^{c1}}|{2:^{c2}}|{3:^{c3}}|{4:^{c4}}|{5:^{c5}}".format(formatted_name, r, d, g, ng, df, c0=cols[0] + 9, c1=cols[1], c2=cols[2], c3=cols[3], c4=cols[4], c5=cols[5]) print(grad_string) diff --git a/paramz/tests/model_tests.py b/paramz/tests/model_tests.py index 77b40d2..b0ee61f 100644 --- a/paramz/tests/model_tests.py +++ b/paramz/tests/model_tests.py @@ -268,7 +268,7 @@ def test_constraints_set_direct(self): #self.assertSequenceEqual(cache_str, str(self.testmodel), None, str) def test_updates(self): - val = float(self.testmodel.objective_function()) + val = self.testmodel.objective_function() self.testmodel.update_toggle() self.testmodel.kern.randomize(np.random.normal, loc=1, scale=.2) self.testmodel.likelihood.randomize() @@ -284,7 +284,7 @@ def test_set_gradients(self): def test_fixing_optimize(self): self.testmodel.kern.lengthscale.fix() - val = float(self.testmodel.kern.lengthscale) + val = self.testmodel.kern.lengthscale self.testmodel.randomize() self.assertEqual(val, self.testmodel.kern.lengthscale) self.testmodel.optimize(max_iters=2) @@ -299,7 +299,7 @@ def test_regular_expression_misc(self): np.testing.assert_((self.testmodel[''][:2] == [10,10]).all()) self.testmodel.kern.lengthscale.fix() - val = float(self.testmodel.kern.lengthscale) + val = self.testmodel.kern.lengthscale self.testmodel.randomize() self.assertEqual(val, self.testmodel.kern.lengthscale) @@ -354,7 +354,7 @@ def test_fix_unfix_constraints(self): # Assert fixing works and does not randomize the - say - lengthscale: - val = float(self.testmodel.kern.lengthscale) + val = self.testmodel.kern.lengthscale self.testmodel.randomize() self.assertEqual(val, self.testmodel.kern.lengthscale) diff --git a/paramz/tests/parameterized_tests.py b/paramz/tests/parameterized_tests.py index 2baf26f..5ca6756 100644 --- a/paramz/tests/parameterized_tests.py +++ b/paramz/tests/parameterized_tests.py @@ -274,7 +274,7 @@ def test_constraints_views(self): def test_fixing_randomize(self): self.white.fix(warning=True) - val = float(self.white.variance) + val = self.white.variance self.test1.randomize() self.assertEqual(val, self.white.variance) @@ -286,7 +286,7 @@ def test_randomize(self): def test_fixing_randomize_parameter_handling(self): self.rbf.fix(0.1, warning=True) - val = float(self.rbf.variance) + val = self.rbf.variance self.test1.kern.randomize() self.assertEqual(val, self.rbf.variance) From f6f5588ed873aecfbef59aedcd42991b49f1d04a Mon Sep 17 00:00:00 2001 From: Martin Bubel Date: Mon, 30 Jun 2025 08:24:08 +0200 Subject: [PATCH 5/7] add debugging config to test to resolve numpy memory addr issues --- .vscode/launch.json | 17 +++++++++++++++++ paramz/tests/parameterized_tests.py | 5 ++++- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..4af2482 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Test: Parameterized Tests", + "type": "debugpy", + "request": "launch", + "program": "parameterized_tests.py", + "console": "integratedTerminal", + "cwd": "${workspaceFolder}/paramz/tests", + "justMyCode": false + } + ] +} \ No newline at end of file diff --git a/paramz/tests/parameterized_tests.py b/paramz/tests/parameterized_tests.py index 5ca6756..62b0770 100644 --- a/paramz/tests/parameterized_tests.py +++ b/paramz/tests/parameterized_tests.py @@ -309,4 +309,7 @@ def test_printing(self): if __name__ == "__main__": #import sys;sys.argv = ['', 'Test.test_add_parameter'] - unittest.main() + # unittest.main() + obj = ParameterizedTest() + obj.setUp() + obj.test_unfixed_param_array() From c0146ac2f7bbd2ba419239b95101ad5db761b5d7 Mon Sep 17 00:00:00 2001 From: Martin Bubel Date: Mon, 30 Jun 2025 08:24:55 +0200 Subject: [PATCH 6/7] add replacement wrapper for numpy's .data access --- paramz/core/parameter_core.py | 6 ++++-- paramz/parameterized.py | 9 ++++++--- paramz/util.py | 22 +++++++++++++++++++++- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/paramz/core/parameter_core.py b/paramz/core/parameter_core.py index 10a141a..ac2a4dc 100644 --- a/paramz/core/parameter_core.py +++ b/paramz/core/parameter_core.py @@ -38,6 +38,8 @@ import re import logging +from paramz.util import _set_mem_addr + from ..transformations import __fixed__, FIXED from .constrainable import Constrainable from .nameable import adjust_name_for_printing @@ -287,8 +289,8 @@ def _propagate_param_grad(self, parray, garray): self.param_array[pislice] = pi.param_array.flat # , requirements=['C', 'W']).flat self.gradient_full[pislice] = pi.gradient_full.flat # , requirements=['C', 'W']).flat - pi.param_array.data = parray[pislice].data - pi.gradient_full.data = garray[pislice].data + _set_mem_addr(pi.param_array, parray[pislice]) + _set_mem_addr(pi.gradient_full, garray[pislice]) pi._propagate_param_grad(parray[pislice], garray[pislice]) pi_old_size += pi.size diff --git a/paramz/parameterized.py b/paramz/parameterized.py index 64ab493..663f11a 100644 --- a/paramz/parameterized.py +++ b/paramz/parameterized.py @@ -28,7 +28,10 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #=============================================================================== -import numpy; np = numpy +import ctypes +import numpy + +from paramz.util import _set_mem_addr; np = numpy from re import compile try: from re import _pattern_type @@ -268,8 +271,8 @@ def _connect_parameters(self, ignore_added_names=False): self.param_array[pslice] = p.param_array.flat # , requirements=['C', 'W']).ravel(order='C') self.gradient_full[pslice] = p.gradient_full.flat # , requirements=['C', 'W']).ravel(order='C') - p.param_array.data = self.param_array[pslice].data - p.gradient_full.data = self.gradient_full[pslice].data + _set_mem_addr(p.param_array, self.param_array[pslice]) + _set_mem_addr(p.gradient_full, self.gradient_full[pslice]) self._param_slices_.append(pslice) diff --git a/paramz/util.py b/paramz/util.py index b0ab6ed..4ff26d1 100644 --- a/paramz/util.py +++ b/paramz/util.py @@ -27,6 +27,7 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #=============================================================================== +import warnings def _inherit_doc(fromclass, done_classes = None): inherited = '' @@ -44,4 +45,23 @@ def _inherit_doc(fromclass, done_classes = None): pass inherited += _inherit_doc(c, done_classes=done_classes) - return inherited \ No newline at end of file + return inherited + + +def _set_mem_addr(dest, src) -> None: + """ + This function serves to replace the `.data` getter/setter that existed in + `numpy<2` and got removed in `numpy>=2`. + The original behavior was setting the memory address of dest to that of src. + However, directly setting the memory address of a numpy array to the data of + another one seems to be unwanted in `numpy>=2`, which is causing some major + problems here. + """ + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + + # original + # dest.data = src.data + + # take 1 + dest.data = memoryview(src) From 451d602062c5a8c1dc4343025f40fa0d2c9725e3 Mon Sep 17 00:00:00 2001 From: Martin Bubel Date: Mon, 30 Jun 2025 09:14:53 +0200 Subject: [PATCH 7/7] deactivate catch warnings --- paramz/util.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/paramz/util.py b/paramz/util.py index 4ff26d1..a1ce814 100644 --- a/paramz/util.py +++ b/paramz/util.py @@ -57,11 +57,11 @@ def _set_mem_addr(dest, src) -> None: another one seems to be unwanted in `numpy>=2`, which is causing some major problems here. """ - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) + # with warnings.catch_warnings(): + # warnings.simplefilter("ignore", DeprecationWarning) - # original - # dest.data = src.data - - # take 1 - dest.data = memoryview(src) + # original + # dest.data = src.data + + # take 1 + dest.data = memoryview(src)