How to access/write a matrix in a function using Eigen? - c++

I'm trying to write a function using Eigen that inverts a diagonal matrix a little bit different from usual. When the element of the diagonal is zero (or relatively close to zero), it should set the value for the diagonal element to zero, but otherwise the value should be 1/(corresponding element). I tried to write a function that receives the diagonal matrix that I want to invert (it is actually a nx1 matrix, hence the name) and another pointer, where I want the result to be put in:
template <typename m1, typename m2>
void invertSingularValues(Eigen::EigenBase<m1>& sing_val_vector,Eigen::EigenBase<m2>& res)
{
for (int i=0; i<sing_val_vector.rows();i++)
res(i,i)=(sing_val_vector[i]<0.0000001?0:1/sing_val_vector[i]);
};
It seems that I cannot access the elements of the matrices by using (i,j) or [i] as I get this errors:
no match for ‘operator[]’ (operand types are ‘Eigen::EigenBase >’ and ‘int’)
res(i,i)=(sing_val_vector[i]<0.0000001?0:1/sing_val_vector[i]);
no match for ‘operator[]’ (operand types are ‘Eigen::EigenBase >’ and ‘int’)
res(i,i)=(sing_val_vector[i]<0.0000001?0:1/sing_val_vector[i]);
no match for call to ‘(Eigen::EigenBase >) (int&, int&)’
res(i,i)=(sing_val_vector[i]<0.0000001?0:1/sing_val_vector[i]);
When I call the function like this:
invertSingularValues(S.data,S_inv);
S.data and S_inv are Eigen matrices.
What can I do?

As the compiler says, you cannot do res(i,i) when res is of type EigenBase because EigenBase does not have this functionality defined. You need to use a more specific class, like MatrixBase or DenseBase.
Relevant documentation:
Writing functions taking Eigen types as parameters
The class hierarchy
Ignoring any code optimisations, something like this would work:
template <typename m1, typename m2>
void invertSingularValues(Eigen::MatrixBase<m1>& sing_val_vector,Eigen::MatrixBase<m2>& res)
{
for (int i(0); i < sing_val_vector.rows(); i++)
for (int j(0); j < sing_val_vector.cols(); j++)
res(i,j) = sing_val_vector(i,j) < 1e-07 ? 0.0 : 1.0/sing_val_vector(i,j);
};

Related

How to explicitly cast argument to match an expected function parameter?

I am trying to write a generic function to compute an average over a certain range.
template <typename Range, typename Ret, typename Func>
Ret average(Range range, Ret zero, Func extract) {
Ret sum = zero;
int numElements = 0;
for (const auto& elem : range) {
sum += extract(elem);
++numElements;
}
if (numElements > 0)
sum /= numElements;
return sum;
}
The problam I am having is with the usage of the /= operator, but to better clarify the arguments of this function, let me clarify them:
Range range is any object that defines a range through begin() and end() member funcitons. I may need to add const& to avoid unnecessary copying.
Ret zero defines the neutral element of the addition used when computing the average. It could be just a scalar, but will work with vectors or matrices too for example.
Func extract is a function (usually given as a lambda function) that converts the elements of the range into Ret values that I average over. In practice I use it as a getter of a specific field in big objects that I iterate over.
I could probably define it as std::function<Ret(decltype(*range.begin()))> or something similar, if C++ didn't have problems deducting types this way.
I assume that Ret provides some /= operator that the above function can work with, but I do not want to require it to take an int specifically.
In my use case, for example, Ret works with float-s and this gives me an annoying warning:
warning: 'argument': conversion from 'int' to 'float', possible loss of data
So, what are my options to make the above function clean and work with any suitable operator/=?
I tried, for example, to deduct the type of the right argument of the operator and explicitly cast to it:
template <typename Range, typename Ret, typename Func>
Ret average(Range range, Ret zero, Func extract) {
Ret sum = zero;
int numElements = 0;
for (const auto& elem : range) {
sum += extract(elem);
++numElements;
}
using F = std::remove_pointer<decltype(&Ret::operator/=)>;
if (numElements > 0)
sum /= static_cast<typename boost::function_traits<F>::arg1_type>(numElements);
return sum;
}
But I get a lot of compile errors, suggesting that I don't know what I am doing. Starts with:
error: 'boost::detail::function_traits_helper<std::remove_pointer<SpecificTypeUsedAsRet &(__cdecl SpecificTypeUsedAsRet::* )(float)> *>': base class undefined
That's probably because boost::function_traits does not work with member functions, just regular ones?
I am also concerned that this solution may not work when:
The operator/= is not given as a member function, but as a regular function with two arguments.
The operator/= is overloaded with respect to its right operand. An int may match only one of the overloads - so there is no ambiguity, but decltype won't know which overload to take.
I would prefer not to use boost but stick to the powers provided by newest C++ standards
You could simply declare Ret numElements = 0; instead of making it an int. If it has /= operator, it probably has an ++ operator; or you could use num_elements += 1 instead.

reduction of eigen based templates

I am trying to do a reduction based on eigen matrix.
#include <iostream>
#include <Eigen/Dense>
#include <type_traits>
template<typename T1, typename T2, int n1, int n2>
auto reduction(Eigen::Matrix<T1, n1, n2> &a1,
Eigen::Matrix<T2, n1, n2> &a2)
-> decltype(T1{}*T2{})
{
using BaseT3 =
typename std::remove_cv<typename std::remove_reference<decltype(T1{}*T2{})>::type>::type;
BaseT3 res = a1(0, 0)*a2(0, 0);
for (int i=0; i<n1; ++i)
for (int j=0; j<n2; ++j)
if (i+j)
res = res + a1(i, j)*a2(i, j);
return res;
}
int main()
{
Eigen::Matrix<double, 3, 3> m;
Eigen::Matrix<Eigen::Vector3d, 3, 3> n;
std::cout << reduction(m, n) << std::endl;
}
Basically, Im a trying to get sum_{i, j} a1[i, j] * a2[i, j] where a1 and a2 are some eigen mathix but I get compilation errors. The error I get is
error: no match for ‘operator=’ (operand types are ‘BaseT3 {aka
Eigen::CwiseUnaryOp<Eigen::internal::scalar_multiple_op<double>,
const Eigen::Matrix<double, 3, 1> >}’
and
‘const Eigen::CwiseBinaryOp<Eigen::internal::scalar_sum_op<double>,
const Eigen::CwiseUnaryOp<Eigen::internal::scalar_multiple_op<double>,
const Eigen::Matrix<double, 3, 1> >,
const Eigen::CwiseUnaryOp<Eigen::internal::scalar_multiple_op<double>,
const Eigen::Matrix<double, 3, 1> > >’)
res = res + a1(i, j)*a2(i, j);
^
If I am not mistaken, for the given main, type BaseT3 should have been Eigen::Vector3d. I also tried to static cast so the operator= should not fail but I then get other errors.
This is c++11, I use Eigen3 and the compiler is g++ 5.4.1.
The decltype of T1 * T2 isn't what you expect here - Eigen heavily uses expression templates. The CWiseUnaryOp and CWiseBinaryOp types in your error are indicative of that. In other words, the result of "double * Vector3d" isn't what you'd expect (it's not a Vector3d, it's a cwisebinaryop).
See also: Writing functions taking Eigen Types.
In this specific case you may find a solution by creating partial specializations for Eigen base types for both the first and second parameters of your template function.
Eigen uses expression templates to optimize chains of operations.
So MatrixA*MatrixB is not a Matrix type, but rather an expression that says "when evaluated this will be the product of a MatrixA times a MatrixB".
The result is that A*B+C*D doesn't create (at least as many) temporary matrixes, but instead when stored in an output matrix the results are "lazily" calculated directly into the output matrix.
Now, you are multipying elements. But one of your element types is in turn a matrix. And Eigen does expression template optimization of scalar times vector it turns out.
The type you want is std::decay_t<decltype((T1{}+T2{}).eval())> (well the C++11 verbose version of that).
You could write a fancy SFINAE thing that checks if it can be evaluated, and if so does that. Or you can test for Eigen expression template types.

Why is below program giving me error when I am assigning true or false to a vector of type bool?

I was doing a problem on TopCoder for finding the longest path in an acyclic directed graph. I have used vector of type bool for visiting vertices. But it is giving me these errors (highlighted in the code below):
error: no match for ‘operator=’ (operand types are ‘std::vector<bool>’ and ‘bool’)
visited[cur_ver]=true;
error: no match for ‘operator==’ (operand types are ‘std::vector<bool>’ and ‘bool’)
if(visited[i]==false)
Here is my code:
#include<bits/stdc++.h>
using namespace std;
class Circuits{
vector<int>adj[51];
vector<int>cost[51];
vector<int>T[51];
vector<bool>visited[51];
vector<int>dist[51];
int glm=0;
public:
void topological_sorting(int cur_ver,int n){
visited[cur_ver]=true; //error 1
for(int i=0;i<adj[cur_ver].size();i++){
if(visited[i]==false) //error 2
topological_sorting(i);
}
T.insert(T.begin(),cur_ver);
}
void Longest_Path(int s,int n){
for(int i=0;i<=n;i++)
dist[i]=NINF;
dist[s]=0;
for(int i=0;i<=n;i++){
int u=T[i]
if(dist[u]!=NINF)
for(int j=0;j<adj[i].size();j++){
int v=adj[u][j];
if(dist[v]<dist[u]+cost[u][v])
dist[v]=dist[u]+cost[u][v];
}
}
for(int i=0;i<=n;i++)
if(dist[i]>glm)
glm=dist[i];
}
int howLong(vector<string>connects,vector<string>costs){
for(int i=0;i<connects.size();i++){
for(int j=0;j<connects[i].size();j++){
adj[i].push_back(int(connects[i][j]));
cost[i].push_back(int(costs[i][j]));
}
}
int n=connects.size();
for(int i=0;i<=n;i++)
visited[i]=false;
topological_sorting(0,n);
int lm=0;
for(int i=0;i<=n;i++){
Longest_Path(i,n);
if(glm>lm)
lm=glm;
glm=0
}
return lm;
}
};
You are confusing built-in array syntax and syntax of the std::vector<T> class. Precisely, with
std::vector<int> myVec[51]
you declare and array of 51 vectors of type int. Thus, the code
visited[cur_ver]=true;
means "take element 52 of the array myVec, and assign true to it". However, that element is not of type bool, but of type std::vector<int>. There is no operator that would allow to assign bool values to a vector object.
To specify the size of a vector, which is your intention, use the appropriate constructor or the resize() method. When you're sure that the size of your container is fixed and known at compilation time, you may use std::array<size_t, T>, which is a fixed-length array container, available in C++11. But this is not the case with your code - you insert elements later on.
Thus, to fix the error, fix the syntax for vector declarations, and then resize in your class' constructor:
vector<int> adj;
// other vectors follow ...
// in Circuit::Circuit:
Circuit:Circuit() {
adj.resize(51); // others follow ...
}
Be sure to replace the 51 with a properly named constant. "Magic" constants are evil!
Vectors are like dynamic arrays with an ability to resize. We've only two ways of the declaration of the vector in c++.
vector <int> myVector;
vector <int> myVector2(4,1000);
The second will initialize a vector of size 4 with initial value 1000. If you want to provide a size maybe you can use like this.
vector <int> myVector(12);

std::set of RTYPE values in Rcpp

Say I would like to implement a function that counts the unique values, e.g.
#include <Rcpp.h>
using Rcpp::Vector;
using Rcpp::traits::is_na;
using Rcpp::IntegerVector;
template <int RTYPE>
IntegerVector nunique( const Vector<RTYPE>& x ) {
std::set<typename Rcpp::traits::storage_type<RTYPE>::type> values;
for ( int i = 0; i < x.length(); ++i ) {
if ( !is_na<RTYPE>(x[i]) )
values.insert(x[i]);
}
return IntegerVector::create(values.size());
}
However this won't compile and throws errors like:
error: call of overloaded 'insert(Rcpp::Vector<19>::const_Proxy)' is ambiguous
values.insert(x[i]);
or
error: no match for 'operator<' (operand types are 'const Rcomplex' and 'const Rcomplex')
{ return __x < __y; }
Is there any way to create a std::set of RTYPE objects? Alternatively, how could I use some kind of hashes of such objects to count the unique values?
We have a few examples at the Rcpp Gallery that show how to do dynamic run-time switching based on the run-time loading the SEXP type coming in here as a compile-time RTYPE.
The compiler can't know whether you call with an integer or numeric... yet the R-based back end you want to insert into needs a type. I think you can do what you want with a std::variant (C++17) or its Boost version.
Or just switch over atomic types.

C++ vector<vector<vector<char> > > myVector - How can I initialize with size?

With a 1D vector, I can use something like this:
vector<char> letters(5).
How can I accomplish the same thing while initializing a 3D vector?
Here's what I've tried:
vector<vector<vector<char> row(farms[0][0].size())> farm(farms[0].size())>
path(farms.size());
That's a bit tricky to parse, but it's just the first example nested thrice and using the same dimensions as the farms 3D vector. It produces these errors:
p1.cpp:109: error: template argument 1 is invalid
p1.cpp:109: error: template argument 2 is invalid
p1.cpp:109: error: template argument 1 is invalid
p1.cpp:109: error: template argument 2 is invalid
p1.cpp:109: error: invalid type in declaration before ‘(’ token
vector<vector<vector<char> row(farms[0][0].size())> is clearly not a type.
The type you're after is the type you wrote in the title:
vector<vector<vector<char> > >
Now, if you want to pre-fill each dimension so that it's a 5×5×5 vector from the outset:
vector<vector<vector<char> > > letters(
5,
vector<vector<char> >(
5,
vector<char>(
5,
'\0'
)
)
);
At each nested level, the first argument is the number of desired elements, and the second is the value with which to fill each of those elements.
I think it's clear that this is not good code. Ask yourself again whether you really need three dimensions and, even if you do, consider a 1D vector of size 5×5×5, with 3D indexing simulated over the top with a wrapper type. This is only inappropriate if your matrix won't always be square, but otherwise has — among other benefits — the property of vastly reduced dynamic allocations and locality-busting indirections.
typedef std::vector<std::vector<std::vector<char>>> threeVec;
static constexpr unsigned int SIZE = 5;
...
threeVec tv;
tv.reserve(SIZE);
for (auto & i : tv) {
i.reserve(SIZE);
for (auto & j : i) {
j.reserve(SIZE);
}
}
I guess, if that is necessary, you'll have to initialize it by iterating over the dimensions, i.e.
typedef std::vector<std::vector<std::vector<char > > > vector3d;
vector3d letters(5);
for(int i=0; i<letters.size(); ++i) {
letters[i].resize(5);
for(int j=0; j<letters[i].size(); ++j) {
letters[i][j].resize(5);
}
}
something like that. Please note, that did not test that code, so there might be small errors.