灵感来自文章 http://gallery.rcpp.org/articles/parallel-distance-matrix/ ,我尝试使用 RcppParallel 在高维参数空间中运行强力搜索以使用多线程进行回测。我一直卡在如何在struct部分调用自定义函数。思路是这样的:
首先,先在R中创建一个参数矩阵NumericMatrix params_mat,使用List, NumericVector, CharacterVector数据类型的回测数据,如List Data_1, NumericVector Data_2, CharacterVector Data_3, ...,对于每个参数场景params_vec都是静态的(注意是params_mat的行)。
接下来,定义回测函数,输出一个包含 3 个关键变量的 vector 来评估策略性能。
这是我的 params_mat 和 Backtesting_Fun 的示例,它们可以分别在 R 和 Rcpp 中运行。
//[[Rcpp::export]]
NumericMatrix data_frame_rcpp(const Rcpp::List& list_params)
{
NumericMatrix res = list_params[0];
return res;
}
# R codes to generate params_mat
params <- expand.grid (x_1=seq(1,100,1), x_2=seq(3,100,2), ..., x_n=seq(4,200,1));
list_params = list(ts(params));
tmp_params_data = data_frame_rcpp(list_params);
params_mat = matrix(tmp_params_data, ncol = ncol(tmp_params_data), dimnames = NULL);
params_vec = params_mat[ii,];
# User-defined Rcpp codes for backtesting
NumericVector Backtesting_Fun (List Data_1, NumericVector Data_2, CharacterVector Data_3, ..., NumericVector params_vec)
{
// Main function parts to run backtesting for each params_vec scenario.
... etc
// save 3 key result variables together with each params_vec (just a simple illustration).
NumericVector res = NumericVector::create(params_vec[0],...,params_vec[size-1],
key_1, key_2, key_3);
return res;
}
当然我们需要用RVector/RMatrix类型重写/修改原来的Rcpp Backtesting_Fun,然后使用下面的RcppParallel代码来调用Backtesting_Fun 在 struct Backtest_parallel 中:
// [[Rcpp::depends(RcppParallel)]]
#include <RcppParallel.h>
using namespace RcppParallel;
RVector<double> Backtesting_Fun (const RVector<double> Data_1, const RVector<double> Data_2,
const RVector<string> Data_3,..., const RVector<double> params_vec)
{
// Main function parts to run backtesting for each params_vec scenario.
... etc;
// save 3 key result variables together with each params_vec
... etc;
return res;
}
struct Backtest_parallel : public Worker
{
// input matrix to read from
const RVector<List> Data_1;
const RVector<double> Data_2;
const RVector<string> Data_3;
...
const RMatrix<double> params_mat;
// output matrix to write to
RMatrix<double> rmat;
// initialize from Rcpp input and output matrixes (the RMatrix class
// can be automatically converted to from the Rcpp matrix type)
Backtest_parallel(const List Data_1, const NumericVector Data_2,
const CharacterVector Data_3, ..., const NumericMatrix params_mat)
: Data_1(Data_1), Data_2(Data_2), Data_3(Data_3), ..., params_mat(params_mat) {}
// function call operator that work for the specified range (begin/end)
void operator()(std::size_t begin, std::size_t end)
{
for (std::size_t ii = begin; ii < end; i++)
{
// params rows that we will operate on
RMatrix<double>::Row params_row = params_mat.row(ii);
// Run the backtesting function defined above
RVector<double> res = Backtesting_Fun(Data_1, Data_2, ..., params_row)
for (std::size_t jj = 0; jj < res.length(); jj++)
{
// write to output matrix
rmat(ii,jj) = res[jj];
}
}
}
};
// [[Rcpp::export]]
NumericMatrix rcpp_parallel_backtest(List Data_1, NumericVector Data_2, CharacterVector Data_3,
..., NumericMatrix params_mat)
{
// allocate the matrix we will return
NumericMatrix rmat(params_mat.nrow(), params_mat.nrow()+3);
// create the worker
Backtest_parallel backtest_parallel(Data_1, Date_2, ..., params_mat);
// call it with parallelFor
parallelFor(0, rmat.nrow(), backtest_parallel);
return rmat;
}
这是我的问题:
RVector 是否可以包含List 数据类型,或者RcppParallel 中是否有任何特定的容器来包含List;
在Backtesting_Fun中,输入应该是RVector/RMatrix类型,这是否意味着我们真的需要将原始Rcpp主代码转换为 NumericVector 转换为 RVector?
或者有没有更好的方法在 RcppParallel 中为我的案例进行并行计算?提前致谢。
编辑:
我查看了 http://gallery.rcpp.org/articles/parallel-matrix-transform/ 中关于 RcppPararrel 的其他示例, http://gallery.rcpp.org/articles/parallel-inner-product/ , struct operator() 中的共同思想是使用指针来操作 operator() 的数据输入,所以有没有办法在我的中构建用户定义的函数指针输入的情况?
如果上述方式不行,是否可以使用wrap将RVector/RMatrix转回Rcpp数据类型,即 ,使自定义函数operator()中的NumericVector..Backtesting_Fun的输入类型保持不变。
最佳答案
我想我可能会找到另一种方法来解决这个问题:关键是使用线程安全访问器将变量包含在 struct 中,并保持 RVector/RMatrix 在外部 main 函数中,以便 parallelFor 可以正常工作,这是这个并行算法中最重要的部分。这是我的方法:
摆脱 List 数据类型:相反,我们可以使用 NumericVector 转换 List 变量>/NumericMatrix 容器并记录其相应的索引,以便子 vector/子矩阵将指向与列表元素相同的元素。
将 RVector/RMatrix 转换为 arma::vec/arma::mat:如RcppParallel Github所述, C++ Armadillo 在结构的运算符中是线程安全的。在这里,我修改了 Parallel Distance Matrix Calculation with RcppParallel 中给出的示例通过使用这个想法,它几乎保持相同的测试速度。
struct JsDistance : public Worker
{
const RMatrix<double> tmp_MAT; // input matrix to read from
RMatrix<double> tmp_rmat; // output matrix to write to
std::size_t row_size, col_size;
// Convert global input/output into RMatrix/RVector type
JsDistance(const NumericMatrix& matrix_input, NumericMatrix& matrix_output,
std::size_t row_size, std::size_t col_size)
: tmp_MAT(matrix_input), tmp_rmat(matrix_output), row_size(row_size), col_size(col_size) {}
// convert RVector/RMatrix into arma type for Rcpp function
// and the follwing arma data will be shared in parallel computing
arma::mat convert()
{
RMatrix<double> tmp_mat = tmp_MAT;
arma::mat MAT(tmp_mat.begin(), row_size, col_size, false);
return MAT;
}
void operator()(std::size_t begin, std::size_t end)
{
for (std::size_t i = begin; i < end; i++)
{
for (std::size_t j = 0; j < i; j++)
{
// rows we will operate on
arma::mat MAT = convert();
arma::rowvec row1 = MAT.row(i); // get the row of arma matrix
arma::rowvec row2 = MAT.row(j);
// compute the average using std::tranform from the STL
std::vector<double> avg(row1.n_elem);
std::transform(row1.begin(), row1.end(), // input range 1
row2.begin(), // input range 2
avg.begin(), // output range
average); // function to apply
// calculate divergences
double d1 = kl_divergence(row1.begin(), row1.end(), avg.begin());
double d2 = kl_divergence(row2.begin(), row2.end(), avg.begin());
// write to output matrix
tmp_rmat(i,j) = sqrt(.5 * (d1 + d2));
}
}
}
};
// [[Rcpp::export]]
NumericMatrix rcpp_parallel_js_distance_modify(const Rcpp::NumericMatrix& matrix_input, int N_cores)
{
// allocate the matrix we will return
NumericMatrix matrix_output(matrix_input.nrow(), matrix_input.nrow());
std::size_t row_size = matrix_input.nrow();
std::size_t col_size = matrix_input.ncol();
// create the worker
JsDistance jsDistance(matrix_input, matrix_output, row_size, col_size);
// call it with parallelFor
parallelFor(0, matrix_input.nrow(), jsDistance, matrix_input.nrow()/N_cores); // parallelFor with grain size setting
return matrix_output;
}
// Example compare:
n_row = 1E3;
n_col = 1E2;
m = matrix(runif(n_row*n_col), nrow = n_row, ncol = n_col);
m = m/rowSums(m);
res <- benchmark(rcpp_parallel_js_distance(m, 6),
rcpp_parallel_js_distance_orignal(m, 6),
order="relative")
res[,1:4];
#test #elapsed #relative
rcpp_parallel_js_distance_orignal(m, 6) 128.069 1.000
rcpp_parallel_js_distance(m, 6) 129.210 1.009
正如我们所见,operator 中的数据类型将是C++ arma,现在我们可以通过直接使用该对象来安全快速地调用我们的用户定义函数仅指针,可能不是通用的或易于设计的。
现在,这个parallelFor结构将在并行计算中共享相同的数据源,无需额外的拷贝,然后我们可以使用上述问题中提到的想法对回测进行一些微调。
关于c++ - RcppParallel 中如何调用自定义函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30791410/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为