diff --git a/nifty/minimization/__init__.py b/nifty/minimization/__init__.py
index ec18339ad552eb727e2eac43c339b769651067d9..a66060e1811b3068622631140c3003531cf7ff1b 100644
--- a/nifty/minimization/__init__.py
+++ b/nifty/minimization/__init__.py
@@ -17,6 +17,9 @@
 # and financially supported by the Studienstiftung des deutschen Volkes.
 
 from line_searching import *
+from iteration_controller import IterationController
+from default_iteration_controller import DefaultIterationController
+from minimizer import Minimizer
 from conjugate_gradient import ConjugateGradient
 from descent_minimizer import DescentMinimizer
 from steepest_descent import SteepestDescent
diff --git a/nifty/minimization/conjugate_gradient.py b/nifty/minimization/conjugate_gradient.py
index e829300bc3eee9e27e725221a1b81e5bdb2c702a..67783bfe966e991a92ad39e5238415b96d0c8332 100644
--- a/nifty/minimization/conjugate_gradient.py
+++ b/nifty/minimization/conjugate_gradient.py
@@ -19,10 +19,10 @@
 from __future__ import division
 import numpy as np
 
-from keepers import Loggable
+from .minimizer import Minimizer
 
 
-class ConjugateGradient(Loggable, object):
+class ConjugateGradient(Minimizer):
     """ Implementation of the Conjugate Gradient scheme.
 
     It is an iterative method for solving a linear system of equations:
@@ -30,43 +30,22 @@ class ConjugateGradient(Loggable, object):
 
     Parameters
     ----------
-    convergence_tolerance : float *optional*
-        Tolerance specifying the case of convergence. (default: 1E-4)
-    convergence_level : integer *optional*
-        Number of times the tolerance must be undershot before convergence
-        is reached. (default: 3)
-    iteration_limit : integer *optional*
-        Maximum number of iterations performed (default: None).
     reset_count : integer *optional*
         Number of iterations after which to restart; i.e., forget previous
         conjugated directions (default: None).
     preconditioner : Operator *optional*
         This operator can be provided which transforms the variables of the
         system to improve the conditioning (default: None).
-    callback : callable *optional*
-        Function f(energy, iteration_number) supplied by the user to perform
-        in-situ analysis at every iteration step. When being called the
-        current energy and iteration_number are passed. (default: None)
 
     Attributes
     ----------
-    convergence_tolerance : float
-        Tolerance specifying the case of convergence.
-    convergence_level : integer
-        Number of times the tolerance must be undershot before convergence
-        is reached. (default: 3)
-    iteration_limit : integer
-        Maximum number of iterations performed.
     reset_count : integer
         Number of iterations after which to restart; i.e., forget previous
         conjugated directions.
     preconditioner : function
         This operator can be provided which transforms the variables of the
         system to improve the conditioning (default: None).
-    callback : callable
-        Function f(energy, iteration_number) supplied by the user to perform
-        in-situ analysis at every iteration step. When being called the
-        current energy and iteration_number are passed. (default: None)
+    controller : IterationController
 
     References
     ----------
@@ -75,23 +54,13 @@ class ConjugateGradient(Loggable, object):
 
     """
 
-    def __init__(self, convergence_tolerance=1E-4, convergence_level=3,
-                 iteration_limit=None, reset_count=None,
-                 preconditioner=None, callback=None):
-
-        self.convergence_tolerance = np.float(convergence_tolerance)
-        self.convergence_level = np.float(convergence_level)
-
-        if iteration_limit is not None:
-            iteration_limit = int(iteration_limit)
-        self.iteration_limit = iteration_limit
-
+    def __init__(self, controller, reset_count=None, preconditioner=None):
         if reset_count is not None:
             reset_count = int(reset_count)
         self.reset_count = reset_count
 
         self.preconditioner = preconditioner
-        self.callback = callback
+        self._controller = controller
 
     def __call__(self, E):
         """ Runs the conjugate gradient minimization.
@@ -111,6 +80,11 @@ class ConjugateGradient(Loggable, object):
 
         """
 
+        controller = self._controller
+        status = controller.start(E)
+        if status != controller.CONTINUE:
+            return E, status
+
         r = -E.gradient
         if self.preconditioner is not None:
             d = self.preconditioner(r)
@@ -118,26 +92,20 @@ class ConjugateGradient(Loggable, object):
             d = r.copy()
         previous_gamma = (r.vdot(d)).real
         if previous_gamma == 0:
-            self.logger.info("The starting guess is already perfect solution "
-                             "for the inverse problem.")
-            return E, self.convergence_level+1
-
-        convergence = 0
-        iteration_number = 1
-        self.logger.info("Starting conjugate gradient.")
+            return E, controller.CONVERGED
 
         while True:
-            if self.callback is not None:
-                self.callback(E, iteration_number)
-
             q = E.curvature(d)
             alpha = previous_gamma/(d.vdot(q).real)
 
             if not np.isfinite(alpha):
                 self.logger.error("Alpha became infinite! Stopping.")
-                return E, 0
+                return E, controller.ERROR
 
             E = E.at(E.position+d*alpha)
+            status = self._controller.check(E)
+            if status != controller.CONTINUE:
+                return E, status
 
             reset = False
             if alpha < 0:
@@ -155,42 +123,14 @@ class ConjugateGradient(Loggable, object):
                 s = self.preconditioner(r)
             else:
                 s = r.copy()
-            gamma = r.vdot(s).real
 
+            gamma = r.vdot(s).real
             if gamma < 0:
                 self.logger.warn("Positive definiteness of preconditioner "
                                  "violated!")
-
-            beta = max(0, gamma/previous_gamma)
-
-            delta = r.norm()
-
-            self.logger.debug("Iteration : %08u   alpha = %3.1E   "
-                              "beta = %3.1E   delta = %3.1E" %
-                              (iteration_number, alpha, beta, delta))
-
             if gamma == 0:
-                convergence = self.convergence_level+1
-                self.logger.info("Reached infinite convergence.")
-                break
-            elif abs(delta) < self.convergence_tolerance:
-                convergence += 1
-                self.logger.info("Updated convergence level to: %u" %
-                                 convergence)
-                if convergence == self.convergence_level:
-                    self.logger.info("Reached target convergence level.")
-                    break
-            else:
-                convergence = max(0, convergence-1)
-
-            if self.iteration_limit is not None:
-                if iteration_number == self.iteration_limit:
-                    self.logger.warn("Reached iteration limit. Stopping.")
-                    break
+                return E, controller.CONVERGED
 
-            d = s + d * beta
+            d = s + d * max(0, gamma/previous_gamma)
 
-            iteration_number += 1
             previous_gamma = gamma
-
-        return E, convergence
diff --git a/nifty/minimization/default_iteration_controller.py b/nifty/minimization/default_iteration_controller.py
new file mode 100644
index 0000000000000000000000000000000000000000..7a538eb5a8513192243c30b0045cac754ed65efc
--- /dev/null
+++ b/nifty/minimization/default_iteration_controller.py
@@ -0,0 +1,48 @@
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright(C) 2013-2017 Max-Planck-Society
+#
+# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik
+# and financially supported by the Studienstiftung des deutschen Volkes.
+
+from .iteration_controller import IterationController
+
+class DefaultIterationController(IterationController):
+    def __init__ (self, tol_gradnorm=None, convergence_level=1,
+                  iteration_limit=None):
+        super(DefaultIterationController, self).__init__()
+        self._tol_gradnorm = tol_gradnorm
+        self._convergence_level = convergence_level
+        self._iteration_limit = iteration_limit
+
+    def start(self, energy):
+        self._itcount = -1
+        self._ccount = 0
+        return self.check(energy)
+
+    def check(self, energy):
+        self._itcount += 1
+        print "iteration",self._itcount,"gradnorm",energy.gradient_norm,"level",self._ccount
+        if self._iteration_limit is not None:
+            if self._itcount >= self._iteration_limit:
+                return self.CONVERGED
+        if self._tol_gradnorm is not None:
+            if energy.gradient_norm <= self._tol_gradnorm:
+                self._ccount += 1
+            if self._ccount >= self._convergence_level:
+                return self.CONVERGED
+        else:
+            self._ccount = max(0, self._ccount-1)
+
+        return self.CONTINUE
diff --git a/nifty/minimization/descent_minimizer.py b/nifty/minimization/descent_minimizer.py
index 57d571bd4bfce970e9d4388c9830f5d8b558fd66..99050a5acfd943276233adfeba9a7c3668aa362c 100644
--- a/nifty/minimization/descent_minimizer.py
+++ b/nifty/minimization/descent_minimizer.py
@@ -17,16 +17,13 @@
 # and financially supported by the Studienstiftung des deutschen Volkes.
 
 import abc
-from nifty.nifty_meta import NiftyMeta
-
 import numpy as np
 
-from keepers import Loggable
-
+from .minimizer import Minimizer
 from .line_searching import LineSearchStrongWolfe
 
 
-class DescentMinimizer(Loggable, object):
+class DescentMinimizer(Minimizer):
     """ A base class used by gradient methods to find a local minimum.
 
     Descent minimization methods are used to find a local minimum of a scalar
@@ -43,23 +40,9 @@ class DescentMinimizer(Loggable, object):
         Function f(energy, iteration_number) supplied by the user to perform
         in-situ analysis at every iteration step. When being called the
         current energy and iteration_number are passed. (default: None)
-    convergence_tolerance : float *optional*
-        Tolerance specifying the case of convergence. (default: 1E-4)
-    convergence_level : integer *optional*
-        Number of times the tolerance must be undershot before convergence
-        is reached. (default: 3)
-    iteration_limit : integer *optional*
-        Maximum number of iterations performed (default: None).
 
     Attributes
     ----------
-    convergence_tolerance : float
-        Tolerance specifying the case of convergence.
-    convergence_level : integer
-        Number of times the tolerance must be undershot before convergence
-        is reached. (default: 3)
-    iteration_limit : integer
-        Maximum number of iterations performed.
     line_searcher : LineSearch
         Function which infers the optimal step size for functional minization
         given a descent direction.
@@ -77,21 +60,11 @@ class DescentMinimizer(Loggable, object):
 
     """
 
-    __metaclass__ = NiftyMeta
-
-    def __init__(self, line_searcher=LineSearchStrongWolfe(), callback=None,
-                 convergence_tolerance=1E-4, convergence_level=3,
-                 iteration_limit=None):
-
-        self.convergence_tolerance = np.float(convergence_tolerance)
-        self.convergence_level = np.int(convergence_level)
-
-        if iteration_limit is not None:
-            iteration_limit = int(iteration_limit)
-        self.iteration_limit = iteration_limit
+    def __init__(self, controller, line_searcher=LineSearchStrongWolfe()):
+        super(DescentMinimizer, self).__init__()
 
         self.line_searcher = line_searcher
-        self.callback = callback
+        self._controller = controller
 
     def __call__(self, energy):
         """ Performs the minimization of the provided Energy functional.
@@ -121,28 +94,17 @@ class DescentMinimizer(Loggable, object):
 
         """
 
-        convergence = 0
         f_k_minus_1 = None
-        iteration_number = 1
+        controller = self._controller
+        status = controller.start(energy)
+        if status != controller.CONTINUE:
+            return E, status
 
         while True:
-            if self.callback is not None:
-                try:
-                    self.callback(energy, iteration_number)
-                except StopIteration:
-                    self.logger.info("Minimization was stopped by callback "
-                                     "function.")
-                    break
-
-            # compute the the gradient for the current location
-            gradient = energy.gradient
-            gradient_norm = gradient.norm()
-
             # check if position is at a flat point
-            if gradient_norm == 0:
+            if energy.gradient_norm == 0:
                 self.logger.info("Reached perfectly flat point. Stopping.")
-                convergence = self.convergence_level+2
-                break
+                return energy, controller.CONVERGED
 
             # current position is encoded in energy object
             descent_direction = self.get_descent_direction(energy)
@@ -157,47 +119,20 @@ class DescentMinimizer(Loggable, object):
             except RuntimeError:
                 self.logger.warn(
                         "Stopping because of RuntimeError in line-search")
-                break
+                return energy, controller.ERROR
 
             f_k_minus_1 = energy.value
-            f_k = new_energy.value
-            delta = (abs(f_k-f_k_minus_1) /
-                     max(abs(f_k), abs(f_k_minus_1), 1.))
             # check if new energy value is bigger than old energy value
             if (new_energy.value - energy.value) > 0:
                 self.logger.info("Line search algorithm returned a new energy "
                                  "that was larger than the old one. Stopping.")
-                break
+                return energy, controller.ERROR
 
             energy = new_energy
-            # check convergence
-            self.logger.debug("Iteration:%08u "
-                              "delta=%3.1E energy=%3.1E" %
-                              (iteration_number, delta,
-                               energy.value))
-            if delta == 0:
-                convergence = self.convergence_level + 2
-                self.logger.info("Found minimum according to line-search. "
-                                 "Stopping.")
-                break
-            elif delta < self.convergence_tolerance:
-                convergence += 1
-                self.logger.info("Updated convergence level to: %u" %
-                                 convergence)
-                if convergence == self.convergence_level:
-                    self.logger.info("Reached target convergence level.")
-                    break
-            else:
-                convergence = max(0, convergence-1)
-
-            if self.iteration_limit is not None:
-                if iteration_number == self.iteration_limit:
-                    self.logger.warn("Reached iteration limit. Stopping.")
-                    break
-
-            iteration_number += 1
-
-        return energy, convergence
+            status = self._controller.check(energy)
+            if status != controller.CONTINUE:
+                return energy, status
+
 
     @abc.abstractmethod
     def get_descent_direction(self, energy):
diff --git a/nifty/minimization/iteration_controller.py b/nifty/minimization/iteration_controller.py
new file mode 100644
index 0000000000000000000000000000000000000000..117a73066de7e366235bda73d1db8075ba62933e
--- /dev/null
+++ b/nifty/minimization/iteration_controller.py
@@ -0,0 +1,60 @@
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright(C) 2013-2017 Max-Planck-Society
+#
+# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik
+# and financially supported by the Studienstiftung des deutschen Volkes.
+
+import abc
+from nifty.nifty_meta import NiftyMeta
+
+import numpy as np
+
+from keepers import Loggable
+
+class IterationController(Loggable, object):
+
+    __metaclass__ = NiftyMeta
+
+    CONVERGED, CONTINUE, ERROR = range(3)
+
+    @abc.abstractmethod
+    def start(self, energy):
+        """
+        Parameters
+        ----------
+        energy : Energy object
+           Energy object at the start of the iteration
+
+        Returns
+        -------
+        status : integer status, can be CONVERGED, CONTINUE or ERROR
+        """
+
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def check(self, energy):
+        """
+        Parameters
+        ----------
+        energy : Energy object
+           Energy object at the start of the iteration
+
+        Returns
+        -------
+        status : integer status, can be CONVERGED, CONTINUE or ERROR
+        """
+
+        raise NotImplementedError
diff --git a/nifty/minimization/minimizer.py b/nifty/minimization/minimizer.py
new file mode 100644
index 0000000000000000000000000000000000000000..6ce4c5d68d48788d15e72d436932b3c10e86ef73
--- /dev/null
+++ b/nifty/minimization/minimizer.py
@@ -0,0 +1,48 @@
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright(C) 2013-2017 Max-Planck-Society
+#
+# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik
+# and financially supported by the Studienstiftung des deutschen Volkes.
+
+import abc
+from nifty.nifty_meta import NiftyMeta
+
+import numpy as np
+
+from keepers import Loggable
+
+class Minimizer(Loggable, object):
+    """ A base class used by all minimizers.
+    """
+    __metaclass__ = NiftyMeta
+
+    @abc.abstractmethod
+    def __call__(self, energy):
+        """ Performs the minimization of the provided Energy functional.
+
+        Parameters
+        ----------
+        energy : Energy object
+           Energy object which provides value, gradient and curvature at a
+           specific position in parameter space.
+
+        Returns
+        -------
+        energy : Energy object
+            Latest `energy` of the minimization.
+        status : integer
+        """
+
+        raise NotImplementedError
diff --git a/nifty/minimization/vl_bfgs.py b/nifty/minimization/vl_bfgs.py
index a7a4770d56b6b366a0056027ed66c1f211ed182c..b997269d351fa532f8daac2647124511b9c407d8 100644
--- a/nifty/minimization/vl_bfgs.py
+++ b/nifty/minimization/vl_bfgs.py
@@ -23,16 +23,12 @@ from .line_searching import LineSearchStrongWolfe
 
 
 class VL_BFGS(DescentMinimizer):
-    def __init__(self, line_searcher=LineSearchStrongWolfe(), callback=None,
-                 convergence_tolerance=1E-4, convergence_level=3,
-                 iteration_limit=None, max_history_length=5):
+    def __init__(self, controller, line_searcher=LineSearchStrongWolfe(),
+                 max_history_length=5):
 
         super(VL_BFGS, self).__init__(
-                                line_searcher=line_searcher,
-                                callback=callback,
-                                convergence_tolerance=convergence_tolerance,
-                                convergence_level=convergence_level,
-                                iteration_limit=iteration_limit)
+                                controller=controller,
+                                line_searcher=line_searcher)
 
         self.max_history_length = max_history_length