This source file includes following definitions.
- getInitStep
- setInitStep
- getFunction
- setFunction
- getTermCriteria
- setTermCriteria
- minimize
- updateCoordSum
- createInitialSimplex
- innerDownhillSimplex
- calc_f
- tryNewPoint
- replacePoint
- create
#include "precomp.hpp"
#if 0
#define dprintf(x) printf x
#define print_matrix(x) print(x)
#else
#define dprintf(x)
#define print_matrix(x)
#endif
namespace cv
{
class DownhillSolverImpl : public DownhillSolver
{
public:
DownhillSolverImpl()
{
_Function=Ptr<Function>();
_step=Mat_<double>();
}
void getInitStep(OutputArray step) const { _step.copyTo(step); }
void setInitStep(InputArray step)
{
Mat m = step.getMat();
dprintf(("m.cols=%d\nm.rows=%d\n", m.cols, m.rows));
if( m.rows == 1 )
m.copyTo(_step);
else
transpose(m, _step);
}
Ptr<MinProblemSolver::Function> getFunction() const { return _Function; }
void setFunction(const Ptr<Function>& f) { _Function=f; }
TermCriteria getTermCriteria() const { return _termcrit; }
void setTermCriteria( const TermCriteria& termcrit )
{
CV_Assert( termcrit.type == (TermCriteria::MAX_ITER + TermCriteria::EPS) &&
termcrit.epsilon > 0 &&
termcrit.maxCount > 0 );
_termcrit=termcrit;
}
double minimize( InputOutputArray x_ )
{
dprintf(("hi from minimize\n"));
CV_Assert( !_Function.empty() );
CV_Assert( std::min(_step.cols, _step.rows) == 1 &&
std::max(_step.cols, _step.rows) >= 2 &&
_step.type() == CV_64FC1 );
dprintf(("termcrit:\n\ttype: %d\n\tmaxCount: %d\n\tEPS: %g\n",_termcrit.type,_termcrit.maxCount,_termcrit.epsilon));
dprintf(("step\n"));
print_matrix(_step);
Mat x = x_.getMat(), simplex;
createInitialSimplex(x, simplex, _step);
int count = 0;
double res = innerDownhillSimplex(simplex,_termcrit.epsilon, _termcrit.epsilon,
count, _termcrit.maxCount);
dprintf(("%d iterations done\n",count));
if( !x.empty() )
{
Mat simplex_0m(x.rows, x.cols, CV_64F, simplex.ptr<double>());
simplex_0m.convertTo(x, x.type());
}
else
{
int x_type = x_.fixedType() ? x_.type() : CV_64F;
simplex.row(0).convertTo(x_, x_type);
}
return res;
}
protected:
Ptr<MinProblemSolver::Function> _Function;
TermCriteria _termcrit;
Mat _step;
inline void updateCoordSum(const Mat& p, Mat& coord_sum)
{
int i, j, m = p.rows, n = p.cols;
double* coord_sum_ = coord_sum.ptr<double>();
CV_Assert( coord_sum.cols == n && coord_sum.rows == 1 );
for( j = 0; j < n; j++ )
coord_sum_[j] = 0.;
for( i = 0; i < m; i++ )
{
const double* p_i = p.ptr<double>(i);
for( j = 0; j < n; j++ )
coord_sum_[j] += p_i[j];
}
dprintf(("\nupdated coord sum:\n"));
print_matrix(coord_sum);
}
inline void createInitialSimplex( const Mat& x0, Mat& simplex, Mat& step )
{
int i, j, ndim = step.cols;
CV_Assert( _Function->getDims() == ndim );
Mat x = x0;
if( x0.empty() )
x = Mat::zeros(1, ndim, CV_64F);
CV_Assert( (x.cols == 1 && x.rows == ndim) || (x.cols == ndim && x.rows == 1) );
CV_Assert( x.type() == CV_32F || x.type() == CV_64F );
simplex.create(ndim + 1, ndim, CV_64F);
Mat simplex_0m(x.rows, x.cols, CV_64F, simplex.ptr<double>());
x.convertTo(simplex_0m, CV_64F);
double* simplex_0 = simplex.ptr<double>();
const double* step_ = step.ptr<double>();
for( i = 1; i <= ndim; i++ )
{
double* simplex_i = simplex.ptr<double>(i);
for( j = 0; j < ndim; j++ )
simplex_i[j] = simplex_0[j];
simplex_i[i-1] += 0.5*step_[i-1];
}
for( j = 0; j < ndim; j++ )
simplex_0[j] -= 0.5*step_[j];
dprintf(("\nthis is simplex\n"));
print_matrix(simplex);
}
double innerDownhillSimplex( Mat& p, double MinRange, double MinError, int& fcount, int nmax )
{
int i, j, ndim = p.cols;
Mat coord_sum(1, ndim, CV_64F), buf(1, ndim, CV_64F), y(1, ndim+1, CV_64F);
double* y_ = y.ptr<double>();
fcount = ndim+1;
for( i = 0; i <= ndim; i++ )
y_[i] = calc_f(p.ptr<double>(i));
updateCoordSum(p, coord_sum);
for (;;)
{
int ilo = 0, ihi, inhi;
if( y_[0] > y_[1] )
{
ihi = 0; inhi = 1;
}
else
{
ihi = 1; inhi = 0;
}
for( i = 0; i <= ndim; i++ )
{
double yval = y_[i];
if (yval <= y_[ilo])
ilo = i;
if (yval > y_[ihi])
{
inhi = ihi;
ihi = i;
}
else if (yval > y_[inhi] && i != ihi)
inhi = i;
}
CV_Assert( ihi != inhi );
if( ilo == inhi || ilo == ihi )
{
for( i = 0; i <= ndim; i++ )
{
double yval = y_[i];
if( yval == y_[ilo] && i != ihi && i != inhi )
{
ilo = i;
break;
}
}
}
dprintf(("\nthis is y on iteration %d:\n",fcount));
print_matrix(y);
double error = fabs(y_[ihi] - y_[ilo]);
double range = 0;
for( j = 0; j < ndim; j++ )
{
double minval, maxval;
minval = maxval = p.at<double>(0, j);
for( i = 1; i <= ndim; i++ )
{
double pval = p.at<double>(i, j);
minval = std::min(minval, pval);
maxval = std::max(maxval, pval);
}
range = std::max(range, fabs(maxval - minval));
}
if( range <= MinRange || error <= MinError || fcount >= nmax )
{
std::swap(y_[0], y_[ilo]);
for( j = 0; j < ndim; j++ )
{
std::swap(p.at<double>(0, j), p.at<double>(ilo, j));
}
break;
}
double y_lo = y_[ilo], y_nhi = y_[inhi], y_hi = y_[ihi];
double alpha = -1.0;
double y_alpha = tryNewPoint(p, coord_sum, ihi, alpha, buf, fcount);
dprintf(("\ny_lo=%g, y_nhi=%g, y_hi=%g, y_alpha=%g, p_alpha:\n", y_lo, y_nhi, y_hi, y_alpha));
print_matrix(buf);
if( y_alpha < y_nhi )
{
if( y_alpha < y_lo )
{
double beta = -2.0;
double y_beta = tryNewPoint(p, coord_sum, ihi, beta, buf, fcount);
dprintf(("\ny_beta=%g, p_beta:\n", y_beta));
print_matrix(buf);
if( y_beta < y_alpha )
{
alpha = beta;
y_alpha = y_beta;
}
}
replacePoint(p, coord_sum, y, ihi, alpha, y_alpha);
}
else
{
double gamma = 0.5;
double y_gamma = tryNewPoint(p, coord_sum, ihi, gamma, buf, fcount);
dprintf(("\ny_gamma=%g, p_gamma:\n", y_gamma));
print_matrix(buf);
if( y_gamma < y_hi )
replacePoint(p, coord_sum, y, ihi, gamma, y_gamma);
else
{
for( i = 0; i <= ndim; i++ )
{
if (i != ilo)
{
for( j = 0; j < ndim; j++ )
p.at<double>(i, j) = 0.5*(p.at<double>(i, j) + p.at<double>(ilo, j));
y_[i] = calc_f(p.ptr<double>(i));
}
}
fcount += ndim;
updateCoordSum(p, coord_sum);
}
}
dprintf(("\nthis is simplex on iteration %d\n",fcount));
print_matrix(p);
}
return y_[0];
}
inline double calc_f(const double* ptr)
{
double res = _Function->calc(ptr);
CV_Assert( !cvIsNaN(res) && !cvIsInf(res) );
return res;
}
double tryNewPoint( Mat& p, Mat& coord_sum, int ihi, double alpha_, Mat& ptry, int& fcount )
{
int j, ndim = p.cols;
double alpha = (1.0 - alpha_)/ndim;
double beta = alpha - alpha_;
double* p_ihi = p.ptr<double>(ihi);
double* ptry_ = ptry.ptr<double>();
double* coord_sum_ = coord_sum.ptr<double>();
for( j = 0; j < ndim; j++ )
ptry_[j] = coord_sum_[j]*alpha - p_ihi[j]*beta;
fcount++;
return calc_f(ptry_);
}
void replacePoint( Mat& p, Mat& coord_sum, Mat& y, int ihi, double alpha_, double ytry )
{
int j, ndim = p.cols;
double alpha = (1.0 - alpha_)/ndim;
double beta = alpha - alpha_;
double* p_ihi = p.ptr<double>(ihi);
double* coord_sum_ = coord_sum.ptr<double>();
for( j = 0; j < ndim; j++ )
p_ihi[j] = coord_sum_[j]*alpha - p_ihi[j]*beta;
y.at<double>(ihi) = ytry;
updateCoordSum(p, coord_sum);
}
};
Ptr<DownhillSolver> DownhillSolver::create( const Ptr<MinProblemSolver::Function>& f,
InputArray initStep, TermCriteria termcrit )
{
Ptr<DownhillSolver> DS = makePtr<DownhillSolverImpl>();
DS->setFunction(f);
DS->setInitStep(initStep);
DS->setTermCriteria(termcrit);
return DS;
}
}