最速下降优化算法的C++实现

头文件:

/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), zmjerry@163.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                                objfunc.h
 *
 * Function Object.
 *
 * We can use this functor computing the value of objective function and it's
 * gradient vector. The objective function is supposed to be multidimensional,
 * one dimention is the special case of "vector.dim()=1".
 *
 * Zhang Ming, 2010-03, Xi'an Jiaotong University.
 *****************************************************************************/


#ifndef OBJFUNC_H
#define OBJFUNC_H


#include <vector.h>


namespace splab
{

    template <typename Type>
    class ObjFunc
    {

    public:

        /**
         * Initialize the parameters
         */
        ObjFunc( Type aa, Type bb, Type cc ) : a(aa), b(bb), c(cc)
        { }

        /**
         * Compute the value of objective function at point x.
         */
        Type operator()( Vector<Type> &x )
        {
            return ( a*x(1) * exp(b*x(1)*x(1)+c*x(2)*x(2)) );
        }

        /**
         * Compute the gradient of objective function at point x.
         */
        Vector<Type> grad( Vector<Type> &x )
        {
            Type expTerm = exp(a*x(1)*x(1)+b*x(2)*x(2));
            Vector<Type> df(x.dim());
            df(1) = (a+2*a*b*x(1)*x(1)) * expTerm;
            df(2) = 2*a*c*x(1)*x(2) * expTerm;

            return df;
        }

    private:

        // parameters
        Type a,
             b,
             c;

    };
    // class ObjFunc

}
// namespace splab


#endif
// OBJFUNC_H
/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), zmjerry@163.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                               linesearch.h
 *
 * Line search algorithm based on quadratic polynomial interpolation.
 *
 * This routine is often used in orther optimation method, so it is designed
 * as a templated base class.
 *
 * Zhang Ming, 2010-03, Xi'an Jiaotong University.
 *****************************************************************************/


#ifndef LINESEARCH_H
#define LINESEARCH_H


#include <vector.h>


namespace splab
{

    template <typename Dtype, typename Ftype>
    class LineSearch
    {

     public:

        LineSearch();
        ~LineSearch();

        Dtype getStep( Ftype &func, Vector<Dtype> &xk, Vector<Dtype> &dk,
                       int maxItr=10 );

        int getFuncNum() const;
        bool isSuccess() const;

    protected:

        int     funcNum;
        bool    success;

    };
    // class LineSearch


    #include <linesearch-impl.h>

}
// namespace splab


#endif
// LINESEARCH_H
/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), zmjerry@163.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                               steepdesc.h
 *
 * Steepest descent optimal method( gradient algorithm ).
 *
 * This class is designed for finding the minimum value of objective function
 * in one dimension or multidimension. Inexact line search algorithm is used
 * to get the step size in each iteration.
 *
 * Zhang Ming, 2010-03, Xi'an Jiaotong University.
 *****************************************************************************/


#ifndef STEEPDESC_H
#define STEEPDESC_H


#include <linesearch.h>


namespace splab
{

    template <typename Dtype, typename Ftype>
    class SteepDesc : public LineSearch<Dtype, Ftype>
    {

    public:

        SteepDesc();
        ~SteepDesc();

        void optimize( Ftype &func, Vector<Dtype> &x0,
                       Dtype tol=Dtype(1.0e-6), int maxItr=100 );

        Vector<Dtype> getOptValue() const;
        Vector<Dtype> getGradNorm() const;
        Dtype getFuncMin() const;
        int getItrNum() const;

    private:

        // iteration number
        int itrNum;

        // minimum value of objective function
        Dtype fMin;

        // optimal solution
        Vector<Dtype> xOpt;

        // gradient norm for each iteration
        Vector<Dtype> gradNorm;

    };
    // class SteepDesc


    #include <steepdesc-impl.h>

}
// namespace splab


#endif
// STEEPDESC_H

实现文件:

/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), zmjerry@163.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                               linesearch-impl.h
 *
 * Implementation for LineSearch class.
 *
 * Zhang Ming, 2010-03, Xi'an Jiaotong University.
 *****************************************************************************/


/**
 * constructors and destructor
 */
template <typename Dtype, typename Ftype>
LineSearch<Dtype, Ftype>::LineSearch()
{
    funcNum = 0;
    success = true;
}

template <typename Dtype, typename Ftype>
LineSearch<Dtype, Ftype>::~LineSearch()
{
}


/**
 * Finding the step size at point "xk" in direction of "dk" of function
 * "func". The default heuristics number is "maxItr=10".
 */
template <typename Dtype, typename Ftype>
Dtype LineSearch<Dtype, Ftype>::getStep( Ftype &func, Vector<Dtype> &xk,
                                         Vector<Dtype> &dk, int maxItr )
{
    // Set line search parameters that everyone uses.
    Dtype mu = Dtype(0.001),
          kUp = Dtype(0.5),
          kLow = Dtype(0.1),
          alpha = Dtype(1.0),
          alphaMin,
          alphaMax;

    Dtype fNew,
          fk = func(xk);

    Vector<Dtype> xNew,
                  gk = func.grad(xk);

    Dtype gd = dotProd( gk, dk );

    for( int i=0; i<maxItr; ++i )
    {
        xNew = xk + alpha*dk;
        fNew = func(xNew);
        funcNum++;

        if( fNew < fk+mu*alpha*gd )
        {
            success = true;
            return alpha;
        }
        else
        {
            alphaMin = kLow*alpha;
            alphaMax = kUp*alpha;

            // Compute the step by using quadratic polynomial interpolation.
            alpha = Dtype(-0.5)*alpha*alpha*gd / ( fNew-fk-alpha*gd );

            // bound checking
            if( alpha < alphaMin )
                alpha = alphaMin;
            else if( alpha > alphaMax )
                alpha = alphaMax;
        }
    }

    if( fNew>=fk )
    {
        success = false;
        return Dtype(0.0);
    }
    else
    {
        success = true;
        return alpha;
    }
}


/**
 * Get the number of objective function's calculation.
 */
template <typename Dtype, typename Ftype>
inline int LineSearch<Dtype, Ftype>::getFuncNum() const
{
    return funcNum;
}


/**
 * Judgement whether the optimal solution is found or not.
 */
template <typename Dtype, typename Ftype>
inline bool LineSearch<Dtype, Ftype>::isSuccess() const
{
    return success;
}
/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), zmjerry@163.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                               steepdesc-impl.h
 *
 * Implementation for SteepDesc class.
 *
 * Zhang Ming, 2010-03, Xi'an Jiaotong University.
 *****************************************************************************/


/**
 * constructors and destructor
 */
template <typename Dtype, typename Ftype>
SteepDesc<Dtype, Ftype>::SteepDesc() : LineSearch<Dtype, Ftype>()
{
}

template <typename Dtype, typename Ftype>
SteepDesc<Dtype, Ftype>::~SteepDesc()
{
}


/**
 * Finding the optimal solution. The default tolerance error and maximum
 * iteratin number are "tol=1.0e-6" and "maxItr=100", respectively.
 */
template <typename Dtype, typename Ftype>
void SteepDesc<Dtype, Ftype>::optimize( Ftype &func, Vector<Dtype> &x0,
                                        Dtype tol, int maxItr )
{
    // initialize parameters.
    int k = 0;
    Vector<Dtype> x(x0);
    Dtype fx = func(x);
    this->funcNum++;
    Vector<Dtype> gnorm(maxItr);
    Vector<Dtype> g = func.grad(x);
    gnorm[k++]= norm(g);

    Dtype alpha;
    Vector<Dtype> d(g.dim());

    while( ( gnorm(k) > tol ) && ( k < maxItr ) )
    {
        // descent direction
        d =  - g;

        // one dimension searching
        alpha = this->getStep( func, x, d );
        if( !this->success )
            break;

		// update
        x += alpha*d;
        fx = func(x);
        this->funcNum++;
        g = func.grad(x);
        gnorm[k++] = norm(g);
    }

    xOpt = x;
    fMin = fx;
    gradNorm.resize(k);
    for( int i=0; i<k; ++i )
        gradNorm[i] = gnorm[i];

    if( gradNorm[k-1] > tol )
        this->success = false;
}


/**
 * Get the optimum point.
 */
template <typename Dtype, typename Ftype>
inline Vector<Dtype> SteepDesc<Dtype, Ftype>::getOptValue() const
{
    return xOpt;
}


/**
 * Get the norm of gradient in each iteration.
 */
template <typename Dtype, typename Ftype>
inline Vector<Dtype> SteepDesc<Dtype, Ftype>::getGradNorm() const
{
    return gradNorm;
}


/**
 * Get the minimum value of objective function.
 */
template <typename Dtype, typename Ftype>
inline Dtype SteepDesc<Dtype, Ftype>::getFuncMin() const
{
    return fMin;
}


/**
 * Get the iteration number.
 */
template <typename Dtype, typename Ftype>
inline int SteepDesc<Dtype, Ftype>::getItrNum() const
{
    return gradNorm.dim()-1;
}

测试代码:

/*****************************************************************************
 *                               steepdesc_test.cpp
 *
 * Steepest descent method testing.
 *
 * Zhang Ming, 2010-03, Xi'an Jiaotong University.
 *****************************************************************************/


#define BOUNDS_CHECK

#include <iostream>
#include <iomanip>
#include <objfunc.h>
#include <steepdesc.h>


using namespace std;
using namespace splab;


typedef float  Type;


int main()
{
    Type a = 1.0,
         b = -1.0,
         c = -1.0;
    ObjFunc<Type> f( a, b, c );
    Vector<Type> x0(2);
    x0(1) = Type(0.0);
    x0(2) = Type(0.0);

    Type tolErr = 1.0e-3;
    SteepDesc< Type, ObjFunc<Type> > steep;
    steep.optimize( f, x0, tolErr );
    if( steep.isSuccess() )
    {
        Vector<Type> xmin = steep.getOptValue();
        int N = steep.getItrNum();
        cout << "The iterative number is:   " << N << endl << endl;
        cout << "The number of function calculation is:   "
             << steep.getFuncNum() << endl << endl;
        cout << setiosflags(ios::fixed) << setprecision(4);
        cout << "The optimal value of x is:   " << xmin << endl;
        cout << "The minimum value of f(x) is:   " << f(xmin) << endl << endl;
        cout << "The gradient's norm at x is:   "
             << steep.getGradNorm()[N] << endl << endl;
    }
    else
        cout << "The optimal solution  can't be found!" << endl;

    return 0;
}

运行结果:

The iterative number is:   14

The number of function calculation is:   43

The optimal value of x is:   size: 2 by 1
-0.7070
0.0000

The minimum value of f(x) is:   -0.4289

The gradient's norm at x is:   0.0006


Process returned 0 (0x0)   execution time : 0.062 s
Press any key to continue.

转载于:https://my.oschina.net/zmjerry/blog/11025

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值