# Path: nlp/model/algopymodel.py
# class AlgopyModel(NLPModel):
#     """Model with derivatives computed by AlgoPy.
# 
#     A class to represent optimization problems in which derivatives
#     are computed via algorithmic differentiation through AlgoPy.
#     AlgoPy only supplies dense derivatives.
#     See the documentation of `NLPModel` for further information.
#     """
# 
#     def __init__(self, n, m=0, name='Algopy-Generic', **kwargs):
#         """Initialize a model with `n` variables and `m` constraints.
# 
#         :parameters:
# 
#             :n:       number of variables (default: 0)
#             :m:       number of general (non bound) constraints (default: 0)
#             :name:    model name (default: 'Generic')
#         """
#         super(AlgopyModel, self).__init__(n, m=m, name=name, **kwargs)
# 
#         self._cg_obj = None
#         self._cg_cons = None
#         self._cg_lag = None
# 
#         self._trace_obj(self.x0)
#         self._trace_lag(self.x0, self.pi0)
#         if m > 0:
#             self._trace_cons(self.x0)
# 
#     @property
#     def cg_obj(self):
#         """Objective function call graph."""
#         return self._cg_obj
# 
#     @property
#     def cg_cons(self):
#         """Constraint call graph."""
#         return self._cg_cons
# 
#     @property
#     def cg_lag(self):
#         """Lagrangian call graph."""
#         return self._cg_lag
# 
#     def _trace_obj(self, x):
#         """Trace the objective function evaluation."""
#         if self._cg_obj is not None:
#             return
#         cg = algopy.CGraph()
#         x = algopy.Function(x)
#         y = self.obj(x)
#         cg.trace_off()
#         cg.independentFunctionList = [x]
#         cg.dependentFunctionList = [y]
#         self._cg_obj = cg
# 
#     def _trace_cons(self, x):
#         """Trace the constraints evaluation."""
#         if self._cg_cons is not None or self.m == 0:
#             return
#         cg = algopy.CGraph()
#         x = algopy.Function(x)
#         y = self.cons(x)
#         cg.trace_off()
#         cg.independentFunctionList = [x]
#         cg.dependentFunctionList = [y]
#         self._cg_cons = cg
# 
#     def _trace_lag(self, x, z):
#         """Trace the Lagrangian evaluation."""
#         if self._cg_lag is not None:
#             return
#         self._trace_obj(x)
#         self._trace_cons(x)
#         unconstrained = self.m == 0 and self.nbounds == 0
# 
#         if unconstrained:
#             self._cg_lag = self._cg_obj
#             return
# 
#         cg = algopy.CGraph()
#         xz = np.concatenate((x, z))
#         xz = algopy.Function(xz)
#         l = self.lag(xz[:self.nvar], xz[self.nvar:])
#         cg.independentFunctionList = [xz]
#         cg.dependentFunctionList = [l]
#         self._cg_lag = cg
# 
#     def grad(self, x, **kwargs):
#         """Evaluate the objective gradient at x."""
#         return self._cg_obj.gradient(x)
# 
#     # Override lag because Algopy won't apply numpy.dot() between a
#     # Numpy array and an array of Functions.
#     def lag(self, x, z, **kwargs):
#         """Evaluate Lagrangian at (x, z).
# 
#         The constraints and bounds are assumed to be ordered as in
#         :meth:`cons_pos` and :meth:`bounds`.
#         """
#         m = self.m
#         nrC = self.nrangeC
# 
#         l = self.obj(x)
#         # The following ifs are necessary because np.dot returns None
#         # when passed empty arrays of objects (i.e., dtype = np.object).
#         # This causes AD tools to error out.
#         if self.m > 0:
#             l -= algopy.dot(z[:m + nrC], self.cons(x))
#         if self.nbounds > 0:
#             l -= algopy.dot(z[m + nrC:], self.bounds(x))
#         return l
# 
#     def hess(self, x, z=None, **kwargs):
#         """Return the Hessian of the objective at x."""
#         if z is None:
#             z = np.zeros(self.ncon)
#         xz = np.concatenate((x, z))
#         return self._cg_lag.hessian(xz)[:self.nvar, :self.nvar]
# 
#     def hprod(self, x, z, v, **kwargs):
#         """Return the Hessian-vector product at x with v."""
#         xz = np.concatenate((x, z))
#         v0 = np.concatenate((v, np.zeros(self.ncon)))
#         return self._cg_lag.hess_vec(xz, v0)[:self.nvar]
# 
#     def cons_pos(self, x):
#         """Identical to `cons` for `AlgopyModel`s."""
#         return self.cons(x)
# 
#     def jac(self, x, **kwargs):
#         """Return constraints Jacobian at x."""
#         return self._cg_cons.jacobian(x)
# 
#     def jac_pos(self, x, **kwargs):
#         """Return reformulated constraints Jacobian at x."""
#         return self.jac(x, **kwargs)
# 
#     def jprod(self, x, v, **kwargs):
#         """Return the Jacobian-vector product at x with v."""
#         return self._cg_cons.jac_vec(x, v)
# 
#     def jtprod(self, x, v, **kwargs):
#         """Return the transpose-Jacobian-vector product at x with v."""
#         return self._cg_cons.vec_jac(v, x)


import algopy
from nlp.model.algopymodel import AlgopyModel


class AlgopyRosenbrock(AlgopyModel):
    """The standard Rosenbrock function."""

    def obj(self, x, **kwargs):
        return algopy.sum(100 * (x[1:] - x[:-1]**2)**2 + (1 - x[:-1])**2)



# Path: nlp/model/algopymodel.py
# class AlgopyModel(NLPModel):
#     """Model with derivatives computed by AlgoPy.
# 
#     A class to represent optimization problems in which derivatives
#     are computed via algorithmic differentiation through AlgoPy.
#     AlgoPy only supplies dense derivatives.
#     See the documentation of `NLPModel` for further information.
#     """
# 
#     def __init__(self, n, m=0, name='Algopy-Generic', **kwargs):
#         """Initialize a model with `n` variables and `m` constraints.
# 
#         :parameters:
# 
#             :n:       number of variables (default: 0)
#             :m:       number of general (non bound) constraints (default: 0)
#             :name:    model name (default: 'Generic')
#         """
#         super(AlgopyModel, self).__init__(n, m=m, name=name, **kwargs)
# 
#         self._cg_obj = None
#         self._cg_cons = None
#         self._cg_lag = None
# 
#         self._trace_obj(self.x0)
#         self._trace_lag(self.x0, self.pi0)
#         if m > 0:
#             self._trace_cons(self.x0)
# 
#     @property
#     def cg_obj(self):
#         """Objective function call graph."""
#         return self._cg_obj
# 
#     @property
#     def cg_cons(self):
#         """Constraint call graph."""
#         return self._cg_cons
# 
#     @property
#     def cg_lag(self):
#         """Lagrangian call graph."""
#         return self._cg_lag
# 
#     def _trace_obj(self, x):
#         """Trace the objective function evaluation."""
#         if self._cg_obj is not None:
#             return
#         cg = algopy.CGraph()
#         x = algopy.Function(x)
#         y = self.obj(x)
#         cg.trace_off()
#         cg.independentFunctionList = [x]
#         cg.dependentFunctionList = [y]
#         self._cg_obj = cg
# 
#     def _trace_cons(self, x):
#         """Trace the constraints evaluation."""
#         if self._cg_cons is not None or self.m == 0:
#             return
#         cg = algopy.CGraph()
#         x = algopy.Function(x)
#         y = self.cons(x)
#         cg.trace_off()
#         cg.independentFunctionList = [x]
#         cg.dependentFunctionList = [y]
#         self._cg_cons = cg
# 
#     def _trace_lag(self, x, z):
#         """Trace the Lagrangian evaluation."""
#         if self._cg_lag is not None:
#             return
#         self._trace_obj(x)
#         self._trace_cons(x)
#         unconstrained = self.m == 0 and self.nbounds == 0
# 
#         if unconstrained:
#             self._cg_lag = self._cg_obj
#             return
# 
#         cg = algopy.CGraph()
#         xz = np.concatenate((x, z))
#         xz = algopy.Function(xz)
#         l = self.lag(xz[:self.nvar], xz[self.nvar:])
#         cg.independentFunctionList = [xz]
#         cg.dependentFunctionList = [l]
#         self._cg_lag = cg
# 
#     def grad(self, x, **kwargs):
#         """Evaluate the objective gradient at x."""
#         return self._cg_obj.gradient(x)
# 
#     # Override lag because Algopy won't apply numpy.dot() between a
#     # Numpy array and an array of Functions.
#     def lag(self, x, z, **kwargs):
#         """Evaluate Lagrangian at (x, z).
# 
#         The constraints and bounds are assumed to be ordered as in
#         :meth:`cons_pos` and :meth:`bounds`.
#         """
#         m = self.m
#         nrC = self.nrangeC
# 
#         l = self.obj(x)
#         # The following ifs are necessary because np.dot returns None
#         # when passed empty arrays of objects (i.e., dtype = np.object).
#         # This causes AD tools to error out.
#         if self.m > 0:
#             l -= algopy.dot(z[:m + nrC], self.cons(x))
#         if self.nbounds > 0:
#             l -= algopy.dot(z[m + nrC:], self.bounds(x))
#         return l
# 
#     def hess(self, x, z=None, **kwargs):
#         """Return the Hessian of the objective at x."""
#         if z is None:
#             z = np.zeros(self.ncon)
#         xz = np.concatenate((x, z))
#         return self._cg_lag.hessian(xz)[:self.nvar, :self.nvar]
# 
#     def hprod(self, x, z, v, **kwargs):
#         """Return the Hessian-vector product at x with v."""
#         xz = np.concatenate((x, z))
#         v0 = np.concatenate((v, np.zeros(self.ncon)))
#         return self._cg_lag.hess_vec(xz, v0)[:self.nvar]
# 
#     def cons_pos(self, x):
#         """Identical to `cons` for `AlgopyModel`s."""
#         return self.cons(x)
# 
#     def jac(self, x, **kwargs):
#         """Return constraints Jacobian at x."""
#         return self._cg_cons.jacobian(x)
# 
#     def jac_pos(self, x, **kwargs):
#         """Return reformulated constraints Jacobian at x."""
#         return self.jac(x, **kwargs)
# 
#     def jprod(self, x, v, **kwargs):
#         """Return the Jacobian-vector product at x with v."""
#         return self._cg_cons.jac_vec(x, v)
# 
#     def jtprod(self, x, v, **kwargs):
#         """Return the transpose-Jacobian-vector product at x with v."""
#         return self._cg_cons.vec_jac(v, x)


# Path: tests/model/algopy_helper.py
import algopy
from nlp.model.algopymodel import AlgopyModel



class AlgopyRosenbrock(AlgopyModel):
    """The standard Rosenbrock function."""

    def obj(self, x, **kwargs):
        return algopy.sum(100 * (x[1:] - x[:-1]**2)**2 + (1 - x[:-1])**2)



class AlgopyHS7(AlgopyModel):