C++ 在这种情况下,为什么使用C数组的实现优于eigen?
一套相对著名的经济学语言编码基准是由S.Borağan Aruoba和JesúS Fernández Villaverde制定的,其代码可以找到。对于C++,有两种实现随机新古典增长模型的方法,一种是使用C风格数组,另一种是用C++ STL数组。最近我一直在练习C++,因为我开始着手研究一些大规模的模型,因为语言可能是有用的(虽然我希望主要是在朱丽亚中工作),并且决定使用EGIN库创建一个变体,因为我对它的使用不太熟悉。有趣的是,我的代码使用特征比在上述链接中的两个C++程序中的任一个都慢得多。我的假设是,这是由于我的实现很差,这个问题太简单,由于它增加了开销,所以Eigen不值得使用,但是我想问这个假设是否正确 我使用eigen的代码是:C++ 在这种情况下,为什么使用C数组的实现优于eigen?,c++,eigen3,economics,C++,Eigen3,Economics,一套相对著名的经济学语言编码基准是由S.Borağan Aruoba和JesúS Fernández Villaverde制定的,其代码可以找到。对于C++,有两种实现随机新古典增长模型的方法,一种是使用C风格数组,另一种是用C++ STL数组。最近我一直在练习C++,因为我开始着手研究一些大规模的模型,因为语言可能是有用的(虽然我希望主要是在朱丽亚中工作),并且决定使用EGIN库创建一个变体,因为我对它的使用不太熟悉。有趣的是,我的代码使用特征比在上述链接中的两个C++程序中的任一个都慢得多。
#include <chrono>
#include <iostream>
#include <Eigen/Dense>
#include <cmath>
int main()
{
//---------------------------------------------------------------------------------------------------
//Timer Start
const auto time_0 = std::chrono::steady_clock::now();
//---------------------------------------------------------------------------------------------------
//Parameter Declaration
const double aalpha = 0.33333333333; // Elasticity of output w.r.t. capital
const double bbeta = 0.95; // Discount factor;
const size_t nGridProductivity = 5;
Eigen::Matrix<double, nGridProductivity, 1> vProductivity;
vProductivity << 0.9792, 0.9896, 1.0000, 1.0106, 1.0212;
Eigen::Matrix<double, nGridProductivity, nGridProductivity> mTransition;
mTransition << 0.9727, 0.0273, 0.0000, 0.0000, 0.0000,
0.0041, 0.9806, 0.0153, 0.0000, 0.0000,
0.0000, 0.0082, 0.9837, 0.0082, 0.0000,
0.0000, 0.0000, 0.0153, 0.9806, 0.0041,
0.0000, 0.0000, 0.0000, 0.0273, 0.9727;
//---------------------------------------------------------------------------------------------------
// Steady State
const double capitalSteadyState = std::pow(aalpha * bbeta, 1. / (1. - aalpha));
const double outputSteadyState = std::pow(capitalSteadyState, aalpha);
const double consumptionSteadyState = outputSteadyState - capitalSteadyState;
std::cout << "Output = " << outputSteadyState << ", Capital = " << capitalSteadyState << ", Consumption = " << consumptionSteadyState << "\n";
std::cout << " ";
// Capital Grid
const int nGridCapital = 17820;
Eigen::VectorXd vGridCapital(nGridCapital);
vGridCapital.setLinSpaced(nGridCapital, 0.5 * capitalSteadyState, 1.5 * capitalSteadyState);
//---------------------------------------------------------------------------------------------------
//Required Matrices and Vectors
Eigen::MatrixXd mOutput(nGridCapital, nGridProductivity);
Eigen::MatrixXd mValueFunction (nGridCapital, nGridProductivity);
mValueFunction.setZero();//Need to initialise to zero for first iteration
Eigen::MatrixXd mValueFunctionNew(nGridCapital, nGridProductivity);
mValueFunctionNew.setZero();
Eigen::MatrixXd mPolicyFunction(nGridCapital, nGridProductivity);
mPolicyFunction.setZero();
Eigen::MatrixXd expectedValueFunction(nGridCapital, nGridProductivity);
//---------------------------------------------------------------------------------------------------
//Pre-Build Output
mOutput = (vGridCapital.array().pow(aalpha).matrix()) * vProductivity.transpose();
std::cout << "Test mOutput" << mOutput(2, 2) << std::endl;
//---------------------------------------------------------------------------------------------------
//Main Iteration
const double tolerance = 0.0000001;
double maxDifference = 10.0;
std::size_t iteration = 0;
while (maxDifference > tolerance)
{
expectedValueFunction = mValueFunction * mTransition.transpose();
for (std::size_t nProductivity = 0; nProductivity < nGridProductivity; ++nProductivity)
{
// We start from previous choice (monotonicity of policy function)
std::size_t gridCapitalNextPeriod = 0;
for (std::size_t nCapital = 0; nCapital < nGridCapital; ++nCapital)
{
double valueHighSoFar = -100000.0;
double capitalChoice = vGridCapital(0);
for (std::size_t nCapitalNextPeriod = gridCapitalNextPeriod; nCapitalNextPeriod < nGridCapital; ++nCapitalNextPeriod)
{
const double consumption = mOutput(nCapital, nProductivity) - vGridCapital(nCapitalNextPeriod);
const double valueProvisional = (1. - bbeta) * std::log(consumption) + bbeta * expectedValueFunction(nCapitalNextPeriod, nProductivity);
if (valueProvisional > valueHighSoFar)
{
valueHighSoFar = valueProvisional;
capitalChoice = vGridCapital(nCapitalNextPeriod);
gridCapitalNextPeriod = nCapitalNextPeriod;
}
else
{
mValueFunctionNew(nCapital, nProductivity) = valueHighSoFar;
mPolicyFunction(nCapital, nProductivity) = capitalChoice;
// We break when we have achieved the max (note: of a monotonic function)
break;
}
mValueFunctionNew(nCapital, nProductivity) = valueHighSoFar;
mPolicyFunction(nCapital, nProductivity) = capitalChoice;
}
}
}
maxDifference = (mValueFunctionNew - mValueFunction).cwiseAbs().maxCoeff();
mValueFunction = mValueFunctionNew;
++iteration;
if ((iteration % 10 == 0) || (iteration == 1))
std::cout << "Iteration = " << iteration << ", Sup Diff = " << maxDifference << "\n";
}
std::cout << "Iteration = " << iteration << ", Sup Diff = " << maxDifference << "\n";
endl(std::cout);
std::cout << "My check = " << mPolicyFunction(999, 2) << "\n";
endl(std::cout);
//---------------------------------------------------------------------------------------------------
//Timer End
const auto time_1 = std::chrono::steady_clock::now();
const auto elapsed_seconds = std::chrono::duration_cast<std::chrono::duration<double>>(time_1 - time_0).count();
std::cout << "Elapsed time is = " << elapsed_seconds << " seconds." << std::endl;
endl(std::cout);
return 0;
}
#包括
#包括
#包括
#包括
int main()
{
//---------------------------------------------------------------------------------------------------
//定时器启动
const auto time_0=std::chrono::staid_clock::now();
//---------------------------------------------------------------------------------------------------
//参数声明
const double aalpha=0.33333;//产出与资本的弹性
常数双bbeta=0.95;//折扣系数;
常数大小=5;
特征::矩阵乘积;
这里的生产率只是一个猜测,但您的算法似乎使用了元素操作(如索引矩阵/向量)。我的猜测是库优化的块操作(向量/矩阵乘法等)。通常在您希望使块操作快速进行时更改元素,如果您只是处理常规数组,则不需要更改额外数据。您可以尝试在禁用断言的情况下进行编译(应使用MSVC进行/NDEBUG
)--在确保代码正确运行后。但MSVC有时在内联某些特征方法时仍然存在问题,因此如果无法切换到clang或gcc,则可能需要承受一些开销。在这里冒险猜测一下,但您的算法似乎使用了元素操作(如索引矩阵/向量)。我猜是库优化的块操作(向量/矩阵乘法等)。通常在您想要使块操作快速时更改元素,如果您只是处理常规数组,则不需要更改额外数据。您可以尝试在禁用断言的情况下编译(应该是MSVC的/NDEBUG
)——在确保代码正确运行后。但MSVC有时在内联某些特征方法时仍然存在问题,因此如果无法切换到clang或gcc,您可能不得不承受一些开销。