"""
SciPy-based function optimization
"""

import numpy as np
import scipy

from autodiff.symbolic import VectorArg
import autodiff.utils as utils


def fmin_l_bfgs_b(fn,
                  args,
                  scalar_bounds=None,
                  return_info=False,
                  **scipy_kwargs):
    """
    Minimize 'fn' using SciPy's L-BFGS-B algorithm. The initial parameter guess
    is 'args'.

    """

    args = utils.as_seq(args, tuple)
    f_df = VectorArg(fn, init_args=args, compile_fn=True, compile_grad=True)
    x0 = f_df.vector_from_args(args)

    if 'approx_grad' in scipy_kwargs:
        raise TypeError('duplicate argument: approx_grad')
    if scalar_bounds is not None:
        lb, ub = scalar_bounds
        bounds = np.empty((len(x0), 2))
        bounds[:, 0] = lb
        bounds[:, 1] = ub
        if 'bounds' in scipy_kwargs:
            raise TypeError('duplicate argument: bounds')
        scipy_kwargs['bounds'] = bounds

    x_opt, mincost, info = scipy.optimize.fmin_l_bfgs_b(
        func=f_df,
        x0=x0,
        approx_grad=False,
        **scipy_kwargs)

    x_reshaped = f_df.args_from_vector(x_opt)
    assert len(x_reshaped) == len(args)
    if len(x_reshaped) == 1:
        x_reshaped = x_reshaped[0]

    if return_info:
        return x_reshaped, {'fopt': mincost, 'info': info}
    else:
        return x_reshaped

@@ -142,16 +142,787 @@
 utils%0A%0A%0A
+def fmin_cg(fn,%0A            args,%0A            return_info=False,%0A            **scipy_kwargs):%0A    %22%22%22%0A    Minimize a scalar valued function using SciPy's nonlinear conjugate%0A    gradient algorithm. The initial parameter guess is 'args'.%0A%0A    %22%22%22%0A%0A    args = utils.as_seq(args, tuple)%0A    f = VectorArg(fn, init_args=args, compile_fn=True)%0A    fprime = VectorArg(fn, init_args=args, compile_grad=True)%0A    x0 = f.vector_from_args(args)%0A%0A    x_opt, f_opt, info = scipy.optimize.fmin_cg(%0A        f=f,%0A        x0=x0,%0A        fprime=fprime,%0A        **scipy_kwargs)%0A%0A    x_reshaped = f.args_from_vector(x_opt)%0A    if len(x_reshaped) == 1:%0A        x_reshaped = x_reshaped%5B0%5D%0A%0A    if return_info:%0A        return x_reshaped, %7B'f_opt': f_opt%7D%0A    else:%0A        return x_reshaped%0A%0A%0A
 def fmin
@@ -931,24 +931,24 @@
 _bfgs_b(fn,%0A
-
             
@@ -1094,12 +1094,32 @@
 ize 
-'fn'
+a scalar valued function
  usi
@@ -1144,32 +1144,36 @@
 B algorithm. The
+%0A   
  initial paramet
@@ -1180,20 +1180,16 @@
 er guess
-%0A   
  is 'arg
@@ -1755,22 +1755,20 @@
  x_opt, 
-mincos
+f_op
 t, info 
@@ -1935,48 +1935,8 @@
 pt)%0A
-    assert len(x_reshaped) == len(args)%0A
     
@@ -2050,20 +2050,19 @@
  %7B'f
+_
 opt': 
-mincos
+f_op
 t, '

add fmin_cg to minimizers