How do I write a function that has optional Eigen :: Ref output arguments?
I am writing a function that has 1 input and 3 outputs, for example:
void ComputeABC(const Eigen::Vector2d& x,
Eigen::Matrix2d& a,
Eigen::Matrix2d& b,
Eigen::Matrix2d& c)
However, I need my output types for compatibility with Eigen::Matrix2d
and Eigen::Map<Eigen::Matrix2d>
. Fortunately, Eigen provides a type Ref
:
void ComputeABC(const Eigen::Vector2d& x,
Eigen::Ref<Eigen::Matrix2d> a,
Eigen::Ref<Eigen::Matrix2d> b,
Eigen::Ref<Eigen::Matrix2d> c)
Now comes the tricky part. a, b and c are all expensive to compute, but some intermediate values can be split up in the computation, thus preserving some computation. Given that it is expensive, I want to calculate each one. I can do this by creating each type of pointer output and passing in NULL
to signal that I don't want to compute that particular value.
void ComputeABC(const Eigen::Vector2d& x,
Eigen::Ref<Eigen::Matrix2d>* optional_a,
Eigen::Ref<Eigen::Matrix2d>* optional_b,
Eigen::Ref<Eigen::Matrix2d>* optional_c)
Unfortunately, this is pretty ugly, as now the user has to build Ref
and then pass it. Trying to navigate to Eigen::Matrix2d*
or Eigen::Map<Eigen::Matrix2d>*
will result in a compilation error.
Does anyone have any suggestions on how to make this function easier to use given the following criteria?
- Adding an extra 3 bools to optionally compute values is rather awkward and the user will still have to create a dummy
Eigen::Ref<Eigen::Matrix2d>
for every unwanted output. - The calling code has either
Eigen::Matrix2d
orEigen::Map<Eigen::Matrix2d>
for each argument that must be filled, preferably with null copies. - Avoid using bare arrays
double*
as they do not provide bounds checking for the memory used. - Any subset of a, b, and c can be requested. ([a], [a, b], [a, b, c], [b], [b, c], [c]). So overloads don't scale very well.
source to share
I'm not sure how you can make a clean interface with so many combinations of output arguments in one function. Instead, I'm probably leaning towards turning it into a class.
class ABCComputer {
public:
setInput(const Eigen::Vector2d& x);
getOptionalA(Eigen::Ref<Eigen::Matrix2d>);
getOptionalB(Eigen::Ref<Eigen::Matrix2d>);
getOptionalC(Eigen::Ref<Eigen::Matrix2d>);
};
Since you say that intermediate value calculations separate A, B and C, you can calculate the requested values right away by specifying which outputs are needed with flags:
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>);
};
and call it something like
ABCComputer abc;
abc.compute(x, ComputeA | ComputeC);
abc.getOptionalA(my_A);
abc.getOptionalC(my_C);
source to share
You can pass Ref<Matrix<double,2,Dynamic> >
for optional arguments and check if there is one 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 */ }
}
To call a function with calculations only a
and c
:
Matrix2d a, c;
Vector2d x(1.0, 2.0);
ComputeABC(x, a, Matrix2xd(), c); // Matrix2xd() constructs a temporary 2x0 matrix
If (internally ComputeABC
) the expression you are assigning a
is known to have 2 columns, you shouldn't even experience the vs difference Matrix2d
, other than checking the assertion that it a
does have 2 columns.
source to share