C++ 特征稀疏矩阵与完全自定义类型相乘
我已经说服艾根这么做了C++ 特征稀疏矩阵与完全自定义类型相乘,c++,operator-overloading,linear-algebra,sparse-matrix,eigen,C++,Operator Overloading,Linear Algebra,Sparse Matrix,Eigen,我已经说服艾根这么做了 class A{...}; class B{...}; class Product{...}; auto operator*(const A&,const B&){return Product{..}} ..operator+.. //"SparseMatrix<A>*SparseVector<B> -> SparseVector<Product>" SparseMatrix<A&
class A{...}; class B{...}; class Product{...};
auto operator*(const A&,const B&){return Product{..}}
..operator+..
//"SparseMatrix<A>*SparseVector<B> -> SparseVector<Product>"
SparseMatrix<A> mymat_A; //...
SparseVector<B> myvec_B; //...
SparseVector<Product> result= mymat_A*myvec_B;
A类{…};B类{…};类乘积{…};
自动运算符*(常数A&,常数B&){返回产品{..}
…运算符+。。
//“SparseMatrix*SparseVector->SparseVector”
SparseMatrix mymat_A;/。。。
SparseVector myvec_B;/。。。
SparseVector结果=mymat_A*myvec_B;
然而,我真正想要的是不同的组件产品和输出累加器类型,例如
class A{}class B{} class Product{} class Accumulator;
auto operator*(const A&,const B&)->Product{..}
auto operator+=(Accumulator& lhs,const Product& p){lhs+=p;return lhs;}
SparseVector<Accumulator> result = mymat_A*myvec_B
类A{}类B{}类乘积{}类累加器;
自动运算符*(常数A&,常数B&)->乘积{..}
自动运算符+=(累加器&lhs,常量乘积&p){lhs+=p;返回lhs;}
SparseVector结果=mymat_A*myvec_B
这可能吗?我需要为A,B,Prod设置eigen的类型特征,以达到这一目的,并设置这些
模板
结构特征::ScalarBinaryOpTraits{
类型定义产品返回类型;
};
我原以为我可以使用“.sum..->累加器暗示存在一个单独的产品,为Prod+Prod->Acc提供重载,但这不起作用
用例=混合精度与小产品,但许多产品需要更大的累加器,并执行非算术操作(信息在图形中流动),恰好适合稀疏矩阵mul所需的存储和遍历模式优化
如果这是不可能的,也许有人可以推荐一个替代的稀疏矩阵库来实现这一点
如果我屈服于NIH,只使用我自己的,我的设计如下-只需使用decltype从运算符重载(提供具有求和重载的自定义乘积类型,生成所需累加器)推断出单独的求和/乘积类型的存在。但它会在内部使用Acc+=Prod(在声明decltype之后)(Prod+Prod)累加器已初始化为“0”。)
模板
SparseVector运算符*(常数SparseMatrix&,常数SparseVector&){…}
//提供适当的运算符+,++=。。。
当前代码(如果Eigen在路径中,则使用clang编译的单个源文件)
#pragma一次
#包括
//MatElem*向量->产品的设置
//目标是添加Prod+Prod->Acc,Acc+=Prod,Acc(Prod)Acc=0
类MatElem{public:MatElem(){}MatElem(intx){};
类VecElem{public:VecElem(){}VecElem(intx){};
类Prod{public:Prod(){}Prod(intx){};
类Acc{public:Acc(){}Acc(constprod&){printf(“Acc(Prod)”);}Acc(Prod&){printf(“Acc(Prod)”);}Acc(intx){};
自动运算符*(常量MatElem&a,常量VecElem&b){printf(“MatElem*VecElem\n”);返回Prod{};}
自动运算符+(constprod&a,constprod&b){printf(“Prod+Prod\n”);返回Prod{};}
自动运算符+=(Prod&a,const Prod&b){printf(“Prod+=Prod\n”);返回a;}
自动运算符+=(Acc&a,const Prod&b){printf(“Acc+=Prod\n”);返回a;}
模板
类特征::NumTraits{
公众:
typedef MatElem Real;
typedef MatElem非整数;
typedef MatElem Literal;
typedef-MatElem嵌套;
枚举{
IsInteger=0,
IsSigned=1,
RequireInitialization=1,
IsComplex=0,
ReadCost=1,
AddCost=1,
成本=1
};
自动静态epsilon(){return MatElem();}
自动静态伪精度(){return MatElem();}
自动静态最高(){return MatElem();}
自动静态最低(){return MatElem();}
自动静态digist10(){return 5;}
};
模板
类特征::NumTraits{
公众:
typedef向量实数;
typedef向量非整数;
typedef向量文字;
typedef向量嵌套;
枚举{
IsInteger=0,
IsSigned=1,
RequireInitialization=1,
IsComplex=0,
ReadCost=1,
AddCost=1,
成本=1
};
自动静态epsilon(){return VecElem{};}
自动静态虚拟_precision(){return VecElem{};}
自动静态最高(){return VecElem{};}
自动静态最低(){return VecElem{};}
自动静态digist10(){return 5;}
};
模板
类特征::NumTraits{
公众:
typedef Prod Real;
typedef产品非整数;
typedef Prod Literal;
typedef-Prod嵌套;
枚举{
IsInteger=0,
IsSigned=1,
RequireInitialization=1,
IsComplex=0,
ReadCost=1,
AddCost=1,
成本=1
};
自动静态epsilon(){return Prod{};}
自动静态伪精度(){return Prod{};}
自动静态最高(){return Prod{};}
自动静态最低(){return Prod{};}
自动静态digist10(){return 5;}
};
模板
类特征::NumTraits{
公众:
typedef Acc Real;
typedef-Acc非整数;
typedef Acc Literal;
typedef-Acc嵌套;
枚举{
IsInteger=0,
IsSigned=1,
RequireInitialization=1,
IsComplex=0,
ReadCost=1,
AddCost=1,
成本=1
};
自动静态epsilon(){return Acc{};}
自动静态虚拟_precision(){return Acc{};}
自动静态最高(){return Acc{};}
自动静态最低(){return Acc{};}
自动静态digist10(){return 5;}
};
模板
结构特征::ScalarBinaryOpTraits{
typedef产品返回类型;
};
模板
结构特征::ScalarBinaryOpTraits{
typedef产品返回类型;
};
空洞本征_实验(){
本征::SparseMatrix mymat(3,3);
mymat.insert(0,0)=MatElem{};
mymat.insert(0,1)=MatElem{};
mymat.insert(1,0)=MatElem{};
mymat.insert(1,1)=MatElem{};
特征:SparseVector-myvec(3);
myvec.insert(0)=向量{};
myvec.insert(1)=向量{};
//在“Acc”中似乎无法做到这一点,即使提供了上述适当的OpTraits等。
Eigen::SparseVector tmp=mymat*myvec;
对于(int k=0;kThank@chtz),只需将两个运算符特性设置为“累加器”(所需输出),而实际运算符重载将返回临时“乘积”“类型,它只是工作。我没有想过尝试它,但它似乎只是使用特征来分配输出,当然它不会影响实际的操作员。调试打印似乎证实了它在做我想做的事情。你能统一Produ吗?”
template<typename A,typename B>
SparseVector<decltype(A()*B()+A()*B())> operator*(const SparseMatrix<A>& ,const SparseVector<B>&){...}
// supply appropriate operator+, +=...
#pragma once
#include <Eigen/Sparse>
// setup for MatElem*VecElem->Prod
// goal is to add Prod+Prod->Acc, Acc+=Prod, Acc(Prod) Acc=0
class MatElem {public:MatElem(){} MatElem(int x){}};
class VecElem {public:VecElem(){} VecElem(int x){}};
class Prod {public:Prod(){} Prod(int x){}};
class Acc {public:Acc(){} Acc(const Prod&){printf("Acc(Prod)");} Acc(Prod&){printf("Acc(Prod)");} Acc(int x){}};
auto operator*(const MatElem& a,const VecElem& b){printf("MatElem*VecElem\n");return Prod{};}
auto operator+(const Prod& a,const Prod& b){printf("Prod+Prod\n");return Prod{};}
auto operator+=(Prod& a,const Prod& b){printf("Prod+=Prod\n");return a;}
auto operator+=(Acc& a,const Prod& b){printf("Acc+=Prod\n");return a;}
template<>
class Eigen::NumTraits<MatElem> {
public:
typedef MatElem Real;
typedef MatElem NonInteger;
typedef MatElem Literal;
typedef MatElem Nested;
enum {
IsInteger=0,
IsSigned=1,
RequireInitialization=1,
IsComplex=0,
ReadCost=1,
AddCost=1,
MulCost=1
};
auto static epsilon(){return MatElem();}
auto static dummy_precision(){return MatElem();}
auto static highest(){return MatElem();}
auto static lowest(){return MatElem();}
auto static digist10(){return 5;}
};
template<>
class Eigen::NumTraits<VecElem> {
public:
typedef VecElem Real;
typedef VecElem NonInteger;
typedef VecElem Literal;
typedef VecElem Nested;
enum {
IsInteger=0,
IsSigned=1,
RequireInitialization=1,
IsComplex=0,
ReadCost=1,
AddCost=1,
MulCost=1
};
auto static epsilon(){return VecElem{};}
auto static dummy_precision(){return VecElem{};}
auto static highest(){return VecElem{};}
auto static lowest(){return VecElem{};}
auto static digist10(){return 5;}
};
template<>
class Eigen::NumTraits<Prod> {
public:
typedef Prod Real;
typedef Prod NonInteger;
typedef Prod Literal;
typedef Prod Nested;
enum {
IsInteger=0,
IsSigned=1,
RequireInitialization=1,
IsComplex=0,
ReadCost=1,
AddCost=1,
MulCost=1
};
auto static epsilon(){return Prod{};}
auto static dummy_precision(){return Prod{};}
auto static highest(){return Prod{};}
auto static lowest(){return Prod{};}
auto static digist10(){return 5;}
};
template<>
class Eigen::NumTraits<Acc> {
public:
typedef Acc Real;
typedef Acc NonInteger;
typedef Acc Literal;
typedef Acc Nested;
enum {
IsInteger=0,
IsSigned=1,
RequireInitialization=1,
IsComplex=0,
ReadCost=1,
AddCost=1,
MulCost=1
};
auto static epsilon(){return Acc{};}
auto static dummy_precision(){return Acc{};}
auto static highest(){return Acc{};}
auto static lowest(){return Acc{};}
auto static digist10(){return 5;}
};
template<>
struct Eigen::ScalarBinaryOpTraits<MatElem,VecElem,Eigen::internal::scalar_product_op<MatElem, VecElem> >{
typedef Prod ReturnType;
};
template<>
struct Eigen::ScalarBinaryOpTraits<Prod,Prod,Eigen::internal::scalar_sum_op<Prod, Prod> >{
typedef Prod ReturnType;
};
void eigen_experiment() {
Eigen::SparseMatrix<MatElem> mymat(3,3);
mymat.insert(0,0)=MatElem{};
mymat.insert(0,1)=MatElem{};
mymat.insert(1,0)=MatElem{};
mymat.insert(1,1)=MatElem{};
Eigen::SparseVector<VecElem> myvec(3);
myvec.insert(0)=VecElem{};
myvec.insert(1)=VecElem{};
// Can't seem to do this with "Acc", even if supplying appropriate OpTraits etc above.
Eigen::SparseVector<Prod> tmp=mymat*myvec;
for (int k=0; k<mymat.outerSize(); ++k){
for (decltype(mymat)::InnerIterator v(mymat,k); v;++v){
printf("%d %d\n",v.row(),v.col());
}
}
for (decltype(tmp)::InnerIterator v(tmp); v;++v){
printf("%d\n",v.index());
}
}
int main(int argc,const char**){
eigen_experiment();
return 0;
}