diff --git a/nifty5/data_objects/distributed_do.py b/nifty5/data_objects/distributed_do.py index da44fac7983b1574f1a03d3b9119a396b6ef447b..ac4bc2327205c7ab426a093e9a119047ca28248e 100644 --- a/nifty5/data_objects/distributed_do.py +++ b/nifty5/data_objects/distributed_do.py @@ -32,7 +32,7 @@ __all__ = ["ntask", "rank", "master", "local_shape", "data_object", "full", "local_data", "ibegin", "ibegin_from_shape", "np_allreduce_sum", "np_allreduce_min", "np_allreduce_max", "distaxis", "from_local_data", "from_global_data", "to_global_data", - "redistribute", "default_distaxis", "is_numpy", + "redistribute", "default_distaxis", "is_numpy", "absmax", "norm", "lock", "locked", "uniform_full", "transpose", "to_global_data_rw", "ensure_not_distributed", "ensure_default_distributed"] @@ -553,3 +553,22 @@ def ensure_default_distributed(arr): if arr._distaxis != 0: arr = redistribute(arr, dist=0) return arr + + +def absmax(arr): + if arr._data.size == 0: + tmp = np.array(0, dtype=arr._data.dtype) + else: + tmp = np.linalg.norm(arr._data, ord=np.inf) + res = np.empty_like(tmp) + _comm.Allreduce(tmp, res, MPI.MAX) + return res[()] + + +def norm(arr, ord=2): + if ord == np.inf: + return absmax(arr) + tmp = np.linalg.norm(np.atleast_1d(arr._data), ord=ord) ** ord + res = np.empty_like(tmp) + _comm.Allreduce(tmp, res, MPI.SUM) + return res[()] ** (1./ord) diff --git a/nifty5/data_objects/numpy_do.py b/nifty5/data_objects/numpy_do.py index 68cfa99db3fa001d1960d6ca704f2ce6b73ed4f8..9cde82533273cd58eb357e9f3feb83cc0eaf8183 100644 --- a/nifty5/data_objects/numpy_do.py +++ b/nifty5/data_objects/numpy_do.py @@ -31,7 +31,7 @@ __all__ = ["ntask", "rank", "master", "local_shape", "data_object", "full", "local_data", "ibegin", "ibegin_from_shape", "np_allreduce_sum", "np_allreduce_min", "np_allreduce_max", "distaxis", "from_local_data", "from_global_data", "to_global_data", - "redistribute", "default_distaxis", "is_numpy", + "redistribute", "default_distaxis", "is_numpy", "absmax", "norm", "lock", "locked", "uniform_full", "to_global_data_rw", "ensure_not_distributed", "ensure_default_distributed"] @@ -141,3 +141,11 @@ def ensure_not_distributed(arr, axes): def ensure_default_distributed(arr): return arr + + +def absmax(arr): + return np.linalg.norm(arr, ord=np.inf) + + +def norm(arr, ord=2): + return np.linalg.norm(np.atleast_1d(arr), ord=ord) diff --git a/nifty5/field.py b/nifty5/field.py index 0785512d50b98469d57fbfbed19caeab8d1967e8..0c418cc7f47c98182bd0ffec3f2f96bdfee6eb69 100644 --- a/nifty5/field.py +++ b/nifty5/field.py @@ -360,25 +360,20 @@ class Field(object): # For the moment, do this the explicit, non-optimized way return (self.conjugate()*x).sum(spaces=spaces) - def norm(self): + def norm(self, ord=2): """ Computes the L2-norm of the field values. - Returns - ------- - float - The L2-norm of the field values. - """ - return np.sqrt(abs(self.vdot(x=self))) - - def squared_norm(self): - """ Computes the square of the L2-norm of the field values. + Parameters + ---------- + ord : int, default=2 + accepted values: 1, 2, ..., np.inf Returns ------- float - The square of the L2-norm of the field values. + The L2-norm of the field values. """ - return abs(self.vdot(x=self)) + return dobj.norm(self._val, ord) def conjugate(self): """ Returns the complex conjugate of the field. diff --git a/nifty5/multi_field.py b/nifty5/multi_field.py index 5f6aa304a56b31a192295cc8118ba804e9ebaffe..10795f819a834a36687be3eec466f2d926c4dd43 100644 --- a/nifty5/multi_field.py +++ b/nifty5/multi_field.py @@ -137,15 +137,24 @@ class MultiField(object): domain, tuple(Field.from_global_data(domain[key], arr[key], sum_up) for key in domain.keys())) - def norm(self): - """ Computes the L2-norm of the field values. + def norm(self, ord=2): + """ Computes the norm of the field values. + + Parameters + ---------- + ord : int, default=2 + accepted values: 1, 2, ..., np.inf Returns ------- norm : float - The L2-norm of the field values. + The norm of the field values. """ - return np.sqrt(np.abs(self.vdot(x=self))) + nrm = np.asarray([f.norm(ord) for f in self._val]) + if ord == np.inf: + return nrm.max() + return (nrm ** ord).sum() ** (1./ord) +# return np.sqrt(np.abs(self.vdot(x=self))) def sum(self): """ Computes the sum all field values. @@ -168,16 +177,6 @@ class MultiField(object): """ return utilities.my_sum(map(lambda d: d.size, self._domain.domains())) - def squared_norm(self): - """ Computes the square of the L2-norm of the field values. - - Returns - ------- - float - The square of the L2-norm of the field values. - """ - return abs(self.vdot(x=self)) - def __neg__(self): return self._transform(lambda x: -x) diff --git a/test/test_field.py b/test/test_field.py index cfc6f7d0e3ddd7553962f30bfbc2e2545fccce03..fce50f8aeae20bc7d402205b9f22a04c0a49d3f3 100644 --- a/test/test_field.py +++ b/test/test_field.py @@ -110,6 +110,16 @@ class Test_Functionality(unittest.TestCase): assert_allclose(sc1.mean.local_data, fp1.local_data, rtol=0.2) assert_allclose(sc2.mean.local_data, fp2.local_data, rtol=0.2) + def test_norm(self): + s = ift.RGSpace((10,)) + f = ift.Field.from_random("normal", domain=s, dtype=np.complex128) + gd = f.to_global_data() + assert_allclose(f.norm(), np.linalg.norm(gd)) + assert_allclose(f.norm(1), np.linalg.norm(gd, ord=1)) + assert_allclose(f.norm(2), np.linalg.norm(gd, ord=2)) + assert_allclose(f.norm(3), np.linalg.norm(gd, ord=3)) + assert_allclose(f.norm(np.inf), np.linalg.norm(gd, ord=np.inf)) + def test_vdot(self): s = ift.RGSpace((10,)) f1 = ift.Field.from_random("normal", domain=s, dtype=np.complex128)