From c2a336473020e11016a678961dcdf1061edf65ed Mon Sep 17 00:00:00 2001 From: BChass <34097574+Bchass@users.noreply.github.com> Date: Wed, 20 Nov 2024 13:03:09 -0500 Subject: [PATCH 01/10] meshgrid and sqrt --- tinynumpy/tinynumpy.py | 59 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/tinynumpy/tinynumpy.py b/tinynumpy/tinynumpy.py index 968524c..8d57040 100644 --- a/tinynumpy/tinynumpy.py +++ b/tinynumpy/tinynumpy.py @@ -382,6 +382,46 @@ def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=Non return a + +def meshgrid(*xi, copy=True, sparse=False, indexing='xy'): + if indexing not in {'xy', 'ij'}: + raise ValueError("Indexing must be 'xy' or 'ij'") + + ndim = len(xi) + if ndim < 1: + raise ValueError("At least one input array is required") + + # Adjust the order of inputs for 'xy' indexing + if indexing == 'xy' and ndim >= 2: + xi = (xi[1], xi[0]) + xi[2:] + + # Get the lengths of each input array + shapes = [len(arr) for arr in xi] + + # Create the output grids + grids = [] + if not sparse: + for i, x in enumerate(xi): + if i == 0: + # Repeat for columns (x-axis direction) + grid = [list(x) for _ in range(shapes[1])] + else: + # Repeat for rows (y-axis direction) + grid = [[x_val] * shapes[0] for x_val in x] + grids.append(array(grid)) + else: + for i, x in enumerate(xi): + shape = [1] * ndim + shape[i] = len(x) + grids.append(array(x)) + + # Swap back grids if 'xy' indexing + if indexing == 'xy' and ndim >= 2: + grids[0], grids[1] = grids[1], grids[0] + + return tuple(grids) + + def add(ndarray_vec1, ndarray_vec2): c = [] for a, b in zip(ndarray_vec1, ndarray_vec2): @@ -484,6 +524,25 @@ def asfortranarray(self): return out +def sqrt(x): + """ + Returns: + ndarry: Array with dtype of float64 + + """ + if isinstance(x, ndarray): + # create arr of same shape and dtype + out = empty(x.shape, dtype="float64") + # apply sqrt + out._data[:] = [value**0.5 if value >= 0 else float ('nan') for value in x._toflatlist()] + return out + elif isinstance(x, (int, float)): + return x**0.5 + else: + raise TypeError("Unsupported type for sqrt") + + + class ndarray(object): """ ndarray(shape, dtype='float64', buffer=None, offset=0, strides=None, order=None) From e37a71f9a3cac2b985ecd10ca445dfa5fe9f45e3 Mon Sep 17 00:00:00 2001 From: BChass <34097574+Bchass@users.noreply.github.com> Date: Wed, 20 Nov 2024 13:03:12 -0500 Subject: [PATCH 02/10] test cases --- tinynumpy/tests/test_tinynumpy.py | 50 ++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/tinynumpy/tests/test_tinynumpy.py b/tinynumpy/tests/test_tinynumpy.py index 21bf898..6bb4409 100644 --- a/tinynumpy/tests/test_tinynumpy.py +++ b/tinynumpy/tests/test_tinynumpy.py @@ -1097,7 +1097,55 @@ def test_logspace(): result = tnp.logspace(2.0, 3.0, num=4, base=[2.0, 3.0], axis=-1) expected_result = tnp.array([9.0, 12.980246132766677, 18.720754407467133, 27.0]) assert all(result[i] == expected_result[i] for i in range(len(result))) - + +def test_meshgrid(): + """test the meshgrid function for tinynumpy""" + # Cartesian indexing + nx, ny = (3, 2) + x = tnp.linspace(0, 1, nx) + y = tnp.linspace(0, 1, ny) + xv, yv = tnp.meshgrid(x, y, indexing='xy') + + xv_expected_result = tnp.array([[0.0, 0.0], + [0.5, 0.5], + [1.0, 1.0]]) + + yv_expected_result = tnp.array([[0.0, 1.0], + [0.0, 1.0], + [0.0, 1.0]]) + + assert (xv == xv_expected_result).all() + assert (yv == yv_expected_result).all() + + # Matrix indexing + ni, nj = (3, 2) + i = tnp.linspace(0, 1, ni) + j = tnp.linspace(0, 1, nj) + iv, jv = tnp.meshgrid(i, j, indexing='ij', sparse=True) + + iv_expected_result = tnp.array([0.0, 0.5, 1.0]) + + jv_expected_result = tnp.array([0.0, 1.0]) + + assert (iv == iv_expected_result).all() + assert (jv == jv_expected_result).all() + + # coordiante arrays + x = tnp.linspace(-5, 5, 101) + y = tnp.linspace(-5, 5, 101) + xx, yy = tnp.meshgrid(x,y) + zz = tnp.sqrt(xx**2 + yy**2) + + xx_shape_expected = (101, 101) + yy_shape_expected = (101, 101) + zz_shape_expected = (101, 101) + + assert (xx.shape == xx_shape_expected) + assert (yy.shape == yy_shape_expected) + assert (zz.shape == zz_shape_expected) + + + def test_astype(): """test the astype function for tinynumpy""" for dtype in ['bool', 'int8', 'uint8', 'int16', 'uint16', From 44d5435e62c7bdc6d614aafd2e006d0f982e2377 Mon Sep 17 00:00:00 2001 From: BChass <34097574+Bchass@users.noreply.github.com> Date: Wed, 20 Nov 2024 13:51:25 -0500 Subject: [PATCH 03/10] cover missing lines for meshgrid --- tinynumpy/tests/test_tinynumpy.py | 8 ++++++++ tinynumpy/tinynumpy.py | 25 +++++++++++++++++++------ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/tinynumpy/tests/test_tinynumpy.py b/tinynumpy/tests/test_tinynumpy.py index 6bb4409..d62c045 100644 --- a/tinynumpy/tests/test_tinynumpy.py +++ b/tinynumpy/tests/test_tinynumpy.py @@ -1144,6 +1144,14 @@ def test_meshgrid(): assert (yy.shape == yy_shape_expected) assert (zz.shape == zz_shape_expected) + # value error for indexing + with pytest.raises(ValueError): + xv, yv = tnp.meshgrid(x, y, indexing='xi') + + # value error for len shapes < 1 + with pytest.raises(ValueError): + xv, yv = tnp.meshgrid(x, indexing='xy') + def test_astype(): diff --git a/tinynumpy/tinynumpy.py b/tinynumpy/tinynumpy.py index 8d57040..73e6ef9 100644 --- a/tinynumpy/tinynumpy.py +++ b/tinynumpy/tinynumpy.py @@ -364,6 +364,11 @@ def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None): return a def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=None): + """ logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=None) + + Return numbers spaced evenly on a log scale. + + """ start, stop = float(start), float(stop) ra = stop - start @@ -384,19 +389,26 @@ def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=Non def meshgrid(*xi, copy=True, sparse=False, indexing='xy'): + """ meshgrid(*xi, copy=True, sparse=False, indexing='xy') + + Return a tuple of coordinate matrices from coordinate vectors. + + """ + + ndim = len(xi) + if indexing not in {'xy', 'ij'}: raise ValueError("Indexing must be 'xy' or 'ij'") - ndim = len(xi) - if ndim < 1: - raise ValueError("At least one input array is required") - # Adjust the order of inputs for 'xy' indexing - if indexing == 'xy' and ndim >= 2: + if indexing == 'xy' and ndim > 1: xi = (xi[1], xi[0]) + xi[2:] # Get the lengths of each input array - shapes = [len(arr) for arr in xi] + shapes = [len(x) for x in xi] + + if len(shapes) < 2: + raise ValueError("At least two input arrays are required") # Create the output grids grids = [] @@ -405,6 +417,7 @@ def meshgrid(*xi, copy=True, sparse=False, indexing='xy'): if i == 0: # Repeat for columns (x-axis direction) grid = [list(x) for _ in range(shapes[1])] + print(grid) else: # Repeat for rows (y-axis direction) grid = [[x_val] * shapes[0] for x_val in x] From 8fadd2ddd3ed9bac5d1037d664f83958e4fb3fdc Mon Sep 17 00:00:00 2001 From: BChass <34097574+Bchass@users.noreply.github.com> Date: Thu, 21 Nov 2024 13:58:08 -0500 Subject: [PATCH 04/10] sqrt for meshgrid --- tinynumpy/tinynumpy.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tinynumpy/tinynumpy.py b/tinynumpy/tinynumpy.py index 73e6ef9..5639bc5 100644 --- a/tinynumpy/tinynumpy.py +++ b/tinynumpy/tinynumpy.py @@ -541,8 +541,15 @@ def sqrt(x): """ Returns: ndarry: Array with dtype of float64 + list: List with sqrt applied """ + + # if a list is passed + if isinstance(x, list): + return [str(sqrt(i)).rstrip('0') for i in x] + + if isinstance(x, ndarray): # create arr of same shape and dtype out = empty(x.shape, dtype="float64") From a1064938f640dc5d2aa267ad36fdf091ea6f0d39 Mon Sep 17 00:00:00 2001 From: BChass <34097574+Bchass@users.noreply.github.com> Date: Thu, 21 Nov 2024 13:58:14 -0500 Subject: [PATCH 05/10] test cases --- tinynumpy/tests/test_tinynumpy.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tinynumpy/tests/test_tinynumpy.py b/tinynumpy/tests/test_tinynumpy.py index d62c045..1f79083 100644 --- a/tinynumpy/tests/test_tinynumpy.py +++ b/tinynumpy/tests/test_tinynumpy.py @@ -1152,7 +1152,22 @@ def test_meshgrid(): with pytest.raises(ValueError): xv, yv = tnp.meshgrid(x, indexing='xy') +def test_sqrt(): + """test the sqrt function for tinynumpy""" + # basic sqrt + x = tnp.sqrt(2) + expected_result = float(1.4142135623730951) + assert x == expected_result + + # pass a list + x = tnp.sqrt([1,4,9]) + expected_result = list(['1.', '2.', '3.']) + assert x == expected_result + + # complex numbers not supported + with pytest.raises(TypeError): + tnp.sqrt([4, -1, -3+4J]) def test_astype(): """test the astype function for tinynumpy""" From a754e378fb3ce691b01820949bde0df48f66e138 Mon Sep 17 00:00:00 2001 From: BChass <34097574+Bchass@users.noreply.github.com> Date: Fri, 22 Nov 2024 11:11:03 -0500 Subject: [PATCH 06/10] More test cases --- tinynumpy/tests/test_tinynumpy.py | 78 ++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/tinynumpy/tests/test_tinynumpy.py b/tinynumpy/tests/test_tinynumpy.py index 1f79083..91a4880 100644 --- a/tinynumpy/tests/test_tinynumpy.py +++ b/tinynumpy/tests/test_tinynumpy.py @@ -1153,21 +1153,87 @@ def test_meshgrid(): xv, yv = tnp.meshgrid(x, indexing='xy') def test_sqrt(): - """test the sqrt function for tinynumpy""" + """Test the sqrt function for tinynumpy.""" - # basic sqrt + # --- Scalar values --- + # Positive integer x = tnp.sqrt(2) expected_result = float(1.4142135623730951) assert x == expected_result - # pass a list - x = tnp.sqrt([1,4,9]) - expected_result = list(['1.', '2.', '3.']) + # Positive float + x = tnp.sqrt(4.0) + expected_result = float(2.0) assert x == expected_result - # complex numbers not supported + # Zero + x = tnp.sqrt(0) + expected_result = float(0.0) + assert x == expected_result + + # Negative number (returns nan) + x = tnp.sqrt(-1) + expected_result = 'nan' + assert str(x) == str(expected_result) + + # Large number + x = tnp.sqrt(1e16) + expected_result = float(100000000.0) + assert x == expected_result + + # Small number + x = tnp.sqrt(1e-16) + expected_result = float(1e-08) + assert x == expected_result + + # Multi-dimensional + x = tnp.sqrt(tnp.array([[1, 4], [9, 16]])) + expected_result = tnp.array([[1, 2], + [3, 4]]) + assert x == expected_result + + # Zero + x = tnp.sqrt(0) + expected_result = float(0.0) + assert x == expected_result + + # --- Lists --- + # Simple positive list + x = tnp.sqrt([1, 4, 9]) + expected_result = ['1.', '2.', '3.'] + assert x == expected_result + + # List with negative number + x = tnp.sqrt([1, -4, 9]) + expected_result = ['1.', 'nan', '3.'] + assert x == expected_result + + # Mixed + x = tnp.sqrt([1, 4.0, 9]) + expected_result = ['1.', '2.', '3.'] + assert x == expected_result + + # Empty input + x = tnp.sqrt([]) + expected_result = [] + assert x == expected_result + + # --- Error handling --- + # Complex numbers (unsupported) with pytest.raises(TypeError): tnp.sqrt([4, -1, -3+4J]) + + # non-numeric types + with pytest.raises(TypeError): + tnp.sqrt("string") + + with pytest.raises(TypeError): + tnp.sqrt(None) + + # Make sure no modifcations are done + x = tnp.array([1, 4, 9]) + result = tnp.sqrt(x) + assert x._toflatlist() == [1, 4, 9] def test_astype(): """test the astype function for tinynumpy""" From ea2f770c60ee01ba9d0d6ff7d67ba94436193520 Mon Sep 17 00:00:00 2001 From: BChass <34097574+Bchass@users.noreply.github.com> Date: Fri, 22 Nov 2024 11:11:32 -0500 Subject: [PATCH 07/10] More checks and simplify --- tinynumpy/tinynumpy.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tinynumpy/tinynumpy.py b/tinynumpy/tinynumpy.py index 5639bc5..cc354ab 100644 --- a/tinynumpy/tinynumpy.py +++ b/tinynumpy/tinynumpy.py @@ -541,23 +541,22 @@ def sqrt(x): """ Returns: ndarry: Array with dtype of float64 - list: List with sqrt applied - """ - - # if a list is passed - if isinstance(x, list): - return [str(sqrt(i)).rstrip('0') for i in x] - + list: List with sqrt applied + """ + # TODO: Fix format for nested lists if isinstance(x, ndarray): # create arr of same shape and dtype out = empty(x.shape, dtype="float64") # apply sqrt - out._data[:] = [value**0.5 if value >= 0 else float ('nan') for value in x._toflatlist()] + out._data[:] = [value**0.5 if value >= 0 else nan for value in x._toflatlist()] return out elif isinstance(x, (int, float)): - return x**0.5 + return x**0.5 if x >= 0 else nan + # list + elif isinstance(x, list): + return [str(sqrt(i)).rstrip('0') for i in x] else: raise TypeError("Unsupported type for sqrt") From 3a8db0ee0dc577a8abfc973a1c0590f052e0879f Mon Sep 17 00:00:00 2001 From: BChass <34097574+Bchass@users.noreply.github.com> Date: Fri, 22 Nov 2024 15:18:31 -0500 Subject: [PATCH 08/10] fix formats --- tinynumpy/tinynumpy.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tinynumpy/tinynumpy.py b/tinynumpy/tinynumpy.py index cc354ab..8d801ce 100644 --- a/tinynumpy/tinynumpy.py +++ b/tinynumpy/tinynumpy.py @@ -545,7 +545,7 @@ def sqrt(x): list: List with sqrt applied """ - # TODO: Fix format for nested lists + if isinstance(x, ndarray): # create arr of same shape and dtype out = empty(x.shape, dtype="float64") @@ -553,10 +553,10 @@ def sqrt(x): out._data[:] = [value**0.5 if value >= 0 else nan for value in x._toflatlist()] return out elif isinstance(x, (int, float)): - return x**0.5 if x >= 0 else nan + return x**0.5 if x >= 0 else float('nan') # list elif isinstance(x, list): - return [str(sqrt(i)).rstrip('0') for i in x] + return [sqrt(i) if isinstance(i, list) else str(i**0.5).rstrip('0') if i >= 0 else 'nan' for i in x] else: raise TypeError("Unsupported type for sqrt") From 7149ed6cbb24779ae8e28453966fac5d312110e5 Mon Sep 17 00:00:00 2001 From: BChass <34097574+Bchass@users.noreply.github.com> Date: Fri, 22 Nov 2024 15:18:39 -0500 Subject: [PATCH 09/10] nested lists --- tinynumpy/tests/test_tinynumpy.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tinynumpy/tests/test_tinynumpy.py b/tinynumpy/tests/test_tinynumpy.py index 91a4880..c892386 100644 --- a/tinynumpy/tests/test_tinynumpy.py +++ b/tinynumpy/tests/test_tinynumpy.py @@ -1213,6 +1213,11 @@ def test_sqrt(): expected_result = ['1.', '2.', '3.'] assert x == expected_result + # Nested lists + x = tnp.sqrt([[1, 4], [9, 16]]) + expected_result = [['1.', '2.'], ['3.', '4.']] + assert x == expected_result + # Empty input x = tnp.sqrt([]) expected_result = [] From a54491338adc544ea31f01320ad2fb4fc3127581 Mon Sep 17 00:00:00 2001 From: BChass <34097574+Bchass@users.noreply.github.com> Date: Mon, 25 Nov 2024 08:55:58 -0500 Subject: [PATCH 10/10] Fix test cases that were failing --- tinynumpy/tests/test_tinyndarray.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tinynumpy/tests/test_tinyndarray.py b/tinynumpy/tests/test_tinyndarray.py index eb9e5c1..fa2e767 100644 --- a/tinynumpy/tests/test_tinyndarray.py +++ b/tinynumpy/tests/test_tinyndarray.py @@ -13,10 +13,8 @@ except ImportError: numpy = tinynumpy -#numpy.set_printoptions(formatter={'float': repr}) - def _clean_repr(a): - return "".join(repr(a).split()) + return "".join(repr(a).replace('.', '').split()) class TestNDArray(unittest.TestCase): def setUp(self):