class_docstr: Scalar function and its derivatives.
  
  This class defines a scalar function F: R^n->R and methods for
  computing or approximating its first and second derivatives.
  
  Notes
  -----
  This class implements a memoization logic. There are methods `fun`,
  `grad`, hess` and corresponding attributes `f`, `g` and `H`. The following
  things should be considered:
  
      1. Use only public methods `fun`, `grad` and `hess`.
      2. After one of the methods is called, the corresponding attribute
         will be set. However, a subsequent call with a different argument
         of *any* of the methods may overwrite the attribute.
class_docstr_tok: ["Scalar","function","and","its","derivatives",".","This","class","defines","a","scalar","function","F",":","R^n-",">","R","and","methods","for","computing","or","approximating","its","first","and","second","derivatives",".","Notes","--","--","-","This","class","implements","a","memoization","logic",".","There","are","methods","`","fun","`",",","`","grad","`",",","hess","`","and","corresponding","attributes","`","f","`",",","`","g","`","and","`","H","`",".","The","following","things","should","be","considered",":","1",".","Use","only","public","methods","`","fun","`",",","`","grad","`","and","`","hess","`",".","2",".","After","one","of","the","methods","is","called",",","the","corresponding","attribute","will","be","set",".","However",",","a","subsequent","call","with","a","different","argument","of","*","any","*","of","the","methods","may","overwrite","the","attribute","."]
code: def __init__(
      self,
      fun,
      x0,
      args,
      grad,
      hess,
      finite_diff_rel_step,
      finite_diff_bounds,
  ):
      if not callable(grad) and grad not in FD_METHODS:
          raise ValueError(
              "`grad` must be either callable or one of {}.".format(
                  FD_METHODS
              )
          )
  
      if not (
          callable(hess)
          or hess in FD_METHODS
          or isinstance(hess, HessianUpdateStrategy)
      ):
          raise ValueError(
              "`hess` must be either callable,"
              "HessianUpdateStrategy or one of {}.".format(FD_METHODS)
          )
  
      if grad in FD_METHODS and hess in FD_METHODS:
          raise ValueError(
              "Whenever the gradient is estimated via "
              "finite-differences, we require the Hessian "
              "to be estimated using one of the "
              "quasi-Newton strategies."
          )
  
      self.x = np.atleast_1d(x0).astype(float)
      self.n = self.x.size
      self.nfev = 0
      self.ngev = 0
      self.nhev = 0
      self.f_updated = False
      self.g_updated = False
      self.H_updated = False
  
      finite_diff_options = {}
      if grad in FD_METHODS:
          finite_diff_options["method"] = grad
          finite_diff_options["rel_step"] = finite_diff_rel_step
          finite_diff_options["bounds"] = finite_diff_bounds
      if hess in FD_METHODS:
          finite_diff_options["method"] = hess
          finite_diff_options["rel_step"] = finite_diff_rel_step
          finite_diff_options["as_linear_operator"] = True
  
      # Function evaluation
      def fun_wrapped(x):
          self.nfev += 1
          return fun(x, *args)
  
      def update_fun():
          self.f = fun_wrapped(self.x)
  
      self._update_fun_impl = update_fun
      self._update_fun()
  
      # Gradient evaluation
      if callable(grad):
  
          def grad_wrapped(x):
              self.ngev += 1
              return np.atleast_1d(grad(x, *args))
  
          def update_grad():
              self.g = grad_wrapped(self.x)
  
      elif grad in FD_METHODS:
  
          def update_grad():
              self._update_fun()
              self.g = approx_derivative(
                  fun_wrapped, self.x, f0=self.f, **finite_diff_options
              )
  
      self._update_grad_impl = update_grad
      self._update_grad()
  
      # Hessian Evaluation
      if callable(hess):
          self.H = hess(x0, *args)
          self.H_updated = True
          self.nhev += 1
  
          if sps.issparse(self.H):
  
              def hess_wrapped(x):
                  self.nhev += 1
                  return sps.csr_matrix(hess(x, *args))
  
              self.H = sps.csr_matrix(self.H)
  
          elif isinstance(self.H, LinearOperator):
  
              def hess_wrapped(x):
                  self.nhev += 1
                  return hess(x, *args)
  
          else:
  
              def hess_wrapped(x):
                  self.nhev += 1
                  return np.atleast_2d(np.asarray(hess(x, *args)))
  
              self.H = np.atleast_2d(np.asarray(self.H))
  
          def update_hess():
              self.H = hess_wrapped(self.x)
  
      elif hess in FD_METHODS:
  
          def update_hess():
              self._update_grad()
              self.H = approx_derivative(
                  grad_wrapped, self.x, f0=self.g, **finite_diff_options
              )
              return self.H
  
          update_hess()
          self.H_updated = True
      elif isinstance(hess, HessianUpdateStrategy):
          self.H = hess
          self.H.initialize(self.n, "hess")
          self.H_updated = True
          self.x_prev = None
          self.g_prev = None
  
          def update_hess():
              self._update_grad()
              self.H.update(self.x - self.x_prev, self.g - self.g_prev)
  
      self._update_hess_impl = update_hess
  
      if isinstance(hess, HessianUpdateStrategy):
  
          def update_x(x):
              self._update_grad()
              self.x_prev = self.x
              self.g_prev = self.g
  
              self.x = x
              self.f_updated = False
              self.g_updated = False
              self.H_updated = False
              self._update_hess()
  
      else:
  
          def update_x(x):
              self.x = x
              self.f_updated = False
              self.g_updated = False
              self.H_updated = False
  
      self._update_x_impl = update_x
  
imports: from __future__ import division, print_function, absolute_import
  import numpy
  import scipy.sparse
  from ._numdiff import approx_derivative, group_columns
  from ._hessian_update_strategy import HessianUpdateStrategy
  from scipy.sparse.linalg import LinearOperator
label_desc: Use image node_id 1 to create a new ScalarFunction object from inherited base classes: object with example: obj = ScalarFunction(fun, x0, args, grad, hess, finite_diff_rel_step, finite_diff_bounds)