diff --git a/demos/bernoulli_demo.py b/demos/bernoulli_demo.py index d8eb410663422f0b7954c449fdabaa06e766bf32..76fec1a116c4f7d804ff108e6935645d6e4e06ef 100644 --- a/demos/bernoulli_demo.py +++ b/demos/bernoulli_demo.py @@ -52,7 +52,7 @@ if __name__ == '__main__': A = ift.create_power_operator(harmonic_space, sqrtpspec) # Set up a sky operator and instrumental response - sky = HT(A).ptw("sigmoid") + sky = ift.sigmoid(HT(A)) GR = ift.GeometryRemover(position_space) R = GR diff --git a/demos/getting_started_2.py b/demos/getting_started_2.py index 49168d45bf8da023a2fbadab88839b96e9695351..7856049d9efac5bb6ca51ce3745be05f0b5a446a 100644 --- a/demos/getting_started_2.py +++ b/demos/getting_started_2.py @@ -80,7 +80,7 @@ if __name__ == '__main__': A = pd(a) # Define sky operator - sky = HT(ift.makeOp(A)).ptw("exp") + sky = ift.exp(HT(ift.makeOp(A))) M = ift.DiagonalOperator(exposure) GR = ift.GeometryRemover(position_space) diff --git a/demos/getting_started_3.py b/demos/getting_started_3.py index b4da83a885fd7fd14d46c76d10648bfcfcda28c3..d83bcf14fa9554291bb1855ca28f78fbbed007f6 100644 --- a/demos/getting_started_3.py +++ b/demos/getting_started_3.py @@ -85,7 +85,7 @@ if __name__ == '__main__': A = cfmaker.amplitude # Apply a nonlinearity - signal = correlated_field.ptw("sigmoid") + signal = ift.sigmoid(correlated_field) # Build the line-of-sight response and define signal response LOS_starts, LOS_ends = random_los(100) if mode == 0 else radial_los(100) @@ -149,7 +149,7 @@ if __name__ == '__main__': filename_res = filename.format("results") plot = ift.Plot() plot.add(sc.mean, title="Posterior Mean") - plot.add(sc.var.ptw("sqrt"), title="Posterior Standard Deviation") + plot.add(ift.sqrt(sc.var), title="Posterior Standard Deviation") powers = [A.force(s + KL.position) for s in KL.samples] plot.add( diff --git a/demos/getting_started_mf.py b/demos/getting_started_mf.py index 992b2b1e45cb700d0943a1895d27433f3b64b452..e4ee04cf6408a8b4308f8b3fa227d7bf4937b27c 100644 --- a/demos/getting_started_mf.py +++ b/demos/getting_started_mf.py @@ -84,7 +84,7 @@ if __name__ == '__main__': DC = SingleDomain(correlated_field.target, position_space) ## Apply a nonlinearity - signal = DC @ correlated_field.ptw("sigmoid") + signal = DC @ ift.sigmoid(correlated_field) # Build the line-of-sight response and define signal response LOS_starts, LOS_ends = random_los(100) if mode == 0 else radial_los(100) @@ -170,7 +170,7 @@ if __name__ == '__main__': filename_res = filename.format("results") plot = ift.Plot() plot.add(sc.mean, title="Posterior Mean") - plot.add(sc.var.ptw("sqrt"), title="Posterior Standard Deviation") + plot.add(ift.sqrt(sc.var), title="Posterior Standard Deviation") powers1 = [A1.force(s + KL.position) for s in KL.samples] powers2 = [A2.force(s + KL.position) for s in KL.samples] diff --git a/nifty6/field.py b/nifty6/field.py index decf826eecb7b197a406b35627067d92de9f05a3..8d4d31970afa822cda43dda44b28e005b5c6e581 100644 --- a/nifty6/field.py +++ b/nifty6/field.py @@ -686,9 +686,6 @@ class Field(Operator): def flexible_addsub(self, other, neg): return self-other if neg else self+other - def clip(self, a_min=None, a_max=None): - return self.ptw("clip", a_min, a_max) - def _binary_op(self, other, op): # if other is a field, make sure that the domains match f = getattr(self._val, op) @@ -700,20 +697,24 @@ class Field(Operator): return Field(self._domain, f(other)) return NotImplemented - def ptw(self, op, *args, **kwargs): - from .pointwise import ptw_dict + def _prep_args(self, args, kwargs): + for arg in args + tuple(kwargs.values()): + if not (arg is None or np.isscalar(arg) or arg.jac is None): + raise TypeError("bad argument") argstmp = tuple(arg if arg is None or np.isscalar(arg) else arg._val for arg in args) kwargstmp = {key: val if val is None or np.isscalar(val) else val._val for key, val in kwargs.items()} + return argstmp, kwargstmp + + def ptw(self, op, *args, **kwargs): + from .pointwise import ptw_dict + argstmp, kwargstmp = self._prep_args(args, kwargs) return Field(self._domain, ptw_dict[op][0](self._val, *argstmp, **kwargstmp)) def ptw_with_deriv(self, op, *args, **kwargs): from .pointwise import ptw_dict - argstmp = tuple(arg if arg is None or np.isscalar(arg) else arg._val - for arg in args) - kwargstmp = {key: val if val is None or np.isscalar(val) else val._val - for key, val in kwargs.items()} + argstmp, kwargstmp = self._prep_args(args, kwargs) tmp = ptw_dict[op][1](self._val, *argstmp, **kwargstmp) return (Field(self._domain, tmp[0]), Field(self._domain, tmp[1])) diff --git a/nifty6/library/correlated_fields.py b/nifty6/library/correlated_fields.py index d010e2999c1fdedb278191843826f8dcccba6453..c5156c3e1836bccc3b59146327e5eaea694dc1f8 100644 --- a/nifty6/library/correlated_fields.py +++ b/nifty6/library/correlated_fields.py @@ -225,7 +225,7 @@ class _Normalization(Operator): def apply(self, x): self._check_input(x) amp = x.ptw("exp") - spec = amp*amp + spec = amp**2 # FIXME This normalizes also the zeromode which is supposed to be left # untouched by this operator return self._specsum(self._mode_multiplicity(spec))**(-0.5)*amp diff --git a/nifty6/linearization.py b/nifty6/linearization.py index bd577f6deb9a4293088a42feff4a3db3757baf62..9b84b86e9637217f859b82611272f4db9723d186 100644 --- a/nifty6/linearization.py +++ b/nifty6/linearization.py @@ -294,15 +294,6 @@ class Linearization(Operator): t1, t2 = self._fld.ptw_with_deriv(op, *args, **kwargs) return self.new(t1, makeOp(t2)(self._jac)) - def clip(self, a_min=None, a_max=None): - if a_min is None and a_max is None: - return self - if not (a_min is None or np.isscalar(a_min) or a_min.jac is None): - return NotImplemented - if not (a_max is None or np.isscalar(a_max) or a_max.jac is None): - return NotImplemented - return self.ptw("clip", a_min, a_max) - def add_metric(self, metric): return self.new(self._fld, self._jac, metric) diff --git a/nifty6/multi_field.py b/nifty6/multi_field.py index aca5f78a53e8653e397f19340936e93707ab7544..a05bd644ab88c84107bbf254bc7602464d0a0412 100644 --- a/nifty6/multi_field.py +++ b/nifty6/multi_field.py @@ -314,25 +314,27 @@ class MultiField(Operator): res[key] = -val if neg else val return MultiField.from_dict(res) + def _prep_args(self, args, kwargs, i): + for arg in args + tuple(kwargs.values()): + if not (arg is None or np.isscalar(arg) or arg.jac is None): + raise TypeError("bad argument") + argstmp = tuple(arg if arg is None or np.isscalar(arg) else arg._val[i] + for arg in args) + kwargstmp = {key: val if val is None or np.isscalar(val) else val._val[i] + for key, val in kwargs.items()} + return argstmp, kwargstmp + def ptw(self, op, *args, **kwargs): -# _check_args(args, kwargs) tmp = [] for i in range(len(self._val)): - argstmp = tuple(arg if arg is None or np.isscalar(arg) else arg._val[i] - for arg in args) - kwargstmp = {key: val if val is None or np.isscalar(val) else val._val[i] - for key, val in kwargs.items()} + argstmp, kwargstmp = self._prep_args(args, kwargs, i) tmp.append(self._val[i].ptw(op, *argstmp, **kwargstmp)) return MultiField(self.domain, tuple(tmp)) def ptw_with_deriv(self, op, *args, **kwargs): -# _check_args(args, kwargs) tmp = [] for i in range(len(self._val)): - argstmp = tuple(arg if arg is None or np.isscalar(arg) else arg._val[i] - for arg in args) - kwargstmp = {key: val if val is None or np.isscalar(val) else val._val[i] - for key, val in kwargs.items()} + argstmp, kwargstmp = self._prep_args(args, kwargs, i) tmp.append(self._val[i].ptw_with_deriv(op, *argstmp, **kwargstmp)) return (MultiField(self.domain, tuple(v[0] for v in tmp)), MultiField(self.domain, tuple(v[1] for v in tmp))) diff --git a/nifty6/operators/operator.py b/nifty6/operators/operator.py index e0808671af85a524ce61c71b57c4659dfd69a302..fa4e63501588df64471426108470cebd70926a80 100644 --- a/nifty6/operators/operator.py +++ b/nifty6/operators/operator.py @@ -18,6 +18,7 @@ import numpy as np from ..utilities import NiftyMeta, indent +from .. import pointwise class Operator(metaclass=NiftyMeta): @@ -221,15 +222,6 @@ class Operator(metaclass=NiftyMeta): return NotImplemented return self.ptw("power", power) - def clip(self, a_min=None, a_max=None): - if a_min is None and a_max is None: - return self - if not (a_min is None or np.isscalar(a_min) or a_min.jac is None): - return NotImplemented - if not (a_max is None or np.isscalar(a_max) or a_max.jac is None): - return NotImplemented - return self.ptw("clip", a_min, a_max) - def apply(self, x): """Applies the operator to a Field or MultiField. @@ -292,6 +284,14 @@ class Operator(metaclass=NiftyMeta): return _OpChain.make((_FunctionApplier(self.target, op, *args, **kwargs), self)) +for f in pointwise.ptw_dict.keys(): + def func(f): + def func2(self, *args, **kwargs): + return self.ptw(f, *args, **kwargs) + return func2 + setattr(Operator, f, func(f)) + + class _ConstCollector(object): def __init__(self): self._const = None diff --git a/nifty6/pointwise.py b/nifty6/pointwise.py index 06f8bedd15c0b978a8195d1bfaac406c890134ac..198518a61bd510f7eb851ff1677c091f3f8b68f9 100644 --- a/nifty6/pointwise.py +++ b/nifty6/pointwise.py @@ -67,7 +67,7 @@ def _power_helper(v, expo): return (np.power(v, expo), expo*np.power(v, expo-1)) -def _clip_helper(v, a_min=None, a_max=None): +def _clip_helper(v, a_min, a_max): if np.issubdtype(v.dtype, np.complexfloating): raise TypeError("Argument must not be complex") tmp = np.clip(v, a_min, a_max) diff --git a/nifty6/sugar.py b/nifty6/sugar.py index 4dd40296bde74032ebf6921b70be4b3fc7e66f39..c1afe9de2737d68709eb1004080675db646d5076 100644 --- a/nifty6/sugar.py +++ b/nifty6/sugar.py @@ -33,13 +33,15 @@ from .operators.distributors import PowerDistributor from .operators.operator import Operator from .operators.scaling_operator import ScalingOperator from .plot import Plot +from . import pointwise + __all__ = ['PS_field', 'power_analyze', 'create_power_operator', 'create_harmonic_smoothing_operator', 'from_random', 'full', 'makeField', 'makeDomain', 'get_signal_variance', 'makeOp', 'domain_union', 'get_default_codomain', 'single_plot', 'exec_time', - 'calculate_position'] + 'calculate_position'] + list(pointwise.ptw_dict.keys()) def PS_field(pspace, func): @@ -341,7 +343,7 @@ def makeOp(input, dom=None): if input is None: return None if np.isscalar(input): - if not isinstance(dom, (DomaiTuple, MultiDomain)): + if not isinstance(dom, (DomainTuple, MultiDomain)): raise TypeError("need proper `dom` argument") return SalingOperator(dom, input) if dom is not None: @@ -373,8 +375,16 @@ def domain_union(domains): return MultiDomain.union(domains) -def clip(a, a_min=None, a_max=None): - return a.clip(a_min, a_max) +# Pointwise functions + +_current_module = sys.modules[__name__] + +for f in pointwise.ptw_dict.keys(): + def func(f): + def func2(x, *args, **kwargs): + return x.ptw(f, *args, **kwargs) + return func2 + setattr(_current_module, f, func(f)) def get_default_codomain(domainoid, space=None): diff --git a/test/test_field.py b/test/test_field.py index 91566d22f37472fc066ba21144bf227f462ca113..6e154cb1994652ae2924ad590502ab53e11f4a23 100644 --- a/test/test_field.py +++ b/test/test_field.py @@ -193,8 +193,8 @@ def test_empty_domain(): def test_trivialities(): s1 = ift.RGSpace((10,)) f1 = ift.Field.full(s1, 27) - assert_equal(f1.clip(a_min=29).val, 29.) - assert_equal(f1.clip(a_max=25).val, 25.) + assert_equal(f1.clip(a_min=29, a_max=50).val, 29.) + assert_equal(f1.clip(a_min=0, a_max=25).val, 25.) assert_equal(f1.val, f1.real.val) assert_equal(f1.val, (+f1).val) f1 = ift.Field.full(s1, 27. + 3j)