Chris@87: from __future__ import division, absolute_import, print_function Chris@87: Chris@87: import warnings Chris@87: import sys Chris@87: Chris@87: import numpy as np Chris@87: from numpy.testing import * Chris@87: import unittest Chris@87: Chris@87: class _GenericTest(object): Chris@87: def _test_equal(self, a, b): Chris@87: self._assert_func(a, b) Chris@87: Chris@87: def _test_not_equal(self, a, b): Chris@87: try: Chris@87: self._assert_func(a, b) Chris@87: passed = True Chris@87: except AssertionError: Chris@87: pass Chris@87: else: Chris@87: raise AssertionError("a and b are found equal but are not") Chris@87: Chris@87: def test_array_rank1_eq(self): Chris@87: """Test two equal array of rank 1 are found equal.""" Chris@87: a = np.array([1, 2]) Chris@87: b = np.array([1, 2]) Chris@87: Chris@87: self._test_equal(a, b) Chris@87: Chris@87: def test_array_rank1_noteq(self): Chris@87: """Test two different array of rank 1 are found not equal.""" Chris@87: a = np.array([1, 2]) Chris@87: b = np.array([2, 2]) Chris@87: Chris@87: self._test_not_equal(a, b) Chris@87: Chris@87: def test_array_rank2_eq(self): Chris@87: """Test two equal array of rank 2 are found equal.""" Chris@87: a = np.array([[1, 2], [3, 4]]) Chris@87: b = np.array([[1, 2], [3, 4]]) Chris@87: Chris@87: self._test_equal(a, b) Chris@87: Chris@87: def test_array_diffshape(self): Chris@87: """Test two arrays with different shapes are found not equal.""" Chris@87: a = np.array([1, 2]) Chris@87: b = np.array([[1, 2], [1, 2]]) Chris@87: Chris@87: self._test_not_equal(a, b) Chris@87: Chris@87: def test_objarray(self): Chris@87: """Test object arrays.""" Chris@87: a = np.array([1, 1], dtype=np.object) Chris@87: self._test_equal(a, 1) Chris@87: Chris@87: def test_array_likes(self): Chris@87: self._test_equal([1, 2, 3], (1, 2, 3)) Chris@87: Chris@87: class TestArrayEqual(_GenericTest, unittest.TestCase): Chris@87: def setUp(self): Chris@87: self._assert_func = assert_array_equal Chris@87: Chris@87: def test_generic_rank1(self): Chris@87: """Test rank 1 array for all dtypes.""" Chris@87: def foo(t): Chris@87: a = np.empty(2, t) Chris@87: a.fill(1) Chris@87: b = a.copy() Chris@87: c = a.copy() Chris@87: c.fill(0) Chris@87: self._test_equal(a, b) Chris@87: self._test_not_equal(c, b) Chris@87: Chris@87: # Test numeric types and object Chris@87: for t in '?bhilqpBHILQPfdgFDG': Chris@87: foo(t) Chris@87: Chris@87: # Test strings Chris@87: for t in ['S1', 'U1']: Chris@87: foo(t) Chris@87: Chris@87: def test_generic_rank3(self): Chris@87: """Test rank 3 array for all dtypes.""" Chris@87: def foo(t): Chris@87: a = np.empty((4, 2, 3), t) Chris@87: a.fill(1) Chris@87: b = a.copy() Chris@87: c = a.copy() Chris@87: c.fill(0) Chris@87: self._test_equal(a, b) Chris@87: self._test_not_equal(c, b) Chris@87: Chris@87: # Test numeric types and object Chris@87: for t in '?bhilqpBHILQPfdgFDG': Chris@87: foo(t) Chris@87: Chris@87: # Test strings Chris@87: for t in ['S1', 'U1']: Chris@87: foo(t) Chris@87: Chris@87: def test_nan_array(self): Chris@87: """Test arrays with nan values in them.""" Chris@87: a = np.array([1, 2, np.nan]) Chris@87: b = np.array([1, 2, np.nan]) Chris@87: Chris@87: self._test_equal(a, b) Chris@87: Chris@87: c = np.array([1, 2, 3]) Chris@87: self._test_not_equal(c, b) Chris@87: Chris@87: def test_string_arrays(self): Chris@87: """Test two arrays with different shapes are found not equal.""" Chris@87: a = np.array(['floupi', 'floupa']) Chris@87: b = np.array(['floupi', 'floupa']) Chris@87: Chris@87: self._test_equal(a, b) Chris@87: Chris@87: c = np.array(['floupipi', 'floupa']) Chris@87: Chris@87: self._test_not_equal(c, b) Chris@87: Chris@87: def test_recarrays(self): Chris@87: """Test record arrays.""" Chris@87: a = np.empty(2, [('floupi', np.float), ('floupa', np.float)]) Chris@87: a['floupi'] = [1, 2] Chris@87: a['floupa'] = [1, 2] Chris@87: b = a.copy() Chris@87: Chris@87: self._test_equal(a, b) Chris@87: Chris@87: c = np.empty(2, [('floupipi', np.float), ('floupa', np.float)]) Chris@87: c['floupipi'] = a['floupi'].copy() Chris@87: c['floupa'] = a['floupa'].copy() Chris@87: Chris@87: self._test_not_equal(c, b) Chris@87: Chris@87: class TestBuildErrorMessage(unittest.TestCase): Chris@87: def test_build_err_msg_defaults(self): Chris@87: x = np.array([1.00001, 2.00002, 3.00003]) Chris@87: y = np.array([1.00002, 2.00003, 3.00004]) Chris@87: err_msg = 'There is a mismatch' Chris@87: Chris@87: a = build_err_msg([x, y], err_msg) Chris@87: b = ('\nItems are not equal: There is a mismatch\n ACTUAL: array([ ' Chris@87: '1.00001, 2.00002, 3.00003])\n DESIRED: array([ 1.00002, ' Chris@87: '2.00003, 3.00004])') Chris@87: self.assertEqual(a, b) Chris@87: Chris@87: def test_build_err_msg_no_verbose(self): Chris@87: x = np.array([1.00001, 2.00002, 3.00003]) Chris@87: y = np.array([1.00002, 2.00003, 3.00004]) Chris@87: err_msg = 'There is a mismatch' Chris@87: Chris@87: a = build_err_msg([x, y], err_msg, verbose=False) Chris@87: b = '\nItems are not equal: There is a mismatch' Chris@87: self.assertEqual(a, b) Chris@87: Chris@87: def test_build_err_msg_custom_names(self): Chris@87: x = np.array([1.00001, 2.00002, 3.00003]) Chris@87: y = np.array([1.00002, 2.00003, 3.00004]) Chris@87: err_msg = 'There is a mismatch' Chris@87: Chris@87: a = build_err_msg([x, y], err_msg, names=('FOO', 'BAR')) Chris@87: b = ('\nItems are not equal: There is a mismatch\n FOO: array([ ' Chris@87: '1.00001, 2.00002, 3.00003])\n BAR: array([ 1.00002, 2.00003, ' Chris@87: '3.00004])') Chris@87: self.assertEqual(a, b) Chris@87: Chris@87: def test_build_err_msg_custom_precision(self): Chris@87: x = np.array([1.000000001, 2.00002, 3.00003]) Chris@87: y = np.array([1.000000002, 2.00003, 3.00004]) Chris@87: err_msg = 'There is a mismatch' Chris@87: Chris@87: a = build_err_msg([x, y], err_msg, precision=10) Chris@87: b = ('\nItems are not equal: There is a mismatch\n ACTUAL: array([ ' Chris@87: '1.000000001, 2.00002 , 3.00003 ])\n DESIRED: array([ ' Chris@87: '1.000000002, 2.00003 , 3.00004 ])') Chris@87: self.assertEqual(a, b) Chris@87: Chris@87: class TestEqual(TestArrayEqual): Chris@87: def setUp(self): Chris@87: self._assert_func = assert_equal Chris@87: Chris@87: def test_nan_items(self): Chris@87: self._assert_func(np.nan, np.nan) Chris@87: self._assert_func([np.nan], [np.nan]) Chris@87: self._test_not_equal(np.nan, [np.nan]) Chris@87: self._test_not_equal(np.nan, 1) Chris@87: Chris@87: def test_inf_items(self): Chris@87: self._assert_func(np.inf, np.inf) Chris@87: self._assert_func([np.inf], [np.inf]) Chris@87: self._test_not_equal(np.inf, [np.inf]) Chris@87: Chris@87: def test_non_numeric(self): Chris@87: self._assert_func('ab', 'ab') Chris@87: self._test_not_equal('ab', 'abb') Chris@87: Chris@87: def test_complex_item(self): Chris@87: self._assert_func(complex(1, 2), complex(1, 2)) Chris@87: self._assert_func(complex(1, np.nan), complex(1, np.nan)) Chris@87: self._test_not_equal(complex(1, np.nan), complex(1, 2)) Chris@87: self._test_not_equal(complex(np.nan, 1), complex(1, np.nan)) Chris@87: self._test_not_equal(complex(np.nan, np.inf), complex(np.nan, 2)) Chris@87: Chris@87: def test_negative_zero(self): Chris@87: self._test_not_equal(np.PZERO, np.NZERO) Chris@87: Chris@87: def test_complex(self): Chris@87: x = np.array([complex(1, 2), complex(1, np.nan)]) Chris@87: y = np.array([complex(1, 2), complex(1, 2)]) Chris@87: self._assert_func(x, x) Chris@87: self._test_not_equal(x, y) Chris@87: Chris@87: class TestArrayAlmostEqual(_GenericTest, unittest.TestCase): Chris@87: def setUp(self): Chris@87: self._assert_func = assert_array_almost_equal Chris@87: Chris@87: def test_simple(self): Chris@87: x = np.array([1234.2222]) Chris@87: y = np.array([1234.2223]) Chris@87: Chris@87: self._assert_func(x, y, decimal=3) Chris@87: self._assert_func(x, y, decimal=4) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda: self._assert_func(x, y, decimal=5)) Chris@87: Chris@87: def test_nan(self): Chris@87: anan = np.array([np.nan]) Chris@87: aone = np.array([1]) Chris@87: ainf = np.array([np.inf]) Chris@87: self._assert_func(anan, anan) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda : self._assert_func(anan, aone)) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda : self._assert_func(anan, ainf)) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda : self._assert_func(ainf, anan)) Chris@87: Chris@87: def test_inf(self): Chris@87: a = np.array([[1., 2.], [3., 4.]]) Chris@87: b = a.copy() Chris@87: a[0, 0] = np.inf Chris@87: self.assertRaises(AssertionError, Chris@87: lambda : self._assert_func(a, b)) Chris@87: Chris@87: def test_subclass(self): Chris@87: a = np.array([[1., 2.], [3., 4.]]) Chris@87: b = np.ma.masked_array([[1., 2.], [0., 4.]], Chris@87: [[False, False], [True, False]]) Chris@87: assert_array_almost_equal(a, b) Chris@87: assert_array_almost_equal(b, a) Chris@87: assert_array_almost_equal(b, b) Chris@87: Chris@87: class TestAlmostEqual(_GenericTest, unittest.TestCase): Chris@87: def setUp(self): Chris@87: self._assert_func = assert_almost_equal Chris@87: Chris@87: def test_nan_item(self): Chris@87: self._assert_func(np.nan, np.nan) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda : self._assert_func(np.nan, 1)) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda : self._assert_func(np.nan, np.inf)) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda : self._assert_func(np.inf, np.nan)) Chris@87: Chris@87: def test_inf_item(self): Chris@87: self._assert_func(np.inf, np.inf) Chris@87: self._assert_func(-np.inf, -np.inf) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda : self._assert_func(np.inf, 1)) Chris@87: Chris@87: def test_simple_item(self): Chris@87: self._test_not_equal(1, 2) Chris@87: Chris@87: def test_complex_item(self): Chris@87: self._assert_func(complex(1, 2), complex(1, 2)) Chris@87: self._assert_func(complex(1, np.nan), complex(1, np.nan)) Chris@87: self._assert_func(complex(np.inf, np.nan), complex(np.inf, np.nan)) Chris@87: self._test_not_equal(complex(1, np.nan), complex(1, 2)) Chris@87: self._test_not_equal(complex(np.nan, 1), complex(1, np.nan)) Chris@87: self._test_not_equal(complex(np.nan, np.inf), complex(np.nan, 2)) Chris@87: Chris@87: def test_complex(self): Chris@87: x = np.array([complex(1, 2), complex(1, np.nan)]) Chris@87: z = np.array([complex(1, 2), complex(np.nan, 1)]) Chris@87: y = np.array([complex(1, 2), complex(1, 2)]) Chris@87: self._assert_func(x, x) Chris@87: self._test_not_equal(x, y) Chris@87: self._test_not_equal(x, z) Chris@87: Chris@87: def test_error_message(self): Chris@87: """Check the message is formatted correctly for the decimal value""" Chris@87: x = np.array([1.00000000001, 2.00000000002, 3.00003]) Chris@87: y = np.array([1.00000000002, 2.00000000003, 3.00004]) Chris@87: Chris@87: # test with a different amount of decimal digits Chris@87: # note that we only check for the formatting of the arrays themselves Chris@87: b = ('x: array([ 1.00000000001, 2.00000000002, 3.00003 ' Chris@87: ' ])\n y: array([ 1.00000000002, 2.00000000003, 3.00004 ])') Chris@87: try: Chris@87: self._assert_func(x, y, decimal=12) Chris@87: except AssertionError as e: Chris@87: # remove anything that's not the array string Chris@87: self.assertEqual(str(e).split('%)\n ')[1], b) Chris@87: Chris@87: # with the default value of decimal digits, only the 3rd element differs Chris@87: # note that we only check for the formatting of the arrays themselves Chris@87: b = ('x: array([ 1. , 2. , 3.00003])\n y: array([ 1. , ' Chris@87: '2. , 3.00004])') Chris@87: try: Chris@87: self._assert_func(x, y) Chris@87: except AssertionError as e: Chris@87: # remove anything that's not the array string Chris@87: self.assertEqual(str(e).split('%)\n ')[1], b) Chris@87: Chris@87: class TestApproxEqual(unittest.TestCase): Chris@87: def setUp(self): Chris@87: self._assert_func = assert_approx_equal Chris@87: Chris@87: def test_simple_arrays(self): Chris@87: x = np.array([1234.22]) Chris@87: y = np.array([1234.23]) Chris@87: Chris@87: self._assert_func(x, y, significant=5) Chris@87: self._assert_func(x, y, significant=6) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda: self._assert_func(x, y, significant=7)) Chris@87: Chris@87: def test_simple_items(self): Chris@87: x = 1234.22 Chris@87: y = 1234.23 Chris@87: Chris@87: self._assert_func(x, y, significant=4) Chris@87: self._assert_func(x, y, significant=5) Chris@87: self._assert_func(x, y, significant=6) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda: self._assert_func(x, y, significant=7)) Chris@87: Chris@87: def test_nan_array(self): Chris@87: anan = np.array(np.nan) Chris@87: aone = np.array(1) Chris@87: ainf = np.array(np.inf) Chris@87: self._assert_func(anan, anan) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda : self._assert_func(anan, aone)) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda : self._assert_func(anan, ainf)) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda : self._assert_func(ainf, anan)) Chris@87: Chris@87: def test_nan_items(self): Chris@87: anan = np.array(np.nan) Chris@87: aone = np.array(1) Chris@87: ainf = np.array(np.inf) Chris@87: self._assert_func(anan, anan) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda : self._assert_func(anan, aone)) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda : self._assert_func(anan, ainf)) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda : self._assert_func(ainf, anan)) Chris@87: Chris@87: class TestRaises(unittest.TestCase): Chris@87: def setUp(self): Chris@87: class MyException(Exception): Chris@87: pass Chris@87: Chris@87: self.e = MyException Chris@87: Chris@87: def raises_exception(self, e): Chris@87: raise e Chris@87: Chris@87: def does_not_raise_exception(self): Chris@87: pass Chris@87: Chris@87: def test_correct_catch(self): Chris@87: f = raises(self.e)(self.raises_exception)(self.e) Chris@87: Chris@87: def test_wrong_exception(self): Chris@87: try: Chris@87: f = raises(self.e)(self.raises_exception)(RuntimeError) Chris@87: except RuntimeError: Chris@87: return Chris@87: else: Chris@87: raise AssertionError("should have caught RuntimeError") Chris@87: Chris@87: def test_catch_no_raise(self): Chris@87: try: Chris@87: f = raises(self.e)(self.does_not_raise_exception)() Chris@87: except AssertionError: Chris@87: return Chris@87: else: Chris@87: raise AssertionError("should have raised an AssertionError") Chris@87: Chris@87: class TestWarns(unittest.TestCase): Chris@87: def test_warn(self): Chris@87: def f(): Chris@87: warnings.warn("yo") Chris@87: return 3 Chris@87: Chris@87: before_filters = sys.modules['warnings'].filters[:] Chris@87: assert_equal(assert_warns(UserWarning, f), 3) Chris@87: after_filters = sys.modules['warnings'].filters Chris@87: Chris@87: assert_raises(AssertionError, assert_no_warnings, f) Chris@87: assert_equal(assert_no_warnings(lambda x: x, 1), 1) Chris@87: Chris@87: # Check that the warnings state is unchanged Chris@87: assert_equal(before_filters, after_filters, Chris@87: "assert_warns does not preserver warnings state") Chris@87: Chris@87: def test_warn_wrong_warning(self): Chris@87: def f(): Chris@87: warnings.warn("yo", DeprecationWarning) Chris@87: Chris@87: failed = False Chris@87: filters = sys.modules['warnings'].filters[:] Chris@87: try: Chris@87: try: Chris@87: # Should raise an AssertionError Chris@87: assert_warns(UserWarning, f) Chris@87: failed = True Chris@87: except AssertionError: Chris@87: pass Chris@87: finally: Chris@87: sys.modules['warnings'].filters = filters Chris@87: Chris@87: if failed: Chris@87: raise AssertionError("wrong warning caught by assert_warn") Chris@87: Chris@87: class TestAssertAllclose(unittest.TestCase): Chris@87: def test_simple(self): Chris@87: x = 1e-3 Chris@87: y = 1e-9 Chris@87: Chris@87: assert_allclose(x, y, atol=1) Chris@87: self.assertRaises(AssertionError, assert_allclose, x, y) Chris@87: Chris@87: a = np.array([x, y, x, y]) Chris@87: b = np.array([x, y, x, x]) Chris@87: Chris@87: assert_allclose(a, b, atol=1) Chris@87: self.assertRaises(AssertionError, assert_allclose, a, b) Chris@87: Chris@87: b[-1] = y * (1 + 1e-8) Chris@87: assert_allclose(a, b) Chris@87: self.assertRaises(AssertionError, assert_allclose, a, b, Chris@87: rtol=1e-9) Chris@87: Chris@87: assert_allclose(6, 10, rtol=0.5) Chris@87: self.assertRaises(AssertionError, assert_allclose, 10, 6, rtol=0.5) Chris@87: Chris@87: def test_min_int(self): Chris@87: a = np.array([np.iinfo(np.int_).min], dtype=np.int_) Chris@87: # Should not raise: Chris@87: assert_allclose(a, a) Chris@87: Chris@87: Chris@87: class TestArrayAlmostEqualNulp(unittest.TestCase): Chris@87: @dec.knownfailureif(True, "Github issue #347") Chris@87: def test_simple(self): Chris@87: np.random.seed(12345) Chris@87: for i in range(100): Chris@87: dev = np.random.randn(10) Chris@87: x = np.ones(10) Chris@87: y = x + dev * np.finfo(np.float64).eps Chris@87: assert_array_almost_equal_nulp(x, y, nulp=2 * np.max(dev)) Chris@87: Chris@87: def test_simple2(self): Chris@87: x = np.random.randn(10) Chris@87: y = 2 * x Chris@87: def failure(): Chris@87: return assert_array_almost_equal_nulp(x, y, Chris@87: nulp=1000) Chris@87: self.assertRaises(AssertionError, failure) Chris@87: Chris@87: def test_big_float32(self): Chris@87: x = (1e10 * np.random.randn(10)).astype(np.float32) Chris@87: y = x + 1 Chris@87: assert_array_almost_equal_nulp(x, y, nulp=1000) Chris@87: Chris@87: def test_big_float64(self): Chris@87: x = 1e10 * np.random.randn(10) Chris@87: y = x + 1 Chris@87: def failure(): Chris@87: assert_array_almost_equal_nulp(x, y, nulp=1000) Chris@87: self.assertRaises(AssertionError, failure) Chris@87: Chris@87: def test_complex(self): Chris@87: x = np.random.randn(10) + 1j * np.random.randn(10) Chris@87: y = x + 1 Chris@87: def failure(): Chris@87: assert_array_almost_equal_nulp(x, y, nulp=1000) Chris@87: self.assertRaises(AssertionError, failure) Chris@87: Chris@87: def test_complex2(self): Chris@87: x = np.random.randn(10) Chris@87: y = np.array(x, np.complex) + 1e-16 * np.random.randn(10) Chris@87: Chris@87: assert_array_almost_equal_nulp(x, y, nulp=1000) Chris@87: Chris@87: class TestULP(unittest.TestCase): Chris@87: def test_equal(self): Chris@87: x = np.random.randn(10) Chris@87: assert_array_max_ulp(x, x, maxulp=0) Chris@87: Chris@87: def test_single(self): Chris@87: # Generate 1 + small deviation, check that adding eps gives a few UNL Chris@87: x = np.ones(10).astype(np.float32) Chris@87: x += 0.01 * np.random.randn(10).astype(np.float32) Chris@87: eps = np.finfo(np.float32).eps Chris@87: assert_array_max_ulp(x, x+eps, maxulp=20) Chris@87: Chris@87: def test_double(self): Chris@87: # Generate 1 + small deviation, check that adding eps gives a few UNL Chris@87: x = np.ones(10).astype(np.float64) Chris@87: x += 0.01 * np.random.randn(10).astype(np.float64) Chris@87: eps = np.finfo(np.float64).eps Chris@87: assert_array_max_ulp(x, x+eps, maxulp=200) Chris@87: Chris@87: def test_inf(self): Chris@87: for dt in [np.float32, np.float64]: Chris@87: inf = np.array([np.inf]).astype(dt) Chris@87: big = np.array([np.finfo(dt).max]) Chris@87: assert_array_max_ulp(inf, big, maxulp=200) Chris@87: Chris@87: def test_nan(self): Chris@87: # Test that nan is 'far' from small, tiny, inf, max and min Chris@87: for dt in [np.float32, np.float64]: Chris@87: if dt == np.float32: Chris@87: maxulp = 1e6 Chris@87: else: Chris@87: maxulp = 1e12 Chris@87: inf = np.array([np.inf]).astype(dt) Chris@87: nan = np.array([np.nan]).astype(dt) Chris@87: big = np.array([np.finfo(dt).max]) Chris@87: tiny = np.array([np.finfo(dt).tiny]) Chris@87: zero = np.array([np.PZERO]).astype(dt) Chris@87: nzero = np.array([np.NZERO]).astype(dt) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda: assert_array_max_ulp(nan, inf, Chris@87: maxulp=maxulp)) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda: assert_array_max_ulp(nan, big, Chris@87: maxulp=maxulp)) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda: assert_array_max_ulp(nan, tiny, Chris@87: maxulp=maxulp)) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda: assert_array_max_ulp(nan, zero, Chris@87: maxulp=maxulp)) Chris@87: self.assertRaises(AssertionError, Chris@87: lambda: assert_array_max_ulp(nan, nzero, Chris@87: maxulp=maxulp)) Chris@87: if __name__ == '__main__': Chris@87: run_module_suite()