[英]How can I define a function using an object created in the main function (c++)?
I'm trying to write a program that will give me the cross-validation bandwidth for a kernel estimator in c++ (there are around 20,000 data points so Matlab is way too slow).我正在尝试编写一个程序,该程序将为 c++ 中的 kernel 估计器提供交叉验证带宽(大约有 20,000 个数据点,所以 ZA5CD8A07B40F6449056939C13140 太慢了)AE I'm doing this by using a secant algorithm on the derivative of the objective of the leave-one-out estimator.
我通过对留一估计器的目标的导数使用割线算法来做到这一点。 My problem is that this function takes as arguments the data, which is pulled in the main function from a csv file.
我的问题是,这个 function 将数据作为 arguments 数据,这些数据是从 Z628ZCB5675FFE884B 文件中提取的主 function
One of the arguments of the secant algorithm is a function that takes a double and returns a double, but the function I've written for the objective's derivative has to take a whole host of other crap that mathematically we'd consider parameters (things like the data, the choice of kernel function, etc.).割线算法的 arguments 之一是 function,它采用双精度并返回双精度,但 function 我已经写了一个像其他目标一样的参数数据,选择kernel function等)。
I need to be able to write a function that uses the function defining the objective, puts in the data that the main function pulls from the file, and takes as its only input a double variable.我需要能够编写一个 function 使用 function 定义目标,放入主要 function 的数据作为输入,并从文件中提取双倍变量。 Is there a way of doing this?
有没有办法做到这一点?
double cvobjective(double data[], int n, double (*k)(double), double (*kd)(double), double h)
{
double cvob = 0;
double xi;
double xj;
for(int i = 0; i < n; ++i)
{
xi = data[i];
double sumki = 0;
double sumkdi = 0;
for(int j = 0; j < n; ++j) //find sum of k((xj-xi)/h) and k'((xj-xi)/h)*(xj-xi)
{
xj = data[j];
sumki = sumki + k((xj-xi)/h);
sumkdi = sumkdi + kd((xj-xi)/h)*(xj-xi);
}
sumki = sumki-k(0);//gets rid of the terms where i=j
sumkdi = sumkdi-kd(0);
cvob = cvob - reciprocal(sumki)*(reciprocal(h)*sumki+reciprocal(pow(h,2))*sumkdi);
}
return cvob;
}
double secantmethod(double (*obj)(double), double init, double tolerance, int giveup)
{
double x = init;
double old = init+1;
double newp;
double fold = obj(old);
double fnew;
for(int i=0;i<giveup;++i)
{
fnew = obj(x);
if(abs(fnew-fold)<tolerance)
{
cout << "Objective values get too close after " << i << " iterations." << endl;
break;
}
newp = newp - (x-old)*reciprocal(fnew-fold)*fnew;
old = x;
x = newp;
cout << "Estimate is currently: " << x << endl;
fold = fnew;
if(abs(fnew)<tolerance)
break;
if(i == giveup - 1)
cout << "Secant algorithm did not converge." << endl;
}
return newp;
}
int main()
{
const int N = 19107;
double incomes[N];
std::ifstream ifile("incomes.csv", std::ios::in);
std::vector<double> scores;
//check to see that the file was opened correctly:
if (!ifile.is_open()) {
std::cerr << "There was a problem opening the input file.\n";
exit(1);//exit or do additional error checking
}
double num = 0.0;
//keep storing values from the text file so long as data exists:
while (ifile >> num) {
scores.push_back(num);
}
//verify that the scores were stored correctly:
for (int i = 0; i < scores.size(); ++i) {
incomes[i]=scores[i];
}
double sv = silverman(incomes,N);
double cvbandwidth = secantmethod(cvobj,sv,0.000001,100);
cout << setprecision(10) << cvbandwidth << endl;
return 0;
}
Obviously I've left out some of the code for the more peripheral functions that aren't important.显然,我省略了一些不重要的外围功能的代码。 I thought about if it would be possible to change the secantmethod algorithm so that it expected to take a function that had as its input all of the things that cvobjective has as inputs but it wasn't immediately clear to me how I'd do that.
我想是否有可能改变 secantmethod 算法,以便它期望采用 function 作为其输入作为输入的所有 cvobjective 作为输入的东西,但我并不清楚我将如何做到这一点.
Ideally I'd be able to create a function inside of main so that the incomes array was in the scope of that function, but either I don't understand lambdas properly or they aren't particularly suited to this purpose.理想情况下,我可以在 main 内部创建一个 function 以便收入数组位于 function 的 scope 中,但我不是特别适合理解这个目的,或者他们不是特别适合理解这个目的。 Failing that, if there's a way for changing secantmethod in the way described above, that would also work.
如果做不到这一点,如果有办法以上述方式更改割线方法,那也可以。
EDIT: In the above cvobj isn't defined and currently serves as a placeholder.编辑:在上面的 cvobj 中没有定义,目前用作占位符。 What I'd like it to be is something like
我希望它是这样的
double cvobj(double h)
return cvobjective(incomes,N,normpdf,normpdfdiff,h);
but obviously when I try that, it complains that incomes and N aren't in the scope of the function.但显然,当我尝试这样做时,它抱怨收入和 N 不在 function 的 scope 中。
So I think I found a workaround, which was to define the class所以我想我找到了一种解决方法,即定义 class
class kernelwdata
{
public:
double observations[N];
double cvobj(double h)
{
return cvobjective(observations,N,normpdf,normpdfdiff,h);
}
};
and change secantmethod so that it takes kernelwdata as the input.并更改 secantmethod 使其将 kernelwdata 作为输入。 Now the code shown before looks like
现在之前显示的代码看起来像
double cvobjective(double data[], int n, double (*k)(double), double (*kd)(double), double h)
{
double cvob = 0;
double xi;
double xj;
for(int i = 0; i < n; ++i)
{
xi = data[i];
double sumki = 0;
double sumkdi = 0;
for(int j = 0; j < n; ++j) //find sum of k((xj-xi)/h) and k'((xj-xi)/h)*(xj-xi)
{
xj = data[j];
if(j==i)
xj=xi+1;
sumki = sumki + k((xj-xi)/h);
sumkdi = sumkdi + kd((xj-xi)/h)*(xj-xi);
}
sumki = sumki-k(1/h);//gets rid of the terms where i=j
sumkdi = sumkdi-kd(1/h);
cvob = cvob - reciprocal(sumki)*(reciprocal(h)*sumki+reciprocal(pow(h,2))*sumkdi);
}
return cvob;
}
class kernelwdata
{
public:
double observations[N];
double cvobj(double h)
{
return cvobjective(observations,N,normpdf,normpdfdiff,h);
}
};
double secantmethod(kernelwdata obj, double init, double tolerance, int giveup)
{
double x = init;
double old = init+1;
double newp;
double fold = obj.cvobj(old);
double fnew;
for(int i=0;i<giveup;++i)
{
fnew = obj.cvobj(x);
cout << "fold is " << fold << " and fnew is " << fnew << endl;
if(abs(fnew-fold)<tolerance)
{
cout << "Objective values get too close after " << i << " iterations." << endl;
break;
}
newp = newp - (x-old)*reciprocal(fnew-fold)*fnew;
old = x;
x = newp;
cout << "Estimate is currently: " << x << endl;
fold = fnew;
if(abs(fnew)<tolerance)
break;
if(i == giveup - 1)
cout << "Secant algorithm did not converge." << endl;
}
return newp;
}
double silverman(double data[], int n)
{
double mean = 0;
for(int counter = 0; counter < n; ++counter)
mean = mean+data[counter]/n;
double sigmahat = 0;
for(int counter = 0; counter < n; ++counter)
{
sigmahat = sigmahat + pow(data[counter]-mean,2);
}
sigmahat = sigmahat/(n-1);
sigmahat = sqrt(sigmahat);
double m = (double) n;
return sigmahat*pow(m,-0.2);
}
int main()
{
kernelwdata incomes;
std::ifstream ifile("incomestest.csv", std::ios::in);
std::vector<double> scores;
//check to see that the file was opened correctly:
if (!ifile.is_open()) {
std::cerr << "There was a problem opening the input file.\n";
exit(1);//exit or do additional error checking
}
double num = 0.0;
//keep storing values from the text file so long as data exists:
while (ifile >> num) {
scores.push_back(num);
}
//verify that the scores were stored correctly:
for (int i = 0; i < scores.size(); ++i) {
incomes.observations[i]=scores[i];
}
//double sv = silverman(incomes.observations,N);
double cvbandwidth = secantmethod(incomes,10,0.000001,100);
cout << "The cross-validation bandwidth is: " << setprecision(10) << cvbandwidth << endl;
return 0;
}
and I'm now arguing with the output it's giving me (pretty sure a maths problem somewhere) rather than not being a thing I can compile yet.我现在正在与 output 争论它给了我(很确定某处的数学问题),而不是我还不能编译的东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.