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;
}