From 6919c2a55cb3fed6e238bcf74688a06e8ade023b Mon Sep 17 00:00:00 2001 From: Stephen Payne Date: Mon, 11 Nov 2024 13:06:23 -0500 Subject: [PATCH] Add support for non-ndarrays as Hypercubes That way we can use CubeMath functions on non-ndarrays, for example. --- python/pjrmi/__init__.py | 14 +++++++++++--- python/tests/pjrmi_tests.py | 11 +++++++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/python/pjrmi/__init__.py b/python/pjrmi/__init__.py index 5e9a11c..5c5b019 100644 --- a/python/pjrmi/__init__.py +++ b/python/pjrmi/__init__.py @@ -3541,12 +3541,20 @@ def _format_by_class(self, klass, value, self._format_int32(self._get_object_id(value))) elif (klass._type_id == self._com_deshaw_hypercube_Hypercube._type_id and - type(value) is numpy.ndarray): + (type(value) is numpy.ndarray or hasattr(value, '__iter__'))): + # Using asarray() will ensure that we share the same semantics + # as how numpy would convert a value to an ndarray. However, + # this might differ from how PJRmi handles integer values (i.e. + # everything winds up being a long). + arr = numpy.asarray(value) return (self._ARGUMENT_VALUE + self._format_int32(klass._type_id) + - self._format_by_class(self._L_java_lang_long, value.shape) + + self._format_by_class(self._L_java_lang_long, arr.shape) + self._format_int32(1) + # num arrays to follow - self._format_by_class(self._java_lang_Object, value.flatten())) + self._format_by_class( + self._java_lang_Object, + arr.flatten() if len(arr.shape) > 1 else arr) + ) elif isinstance(value, JavaMethod) and value._can_format_as(klass): return self._format_method_as(value, klass) diff --git a/python/tests/pjrmi_tests.py b/python/tests/pjrmi_tests.py index 17e7129..1e54c07 100644 --- a/python/tests/pjrmi_tests.py +++ b/python/tests/pjrmi_tests.py @@ -1354,6 +1354,13 @@ def test_cubemath(self): CubeMath = get_pjrmi().class_for_name('com.deshaw.hypercube.CubeMath') IllegalArgumentException = get_pjrmi().class_for_name('java.lang.IllegalArgumentException') + # Ensure that calling sum() and copy() for non-ndarrays works. This + # tests marshalling non-ndarrays as Hypercubes. + l22 = [[0,1], + [2,3]] + self.assertEqual(CubeMath.sum(range(10)), 45) + self.assertTrue(numpy.all(CubeMath.copy(l22) == numpy.asarray(l22))) + # Create an ndarray to work on. We futz with the values a little so that # floating point noise doesn't cause some of the comparisons (e.g. the # trig ones) to fail. @@ -1387,8 +1394,8 @@ def test_cubemath(self): self.assertTrue(numpy.all((dac / dac) == (nda / nda))) # We get floating point noise for some of the tests in the below since - # CubeMath and numpy work slightly differently and we get floating point - # noise. Compare against an epsilon value in order to handle this. + # CubeMath and numpy work slightly differently. Compare against an + # epsilon value in order to handle this. EPS = 1e-15 # Hyperbolic and trig