Esempio n. 1
0
def _minimize_pso(fun,
                  x0,
                  confunc=None,
                  friction=.8,
                  max_velocity=5.,
                  g_rate=.8,
                  l_rate=.5,
                  max_iter=1000,
                  stable_iter=100,
                  ptol=1e-6,
                  ctol=1e-6,
                  callback=None,
                  verbose=False,
                  savefile=None):
    """Internal implementation for ``psopy.minimize``.

    See Also
    --------
    psopy.minimize : The SciPy compatible interface to this function. Refer to
        its documentation for an explanation of the parameters.
    psopy.gen_confunc : Utility function to convert SciPy style constraints
        to the form required by this function.

    Parameters
    ----------
    x0 : array_like of shape (N, D)
        Initial position to begin PSO from, where ``N`` is the number of points
        and ``D`` the dimensionality of each point. For the constrained case
        these points should satisfy all constraints.
    fun : callable
        The objective function to be minimized. Must be in the form
        ``fun(pos, *args)``. The argument ``pos``, is a 2-D array for initial
        positions, where each row specifies the position of a different
        particle, and ``args`` is a tuple of any additional fixed parameters
        needed to completely specify the function.
    confunc : callable
        The function that describes constraints. Must be of the form
        ``confunc(pos)`` that returns the constraint matrix.

    Notes
    -----
    Using this function directly allows for a slightly faster implementation
    that does away with the need for the additional recursive calls needed to
    wrap the constraint and objective functions for compatibility with Scipy.

    Examples
    --------
    These examples are identical to those laid out in ``psopy.minimize`` and
    serve to illustrate the additional overhead in ensuring compatibility.

    >>> import numpy as np
    >>> from psopy import _minimize_pso

    Consider the problem of minimizing the Rosenbrock function implemented as
    ``scipy.optimize.rosen``.

    >>> from scipy.optimize import rosen
    >>> fun = lambda x: np.apply_along_axis(rosen, 1, x)

    Initialize 1000 particles and run the minimization function.

    >>> x0 = np.random.uniform(0, 2, (1000, 5))
    >>> res = _minimize_pso(fun, x0, stable_iter=50)
    >>> res.x
    array([1.00000003, 1.00000017, 1.00000034, 1.0000006 , 1.00000135])

    Consider the constrained optimization problem with the objective function
    defined as:

    >>> fun = lambda x: (x[0] - 1)**2 + (x[1] - 2.5)**2
    >>> fun_ = lambda x: np.apply_along_axis(fun, 1, x)

    and constraints defined as:

    >>> cons = ({'type': 'ineq', 'fun': lambda x:  x[0] - 2 * x[1] + 2},
    ...         {'type': 'ineq', 'fun': lambda x: -x[0] - 2 * x[1] + 6},
    ...         {'type': 'ineq', 'fun': lambda x: -x[0] + 2 * x[1] + 2},
    ...         {'type': 'ineq', 'fun': lambda x: x[0]},
    ...         {'type': 'ineq', 'fun': lambda x: x[1]})

    Initializing the constraint function and feasible solutions:

    >>> from psopy import init_feasible, gen_confunc
    >>> x0 = init_feasible(cons, low=0., high=2., shape=(1000, 2))
    >>> confunc = gen_confunc(cons)

    Running the constrained version of the function:

    >>> res = _minimize_pso(fun_, x0, confunc=confunc, options={
    ...     'g_rate': 1., 'l_rate': 1., 'max_velocity': 4., 'stable_iter': 50})
    >>> res.x
    array([ 1.39985398,  1.69992748])

    """
    if verbose:
        message = setup_print(x0.shape[1], max_iter, confunc is not None)
    if savefile:
        iterinfo = []

    position = np.copy(x0)
    velocity = np.random.uniform(-max_velocity, max_velocity, position.shape)
    pbest = np.copy(position)
    gbest = pbest[np.argmin(fun(pbest))]
    oldfit = fun(gbest[None])[0]
    stable_count = 0

    for ii in range(max_iter):
        # Determine global and local gradient.
        dv_g = g_rate * uniform(0, 1) * (gbest - position)
        if confunc is not None:
            leaders = np.argmin(distance.cdist(position, pbest, 'sqeuclidean'),
                                axis=1)
            dv_l = l_rate * uniform(0, 1) * (pbest[leaders] - position)
        else:
            dv_l = l_rate * uniform(0, 1) * (pbest - position)

        # Update velocity and position of particles.
        velocity *= friction
        velocity += (dv_g + dv_l)
        np.clip(velocity, -max_velocity, max_velocity, out=velocity)

        position += velocity
        to_update = (fun(position) < fun(pbest))
        if confunc is not None:
            to_update &= (confunc(position).sum(axis=1) < ctol)

        if to_update.any():
            pbest[to_update] = position[to_update]
            gbest = pbest[np.argmin(fun(pbest))]

        # Termination criteria.
        fval = fun(gbest[None])[0]
        if np.abs(oldfit - fval) < ptol:
            stable_count += 1
            if stable_count == stable_iter:
                break
        else:
            stable_count = 0
        oldfit = fval

        if verbose or savefile:
            info = [ii, gbest, fval]
            if confunc is not None:
                cv = np.max(confunc(gbest[None]))
                info.append(cv)

            if verbose:
                print(message.format(*info))

            if savefile:
                iterinfo.append(info)

        # Final callback.
        if callback is not None:
            position = callback(position)

    if savefile:
        save_info(savefile, iterinfo, constraints=confunc is not None)

    result = OptimizeResult(x=gbest,
                            fun=fun(gbest[None])[0],
                            nit=ii,
                            nsit=stable_count)

    violation = False
    if confunc is not None:
        convec = confunc(gbest[None])
        result.maxcv = np.max(convec)
        result.cvec = convec
        if convec.sum() > ctol:
            violation = True

    if violation:
        result.status = 2
    elif ii == max_iter:
        result.status = 1
    else:
        result.status = 0

    result.success = not result.status
    return result
Esempio n. 2
0
def _minimize_qpso(fun,
                   x0,
                   confunc=None,
                   g=.96,
                   max_iter=1000,
                   stable_iter=40,
                   ptol=1e-6,
                   ctol=1e-6,
                   levy_rate=0,
                   decay_rate=0,
                   reduction_rate=0.5,
                   callback=None,
                   verbose=False,
                   savefile=None):
    """Internal implementation for ``psopy.minimize_qpso``.

    See Also
    --------
    psopy.minimize_qpso : The SciPy compatible interface to this function. Refer to
        its documentation for an explanation of the parameters.
    psopy.gen_confunc : Utility function to convert SciPy style constraints
        to the form required by this function.

    Parameters
    ----------
    x0 : array_like of shape (N, D)
        Initial position to begin QPSO from, where ``N`` is the number of points
        and ``D`` the dimensionality of each point. For the constrained case
        these points should satisfy all constraints.
    fun : callable
        The objective function to be minimized. Must be in the form
        ``fun(pos, *args)``. The argument ``pos``, is a 2-D array for initial
        positions, where each row specifies the position of a different
        particle, and ``args`` is a tuple of any additional fixed parameters
        needed to completely specify the function.
    confunc : callable
        The function that describes constraints. Must be of the form
        ``confunc(pos)`` that returns the constraint matrix.

    levy_rate: float
        Whether to run the levy decay qpso or not. > 0 value turns on levy walk

    decay_rate: float
        Whether to turn on the decay function or not. > 0 value turns on the decay rate 

    Notes
    -----
    Chaotic Quantum PSO
    Using this function directly allows for a slightly faster implementation
    that does away with the need for the additional recursive calls needed to
    wrap the constraint and objective functions for compatibility with Scipy. 
    """

    if verbose:
        message = setup_print(x0.shape[1], max_iter, confunc is not None)
    if savefile:
        iterinfo = []

    position = np.copy(x0)
    nparam = len(position)
    pbest = np.copy(position)
    gbest = pbest[np.argmin(fun(pbest))]
    oldfit = fun(gbest[None])[0]
    stable_count = 0
    dimension = len(position[0])

    #simple levy walk. Make a decay function which will push particles around using stable_iter,max_iter is reached, pushing them away from pbest
    beta = 3 / 2
    sigma = (gamma(1 + beta) * sin(pi * beta / 2) / (gamma(
        (1 + beta) / 2) * beta * 2**((beta - 1) / 2)))**(1 / beta)
    decay = 1
    stepsize = 1.0
    for ii in range(max_iter):
        mbest = np.sum(pbest, axis=0) / pbest.shape[0]
        u = np.random.normal(0, 1, size=dimension) * sigma
        v = np.random.normal(0, 1, size=dimension)
        step = u / abs(v)**(1 / beta)
        psi_1 = uniform(0, 1)
        psi_2 = uniform(0, 1)
        dv_g = psi_1 * gbest

        if confunc is not None:
            leaders = np.argmin(distance.cdist(position, pbest, 'sqeuclidean'),
                                axis=1)
            dv_l = psi_2 * pbest[leaders]
        else:
            dv_l = psi_2 * pbest

        P = (dv_g + dv_l) / (psi_1 + psi_2)
        u = uniform(0, 1, nparam)

        stepsize = 1.0
        for i in range(0, nparam):
            if levy_rate > 0:
                stepsize = 0.01 * step * (1 /
                                          (0.0000001 + position[i] - gbest[i]))
                if decay_rate > 0:
                    decay = stepsize * 5 * (0.001)**(ii /
                                                     (max_iter * 0.05)) + 1

            if uniform(0, 1) > 0.5:
                position[i] = P[i] - mbest * np.log(1 / u[i]) * decay
            else:
                position[i] = P[i] + mbest * np.log(1 / u[i]) * decay

        to_update = (fun(position) < fun(pbest))
        if confunc is not None:
            to_update &= (confunc(position).sum(axis=1) < ctol)

        if to_update.any():
            pbest[to_update] = position[to_update]
            gbest = pbest[np.argmin(fun(pbest))]

        # Termination criteria.
        fval = fun(gbest[None])[0]
        if np.abs(oldfit - fval) < ptol:
            stable_count += 1
            if stable_count == stable_iter:
                break
        else:
            stable_count = 0
        oldfit = fval

        if verbose or savefile:
            info = [ii, gbest, fval]
            if confunc is not None:
                cv = np.max(confunc(gbest[None]))
                info.append(cv)

            if verbose:
                print(message.format(*info))

            if savefile:
                iterinfo.append(info)

        # Final callback.
        if callback is not None:
            position = callback(position)

    if savefile:
        save_info(savefile, iterinfo, constraints=confunc is not None)

    result = OptimizeResult(x=gbest,
                            fun=fun(gbest[None])[0],
                            nit=ii,
                            nsit=stable_count)

    violation = False
    if confunc is not None:
        convec = confunc(gbest[None])
        result.maxcv = np.max(convec)
        result.cvec = convec
        if convec.sum() > ctol:
            violation = True

    if violation:
        result.status = 2
    elif ii == max_iter:
        result.status = 1
    else:
        result.status = 0

    result.success = not result.status
    return result