J'ai un algorithme d'optimisation continue qui prend une fonction Oracle comme paramètre de modèle. La classe d'optimisation spécifique est définie comme:Fonction globale et pointeur de fonction de membre non statique
template<class Space, class Solution, class Oracle>
class ConjugateGradient : public ContinuousOptimizerInterface<Space, Solution, Oracle> {
public:
// Returns the optimal solution found for a given search space
virtual const Solution& search(const Space& space, Oracle f);
};
et dans le cadre de la mise en œuvre de la recherche J'ai appels à la fonction oracle:
template<class Space, class Solution, class Oracle>
inline const Solution& ConjugateGradient<Space, Solution, Oracle>::search(const Space& space, Oracle f) {
// ...
// get function value and gradient at X
double fx;
Solution dfx;
tie(fx, dfx) = f(X);
// ..
}
Un exemple simple en utilisant une fonction quadratique globale:
typedef tuple<double, VectorXd> (*oracle_f)(const VectorXd&);
static tuple<double, VectorXd> f(const VectorXd& X) {
double f = pow((4.0-X(0)), 2) + 10.0;
VectorXd df = 2.0*X - VectorXd::Ones(X.rows())*8.0;
return make_tuple(f, df);
}
// ...
ConjugateGradient<TestSpace, VectorXd, oracle_f> optimizer;
VectorXd optimal = optimizer.search(TestSpace(), f);
Cela fonctionne bien, mais maintenant je dois être en mesure de passer une fonction membre non statique d'une classe en tant que fonction Oracle à l'algorithme ConjugateGradient
. Comment dois-je modifier la déclaration de modèle ConjugateGradient
et l'implémentation de la fonction oracle pour qu'elle soit une fonction globale ou une fonction de membre non statique? Une approche alternative serait de créer une fonction d'enveloppement globale et d'utiliser varargs pour passer des arguments à la fonction d'encapsulation, mais c'est moche et pas de type sécurisé.
MISE À JOUR: Cet exemple utilise l'idée de liaison de la réponse ci-dessous mais en utilisant boost :: bind au lieu de std :: bind car je ne suis pas sur C++ 11 et std :: bind n'est disponible que pour C++ 11.
#include <Eigen/Dense>
#include <boost/tuple/tuple.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
using namespace Eigen;
using namespace boost;
// the class is parameterized with the appropriate minimizer strategy
enum Minimizer { kNormalEquations, kConjugateGradient };
template <Minimizer M = kNormalEquations>
class SomeANN : AnnInterface {
private:
// ...
public:
// define the oracle function type and member function
typedef tuple<double, VectorXd> (SomeANN::*oracle_f)(const VectorXd&);
tuple<double, VectorXd> f(const VectorXd& theta);
};
template <>
inline tuple<double, VectorXd> SomeANN<kConjugateGradient>::f(const VectorXd& theta) {
double f = 0.0;
VectorXd df;
return make_tuple(f, df);
}
// ridge solver using conjugate gradient
template <>
inline void SomeANN<kConjugateGradient>::ridge_solve(const VectorXd& Y) {
ConjugateGradient<BeginSpace, VectorXd, SomeANN::oracle_f> optimizer;
// ...
optimizer.search(BeginSpace(Y.rows()), boost::bind(&SomeANN::f, this, _1));
}
puis-je obtenir l'erreur:
some_ann.h:163:84: error: no matching function for call to 'ConjugateGradient<BeginSpace, Eigen::Matrix<double, -0x00000000000000001, 1>, boost::tuples::tuple<double, Eigen::Matrix<double, -0x00000000000000001, 1> > (SomeANN<(Minimizer)1u>::*)(const Eigen::Matrix<double, -0x00000000000000001, 1>&)>::search(BeginSpace, boost::_bi::bind_t<boost::tuples::tuple<double, Eigen::Matrix<double, -0x00000000000000001, 1> >, boost::_mfi::mf1<boost::tuples::tuple<double, Eigen::Matrix<double, -0x00000000000000001, 1> >, SomeANN<(Minimizer)1u>, const Eigen::Matrix<double, -0x00000000000000001, 1>&>, boost::_bi::list2<boost::_bi::value<SomeANN<(Minimizer)1u>*>, boost::arg<1> > >)'
conjugate_gradient.h:67:2: error: must use '.*' or '->*' to call pointer-to-member function in 'f (...)', e.g. '(... ->* f) (...)'
conjugate_gradient.h:84:3: error: must use '.*' or '->*' to call pointer-to-member function in 'f (...)', e.g. '(... ->* f) (...)'
conjugate_gradient.h:111:5: error: must use '.*' or '->*' to call pointer-to-member function in 'f (...)', e.g. '(... ->* f) (...)'
conjugate_gradient.h:153:4: error: must use '.*' or '->*' to call pointer-to-member function in 'f (...)', e.g. '(... ->* f) (...)'
make[2]: *** [CMakeFiles/some_ann_library.dir/main/cpp/some_ann.cc.o] Error 1
make[1]: *** [CMakeFiles/some_ann_library.dir/all] Error 2
make: *** [all] Error 2
bind fonctionnera très bien – count0
note d'un côté est que pour cette Pour travailler j'ai besoin de C11 et je ne le fais pas actuellement. Je suis sur GNU MacPorts gcc46 4.6.3_9 –
4.6 -std = C++ 0x mode n'a pas std :: bind? –