Sorting a structure of arrays using Thrust - sorting

I am working on CUDA and facing the following problem.
I have a following structure of arrays:
typedef struct Edge{
int *from, *to, *weight;
}
I want to sort this structure on weight array such that the corresponding "from" and "to" arrays get updated too. I thought of using Thrust library but it works only on vectors is what I understood. I can sort_by_key and get two arrays sorted but I am not able to understand how to sort three arrays? I even looked at zip_iterator but did not understand how to use it to serve my purpose. Please help

First decouple the structure into 1) keys, and 2) paddings. Then sort the keys and reorder paddings accordingly. For example, break this structure:
typedef struct Edge{
int from, to, weight;
}
into:
int weight[N];
typedef struct Edge{
int from, to;
}
The full code is here:
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <cmath>
#include <thrust/sort.h>
typedef struct pad {
int from;
int to;
} padd;
__host__ padd randPad() {
padd p;
p.from = rand();
p.to = rand();
return p;
}
__host__ std::ostream& operator<< (std::ostream& os, const padd& p) {
os << "(" << p.to << " , " << p.from << " )";
return os;
}
int main(void)
{
// allocation
#define N 4
thrust::host_vector<int> h_keys(4);
thrust::host_vector<padd> h_pad(4);
// initilization
thrust::generate(h_keys.begin(), h_keys.end(), rand);
thrust::generate(h_pad.begin(), h_pad.end(), randPad);
// print unsorted data
std::cout<<"Unsorted keys\n";
thrust::copy(h_keys.begin(), h_keys.end(), std::ostream_iterator<int>(std::cout, "\n"));
std::cout<<"\nUnsorted paddings\n";
thrust::copy(h_pad.begin(), h_pad.end(), std::ostream_iterator<padd>(std::cout, "\n"));
// transfer to device
thrust::device_vector<int> d_keys = h_keys;
thrust::device_vector<padd> d_pad = h_pad;
//thrust::sort(d_keys.begin(), d_keys.end());
// sort
thrust::sort_by_key(d_keys.begin(), d_keys.end(), d_pad.begin());
// transfer back to host
thrust::copy(d_keys.begin(), d_keys.end(), h_keys.begin());
thrust::copy(d_pad.begin(), d_pad.end(), h_pad.begin());
// print the results
std::cout<<"\nSorted keys\n";
thrust::copy(h_keys.begin(), h_keys.end(), std::ostream_iterator<int>(std::cout, "\n"));
std::cout<<"\nSorted paddings\n";
thrust::copy(h_pad.begin(), h_pad.end(), std::ostream_iterator<padd>(std::cout, "\n"));
return 0;
}
The output would be something like this:
Unsorted keys
1804289383
846930886
1681692777
1714636915
Unsorted paddings
(424238335 , 1957747793 )
(1649760492 , 719885386 )
(1189641421 , 596516649 )
(1350490027 , 1025202362 )
Sorted keys
846930886
1681692777
1714636915
1804289383
Sorted paddings
(1649760492 , 719885386 )
(1189641421 , 596516649 )
(1350490027 , 1025202362 )
(424238335 , 1957747793 )

Related

C++: No viable overloaded '=' data.end() -1 = '\0'

I'm trying to create a program that filters through speech text, removes any unwanted characters (",", "?", etc., etc.") and then produces a new speech where the words are jumbled based on what words follow or precede them. So for example, if you had the Gettysburg Address:
Four score and seven years ago our fathers brought forth, on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.
my program would take that text, put it into a set of strings. i.e. ["Four","score","and","seven",...."continent,"..."Liberty,"..."equal."] Then it would remove any unwanted characters from each string using c++ .erase and c++ .remove, like "," or "." and capitals. After, you'd have a filtered string like ["four","score","and","seven",...."continent"..."liberty"..."equal."]
After that then the words would be rearranged into a new coherent, funnier speech, like:
"Seven years ago our fathers conceived on men...", etc.
That was just so you know the scope of this project. My trouble at the moment has to do with either using my iterator properly or null terminators.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <set>
#include <iterator> //iterates through sets
#include <algorithm>
using namespace std;
int main() {
set <string> speechSet;
set <string> ::iterator itr; //forgot what :: means. Declares iterator as set
int sum = 0;
int x;
string data;
ofstream out;
string setString;
ifstream speechFile; //declare output file stream object. Unknown type name
speechFile.open("./MySpeech");
if (!speechFile) {
cerr << "Unable to open file " << endl;
exit(1);
}
char unwantedCharacters[] = ".";
while (!speechFile.eof()) {
speechFile >> data; //speechFile input into data
for (unsigned int i = 0; i < strlen(unwantedCharacters); ++i) {
data.erase((remove(data.begin(), data.end(),
unwantedCharacters[i]), data.end())); //remove doesn't delete.
data.end() - 1 = '\0'; //Reorganizes
cout << data << endl;
}
speechSet.insert(string(data));
}
//Go through each string (word) one at a time and remove "",?, etc.
/*for(itr = speechSet.begin(); itr != speechSet.end(); ++itr){
if(*itr == ".")//if value pointed to by *itr is equal to '.'
itr = speechSet.erase(itr);//erase the value in the set and leave blank
cout << " " << *itr;//print out the blank
else{
cout << " " << *itr;
}
}*/
speechFile.close();
return (0);
}
I keep getting an error that says error: no viable overloaded '='. At first I thought it might be due to .end() not being a command for a C++ string, but I checked the documentation and it shouldn't be an issue of mismatched data typed. Then I thought it might have to set the iterator itr equal to the end of the data.
iterator itr = data.end() - 1;
and then dereference that pointer and set it equal to the null terminator
itr* = '\0';
That removed the overload error, but I still had another error use of class template 'iterator' requires template arguments. Let me know if any more clarification is needed.
In the for loop, use auto for iterator so you don't have to specify its type like:
for(auto itr = speechSet.begin(); itr != speechSet.end(); ++itr){

C++ range-for and boost::irange

I'm using boost::irange and created a helper function to simplify the code by removing the need for explicit template parameters. I don't understand why it doesn't work. Here's the code:
#include <iostream>
#include <boost/range/irange.hpp>
template<typename T>
boost::irange<T> range_from_zero(T limit)
{
return boost::irange<T>(T(), limit);
}
int main() {
size_t end = 100;
for (auto i : range_from_zero(0,end))
std::cout << i << ' ';
return 0;
}
There's a live version here https://ideone.com/VVvW6e, which produces compilation errors
prog.cpp:5:8: error: 'irange<T>' in namespace 'boost' does not name a type
boost::irange<T> range_from_zero(T limit)
^
prog.cpp: In function 'int main()':
prog.cpp:12:41: error: 'range_from_zero' was not declared in this scope
for (auto i : range_from_zero(0,end))
If I use boost::irange directly in the range-for, then it works:
#include <iostream>
#include <boost/range/irange.hpp>
int main() {
size_t end = 100;
for (auto i : boost::irange<size_t>(0,end))
std::cout << i << ' ';
return 0;
}
this works fine: https://ideone.com/TOWY6H
I thought maybe is was a problem using range-for on the return of a function, but it isn't; this works using a std::vector:
#include <iostream>
#include <boost/range/irange.hpp>
template<typename T>
std::vector<T> range_from_zero(T limit)
{
auto range = boost::irange<T>(T(), limit);
return { std::begin(range), std::end(range) };
}
int main() {
size_t end = 100;
for (auto i : range_from_zero(end))
std::cout << i << ' ';
return 0;
}
See https://ideone.com/TYRXnC
Any ideas, please?
But, first off, what's wrong with Live On Coliru
for (size_t i : irange(0, 100))
or even Live On Coliru
size_t end = 100;
for (auto i : irange(0ul, end))
irange is a function template, and it cannot be used as a return type.
The return type is integer_range or strided_integer_range. As such, irange is already the function you were looking for.
Only, you didn't pass arguments that could be unambiguously deduced. If you can to allow this, "copy" irange() implementation using separate template argument types for the boundary values and use e.g. std::common_type<T1,T2>::type as the range element.
Here's my stab at writing range_from_zero without naming implementation details in the interface:
Live On Coliru
#include <iostream>
#include <boost/range/irange.hpp>
template <typename T>
auto izrange(T upper) -> decltype(boost::irange(static_cast<T>(0), upper)) {
return boost::irange(static_cast<T>(0), upper);
}
int main() {
size_t end = 100;
for (size_t i : izrange(end))
std::cout << i << ' ';
}

boost::interprocess Containers of containers NOT in shared memory

I have the example demo program with a boost::interprocess Containers of containers type.
But I like to use the class also a normal class within my process memory.
Can someone help me to write a constructor which takes no arguments to have the class initialized in my current process memory.
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <shmfw/serialization/interprocess_vector.hpp>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
using namespace boost::interprocess;
//Alias an STL-like allocator of ints that allocates ints from the segment
typedef allocator<int, managed_shared_memory::segment_manager> ShmemAllocator;
//Alias a vector that uses the previous STL-like allocator
typedef vector<int, ShmemAllocator> MyVector;
typedef allocator<void, managed_shared_memory::segment_manager > void_allocator;
class MyStruct {
public:
MyVector myVector;
//Since void_allocator is convertible to any other allocator<T>, we can simplify
//the initialization taking just one allocator for all inner containers.
MyStruct ( const void_allocator &void_alloc )
: myVector ( void_alloc )
{}
// Thats what I like to have
//MyStruct ()
// : myVector ( ?? )
//{}
};
int main () {
// I would like to have something like that working and also the shm stuff below
// MyStruct x;
managed_shared_memory segment;
//A managed shared memory where we can construct objects
//associated with a c-string
try {
segment = managed_shared_memory( create_only, "MySharedMemory", 65536 );
} catch (...){
segment = managed_shared_memory( open_only, "MySharedMemory" );
}
//Initialize the STL-like allocator
const ShmemAllocator alloc_inst ( segment.get_segment_manager() );
MyStruct *myStruct_src = segment.find_or_construct<MyStruct> ( "MyStruct" ) ( alloc_inst );
srand (time(NULL));
myStruct_src->myVector.push_back ( rand() );
MyStruct *myStruct_des = segment.find_or_construct<MyStruct> ( "MyStruct" ) ( alloc_inst );
for ( size_t i = 0; i < myStruct_src->myVector.size(); i++ ) {
std::cout << i << ": " << myStruct_src->myVector[i] << " = " << myStruct_des->myVector[i] << std::endl;
if(myStruct_src->myVector[i] != myStruct_des->myVector[i]) {
std::cout << "Something went wrong!" << std::endl;
}
}
//segment.destroy<MyVector> ( "MyVector" );
return 0;
}
If you change the allocator type, you change the container (such is the nature of compile-time template instantiation).
Technically, you could devise a type-erased allocator (à la std::function or boost::any_iterator) but this would probably result in abysmal performance. Also, it would still require all the allocators to correspond in all the statically known properties, reducing flexibility.
In reality, I suggest just templatizing MyStruct on the Allocator type to be used for any embedded containers. Then specifically take such an allocator in the constructor:
// Variant to use on the heap:
using HeapStruct = MyStruct<std::allocator>;
// Variant to use in shared memory:
using ShmemStruct = MyStruct<BoundShmemAllocator>;
Demo Program:
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/range/algorithm.hpp>
#include <iostream>
#include <cassert>
namespace bip = boost::interprocess;
template <typename T>
using BoundShmemAllocator = bip::allocator<T, bip::managed_shared_memory::segment_manager>;
///////////////////////////////////////////////////////////////
// Your MyStruct, templatized for an Allocator class template
template <template<typename...> class Allocator>
class MyStruct {
public:
bip::vector<int, Allocator<int> > ints;
bip::vector<double, Allocator<double> > doubles;
MyStruct(const Allocator<void>& void_alloc = {})
: ints(void_alloc),
doubles(void_alloc)
{}
};
// Variant to use on the heap:
using HeapStruct = MyStruct<std::allocator>;
// Variant to use in shared memory:
using ShmemStruct = MyStruct<BoundShmemAllocator>;
//
///////////////////////////////////////////////////////////////
int main() {
srand(time(NULL));
// You can have something like this working:
HeapStruct x; // and also the shm stuff below
std::generate_n(std::back_inserter(x.ints), 20, &std::rand);
std::generate_n(std::back_inserter(x.doubles), 20, &std::rand);
// A managed shared memory where we can construct objects
bip::managed_shared_memory segment = bip::managed_shared_memory(bip::open_or_create, "MySharedMemory", 65536);
BoundShmemAllocator<int> const shmem_alloc(segment.get_segment_manager());
auto src = segment.find_or_construct<ShmemStruct>("MyStruct")(shmem_alloc);
src->ints.insert(src->ints.end(), x.ints.begin(), x.ints.end());
src->doubles.insert(src->doubles.end(), x.doubles.begin(), x.doubles.end());
auto des = segment.find_or_construct<ShmemStruct>("MyStruct")(shmem_alloc);
std::cout << "-------------------------";
boost::copy(src->ints, std::ostream_iterator<int>(std::cout << "\nsrc ints: ", "; "));
boost::copy(des->ints, std::ostream_iterator<int>(std::cout << "\ndes ints: ", "; "));
std::cout << "\n-------------------------";
boost::copy(src->doubles, std::ostream_iterator<double>(std::cout << "\nsrc doubles: ", "; "));
boost::copy(des->doubles, std::ostream_iterator<double>(std::cout << "\ndes doubles: ", "; "));
assert(src->ints.size() == des->ints.size());
assert(src->doubles.size() == des->doubles.size());
assert(boost::mismatch(src->ints, des->ints) == std::make_pair(src->ints.end(), des->ints.end()));
assert(boost::mismatch(src->doubles, des->doubles) == std::make_pair(src->doubles.end(), des->doubles.end()));
segment.destroy<ShmemStruct>("MyStruct");
}

sort files by ascii order

I'm trying to code a simple function to sort the content of a directory. The Thing is, it comes out in alphabetical order, regardless of uppercase or lowercase. I'd like to sort this content in ASCII order.
example: I got 4 files, named Art, boat, Cat and donkey. My actual code sort them in this order, while i'd like to get Art, Cat, boat and donkey.
void list_dir(char *str){
DIR *rep = NULL;
struct dirent* read_file = NULL;
rep = opendir(str);
if (!rep)
{
ft_putstr("ft_ls: ");
perror(str);
ft_putchar('\n');
}
while((read_file = readdir(rep)) != NULL)
{
if (read_file->d_name[0] != '.')
{
ft_putstr(read_file->d_name);
ft_putchar('\n');
}
}
}
readdir(3) does not normally sort at all, it lists the entries in directory order. If the list is sorted, either the files were created sorted, or the OS sorts them.
In order to sort the output yourself, put the list of names into an array then sort it e.g. with qsort(3) and strcmp(3).
Alternatively, just pipe the output through sort(1). Do make sure that the LC_COLLATION environment variable is set proper. For example, run ./yourprogram | (unset LC_ALL; LC_CTYPE=en_US.UTF-8 LC_COLLATE=C sort).
By calling scandir with user defined filter & comparator is a simple solution imho. Here is the code:
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static int my_dir_filter(const struct dirent* dir);
static int my_dir_comparator(const struct dirent**, const struct dirent**);
int main(int argc, char* const* argv) {
struct dirent** ent_list_ = NULL;
int r = scandir(".", &ent_list_, my_dir_filter, my_dir_comparator);
for (int i = 0; i < r; ++i)
printf("No. %-3d [%s]\n", i + 1, ent_list_[i]->d_name);
for (int i = 0; i < r; ++i)
free(ent_list_[i]);
free(ent_list_);
return r < 0 ? 1 : 0;
}
int my_dir_filter(const struct dirent* dir) {
return (dir->d_type == DT_REG) ? 1 : 0;
}
int my_dir_comparator(const struct dirent** lhs, const struct dirent** rhs) {
return strcasecmp((*lhs)->d_name, (*rhs)->d_name);
}
And test result:
$ ls|LANG=C sort ## in ASCII order
Art
Cat
boat
donkey
$ ../a.out ## in my_dir_comparator order
No. 1 [Art]
No. 2 [boat]
No. 3 [Cat]
No. 4 [donkey]

Priority of a priority queue always needs to be integral?

I'm just curious if I can have any other data type to give the priority? Like strings, floats, etc?
In the abstract, any type with a reasonable Strict Weak Ordering can be used as the priority in a priority queue. The language you are using will determine how to define this ordering: in C++, operator< is used in standard containers, in Java, the interface Comparable and function compareTo are typically used. Custom comparison functions are also often supported, which can compare elements in a manner different than the default.
No.
The ordering element of a priority queue does not have to be integral.
Yes.
You can use whatever type you want, as long as two values of that type can be compared to determine their inherent ordering.
Basically, you can build a priority queue that uses whatever type you want, even a complex number if you can determine an ordering that makes sense for those.
There is, however, another, unasked, question here, for which the answer is:
Yes, most existing implementations of a priority queue will use an integer as the ordering element as that is the easiest, and most common, value used for this purpose.
Here is a fullblown C++ demo of how to queue SillyJobs, defined as
struct SillyJob
{
std::string description;
std::string priority;
// ...
};
It does so in two ways: using the member operator< (default) and by passing an explicit comparison predicate to priority_queue constructor.
Let's see the output up-front:
Silly: (by description length)
LOW: very very long description
HIGH: short
------------------------------------------------------------
Not so silly: (by priority value)
HIGH: short
LOW: very very long description
See it live on http://ideone.com/VEEQa
#include <queue>
#include <algorithm>
#include <functional>
#include <iostream>
#include <string>
#include <map>
struct SillyJob
{
std::string description;
std::string priority;
SillyJob(const std::string& d, const std::string& p)
: description(d), priority(p) { }
bool operator<(const SillyJob& sj) const { return description.size() < sj.description.size(); }
friend std::ostream& operator<<(std::ostream& os, const SillyJob& sj)
{ return os << sj.priority << ": " << sj.description; }
};
static bool by_priority(const SillyJob& a, const SillyJob& b)
{
static std::map<std::string, int> prio_map;
if (prio_map.empty())
{
prio_map["HIGH"] = 3;
prio_map["MEDIUM"] = 2;
prio_map["LOW"] = 1;
}
return prio_map[a.priority] < prio_map[b.priority];
}
int main()
{
std::cout << "Silly: (by description length)" << std::endl;
{
// by description length (member operator<)
std::priority_queue<SillyJob> silly_queue;
silly_queue.push(SillyJob("short", "HIGH"));
silly_queue.push(SillyJob("very very long description", "LOW"));
while (!silly_queue.empty())
{
std::cout << silly_queue.top() << std::endl;
silly_queue.pop();
}
}
std::cout << std::string(60, '-') << "\nNot so silly: (by priority value)" << std::endl;
{
// by description length (member operator<)
typedef bool (*cmpf)(const SillyJob&, const SillyJob&);
typedef std::priority_queue<SillyJob, std::vector<SillyJob>, cmpf> not_so_silly_queue;
not_so_silly_queue queue(by_priority);
queue.push(SillyJob("short", "HIGH"));
queue.push(SillyJob("very very long description", "LOW"));
while (!queue.empty())
{
std::cout << queue.top() << std::endl;
queue.pop();
}
}
}
PS. The by_priority comparison function is quite a good example of bad design, but bear in mind it was for demonstrational purposes only :)
You can use any type for priority if the values of the type can be compared with each other.

Resources