From 4aa2cb82fbb56229cc0c65a8837e761d92d8f342 Mon Sep 17 00:00:00 2001
From: "Knollmueller, Jakob (kjako)" <jakob@knollmueller.de>
Date: Sat, 15 Dec 2018 16:09:21 +0100
Subject: [PATCH] added a number of local nonlinear functions

---
 nifty5/data_objects/numpy_do.py | 10 +++++--
 nifty5/field.py                 | 12 +++++++--
 nifty5/linearization.py         | 47 ++++++++++++++++++++++++++++++++-
 nifty5/operators/operator.py    |  4 ++-
 4 files changed, 67 insertions(+), 6 deletions(-)

diff --git a/nifty5/data_objects/numpy_do.py b/nifty5/data_objects/numpy_do.py
index 779b0d0ab..2b93b3c49 100644
--- a/nifty5/data_objects/numpy_do.py
+++ b/nifty5/data_objects/numpy_do.py
@@ -22,7 +22,8 @@ import numpy as np
 from numpy import empty, empty_like, exp, full, log
 from numpy import ndarray as data_object
 from numpy import ones, sqrt, tanh, vdot, zeros
-
+from numpy import sin, cos, tan, sinh, cosh, sinc
+from numpy import absolute, sign
 from .random import Random
 
 __all__ = ["ntask", "rank", "master", "local_shape", "data_object", "full",
@@ -34,7 +35,8 @@ __all__ = ["ntask", "rank", "master", "local_shape", "data_object", "full",
            "redistribute", "default_distaxis", "is_numpy", "absmax", "norm",
            "lock", "locked", "uniform_full", "to_global_data_rw",
            "ensure_not_distributed", "ensure_default_distributed",
-           "clipped_exp"]
+           "clipped_exp", "hardplus", "sin", "cos", "tan", "sinh",
+           "cosh","absolute", "sign", "sinc"]
 
 ntask = 1
 rank = 0
@@ -154,3 +156,7 @@ def norm(arr, ord=2):
 
 def clipped_exp(arr):
     return np.exp(np.clip(arr, -300, 300))
+
+
+def hardplus(arr):
+    return np.clip(arr, 1e-20, None)
\ No newline at end of file
diff --git a/nifty5/field.py b/nifty5/field.py
index 2eeb0126d..b5ab6f1b3 100644
--- a/nifty5/field.py
+++ b/nifty5/field.py
@@ -631,12 +631,18 @@ class Field(object):
     def flexible_addsub(self, other, neg):
         return self-other if neg else self+other
 
-    def positive_tanh(self):
+    def sigmoid(self):
         return 0.5*(1.+self.tanh())
 
     def clipped_exp(self):
         return Field(self._domain, dobj.clipped_exp(self._val))
 
+    def hardplus(self):
+        return Field(self._domain, dobj.hardplus(self._val))
+
+    def one_over(self):
+        return 1/self
+
     def _binary_op(self, other, op):
         # if other is a field, make sure that the domains match
         f = getattr(self._val, op)
@@ -672,7 +678,9 @@ for op in ["__iadd__", "__isub__", "__imul__", "__idiv__",
         return func2
     setattr(Field, op, func(op))
 
-for f in ["sqrt", "exp", "log", "tanh"]:
+for f in ["sqrt", "exp", "log", "tanh",
+          "sin", "cos", "tan", "cosh", "sinh",
+          "absolute", "sinc", "sign"]:
     def func(f):
         def func2(self):
             return Field(self._domain, getattr(dobj, f)(self.val))
diff --git a/nifty5/linearization.py b/nifty5/linearization.py
index 9761736c0..e9e353e8f 100644
--- a/nifty5/linearization.py
+++ b/nifty5/linearization.py
@@ -187,19 +187,64 @@ class Linearization(object):
         tmp = self._val.clipped_exp()
         return self.new(tmp, makeOp(tmp)(self._jac))
 
+    def hardplus(self):
+        tmp = self._val.hardplus()
+        tmp2 = makeOp(1.-(tmp==1e-20))
+        return self.new(tmp, tmp2(self._jac))
+
+    def sin(self):
+        tmp = self._val.sin()
+        tmp2 = self._val.cos()
+        return self.new(tmp, makeOp(tmp2)(self._jac))
+
+    def cos(self):
+        tmp = self._val.cos()
+        tmp2 = - self._val.sin()
+        return self.new(tmp, makeOp(tmp2)(self._jac))
+
+    def tan(self):
+        tmp = self._val.tan()
+        tmp2 = 1./(self._val.cos()**2)
+        return self.new(tmp, makeOp(tmp2)(self._jac))
+
+    def sinc(self):
+        tmp = self._val.sinc()
+        tmp2 = (self._val.cos()-tmp)/self._val
+        return self.new(tmp, makeOp(tmp2)(self._jac))
+
     def log(self):
         tmp = self._val.log()
         return self.new(tmp, makeOp(1./self._val)(self._jac))
 
+    def sinh(self):
+        tmp = self._val.sinh()
+        tmp2 = self._val.cosh()
+        return self.new(tmp, makeOp(tmp2)(self._jac))
+
+    def cosh(self):
+        tmp = self._val.cosh()
+        tmp2 = self._val.sinh()
+        return self.new(tmp, makeOp(tmp2)(self._jac))
+
     def tanh(self):
         tmp = self._val.tanh()
         return self.new(tmp, makeOp(1.-tmp**2)(self._jac))
 
-    def positive_tanh(self):
+    def sigmoid(self):
         tmp = self._val.tanh()
         tmp2 = 0.5*(1.+tmp)
         return self.new(tmp2, makeOp(0.5*(1.-tmp**2))(self._jac))
 
+    def absolute(self):
+        tmp = self._val.absolute()
+        tmp2 = self._val.sign()
+        return self.new(tmp, makeOp(tmp2)(self._jac))
+
+    def one_over(self):
+        tmp = 1./self._val
+        tmp2 = - tmp/self._val
+        return self.new(tmp, makeOp(tmp2)(self._jac))
+
     def add_metric(self, metric):
         return self.new(self._val, self._jac, metric)
 
diff --git a/nifty5/operators/operator.py b/nifty5/operators/operator.py
index 4a11dfb50..34748c8e7 100644
--- a/nifty5/operators/operator.py
+++ b/nifty5/operators/operator.py
@@ -107,7 +107,9 @@ class Operator(NiftyMetaBase()):
         return self.__class__.__name__
 
 
-for f in ["sqrt", "exp", "log", "tanh", "positive_tanh", 'clipped_exp']:
+for f in ["sqrt", "exp", "log", "tanh", "sigmoid",
+          'clipped_exp', 'hardplus', 'sin', 'cos', 'tan',
+          'sinh', 'cosh', 'absolute', 'sinc', 'one_over']:
     def func(f):
         def func2(self):
             fa = _FunctionApplier(self.target, f)
-- 
GitLab