Теперь я пытаюсь научить g ++ компилятора линейной алгебры, так что g ++ может переписать выражение типа (matrix * vector)(index)
как цикл для оценки выражения. В основном это то, что я ожидаю в следующей статье the last article в серии «Expressive C++». В этой последней статье объясняется, как создать EDSL для добавления векторов, так что я написал еще один EDSL для умножения матрицы на вектор.Boost.Proto: Возможно ли преобразование Proto для оценки выражения смеси матрицы и вектора?
Но макрос BOOST_PROTO_DEFINE_OPERATORS не может быть скомпилирован, когда имя домена Proto для моего собственного матричного и векторного классов передается в качестве первого параметра макроса.
Так что мне интересно, возможно ли преобразование Прото, чтобы оценить выражение смеси матричных и векторных объектов. Кажется, что нет такого примерного кода, который может быть скомпилирован, а пример кода в "Adapting Existing Types to Proto" в руководстве пользователя Proto 1.57.0 является неполным, хотя речь идет о том, как адаптировать существующие матрицы и векторные типы к Proto.
Я в затруднении .. Не могли бы вы дать мне несколько советов или советов?
И вот мой исходный код. Я был бы очень признателен, если бы вы мне советы о том, как это исправить:
#include <iostream>
#include <boost/proto/proto.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
namespace LinAlg {
class Vector;
class Matrix;
// Functor for lazy evaluation
struct ElmOfMatVecMult;
// The grammar for an expression like (matrix * vector)(index)
struct MatVecMultElmGrammar : proto::or_<
proto::when< proto::multiplies< Matrix, Vector>,
proto::_make_function(ElmOfMatVecMult,
proto::_left, proto::_right,
proto::_state) >
> {};
// The grammar for a vector expression
// (Now I consider just one form : matrix * vector .)
struct VecExprGrammar : proto::or_<
proto::when< proto::function< MatVecMultElmGrammar, proto::_>,
MatVecMultElmGrammar(proto::_left, proto::_right) >,
proto::multiplies< Matrix, Vector>
> {};
template<typename E> struct Expr;
// The above grammar is associated with this domain.
struct Domain
: proto::domain<proto::generator<Expr>, VecExprGrammar>
{};
// A wrapper template for linear algebraic expressions
// including matrices and vectors
template<typename ExprType>
struct Expr
: proto::extends<ExprType, Expr<ExprType>, Domain>
{
explicit Expr(const ExprType& e)
: proto::extends<ExprType, Expr<ExprType>, Domain>(e)
{}
};
// Testing if data in an heap array can be a vector object
class Vector {
private:
int sz;
double* data;
public:
template <typename Sig> struct result;
template <typename This, typename T>
struct result< This(T) > { typedef double type; };
typedef double result_type;
explicit Vector(int sz_ = 1, double iniVal = 0.0) :
sz(sz_), data(new double[sz]) {
for (int i = 0; i < sz; i++) data[i] = iniVal;
std::cout << "Created" << std::endl;
}
Vector(const Vector& vec) :
sz(vec.sz), data(new double[sz]) {
for (int i = 0; i < sz; i++) data[i] = vec.data[i];
std::cout << "Copied! " << std::endl;
}
~Vector() {
delete [] data;
std::cout << "Deleted" << std::endl;
}
// accessing to an element of this vector
double& operator()(int i) { return data[i]; }
const double& operator()(int i) const { return data[i]; }
};
// Testing if data in an heap array can be a matrix object
class Matrix
{
private:
int rowSz, colSz;
double* data;
double** m;
public:
template <typename Signature> struct result;
template <typename This, typename T>
struct result< This(T,T) > { typedef double type; };
explicit Matrix(int rowSize = 1, int columnSize =1,
double iniVal = 0.0) :
rowSz(rowSize), colSz(columnSize),
data(new double[rowSz*colSz]), m(new double*[rowSz])
{
for (int i = 0; i < rowSz; i++) m[i] = data + i*colSz;
for (int ri = 0; ri < rowSz; ri++)
for (int ci = 0; ci < colSz; ci++) m[ri][ci] = iniVal;
std::cout << "Created" << std::endl;
}
Matrix(const Matrix& mat) :
rowSz(mat.rowSz), colSz(mat.colSz),
data(new double[rowSz*colSz]), m(new double*[rowSz])
{
for (int i = 0; i < rowSz; i++) m[i] = data + i*colSz;
for (int ri = 0; ri < rowSz; ri++)
for (int ci = 0; ci < colSz; ci++)
m[ri][ci] = mat.m[ri][ci];
std::cout << "Copied! " << std::endl;
}
~Matrix()
{
delete [] m;
delete [] data;
std::cout << "Deleted" << std::endl;
}
int rowSize() const { return rowSz; }
int columnSize() const { return colSz; }
// accesing to a vector element
double& operator()(int ri, int ci) { return m[ri][ci]; }
const double& operator()(int ri, int ci) const { return m[ri][ci]; }
};
// An expression like (matrix * vector)(index) is transformed
// into the loop for calculating the dot product between
// the vector and matrix.
struct ElmOfMatVecMult
{
double operator()(Matrix const& mat, Vector const& vec,
int index) const
{
double elm = 0.0;
for (int ci =0; ci < mat.columnSize(); ci++)
elm += mat(index, ci) * vec(ci);
return elm;
}
};
// Define a trait for detecting linear algebraic terminals, to be used
// by the BOOST_PROTO_DEFINE_OPERATORS macro below.
template<typename> struct IsExpr : mpl::false_ {};
template<> struct IsExpr< Vector> : mpl::true_ {};
template<> struct IsExpr< Matrix> : mpl::true_ {};
// This defines all the overloads to make expressions involving
// Vector and Matrix objects to build Proto's expression templates.
BOOST_PROTO_DEFINE_OPERATORS(IsExpr, Domain)
}
int main()
{
using namespace LinAlg;
proto::_default<> trans;
Matrix mat(3, 3);
Vector vec1(3);
mat(0,0) = 1.00; mat(0,1) = 1.01; mat(0,2) = 1.02;
mat(1,0) = 1.10; mat(1,1) = 1.11; mat(1,2) = 1.12;
mat(2,0) = 1.20; mat(2,1) = 1.21; mat(2,2) = 1.22;
vec1(0) = 1.0;
vec1(1) = 2.0;
vec1(2) = 3.0;
proto::display_expr((mat * vec1)(2));
proto::display_expr(VecExprGrammar()((mat * vec1)(2));
double vecElm = trans(VecExprGrammar()((mat * vec1)(2));
return 0;
}