Vorrei utilizzare Boost.Proto per trasformare un linguaggio specifico del dominio incorporato in una serie di operazioni di matrice implementate con la libreria Eigen. Poiché l'efficienza è importante, voglio che proto generi modelli di espressione Eigen ed eviti una valutazione prematura.Creazione di modelli di espressioni Eigen con Boost.Proto
Ho implementato una semplice grammatica che può generare espressioni di moltiplicazione di matrici. Il codice sotto compila senza avvisi (su g ++ 4.8.0 e Intel C++ 2013.3, con Boost 1.54.0 ed Eigen 3.1.3) e funziona fintanto che la mia espressione ha solo una singola operazione di moltiplicazione. Non appena aggiungo più moltiplicazioni alla catena, si blocca. Valgrind mi dice che questo è dovuto al fatto che uno dei provini del modello di espressione Eigen :: GeneralProduct viene distrutto prima che la valutazione sia completata.
Non capisco perché questo accada, o cosa posso fare per impedirlo. Tutto l'aiuto è apprezzato!
#include <iostream>
#include <boost/fusion/container.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/void.hpp>
#include <boost/proto/proto.hpp>
#include <boost/ref.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/utility.hpp>
#include <Eigen/Dense>
namespace fusion = boost::fusion;
namespace mpl = boost::mpl;
namespace proto = boost::proto;
typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> matrix;
// Placeholders
const proto::terminal<mpl::int_<0> >::type I1 = {{}};
const proto::terminal<mpl::int_<1> >::type I2 = {{}};
const proto::terminal<mpl::int_<2> >::type I3 = {{}};
// Grammar
template<class Rule, class Callable = proto::callable>
struct External :
proto::when<Rule, proto::external_transform> {};
struct matmul_transform : proto::callable {
template<class Sig> struct result;
template<class This, class MatrixExpr1, class MatrixExpr2>
struct result<This(MatrixExpr1, MatrixExpr2)> {
typedef typename Eigen::ProductReturnType<
typename boost::remove_const<typename boost::remove_reference<MatrixExpr1>::type>::type,
typename boost::remove_const<typename boost::remove_reference<MatrixExpr2>::type>::type>::Type
type;
};
template<class MatrixExpr1, class MatrixExpr2>
typename result<matmul_transform(MatrixExpr1, MatrixExpr2)>::type
operator()(const MatrixExpr1 &a, const MatrixExpr2 &b) const {
return a * b;
}
};
struct MatmulGrammar;
struct InputPlaceholder : proto::terminal<proto::_> {};
struct MatrixMultiplication :
proto::multiplies<MatmulGrammar, MatmulGrammar> {};
struct MatmulGrammar : proto::or_<
External<InputPlaceholder>,
External<MatrixMultiplication> > {};
struct matmul_transforms : proto::external_transforms<
proto::when<MatrixMultiplication, matmul_transform(MatmulGrammar(proto::_left), MatmulGrammar(proto::_right))>,
proto::when<InputPlaceholder, proto::functional::at(proto::_data, proto::_value)> > {};
int main() {
matrix mat1(2,2), mat2(2,2), mat3(2,2), result(2,2);
mat1 << 1, 2, 3, 4;
mat2 << 5, 6, 7, 8;
mat3 << 1, 3, 6, 9;
MatmulGrammar mmg;
// THIS WORKS:
result = mmg(I1 * I2,
mpl::void_(),
(proto::data = fusion::make_vector(boost::cref(mat1), boost::cref(mat2), boost::cref(mat3)),
proto::transforms = matmul_transforms()));
std::cout << result << std::endl;
// THIS CRASHES:
result = mmg(I1 * I2 * I3,
mpl::void_(),
(proto::data = fusion::make_vector(boost::cref(mat1), boost::cref(mat2), boost::cref(mat3)),
proto::transforms = matmul_transforms()));
std::cout << result << std::endl;
return 0;
}
C'era un discorso in questo anni C++ Ora sull'utilizzo Eigen con proto. Se ricordo bene, hanno parlato esplicitamente di questo problema e hanno spiegato come lo hanno risolto. Puoi trovare le diapositive [qui] (https://github.com/boostcon/cppnow_presentations_2013/blob/master/fri/proto-eigen-fem.pdf?raw=true), il video del discorso [qui] (http : //www.youtube.com/watch? v = pDTQlwXkjvU) e il codice sorgente [qui] (https://github.com/barche/eigen-proto) se sei interessato.Sfortunatamente manca l'audio negli ultimi minuti, ma tutto funziona fino ad allora. – llonesmiz