I think this should be a really simple thing but I don't get it solved. I'm trying to do a double contraction of two senond order Eigen tensors. Everything works well, but the result of the double contraction is an Eigen type:
Eigen::TensorContractionOp<const std::array<Eigen::IndexPair<int>, 2ul>, const Eigen::TensorFixedSize<double, Eigen::Sizes<3l, 3l> >, const Eigen::TensorFixedSize<double, Eigen::Sizes<3l, 3l> > >
but I need a double. I can print it but its not possible for me to work with it.
The code is the following
#include <iostream>
#include <unsupported/Eigen/CXX11/Tensor>
int main()
{
auto tensor1 = Eigen::TensorFixedSize<double, Eigen::Sizes<3,3>>();
tensor1.setValues({ {1, 0, 0},
{0, 1, 0},
{0, 0, 1} });
std::cout << "tensor1:\n" << tensor1 << "\n";
auto tensor2 = Eigen::TensorFixedSize<double, Eigen::Sizes<3,3>>();
tensor2.setValues({ {2, 0, 0},
{0, 2, 0},
{0, 0, 2} });
std::cout << "tensor2:\n" << tensor2 << "\n";
Eigen::array<Eigen::IndexPair<int>, 2> contraction_pair0011
= { Eigen::IndexPair<int>(0, 0), Eigen::IndexPair<int>(1, 1)};
auto tensor1_tensor2 = tensor1.contract(tensor2, contraction_pair0011);
std::cout << "tensor1 : tensor2:\n" << tensor1_tensor2 << "\n";
// double value = tensor1_tensor2; // won't compile
}
I need a function or call to get the value of the result, hope someone could help me.
Cheers Jonas
I solved the problem but think it will help you too if you are working with Eigen::Tensor module.
As written here in section Tensor Operations and C++ "auto":
Because Tensor operations create tensor operators, the C++ auto keyword does not have its intuitive meaning. When you use auto you do not get a Tensor as a result but instead a non-evaluated expression...
So the result of a tensor contraction is a
Eigen::TensorContractionOp<...>
and not a tensor from which we can get its elements. So we need to know the size of the resulting tensor. The Problem was that the result has to be a scalar tensor which is done with empty Eigen::Sizes<>
Eigen::TensorFixedSize<double, Eigen::Sizes<>>
Here the running code. I hope it helps somebody...
#include <iostream>
#include <unsupported/Eigen/CXX11/Tensor>
int main()
{
auto tensor1 = Eigen::TensorFixedSize<double, Eigen::Sizes<3,3>>();
tensor1.setValues({ {1, 0, 0},
{0, 1, 0},
{0, 0, 1} });
std::cout << "tensor1:\n" << tensor1 << "\n";
auto tensor2 = Eigen::TensorFixedSize<double, Eigen::Sizes<3,3>>();
tensor2.setValues({ {2, 0, 0},
{0, 2, 0},
{0, 0, 2} });
std::cout << "tensor2:\n" << tensor2 << "\n";
Eigen::array<Eigen::IndexPair<int>, 2> contraction_pair0011
= { Eigen::IndexPair<int>(0, 0), Eigen::IndexPair<int>(1, 1)};
Eigen::TensorFixedSize<double, Eigen::Sizes<>> tensor1_tensor2 = tensor1.contract(tensor2, contraction_pair0011);
std::cout << "tensor1 : tensor1:\n" << tensor1_tensor2 << "\n";
double t1_t2 = tensor1_tensor2(0);
std::cout << "result in double:\n" << t1_t2 << "\n";
}
Related
I am having trouble swapping rows inside a Matrix (nested array) according to the value of a specific column, I am making a console application that displays the results of a group stage in the football world cup so first I insert the results of the games to update the statistics of each team (rows) and generate the input array, but finally, I need to sort the rows according to the number of points of each team (the last position in each row). I need to create a function to generate the output array.
Input array:
inputArray[4][7] {
{0, 2, 1, 1, 3, -2, 2},
{1, 1, 1, 3, 3, 0, 4},
{2, 0, 1, 3, 1, 2, 6},
{1, 1, 1, 2, 2, 0, 4},
}
Output array of the function:
outputArray[4][7] {
{2, 0, 1, 3, 1, 2, 6},
{1, 1, 1, 3, 3, 0, 4},
{1, 1, 1, 2, 2, 0, 4},
{0, 2, 1, 1, 3, -2, 2},
}
The solution is straightforward. But my guess is that this is not what you want.
And, I think that the last value in the row is not the sum . . .
But let us first look at one potential solution:
#include <iostream>
#include <algorithm>
#include <array>
constexpr size_t NumberOfRows = 4u;
constexpr size_t NumberOfColumns = 7u;
using Columns = std::array<int, NumberOfColumns>;
using Array = std::array<Columns,NumberOfRows>;
int main() {
Array array{{ {0, 2, 1, 1, 3, -2, 2},
{1, 1, 1, 3, 3, 0, 4},
{2, 0, 1, 3, 1, 2, 6},
{1, 1, 1, 2, 2, 0, 4} }};
std::sort(std::begin(array), std::end(array), [](const Columns& c1, const Columns& c2) {return c1[6] < c2[6]; });
for (const Columns& c : array) {
for (const int i : c) std::cout << i << '\t';
std::cout << '\n';
}
}
If you want the array to be dynamic, then you may use a std::vector instead. You can then resize the number of rows and then number of columns.
#include <iostream>
#include <algorithm>
#include <vector>
constexpr size_t NumberOfRows = 4u;
constexpr size_t NumberOfColumns = 7u;
using Columns = std::vector<int>;
using Array = std::vector<Columns>;
int main() {
Array array{ {0, 2, 1, 1, 3, -2, 2},
{1, 1, 1, 3, 3, 0, 4},
{2, 0, 1, 3, 1, 2, 6},
{1, 1, 1, 2, 2, 0, 4} };
std::sort(std::begin(array), std::end(array), [](const Columns& c1, const Columns& c2) {return c1[6] < c2[6]; });
for (const Columns& c : array) {
for (const int i : c) std::cout << i << '\t';
std::cout << '\n';
}
}
But I still think that this is the wrong design. Becuase the last value in a row is the sum of other values. It is dependent, can be calculated, and there is no need to store ist.
See the following better design:
#include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>
struct Result {
std::vector<int> values{};
int sum() const { return std::accumulate(values.begin(), values.end(), 0); }
friend std::ostream& operator << (std::ostream& os, const Result& r) {
for (const int i : r.values) os << i << '\t';
return os << "--> " << r.sum();;
}
};
struct Series {
std::vector<Result> results{};
friend std::ostream& operator << (std::ostream& os, const Series& s) {
for (const Result r : s.results) os << r << '\n';
return os;
}
};
int main() {
Series series{{
{{0, 2, 1, 1, 3,-2}},
{{1, 1, 1, 3, 3, 0}},
{{2, 0, 1, 3, 1, 2}},
{{ 1, 1, 1, 2, 2, 0}}
}};
std::sort(series.results.begin(), series.results.end(), [](const Result& r1, const Result& r2) {return r1.sum() < r2.sum(); });
std::cout << series;
}
But you did not give enough information to give a good answer.
There are a function called inner_product, but I failed miserably in use that. I'll need to use this function several times for different matrices and vectors. Bellow my current code:
std::vector<vector<int>> matrix_a = {{0, 0},
{0, 1},
{1, 0},
{1, 1}};
std::vector<float> vector_b = {0.5, 0.8};
dot_produt(matrix_a, vettor_b);
float dot_produt(vector<vector<int>> e, vector<float> p){
return std::inner_product(std::begin(e), std::end(e), std::begin(p), 0.0);
}
The process is like:
(0.5 * 0) + (0.8 * 0) + (0.5 * 0) + (0.8 * 1)... ...
Expected output:
2.6
Error:
no match for 'operator*' (operand types are 'std::vector<int>' and 'float')
__init = __init + (*__first1 * *__first2);
You are trying to use pointers to begin and end of a vector of vectors, inner_product requires pointers to beginning and end of a vector.
Also, vectors have their own iterators, you can use them instead of std::begin and std::end.
Live demo
#include <iostream>
#include <numeric>
#include <vector>
//passing vectors by reference avoids unnecessary copies
double dot_produt(const std::vector<std::vector<int>> &e, const std::vector<float> &p)
{
double result = 0;
for (auto& v : e) //range based loop
result += std::inner_product(v.begin(), v.end(), p.begin(), 0.0);
return result;
}
int main()
{
std::vector<std::vector<int>> matrix_a = {{0, 0},
{0, 1},
{1, 0},
{1, 1}};
std::vector<float> vector_b = {0.5, 0.8};
std::cout << dot_produt(matrix_a, vector_b); //test print
}
Output:
2.6
I have these codes below. What's wrong with the const auto& in this context, it caused unexpected outputs.
It works fine while compiled with gcc-4.8.5, but gets unexpected outputs with gcc-4.9.2.
If I remove the & in const auto&, it works fine with both gcc versions.
// max_dim is a protobuf filed: const auto max_dim = msg.max();
// cat2_num is an element in std::vector<int32_t>: const auto cat2_num = vec[i]
const auto& res_num = std::max(1, std::min(max_dim, cat2_num));
LOG(ERROR) << res_num << ", " << max_dim << ", " << cat2_num
<< ", " << std::max(1, std::min(max_dim, cat2_num));
outputs:
-1392522416, 3, 1, 1
2, 3, 2, 2
3, 3, 3, 3
-1392522416, 3, 1, 1
3, 3, 6, 3
2, 3, 2, 2
-1392522416, 3, 1, 1
-1392522416, 3, 1, 1
2, 3, 2, 2
=========== updated ========
I couldn't reproduce the undefined behavior with these codes:
#include <iostream>
#include <vector>
int main() {
std::vector<int32_t> v = {-1, 0, 1, 2, 3, 6};
const int a = 3;
const auto& b = a;
for(size_t i = 0; i < v.size(); i++) {
const auto& c = v[i];
const auto& d = std::max(1, std::min(b, c));
std::cout << d << ", " << b << ", " << c << std::endl;
}
return 0;
}
output:
1, 3, -1
1, 3, 0
1, 3, 1
2, 3, 2
3, 3, 3
3, 3, 6
Your code has undefined behavior. In
const auto& res_num = std::max(1, std::min(max_dim, cat2_num));
The 1 is a prvalue, so a temporary integer is created that gets bound to the function parameter. This would be okay of max was like
template <typename T> const T max(const T&, const T&);
but instead it is defined like
template <typename T> const T& max(const T&, const T&);
So, if that 1 happens to be the maximum value, then max returns to you a reference to that temporary object that was created. After that, the temporary object is destroyed1, leaving res_num as a dangling reference. To fix the code make res_num a non-reference like
const auto res_num = std::max(1, std::min(max_dim, cat2_num));
and now you get a copy of the correct value.
1: all temporaries are destroyed at the end of the full expression the are created in
#NathanOliver has given clear declaration for the cause. Here is some other related infomation.
const T& is helpful for large objects, but it involves lifetime and aliasing problem. So be careful.
For int, double, pointers values, const T& gains nothing. In this situation, copy is cheaper than reference.
reference: int vs const int&
I'm trying to compare two histograms which I stored as an array. I'm new with the c++ interface (cv::Mat) and calculating histograms in OpenCV.
My code:
int testArr1[4] = {12, 10, 11, 11};
int testArr2[4] = {12, 0, 11, 0};
cv::Mat M1 = cv::Mat(1,4,CV_8UC1, testArr1);
cv::Mat M2 = cv::Mat(1,4,CV_8UC1, testArr2);
int histSize = 4;
float range[] = {0, 20};
const float* histRange = {range};
bool uniform = true;
bool accumulate = false;
cv::Mat a1_hist, a2_hist;
cv::calcHist(&M1, 1, 0, cv::Mat(), a1_hist, 1, &histSize, &histRange, uniform, accumulate );
cv::calcHist(&M2, 1, 0, cv::Mat(), a2_hist, 1, &histSize, &histRange, uniform, accumulate );
double compar_c = cv::compareHist(a1_hist, a2_hist, CV_COMP_CORREL);
double compar_chi = cv::compareHist(a1_hist, a2_hist, CV_COMP_CHISQR);
double compar_bh = cv::compareHist(a1_hist, a2_hist, CV_COMP_BHATTACHARYYA);
double compar_i = cv::compareHist(a1_hist, a2_hist, CV_COMP_INTERSECT);
cout << "compare(CV_COMP_CORREL): " << compar_c << "\n";
cout << "compare(CV_COMP_CHISQR): " << compar_chi << "\n";
cout << "compare(CV_COMP_BHATTACHARYYA): " << compar_bh << "\n";
cout << "compare(CV_COMP_INTERSECT): " << compar_i << "\n";
The results are a bit unexpected:
compare(CV_COMP_CORREL): 1
compare(CV_COMP_CHISQR): 0
compare(CV_COMP_BHATTACHARYYA): 0
compare(CV_COMP_INTERSECT): 4
For intersection, for example, I expected something like 0.5. What am I doing wrong? Can I not put arrays in a cv::mat? Or did I choose the wrong histogram "settings"?
The problem are your first 4 lines where you are converting the c array of integers to a matrix of chars. The constructor assumes a char array and therefore can't read the values properly. Your matrices M1 and M2 don't contain the correct values.
But if you change the following lines, so that the type of the array matches the type of the matrix:
char testArr1[4] = {12, 10, 11, 11};
char testArr2[4] = {12, 0, 11, 0};
I get the following output from your program:
compare(CV_COMP_CORREL): 0.57735
compare(CV_COMP_CHISQR): 2.66667
compare(CV_COMP_BHATTACHARYYA): 0.541196
compare(CV_COMP_INTERSECT): 2
With Boost's accumulators I can easily calculate statistical quantities for
weighted or unweighted input sets. I wonder if it is possible to mix weighted
and unweighted quantities inside the same accumulator. Looking at the
docs it doesn't seem that way.
This compiles fine but produces another result than I would have liked:
using namespace boost::accumulators;
const double a[] = {1, 1, 1, 1, 1, 2, 2, 2, 2};
const double w[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
accumulator_set<double, features<tag::sum, tag::weighted_sum>, double> stats;
for (size_t i=0; i<9; ++i)
stats(a[i], weight = w[i]);
std::cout << sum(stats) <<" "<< weighted_sum(stats) << std::endl;
// outputs "75 75" instead of "13 75"
Also, with a third template parameter to accumulator_set I always seems to
get weighted quantities, even when using an "unweighted" feature and extractor:
accumulator_set<double, features<tag::sum>, double> stats;
for (size_t i=0; i<9; ++i)
stats(a[i], weight = w[i]);
std::cout << sum(stats) << std::endl;
// outputs "75" instead of 13
Do I always have to use two different accumulators if I want to calculate both
weighted and unweighted quantities?
EDIT
I just use sum as an example, in reality I am interested in multiple, more complicated quantities.
It does say in the documentation that
When you specify a weight, all the
accumulators in the set are replaced
with their weighted equivalents.
There are probably better ways to do it but you can try something like this (basically swapping the meaning of the value with that of the weight):
accumulator_set< double, stats< tag::sum, tag::sum_of_weights >, double > acc;
const double a[] = {1, 1, 1, 1, 1, 2, 2, 2, 2};
const double w[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for( int i = 0; i < sizeof( a ) / sizeof( a[ 0 ] ); i++ )
acc( w[ i ], weight = a[ i ] );
std::cout << extract_result< tag::sum >( acc ) << std::endl; // weighted sum, prints 75
std::cout << extract_result< tag::sum_of_weights >( acc ) << std::endl; // sum, prints 13