如何编写具有可选Eigen :: Ref输出参数的函数?

时间:2015-05-22 01:17:51

标签: c++ eigen eigen3

我正在编写一个具有1个输入和3个输出的函数,如下所示:

void ComputeABC(const Eigen::Vector2d& x,
                Eigen::Matrix2d& a,
                Eigen::Matrix2d& b,
                Eigen::Matrix2d& c)

但是,我需要输出类型与Eigen::Matrix2dEigen::Map<Eigen::Matrix2d>兼容。幸运的是,Eigen提供了Ref类型:

void ComputeABC(const Eigen::Vector2d& x,
                Eigen::Ref<Eigen::Matrix2d> a,
                Eigen::Ref<Eigen::Matrix2d> b,
                Eigen::Ref<Eigen::Matrix2d> c)

现在是棘手的部分。 a,b和c的计算成本都很高,但是一些中间值可以在计算中共享,从而节省了一些计算量。鉴于这些都很昂贵,我想选择计算其中的每一个。我可以通过制作每种输出类型的指针来执行此操作,并传入NULL以表示我不想计算该特定值。

void ComputeABC(const Eigen::Vector2d& x,
                Eigen::Ref<Eigen::Matrix2d>* optional_a,
                Eigen::Ref<Eigen::Matrix2d>* optional_b,
                Eigen::Ref<Eigen::Matrix2d>* optional_c)

不幸的是,这非常难看,因为用户现在必须构建一个Ref然后将其传入。尝试传入Eigen::Matrix2d*Eigen::Map<Eigen::Matrix2d>*将导致编译错误。

根据以下标准,有没有人对如何使这个功能更容易使用有任何建议?

  • 添加额外的3个bool以选择性地计算值非常笨重,并且用户仍然必须为每个不需要的输出构建一个虚拟Eigen::Ref<Eigen::Matrix2d>
  • 对于需要填充的每个arg,调用代码都有Eigen::Matrix2dEigen::Map<Eigen::Matrix2d>,最好是零拷贝。
  • 避免使用裸double*数组,因为这些数组不会对正在使用的内存进行任何边界检查。
  • a,b和&amp;的任何子集c可以要求。 ([a],[a,b],[a,b,c],[b],[b,c],[c])。因此,过载不能很好地扩展。

3 个答案:

答案 0 :(得分:0)

我不确定如何在单个函数中使用如此多的输出参数组合创建一个干净的接口。相反,我可能倾向于把它变成一个班级。

class ABCComputer {
public:
  setInput(const Eigen::Vector2d& x);

  getOptionalA(Eigen::Ref<Eigen::Matrix2d>);
  getOptionalB(Eigen::Ref<Eigen::Matrix2d>);
  getOptionalC(Eigen::Ref<Eigen::Matrix2d>);
};

因为您说A,B和C的计算共享中间值,您可以通过使用标志指定所需的输出来一次计算所请求的值:

enum ABCOptions {
  ComputeA = 0x01,
  ComputeB = 0x02,
  ComputeC = 0x04
};


class ABCComputer {
public:
  compute(const Eigen::Vector2d& x, unsigned int options);

  getOptionalA(Eigen::Ref<Eigen::Matrix2d>);
  getOptionalB(Eigen::Ref<Eigen::Matrix2d>);
  getOptionalC(Eigen::Ref<Eigen::Matrix2d>);
};

并使用类似

的方式调用它
ABCComputer abc;
abc.compute(x, ComputeA | ComputeC);
abc.getOptionalA(my_A);
abc.getOptionalC(my_C);

答案 1 :(得分:0)

您可以为Ref<Matrix<double,2,Dynamic> >传递可选参数,并检查cols()==0

using namespace Eigen;
typedef Matrix<double,2,Dynamic> Matrix2xd;
void ComputeABC(const Vector2d& x,
            Ref<Matrix2xd> a, Ref<Matrix2xd> b, Ref<Matrix2xd> c)
{
   if(a.cols()>0) { /* compute a */ }
   if(b.cols()>0) { /* compute b */ }
   if(c.cols()>0) { /* compute c */ }
}

仅使用计算ac调用该函数:

Matrix2d a, c;
Vector2d x(1.0, 2.0);
ComputeABC(x, a, Matrix2xd(), c); // Matrix2xd() constructs a temporary 2x0 matrix

如果(在ComputeABC内)已分配给a的表达式已知有2列,则除了断言检查Matrix2d之外,您甚至不应遇到差异a {1}}确实有两列。

答案 2 :(得分:0)

您可以将Eigen :: Ref包装在c ++ 17 std :: optional中。有一个向c ++ 11的移植。

另一个选项使用EigenRef可默认构造为执行以下操作的事实:

template<class Obj>
class Opt
{
    const bool has;
    Obj obj;
public:
    Opt(std::nullptr_t n=nullptr) : has(false) {}
    template<class T>
    Opt(T && o) : has(true), obj(std::forward<T>(o)) {}
    Obj const& operator*() { return obj; }
    operator bool() { return has; }
};

using namespace Eigen;

void print(Opt<Ref<VectorXf>> a, Opt<std::string> b)
{
    if(a) { std::cout << "a=" << *a << std::endl; }
    if(b) { std::cout << "b=" << *b << std::endl; }
}

int main()
{
    VectorXf aaa;
    print(aaa, nullptr);
    std::cout << "Hello World!\n";
}