get the rank of an element of a boost::multi_index container - c++

The code below shows a multi_index container which is indexed by sequence and order.
In my use case elements will be mainly searched by index, and if existing, the next element (by order) is obtained.
My question is, how to get the rank (by order) of obtained next element?
#include <iostream>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/ranked_index.hpp>
#include <boost/multi_index/identity.hpp>
using namespace boost::multi_index;
typedef multi_index_container <
int
, indexed_by<
sequenced<>
, ordered_non_unique<identity<int>>
, ranked_non_unique<identity<int>>
>
> Ints;
int main() {
Ints ints;
auto & sequence=ints.get<0>();
auto & order=ints.get<1>();
sequence.push_back(2);
sequence.push_back(-1);
sequence.push_back(5);
sequence.push_back(6);
auto it = order.find(2);
if (it!=order.end()) {
std::cout
<< "next to "
<< *it
<< " by sequence is "
<< *(++(ints.project<0>(it)))
<< std::endl
;
std::cout
<< "next to "
<< *it
<< " by order is "
<< *(++(ints.project<1>(it))) //++it is good too
<< std::endl
;
std::cout
<< "rank of next by sequence is "
// << ??? ints.rank<???>(???)
<< std::endl
;
std::cout
<< "rank of next by order is "
// << ??? ints.rank<???>(???)
<< std::endl
;
}
}

#sehe's answer is perfectly valid but runs in linear time. If you want better performance, consider defining your index #0 as random_access and #1 as ranked_non_unique (index #2 is redundant):
typedef multi_index_container <
int
, indexed_by<
random_access<>
, ranked_non_unique<identity<int>>
>
> Ints;
so that you can write:
std::cout
<< "rank of next by sequence is "
<< ints.project<0>(it)-sequence.begin()+1 // O(1)
<< std::endl
;
std::cout
<< "rank of next by order is "
<< order.rank(it)+1 // O(log n)
<< std::endl
;

Assuming you want some kind of "index into" or "offset from begin" in the sequenced index:
if (it!=order.end()) {
auto rank_of = [&](auto it) {
return std::distance(sequence.begin(), ints.project<0>(it));
};
auto seq_next = std::next(seq_it);
auto ord_next = std::next(it);
if (seq_next!=sequence.end())
{
std::cout << "next to " << *it << " by sequence is " << *seq_next << std::endl;
std::cout << "rank of next by sequence is " << rank_of(seq_next) << std::endl;
}
if (ord_next!=order.end())
{
std::cout << "next to " << *it << " by order is " << *ord_next << std::endl ;
std::cout << "rank of next by order is " << rank_of(ord_next) << std::endl;
}
}
Without polymorphic lambdas you should write it out

Related

Move semantics in parameter passing

I have following test example:
#include <iostream>
#include <vector>
void foo (std::vector<int> value) {
std::cout << "value "
<< &value
<< " "
<< value.data()
<< " "
<< value.size()
<< std::endl;
}
void foo2 (std::vector<int>&& rvalure_ref) {
std::cout << "rvalue_ref "
<< &rvalure_ref
<< " "
<< rvalure_ref.data()
<< " "
<< rvalure_ref.size()
<< std::endl;
}
int main() {
std::vector<int> value(5, 0);
std::cout << "init "
<< &value
<< " "
<< value.data()
<< " "
<< value.size()
<< std::endl;
foo(std::move(value));
std::cout << "done "
<< &value
<< " "
<< value.data()
<< " "
<< value.size()
<< std::endl;
}
The result of the code above is:
init 0x7ffed27c6450 0x56480bc1eeb0 5
value 0x7ffed27c6470 0x56480bc1eeb0 5
done 0x7ffed27c6450 0 0
Looks great:
Now, move to:
#include <iostream>
#include <vector>
void foo (std::vector<int> value) {
std::cout << "value "
<< &value
<< " "
<< value.data()
<< " "
<< value.size()
<< std::endl;
}
void foo2 (std::vector<int>&& rvalure_ref) {
std::cout << "rvalue_ref "
<< &rvalure_ref
<< " "
<< rvalure_ref.data()
<< " "
<< rvalure_ref.size()
<< std::endl;
}
int main() {
std::vector<int> value(5, 0);
std::cout << "init "
<< &value
<< " "
<< value.data()
<< " "
<< value.size()
<< std::endl;
foo2(std::move(value));
std::cout << "done "
<< &value
<< " "
<< value.data()
<< " "
<< value.size()
<< std::endl;
}
The result is:
init 0x7ffccc93a5c0 0x56124b3a8eb0 5
rvalue_ref 0x7ffccc93a5c0 0x56124b3a8eb0 5
done 0x7ffccc93a5c0 0x56124b3a8eb0 5
My problem is:
For the 1st case, it is perfectly called by "move semantics", and as you see, the ownership of the vector has been transfered to the function parameter. Finally, at "done", the data is null to verify the the vector at main() no longer owns the vector.
Now to explicitly claim the parameter is "rvalue reference", as case 2. As you see, actually it is like "call by (l)reference".
How can I figure out it?

Loop through unknown number of dimensions

I want to write a loop, that can give me the dimensions of an array. I want to make it usable for any array and it should return the sizes of the dimensions.
int arr[3][5][10][9] ;
cout << "dimension 1: " << sizeof(arr)/sizeof(arr[0]) << endl;
cout << "dimension 2: " << sizeof(arr[0])/sizeof(arr[0][0]) << endl;
cout << "dimension 3: " << sizeof(arr[0][0])/sizeof(arr[0][0][0]) << endl;
cout << "dimension 4: " << sizeof(arr[0][0][0])/sizeof(arr[0][0][0][0]) << endl;
cout << "dimension 5: " << sizeof(arr[0][0][0][0])/sizeof(arr[0][0][0][0][0]) << endl;
This should return 3,5,10,9 (and fail for the last statement).
So the pattern seems clear "each iteration add [0] after arr. The last iteration will fail, which should stop the while-loop.
How can I "concatenate + evaluate" the array name?
I would also appreciate help on what test checks "Will this fail?", or "Is there another dimension?" in C++, as I'm just learning it.
if you are using c++ 17 compiler, you can use type traits structs std::rank and std::extent as following
#include <iostream>
#include <type_traits>
template<typename T>
void print_dimension(std::size_t i) {
if (std::rank_v<T> > 0) {
std::cout << "Dimension " << i << ":" << std::extent_v<T> << std::endl;
print_dimension<typename std::remove_extent_t<T>>(i + 1);
}
}
int main() {
int arr[3][5][10][9] ;
print_dimension<decltype(arr)>(1);
return 0;
}
If you are using C++ 11/14 compiler, it would need slight modification
#include <iostream>
#include <type_traits>
template<typename T>
void print_dimension(std::size_t i) {
if (std::rank<T>::value > 0) {
std::cout << "Dimension " << i << ":" << std::extent<T>::value << std::endl;
print_dimension<typename std::remove_extent<T>::type>(i + 1);
}
}
int main() {
int arr[3][5][10][9] ;
print_dimension<decltype(arr)>(1);
return 0;
}

The procedure entry point _ZDt24__throw_out_of_range_fmtPKcz could not be located in the dynamic link library c:\[Location of vector.exe]

This question IS different than the others. I am a beginner C++ programmer and I was recently learning vector arrays. Here is my code, which is straight from my book:
#include <vector>
#include <iostream>
using namespace std ;
int main()
{
vector <int> vec(3,100) ;
cout << "Vector size: " << vec.size() << endl ;
cout << "Is empty?: " << vec.empty() << endl ;
cout << "First element: " << vec.at(0) << endl ;
vec.pop_back() ; // Remove final element.
cout << "Vector size: " << vec.size() << endl ;
cout << "Final element: " << vec.back() << endl;
vec.clear() ; // Remove all elements.
cout << "Vector size: " << vec.size() << endl;
vec.push_back( 200 ) ; // Add an element.
cout << "Vector size: " << vec.size() << endl ;
cout << "First element: " << vec.front() << endl ;
return 0 ;
}
I keep getting the error message
The procedure entry point _ZDt24__throw_out_of_range_fmtPKcz could not be located in the dynamic link library c:\[Location of vector.exe]
Please keep in mind that I am a beginner and I just want to know how to fix this. I am using the MinGW compiler. Thanks!

How to decrease a size of a specific bucket in unordered_set by one?

I am using std::unordered_set to count how many different numbers do I have in my array.
What I am trying to do is to decrease a size of a specific bucket by one when one of the occurrences of a number is being deleted from my array.
I tried using erase(), but that removes the whole bucket. Is there any possibility to do it somehow?
It should work like this:
std::unordered_set<int> P;
P.insert(0);
P.insert(0);
printf("%d", P.count(0)); //this prints 2
//P.decrease(0) <-- I'm looking for something like this
printf("%d", P.count(0)); //this should print 1
You can't have a count with set. Everything is either in the set, or not in the set. Perhaps you want to use a map? I just wrote some sample code to demonstrate the difference.
#include <unordered_set>
#include <unordered_map>
#include <iostream>
int main() {
// http://en.cppreference.com/w/cpp/container/unordered_set
std::unordered_set<int> s;
std::cout << "Things are either in the set, or not in the set. There is no count." << std::endl;
std::cout << "insert 0" << std::endl;
s.insert(0);
std::cout << "insert 0" << std::endl;
s.insert(0);
std::cout << "have we seen a 0, yes or no? " << s.count(0) << std::endl;
std::cout << "erase 0" << std::endl;
s.erase(0);
std::cout << "have we seen a 0, yes or no? " << s.count(0) << std::endl;
// http://en.cppreference.com/w/cpp/container/unordered_map
std::unordered_map<int, int> m;
std::cout << "Every key in the map has a value. We can use that to represent count." << std::endl;
std::cout << "add 1 to the count for value 0" << std::endl;
m[0] += 1;
std::cout << "add 1 to the count for value 0" << std::endl;
m[0] += 1;
std::cout << "How many zeroes are in the bucket? " << m[0] << std::endl;
std::cout << "subtract 1 from the count for key==0" << std::endl;
m[0] -= 1;
std::cout << "How many zeroes are in the bucket? " << m[0] << std::endl;
}

Get a mesh_3 'off' from Projection_traits_xy_3 constrained delaunay

I've computed a 2D constrained delaunay triangulation from 2.5D data using the projection_traits_xy_3 [1]. Now I would like to get a mesh that I can visualize.
I've managed to do that with 3d delaunay following the manual[2], how could I achieve it with a 2.5D CDT ?
[...]
typedef CGAL::Projection_traits_xy_3<K> Gt;
typedef CGAL::Constrained_Delaunay_triangulation_2<Gt, Tds> CDT;
[...]
CDT cdt;
cdt.insert(points.begin(),points.end());
[...]
¿?
[...]
std::ofstream out(outdir + "out.off");
Polyhedron output_mesh;
CGAL::output_surface_facets_to_polyhedron(¿?, output_mesh);
out << output_mesh;
[1] http://pastebin.com/HzAwrnW5
[2] http://doc.cgal.org/latest/Point_set_processing_3/index.html#chappoint_set_processing_3
http://doc.cgal.org/latest/Surface_reconstruction_points_3/
Here comes pseudocode forwriting it into an off file
cout << "OFF\n" << cdt.number_of_vertices()
<< " " << cdt.number_of_faces() << " 0" << std::endl;
std::map<vertex_handle,int> indices;
int counter = 0;
for all finite vertices v {
cout << v->point() <<std::endl;
indices.insert(v, counter++);
}
for all finite faces f {
cout << "3 " << indices[f->vertex(0)]
<< " " << indices[f->vertex(1)]
<< " " << indices[f->vertex(2)] << std::endl;
}
From #Andreas suggestion:
Here comes the code for writing it into an off file
std::ofstream outstream("output.off");
outstream << "OFF\n" << cdt.number_of_vertices()
<< " " << cdt.number_of_faces() << " 0" << std::endl;
std::map<CDT::Vertex_handle,int> indices;
int counter = 0;
for(CDT::Finite_vertices_iterator it = cdt.finite_vertices_begin(); it != cdt.finite_vertices_end(); ++it)
{
outstream << it->point() << std::endl;
indices.insert(std::pair<CDT::Vertex_handle,int>(it, counter++));
}
for(CDT::Finite_faces_iterator it = cdt.finite_faces_begin(); it != cdt.finite_faces_end(); ++it)
{
outstream << "3 " << indices[it->vertex(0)]
<< " " << indices[it->vertex(1)]
<< " " << indices[it->vertex(2)] << std::endl;
}