将额外数据传递给函数

时间:2015-11-08 17:28:15

标签: c++ parameters parameter-passing dlib

我正在使用C ++的dlib优化库,特别是以下函数:

template <
    typename search_strategy_type,
    typename stop_strategy_type,
    typename funct, 
    typename funct_der, 
    typename T
    >
double find_max (
    search_strategy_type search_strategy,
    stop_strategy_type stop_strategy,
    const funct& f, 
    const funct_der& der, 
    T& x, 
    double max_f
);

函数f和der旨在获取被修改的数据参数的向量,以获得函数的最大值。但是我的函数最大化有四个参数(一个是我的数据集,另一个是我修复的)。但是,由于它们应具有的格式,我无法将这些作为输入传递给我的f和der函数。如何将这些数据输入我的函数?我目前正在尝试以下(我硬设置变量c但是对于矢量xgrequ我每次处理函数时都从文件中读取数据。

//Function to be minimized
double mleGPD(const column_vector& p)
{
    std::ifstream infile("Xm-EVT.csv");
    long double swapRet;
    std::string closeStr;
    std::vector<double> histRet;

    //Read in historical swap data file
    if (infile.is_open())
    {
        while (!infile.eof())
        {
            infile >> swapRet;
            histRet.push_back(swapRet);
        }
    }
    sort(histRet.begin(), histRet.end());
    std::vector<double> negRet;
    //separate out losses
    for (unsigned c = 0; c < histRet.size(); c++)
    {
        if (histRet[c] < 0)
        {
            negRet.push_back(histRet[c]);
        }
    }
    std::vector<double> absValRet;
    //make all losses positive to fit with EVT convention
    for (unsigned s = 0; s < negRet.size(); s++)
    {
        absValRet.push_back(abs(negRet[s]));
    }
    std::vector<double> xminusu, xmu, xgrequ;
    int count = absValRet.size();
    double uPercent = .9;
    int uValIndex = ceil((1 - uPercent)*count);
    int countAbove = count - uValIndex;
    double c = (double)absValRet[uValIndex - 1];
    //looking at returns above u
    for (unsigned o = 0; o < uValIndex; ++o)
    {
        xmu.push_back(absValRet[o] - c);
        if (xmu[o] >= 0)
        {
            xgrequ.push_back(absValRet[o]);
            xminusu.push_back(xmu[o]);
        }
    }
    double nu = xgrequ.size();
    double sum = 0.0;
    double a = p(0);
    double b = p(1);

    for (unsigned h = 0; h < nu; ++h)
    {
        sum += log((1 / b)*pow(1 - a*((xgrequ[h] - c) / b), -1 + (1 / a)));
    }
    return sum;
}
//Derivative of function to be minimized
const column_vector mleGPDDer(const column_vector& p)
{
    std::ifstream infile("Xm-EVT.csv");
    long double swapRet;
    std::string closeStr;
    std::vector<double> histRet;

    //Read in historical swap data file
    if (infile.is_open())
    {
        while (!infile.eof())
        {
            infile >> swapRet;
            histRet.push_back(swapRet);
        }
    }
    sort(histRet.begin(), histRet.end());
    std::vector<double> negRet;
    //separate out losses
    for (unsigned c = 0; c < histRet.size(); c++)
    {
        if (histRet[c] < 0)
        {
            negRet.push_back(histRet[c]);
        }
    }
    std::vector<double> absValRet;
    //make all losses positive to fit with EVT convention
    for (unsigned s = 0; s < negRet.size(); s++)
    {
        absValRet.push_back(abs(negRet[s]));
    }
    std::vector<double> xminusu, xmu, xgrequ;
    int count = absValRet.size();
    double uPercent = .9;
    int uValIndex = ceil((1 - uPercent)*count);
    int countAbove = count - uValIndex;
    double c = (double)absValRet[uValIndex - 1];
    //looking at returns above u
    for (unsigned o = 0; o < uValIndex; ++o)
    {
        xmu.push_back(absValRet[o] - c);
        if (xmu[o] >= 0)
        {
            xgrequ.push_back(absValRet[o]);
            xminusu.push_back(xmu[o]);
        }
    }
    column_vector res(2);
    const double a = p(0);
    const double b = p(1);
    double nu = xgrequ.size();
    double sum1 = 0.0;
    double sum2 = 0.0;
    for (unsigned h = 0; h < nu; ++h)
    {
        sum1 += ((xgrequ[h]-c)/b)/(1-a*((xgrequ[h]-c)/b));
        sum2 += log(1 - a*((xgrequ[h] - c) / b));
    }
    res(0) = sum1;//df/da
    res(1) = sum2;//df/db
    return res;
}

以下是我的实际函数调用:

//Dlib max finding
    column_vector start(2);
    start = .1, .1; //starting point for a and b
    find_max(bfgs_search_strategy(), objective_delta_stop_strategy(1e-6), mleGPD, mleGPDDer, start,100);
    std::cout << "solution" << start << std::endl;

1 个答案:

答案 0 :(得分:0)

这种API很常见。 fder对任何可调用的几乎总是可行,而不仅仅是静态函数。也就是说,您可以将带有operator()的自定义类对象传递给它。

例如

struct MyF {
  //int m_state; 
  //   or other state variables, such as 
  std::vector<double> m_histRet;
  // (default constructors will do)

  double operator()(const column_vector& p) const {
    return some_function_of(p, m_state);
  }
};

int main(){
  . . . 
  MyF myf{42};
  // or
  MyF myf{someVectorContainingHistRet};

  // then use myf as you would have used mleGPD
}

你需要以相同的状态启动MyF和MyDer(我假设std::vector<double> histRet。)作为副本或(const)引用相同的状态。

修改:更完整的示例:

struct MLGDPG_State {
  std::vector<double> xgrequ;
  // . . . and more you need in f or fder
}

MLGDPG_State makeMLGDPG_State(const std::string& filename){
    std::ifstream infile(filename);
    std::ifstream infile("Xm-EVT.csv");
    long double swapRet;
    std::string closeStr;
    std::vector<double> histRet;

    //Read in historical swap data file
    if (infile.is_open())
    {
        while (!infile.eof())
        {
            infile >> swapRet;
            histRet.push_back(swapRet);
        }
    }
    sort(histRet.begin(), histRet.end());
    std::vector<double> negRet;
    //separate out losses
    for (unsigned c = 0; c < histRet.size(); c++)
    {
        if (histRet[c] < 0)
        {
            negRet.push_back(histRet[c]);
        }
    }
    std::vector<double> absValRet;
    //make all losses positive to fit with EVT convention
    for (unsigned s = 0; s < negRet.size(); s++)
    {
        absValRet.push_back(abs(negRet[s]));
    }
    std::vector<double> xminusu, xmu, xgrequ;
    int count = absValRet.size();
    double uPercent = .9;
    int uValIndex = ceil((1 - uPercent)*count);
    int countAbove = count - uValIndex;
    double c = (double)absValRet[uValIndex - 1];
    //looking at returns above u
    for (unsigned o = 0; o < uValIndex; ++o)
    {
        xmu.push_back(absValRet[o] - c);
        if (xmu[o] >= 0)
        {
            xgrequ.push_back(absValRet[o]);
            xminusu.push_back(xmu[o]);
        }
    }
    return {std::move(xgrequ)}; 
    // Or just 'return MleGPD(xgrequ)' if you are scared of {} and move
}

//Functor Class, for ion to be minimized
struct MleGPD{
  MLGDPG_State state;  
  double operator()(const column_vector& p) const {   
    auto mu = state.xgrequ.size();
    double sum = 0.0;
    double a = p(0);
    double b = p(1);
    for (unsigned h = 0; h < nu; ++h)
    {
        sum += log((1 / b)*pow(1 - a*((xgrequ[h] - c) / b), -1 + (1 / a)));
    }
    return sum;
};

对结构MleGPD_Derivative使用相同的模式。

用法:

const auto state = makeMLGDPG_State("Xm-EVT.csv");
const auto f = MleGPD{state};
const auto der = MleGPD_Derivative{state};

start = .1, .1; //starting point for a and b
find_max(bfgs_search_strategy(), objective_delta_stop_strategy(1e-6), f, der, start,100);
std::cout << "solution" << start << std::endl;

注意,对于像这样的简单结构,使用默认构造函数,复制构造函数等通常很好。另请注意http://en.cppreference.com/w/cpp/language/aggregate_initialization