1

我正在使用 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;
4

1 回答 1

0

这种 API 很常见。几乎总是可以 forfderto 任何callable,而不仅仅是静态函数。也就是说,您可以将带有 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;
};

对 struct 使用相同的模式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

于 2015-11-08T17:37:03.463 回答