# Path: tensorprob/optimizers/base.py
# class BaseOptimizer(object):
# 
#     def __init__(self, session=None):
#         self._session = session or tf.Session()
# 
#     def minimize_impl(self, objective, gradient, inits, bounds):
#         raise NotImplementedError
# 
#     def minimize(self, variables, cost, gradient=None, bounds=None):
#         # Check if variables is iterable
#         if not isinstance(variables, Iterable):
#             raise ValueError("Variables parameter is not iterable")
# 
#         for v in variables:
#             if not isinstance(v, tf.Variable):
#                 raise ValueError("Parameter {} is not a tensorflow variable".format(v))
# 
#         inits = self._session.run(variables)
# 
#         def objective(xs):
#             feed_dict = {k: v for k, v in zip(variables, xs)}
#             # Cast just in case the user-supplied function returns something else
#             val = np.float64(self._session.run(cost, feed_dict=feed_dict))
#             logger.debug('Objective: {} {}'.format(val, xs))
#             return val
# 
#         if gradient is not None:
#             def gradient_(xs):
#                 feed_dict = {k: v for k, v in zip(variables, xs)}
#                 # Cast just in case the user-supplied function returns something else
#                 val = np.array(self._session.run(gradient, feed_dict=feed_dict))
#                 logger.debug('Gradient: {} {}'.format(val, xs))
#                 return val
#             approx_grad = False
#         else:
#             gradient_ = None
# 
#         if bounds:
#             min_bounds = []
#             for current in bounds:
#                 lower, upper = current
# 
#                 if isinstance(lower, tf.Tensor) or isinstance(upper, tf.Tensor):
#                     raise NotImplementedError("Specifying variable bounds to optimizers is not yet supported")
# 
#                 # Translate inf to None, which is what this minimizer understands
#                 if lower is not None and np.isinf(lower):
#                     lower = None
#                 if upper is not None and np.isinf(upper):
#                     upper = None
#                 # This optimizer likes to evaluate the function at the boundaries.
#                 # Slightly move the bounds so that the edges are not included.
#                 if lower is not None:
#                     lower = lower + 1e-10
#                 if upper is not None:
#                     upper = upper - 1e-10
# 
#                 min_bounds.append((lower, upper))
#         else:
#             min_bounds = None
# 
#         return self.minimize_impl(objective, gradient_, inits, min_bounds)
# 
# 
#     @property
#     def session(self):
#         return self._session
# 
#     @session.setter
#     def session(self, session):
#         self._session = session
# 
# Path: tensorprob/optimization_result.py
# class OptimizationResult(dict):
# 
#     def __getattr__(self, name):
#         try:
#             return self[name]
#         except KeyError:
#             raise AttributeError(name)
# 
#     __setattr__ = dict.__setitem__
#     __delattr__ = dict.__delitem__
# 
#     def __repr__(self):
#         if self.keys():
#             header = '\n' + self.__class__.__name__ + ':\n'
#             m = max(map(len, list(self.keys()))) + 1
#             return header + '\n'.join([k.rjust(m) + ': ' + repr(v)
#                               for k, v in sorted(self.items())])
#         else:
#             return self.__class__.__name__ + "()"


import numpy as np
            import iminuit
from .base import BaseOptimizer
from ..optimization_result import OptimizationResult
        from iminuit.util import make_func_code
                all_kwargs['limit_' + n] = b

        if gradient:
            def mygrad_func(*x):
                out = gradient(x)
                return out
        else:
            mygrad_func = None

        def objective_(x):
            val = objective(x)
            if np.isnan(val) or np.isinf(val):
                return 1e10
            return val

        m = self.iminuit.Minuit(
            Min_Func(objective_, names),
            grad_fcn=mygrad_func,
            print_level=print_level,
            errordef=1,
            **all_kwargs
        )

        m.set_strategy(2)
        a, b = m.migrad()

        x = []
        for name in names:
            x.append(m.values[name])


# Path: tensorprob/optimizers/base.py
# class BaseOptimizer(object):
# 
#     def __init__(self, session=None):
#         self._session = session or tf.Session()
# 
#     def minimize_impl(self, objective, gradient, inits, bounds):
#         raise NotImplementedError
# 
#     def minimize(self, variables, cost, gradient=None, bounds=None):
#         # Check if variables is iterable
#         if not isinstance(variables, Iterable):
#             raise ValueError("Variables parameter is not iterable")
# 
#         for v in variables:
#             if not isinstance(v, tf.Variable):
#                 raise ValueError("Parameter {} is not a tensorflow variable".format(v))
# 
#         inits = self._session.run(variables)
# 
#         def objective(xs):
#             feed_dict = {k: v for k, v in zip(variables, xs)}
#             # Cast just in case the user-supplied function returns something else
#             val = np.float64(self._session.run(cost, feed_dict=feed_dict))
#             logger.debug('Objective: {} {}'.format(val, xs))
#             return val
# 
#         if gradient is not None:
#             def gradient_(xs):
#                 feed_dict = {k: v for k, v in zip(variables, xs)}
#                 # Cast just in case the user-supplied function returns something else
#                 val = np.array(self._session.run(gradient, feed_dict=feed_dict))
#                 logger.debug('Gradient: {} {}'.format(val, xs))
#                 return val
#             approx_grad = False
#         else:
#             gradient_ = None
# 
#         if bounds:
#             min_bounds = []
#             for current in bounds:
#                 lower, upper = current
# 
#                 if isinstance(lower, tf.Tensor) or isinstance(upper, tf.Tensor):
#                     raise NotImplementedError("Specifying variable bounds to optimizers is not yet supported")
# 
#                 # Translate inf to None, which is what this minimizer understands
#                 if lower is not None and np.isinf(lower):
#                     lower = None
#                 if upper is not None and np.isinf(upper):
#                     upper = None
#                 # This optimizer likes to evaluate the function at the boundaries.
#                 # Slightly move the bounds so that the edges are not included.
#                 if lower is not None:
#                     lower = lower + 1e-10
#                 if upper is not None:
#                     upper = upper - 1e-10
# 
#                 min_bounds.append((lower, upper))
#         else:
#             min_bounds = None
# 
#         return self.minimize_impl(objective, gradient_, inits, min_bounds)
# 
# 
#     @property
#     def session(self):
#         return self._session
# 
#     @session.setter
#     def session(self, session):
#         self._session = session
# 
# Path: tensorprob/optimization_result.py
# class OptimizationResult(dict):
# 
#     def __getattr__(self, name):
#         try:
#             return self[name]
#         except KeyError:
#             raise AttributeError(name)
# 
#     __setattr__ = dict.__setitem__
#     __delattr__ = dict.__delitem__
# 
#     def __repr__(self):
#         if self.keys():
#             header = '\n' + self.__class__.__name__ + ':\n'
#             m = max(map(len, list(self.keys()))) + 1
#             return header + '\n'.join([k.rjust(m) + ': ' + repr(v)
#                               for k, v in sorted(self.items())])
#         else:
#             return self.__class__.__name__ + "()"


# Path: tensorprob/optimizers/migrad.py
import numpy as np
            import iminuit
from .base import BaseOptimizer
from ..optimization_result import OptimizationResult
        from iminuit.util import make_func_code

                all_kwargs['limit_' + n] = b

        if gradient:
            def mygrad_func(*x):
                out = gradient(x)
                return out
        else:
            mygrad_func = None

        def objective_(x):
            val = objective(x)
            if np.isnan(val) or np.isinf(val):
                return 1e10
            return val

        m = self.iminuit.Minuit(
            Min_Func(objective_, names),
            grad_fcn=mygrad_func,
            print_level=print_level,
            errordef=1,
            **all_kwargs
        )

        m.set_strategy(2)
        a, b = m.migrad()

        x = []
        for name in names:
            x.append(m.values[name])


        return OptimizationResult(