Group and Game Algorithm - algorithm

I am thinking of an algorithm that assign games to pairs of opponents which play the game.
I have x opponents and y games (I think y should be x - 1, but I am not sure)
Every opponent should play each game once and if possible play against every opponent once.
What I want is a list of group pairings assigned to a game.
The number of games overall should be minimal.
An example with 4 opponents A, B, C, D and 3 games:
Opp1
Game
Opp2
A
1
B
A
2
C
A
3
D
B
2
C
B
3
D
C
1
D
Here, each opponent plays against another opponent exactly once, and every opponent plays each game exactly once.
Trying that manually for 5 opponents and 4 games already gets complex.
How about 7 opponents and 6 games?
Is that possible at all?
I tried that to solve the problem manually, then I found out that this is too complex.
After that I thought about how I could maybe solve it using an algorithm, but I could not come up with a solution.
I thought maybe a graph algorithm which tries to minimize the overall games count could help.

- LOOP Op1 over groups ( e.g. A,B,C,... )
- LOOP Op2 over groups starting at Op1 + 1 ( e.g B,C, ... )
- LOOP G over games
- IF neither Op1 nor Op2 has played game G
- ASSIGN Op1 v Op2 in game G
- BREAK from LOOP G
Here is the C++ code
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
#include <algorithm>
class cMatchMaker
{
public:
void ParseCommand(int argc, char *argv[])
{
if (argc != 3)
exit(1);
groupCount = atoi(argv[1]);
gameCount = atoi(argv[2]);
}
void ConstructGroups()
{
for (int kg = 0; kg < groupCount; kg++)
{
std::string s({'A' + kg});
vGroup.push_back(s);
vGroupHasPlayed.push_back({});
}
}
void ConstructGames()
{
for (int kg = 0; kg < gameCount; kg++)
{
vGame.push_back(std::to_string(kg + 1));
}
}
void MakeMatches()
{
// loop over groups
for (kop1 = 0; kop1 < groupCount; kop1++)
{
// loop over possible opponents
for (kop2 = kop1 + 1; kop2 < groupCount; kop2++)
{
// loop over games
for (auto &game : vGame)
{
// check neither group has played game
if (!HasGameBeenPlayed(
game))
{
// we have a match!
DisplayMatch(
game);
// remember who played what
Remember(
game);
break;
}
}
}
}
}
private:
int groupCount, gameCount;
std::vector<std::string> vGroup, vGame;
std::vector<std::vector<std::string>> vGroupHasPlayed;
int kop1, kop2;
bool HasGameBeenPlayed(
const std::string &game)
{
if (std::find(
vGroupHasPlayed[kop1].begin(),
vGroupHasPlayed[kop1].end(),
game) != vGroupHasPlayed[kop1].end())
return true;
if (std::find(
vGroupHasPlayed[kop2].begin(),
vGroupHasPlayed[kop2].end(),
game) != vGroupHasPlayed[kop2].end())
return true;
return false;
}
void DisplayMatch(
const std::string &game)
{
std::cout << " | " << vGroup[kop1]
<< " | " << game << " | "
<< vGroup[kop2] << " |\n";
}
void Remember(
const std::string &game)
{
vGroupHasPlayed[kop1].push_back(game);
vGroupHasPlayed[kop2].push_back(game);
}
};
main(int argc, char *argv[])
{
cMatchMaker theMatchMaker;
theMatchMaker.ParseCommand(argc, argv);
theMatchMaker.ConstructGroups();
theMatchMaker.ConstructGames();
theMatchMaker.MakeMatches();
return 0;
}
Here is the output for 7 and 6
Op1
Game
Op2
A
1
B
A
2
C
A
3
D
A
4
E
A
5
F
A
6
G
B
3
C
B
2
D
B
5
E
B
4
F
C
1
D
C
6
E
C
4
G
D
6
F
D
5
G
E
1
F
E
2
G
F
3
G

Related

Using the lightest carriage to move n objects in specific days

I have to solve this problem but I can't think of any algorithm for it . Any help is appreciated :)
Problem : we want to move n objects with different weights to another location using a carriage and we have limited days to do so . we can only use the carriage once a day and because it costs a lot we want to choose a carriage that can move all of our product in the given days but pay the minimum amount for it so the objective is to choose a carriage with the least capacity that will do the job ( the price we have to pay for the carriage increases greatly as the capacity goes higher ) . Also the items should be moved according to their weight and the smallest items go first .
the given data : n items , i'th object wights Wi , d days
wanted : c which shows the minimum capacity for our chosen carriage
Example :
10 items
weights : 1 2 3 4 5 6 7 8 9 10
5 days
answer : 15
day 1 -> 1,2,3,4
day 2 -> 5,6
day 3 -> 7,8
day 4 -> 9
day 5 -> 10
To solve this problem efficiently, you should do binary search. You can do binary search on carriage and check for which minimum value you can do that. You can see my C++ solution below for better understanding.
#include<bits/stdc++.h>
//#include <ext/pb_ds/tree_policy.hpp>
//#include <ext/pb_ds/assoc_container.hpp>
using namespace std;
//using namespace __gnu_pbds;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pll;
typedef pair<int,int> pii;
//typedef tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>ordered_set;
#define fread freopen("input.txt","r",stdin)
#define fwrite freopen("output.txt","w",stdout)
#define eb emplace_back
#define em emplace
#define pb push_back
#define Mp make_pair
#define ff first
#define ss second
#define all(a) a.begin(),a.end()
#define Unique(a) sort(all(a)),a.erase(unique(all(a)),a.end())
#define FastRead ios_base::sync_with_stdio(0);cin.tie(0);
#define memo(ara,val) memset(ara,val,sizeof(ara))
#define II ( { int a ; read(a) ; a; } )
#define LL ( { ll a ; read(a) ; a; } )
#define DD ({double a; scanf("%lf", &a); a;})
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define rrep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define pf(n) printf("%lld",n)
#define pfi(n) printf("%d",n)
#define sp printf(" ")
#define ln printf("\n")
#define sc(x) scanf("%lld",&x)
#define scw(x) scanf("%I64d",&x)
#define sci(x) scanf("%d",&x)
#define sc2(x,y) scanf("%lld %lld",&x,&y)
#define sc3(x,y,z) scanf("%lld %lld %lld",&x,&y,&z)
#define Found(a, b) a.find(b) != a.end()
// bool operator< (const node& sx) const { return sx.val < val; }
//set<ll,greater<ll> >st;
//priority_queue<ll , vector<ll> , greater<ll> >
template<class T>inline bool read(T &x){ int c=getchar();int sgn=1;
while(~c&&c<'0'|c>'9'){if(c=='-')sgn=-1;c=getchar();}
for(x=0; ~c&&'0'<=c&&c<='9'; c=getchar())x=x*10+c-'0';x*=sgn;return ~c;
}
const ll N = 200005;
const ll MOD = 1e9+7;
ll ara[N], d, n;
bool check(ll carriageCapacity) {
ll days = 1;
ll s = 0;
bool f = true;
rep1(i, n) {
s += ara[i];
if(s > carriageCapacity) {
days += 1;
s = ara[i];
}
}
if(days > d) f = false;
return f;
}
int main(){
//fread;
//fwrite;
n = LL;
ll sum = 0;
rep1(i,n) {
ara[i] = LL;
sum += ara[i];
}
d = LL;
ll lo = ara[n], hi = sum, ans;
while(lo <= hi) {
ll mid = (lo + hi) >> 1;
if(check(mid)) {
hi = mid - 1;
ans = mid;
}
else {
lo = mid + 1;
}
}
cout << ans << endl;
}
Python solution would look like this.
Using binary search to find the container size that will satisfy the given condition. Complexity of this solution would be O(n * log n)
def shipWithinDays(weights: List[int], D: int) -> int:
def feasible(capacity) -> bool:
days = 1
total = 0
for weight in weights:
total += weight
if total > capacity: # too heavy, wait for the next day
total = weight
days += 1
if days > D: # cannot ship within D days
return False
return True
left, right = max(weights), sum(weights)
while left < right:
mid = left + (right - left) // 2
if feasible(mid):
right = mid
else:
left = mid + 1
return left

Why is my search function not working as expected and how do I fix it?

I am trying to make a comparison search function that can compare two strings together based on chars. For example:
Input: "ca"
Struct vector contents under last name fields(sorted vector)(index/value): 0/"cars", 1/"roads"
Result: "Name Found at index 0 - cars"
I want users to be able to use any number of chars. The program should then compare the provided search criteria to the content of the vector and return the index of any matches.
So far I have tried to implement this alogorithm without any success, here is my code so far. Also I am pretty new to C++.
// Function for searching through an array for a string value.
int searchArray(std::vector<playerdata> (&people), std::string name) {
int loc = -1;
int counter = 0;
int index = 0;
//when loc is no longer -1, that means the person has been found
for (int i = 0; i < people.size(); i++)
for(int k = 0; k < name.length(); k++) {
std::cout << name[k-1] << std::endl;
std::cout << people[i].lastname[k-1] << std::endl;
std::cout << counter << std::endl;
std::cout << "" << std::endl;
if(name[k-1] == people[i].lastname[k-1]) {
counter++;
}
if(counter == name.length()) {
loc = i;
break;
}
}
//if (people[i].lastname.compare(name) == 0)
//loc = i;
return loc;
}
Here is what I get in my console, I am using cout to debug:
What is player 1 information (F/L/DOB (DD/MM/YYY)), Seperate using a space):
hello sunshine
What is player 2 information (F/L/DOB (DD/MM/YYY)), Seperate using a space):
good bye
Pick from the available options:
1 - Input Data:
2 - Display Original Data:
3 - Sort Data:
4 - Display Sorted Data:
5 - Search By Last Name:
6 - Exit The Program;
3
Array Sorted!!!
Pick from the available options:
1 - Input Data:
2 - Display Original Data:
3 - Sort Data:
4 - Display Sorted Data:
5 - Search By Last Name:
6 - Exit The Program;
4
Player 1: good bye
Player 2: hello sunshine
Pick from the available options:
1 - Input Data:
2 - Display Original Data:
3 - Sort Data:
4 - Display Sorted Data:
5 - Search By Last Name:
6 - Exit The Program;
5
Enter the name to search:
bye
b
b
0
y
y
1
e
e
2
b
s
3
y
u
4
e
n
4
Player Found: good bye
Enter the name to search:
by
y
b
0
y
s
1
Player Found: good bye
Enter the name to search:
b
The player was not found, try again.
Enter the name to search:
sun
u
b
0
n
y
1
u
s
1
Player Found: hello sunshine
Enter the name to search:
sunshine
u
b
0
n
y
1
s
e
1
h
1
i
h
1
n
i
1
e
n
1
u
s
1
n
u
2
s
n
2
h
s
2
i
h
2
n
i
2
e
n
2
The player was not found, try again.
Enter the name to search:
EDIT: As you can see from my console output the code is returning true comparisons when it shouldn't be doing so. An example is the last comparison of is (e == n). The answer should be false but it keeps returning true.
After using code suggested in the comments I still cant get my code to work as expected and get the following errors:
||=== Build file: "no target" in "no project" (compiler: unknown) ===|
E:\Coding\Cplus_work\assignmentseven.cpp||In function 'int main()':|
E:\Coding\Cplus_work\assignmentseven.cpp|68|warning: NULL used in arithmetic [-Wpointer-arith]|
E:\Coding\Cplus_work\assignmentseven.cpp|158|warning: NULL used in arithmetic [-Wpointer-arith]|
c:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\predefined_ops.h||In instantiation of 'bool __gnu_cxx::__ops::_Iter_pred<_Predicate>::operator()(_Iterator) [with _Iterator = __gnu_cxx::__normal_iterator<playerdata*, std::vector<playerdata> >; _Predicate = searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)>]':|
c:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\stl_algo.h|120|required from '_RandomAccessIterator std::__find_if(_RandomAccessIterator, _RandomAccessIterator, _Predicate, std::random_access_iterator_tag) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<playerdata*, std::vector<playerdata> >; _Predicate = __gnu_cxx::__ops::_Iter_pred<searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)> >]'|
c:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\stl_algo.h|161|required from '_Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [with _Iterator = __gnu_cxx::__normal_iterator<playerdata*, std::vector<playerdata> >; _Predicate = __gnu_cxx::__ops::_Iter_pred<searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)> >]'|
c:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\stl_algo.h|3930|required from '_IIter std::find_if(_IIter, _IIter, _Predicate) [with _IIter = __gnu_cxx::__normal_iterator<playerdata*, std::vector<playerdata> >; _Predicate = searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)>]'|
E:\Coding\Cplus_work\assignmentseven.cpp|35|required from here|
c:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\predefined_ops.h|283|error: no match for call to '(searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)>) (playerdata&)'|
E:\Coding\Cplus_work\assignmentseven.cpp|33|note: candidate: 'searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)>'|
E:\Coding\Cplus_work\assignmentseven.cpp|33|note: no known conversion for argument 1 from 'playerdata' to 'std::__cxx11::string&' {aka 'std::__cxx11::basic_string<char>&'}|
E:\Coding\Cplus_work\assignmentseven.cpp||In function 'bool sortArray(const playerdata&, const playerdata&)':|
E:\Coding\Cplus_work\assignmentseven.cpp|28|warning: control reaches end of non-void function [-Wreturn-type]|
||=== Build failed: 1 error(s), 8 warning(s) (0 minute(s), 0 second(s)) ===|
Exact code I used:
// Function for searching through an array for a string value.
int searchArray(std::vector<playerdata> (&people), std::string (&name))
{
auto it = std::find_if(people.begin(), people.end(), [&name](std::string& person){
return person.find(name) != std::string::npos;
});
if(it != people.end()) {
return std::distance(people.begin(), it);
} else {
return -1;
}
}
Probably the main problem is that you are trying to access name[k-1] and lastname[k-1], when k=0, which results in UB.
Before continuing with your work, start learning the STL algorithms. With that in mind, your task becomes trivial using only find_if and std::string::find:
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
struct playerdata
{
std::string lastname;
playerdata(std::string lastname) :
lastname(std::move(lastname))
{
}
};
int searchArray(std::vector<playerdata>& people, const std::string& name)
{
auto it = std::find_if(people.cbegin(), people.cend(), [&name](const playerdata& player){
return player.lastname.find(name) != std::string::npos;
});
if(it != people.end())
return std::distance(people.cbegin(), it);
else
return -1;
}
}
LIVE DEMO
First of all your approach to solution is correct but needs some
improvement.
I assumed that you don`t want to solve it using regular expression or a template c++ function
which would be better way
You may have a misunderstanding about break statement which affects
only the loop it is written in break
I've explained missing points and required improvements in comment
lines
Since you didn`t specify all details I had to assume them.
`
SearchArray(std::vector<playerdata>& people, const std::string& keyWord)
{
int loc = -1;
// Use a better variable name to explain its purpose instead of `i`
// so you and other people like us can understand its meaning much faster
for (int vectorIndex = 0; vectorIndex < people.size(); vectorIndex++)
{
// if length of the name is bigger than a lastname it can`t be a match so just continue
if (keyWord.length() > people[vectorIndex].lastname.length())
{
continue;
}
int counter = 0;
int charIndexKeyWord = 0;
// Use a better variable name to explain its purpose instead of `k`
for (int charIndexIarget = 0; charIndexIarget < people[vectorIndex].lastname.length(); charIndexIarget++)
{
// Your for loop starts from 0 but you're trying to use [k-1] in your code
// you shouldn't do that, because in the first iteration of the loop it will indicate -1 [k-1]
// but it starts with 0,
//std::cout << keyWord[charIndexKeyWord] << std::endl;
//std::cout << people[vectorIndex].lastname[charIndexIarget] << std::endl;
//std::cout << counter << std::endl;
//std::cout << "" << std::endl;
// This is part of your code which needs improvment
if (keyWord[charIndexKeyWord] == people[vectorIndex].lastname[charIndexIarget])
{
counter++;
charIndexKeyWord++;
}
else
{
// If you keep your code as it is, it will may also consider matches like susnhine `sun` because
// so you need to make some improvements to get rid of it.
// if you have already founded a match but next word is not a match then you need to start looking from the beginning
if (counter != 0)
{
counter = 0;
charIndexKeyWord = 0;
}
}
if (counter == keyWord.length())
{
loc = vectorIndex;
}
}
if (loc != -1)
{
break;
}
}
return loc;
}

Number of ways to seat people given certain constraints

I'm struggling with this problem so if anyone can help, that would be appreciated. The problem goes like this:
Calculate the number of ways that k people can sit in a 2 x n matrix (n and k are obtained from the user through standard input). The matrix is also given by the user and can contain the following characters: '.' - people can sit here, '#' - people can't sit here.
People in the matrix can't be adjacent (that is if one person is situated at (row, column), another person can't sit at (row-1, column) or at (row, column-1) - notice that they can sit on (row-1, column-1)).
For example, if n = 3, k = 2 and given the following matrix:
..#
...
the answer would be 5. All possible ways to seat 2 people in the matrix are (u means that a person is sitting on that field):
u.# .u# ..# u.# .u#
.u. u.. u.u ..u ..u
Let's go through 2 x N matrix from left to right. On each column we could have only 3 states:
User on top position
User on bottom position
No users
So, on each step we could move from previous states and all we need to keep number of ways for each state and each number of users:
State Top can move to states: Bottom or None
State Bottom can move to states: Top or None
State None can move to states: Top, Bottom or None
Answer is a sum of all states with K users.
Sample code:
#include <iostream>
#include <map>
#include <string>
using namespace std;
enum State: int
{
Top, // u
// -
Bottom, // -
// u
None, // -
// -
};
int main()
{
int N, K; cin >> N >> K;
string S[2]; cin >> S[0] >> S[1];
map<State, map<int, int>> prev = { { None, {{0,1}} } };
for (int i = 0; i < N; ++i) {
map<State, map<int, int>> cur;
if (S[0][i] == '.') {
for (auto& w : prev[None]) cur[Top][w.first + 1] += w.second;
for (auto& w : prev[Bottom]) cur[Top][w.first + 1] += w.second;
}
if (S[1][i] == '.') {
for (auto& w : prev[None]) cur[Bottom][w.first + 1] += w.second;
for (auto& w : prev[Top]) cur[Bottom][w.first + 1] += w.second;
}
for (auto& w : prev[None]) cur[None][w.first] += w.second;
for (auto& w : prev[Top]) cur[None][w.first] += w.second;
for (auto& w : prev[Bottom]) cur[None][w.first] += w.second;
swap(cur, prev);
}
cout << (prev[Top][K] + prev[Bottom][K] + prev[None][K]) << endl;
return 0;
}

Reading a file containing characters in parentheses into a vector of integers

I am attempting to read in a file containing characters enclosed in parentheses into a vector of integers.
My text file:
(2 3 4 9 10 14 15 16 17 19)
Heres my code:
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main(){
ifstream file;
file.open("moves.txt");
vector<int> V;
char c;
if (file){
while (file.get(c)){
if (c != '(' && c != ')' && c != ' ')
V.push_back(c - '0');
}
}
else{
cout << "Error openning file." << endl;
}
for (int i = 0; i < V.size(); i++)
cout << V[i] << endl;
}
My Output:
2
3
4
9
1
0
1
4
1
5
1
6
1
7
1
9
-38
Desired output:
2
3
4
9
10
14
15
16
17
19
What is causing the separation of two digit numbers and why is there a negative number at the end of my output?
Don't read characters one by one : read a line, and parse the numbers within it.
By using the is_number (c++11) function of this answer :
bool is_number(const std::string& s)
{
return !s.empty() && std::find_if(s.begin(),
s.end(), [](char c) { return !std::isdigit(c); }) == s.end();
}
You can read line by line with std::getline and then stream the numbers to a std::stringstream. std::stoi can be used to convert a string to an integer :
std::string line;
while(std::getline(file, line))
{
line.replace(line.begin(), line.begin() + 1, "");
line.replace(line.end() - 2, line.end() - 1, "");
std::string numberStr;
std::stringstream ss(line);
while (ss >> numberStr){
if (is_number(numberStr))
v.push_back(std::stoi(numberStr));
}
}
You'd have to make the replace more robust (by checking the presence of parentheses at these positions)

How to partly sort arrays on CUDA?

Problem
Provided I have two arrays:
const int N = 1000000;
float A[N];
myStruct *B[N];
The numbers in A can be positive or negative (e.g. A[N]={3,2,-1,0,5,-2}), how can I make the array A partly sorted (all positive values first, not need to be sorted, then negative values)(e.g. A[N]={3,2,5,0,-1,-2} or A[N]={5,2,3,0,-2,-1}) on the GPU? The array B should be changed according to A (A is keys, B is values).
Since the scale of A,B can be very large, I think the sort algorithm should be implemented on GPU (especially on CUDA, because I use this platform). Surely I know thrust::sort_by_key can do this work, but it does muck extra work since I do not need the array A&B to be sorted entirely.
Has anyone come across this kind of problem?
Thrust example
thrust::sort_by_key(thrust::device_ptr<float> (A),
thrust::device_ptr<float> ( A + N ),
thrust::device_ptr<myStruct> ( B ),
thrust::greater<float>() );
Thrust's documentation on Github is not up-to-date. As #JaredHoberock said, thrust::partition is the way to go since it now supports stencils. You may need to get a copy from the Github repository:
git clone git://github.com/thrust/thrust.git
Then run scons doc in the Thrust folder to get an updated documentation, and use these updated Thrust sources when compiling your code (nvcc -I/path/to/thrust ...). With the new stencil partition, you can do:
#include <thrust/partition.h>
#include <thrust/execution_policy.h>
#include <thrust/iterator/zip_iterator.h>
#include <thrust/tuple.h>
struct is_positive
{
__host__ __device__
bool operator()(const int &x)
{
return x >= 0;
}
};
thrust::partition(thrust::host, // if you want to test on the host
thrust::make_zip_iterator(thrust::make_tuple(keyVec.begin(), valVec.begin())),
thrust::make_zip_iterator(thrust::make_tuple(keyVec.end(), valVec.end())),
keyVec.begin(),
is_positive());
This returns:
Before:
keyVec = 0 -1 2 -3 4 -5 6 -7 8 -9
valVec = 0 1 2 3 4 5 6 7 8 9
After:
keyVec = 0 2 4 6 8 -5 -3 -7 -1 -9
valVec = 0 2 4 6 8 5 3 7 1 9
Note that the 2 partitions are not necessarily sorted. Also, the order may differ between the original vectors and the partitions. If this is important to you, you can use thrust::stable_partition:
stable_partition differs from partition in that stable_partition is
guaranteed to preserve relative order. That is, if x and y are
elements in [first, last), such that pred(x) == pred(y), and if x
precedes y, then it will still be true after stable_partition that x
precedes y.
If you want a complete example, here it is:
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/partition.h>
#include <thrust/iterator/zip_iterator.h>
#include <thrust/tuple.h>
struct is_positive
{
__host__ __device__
bool operator()(const int &x)
{
return x >= 0;
}
};
void print_vec(const thrust::host_vector<int>& v)
{
for(size_t i = 0; i < v.size(); i++)
std::cout << " " << v[i];
std::cout << "\n";
}
int main ()
{
const int N = 10;
thrust::host_vector<int> keyVec(N);
thrust::host_vector<int> valVec(N);
int sign = 1;
for(int i = 0; i < N; ++i)
{
keyVec[i] = sign * i;
valVec[i] = i;
sign *= -1;
}
// Copy host to device
thrust::device_vector<int> d_keyVec = keyVec;
thrust::device_vector<int> d_valVec = valVec;
std::cout << "Before:\n keyVec = ";
print_vec(keyVec);
std::cout << " valVec = ";
print_vec(valVec);
// Partition key-val on device
thrust::partition(thrust::make_zip_iterator(thrust::make_tuple(d_keyVec.begin(), d_valVec.begin())),
thrust::make_zip_iterator(thrust::make_tuple(d_keyVec.end(), d_valVec.end())),
d_keyVec.begin(),
is_positive());
// Copy result back to host
keyVec = d_keyVec;
valVec = d_valVec;
std::cout << "After:\n keyVec = ";
print_vec(keyVec);
std::cout << " valVec = ";
print_vec(valVec);
}
UPDATE
I made a quick comparison with the thrust::sort_by_key version, and the thrust::partition implementation does seem to be faster (which is what we could naturally expect). Here is what I obtain on NVIDIA Visual Profiler, with N = 1024 * 1024, with the sort version on the left, and the partition version on the right. You may want to do the same kind of tests on your own.
How about this?:
Count how many positive numbers to determine the inflexion point
Evenly divide each side of the inflexion point into groups (negative-groups are all same length but different length to positive-groups. these groups are the memory chunks for the results)
Use one kernel call (one thread) per chunk pair
Each kernel swaps any out-of-place elements in the input groups into the desired output groups. You will need to flag any chunks that have more swaps than the maximum so that you can fix them during subsequent iterations.
Repeat until done
Memory traffic is swaps only (from original element position, to sorted position). I don't know if this algorithm sounds like anything already defined...
You should be able to achieve this in thrust simply with a modification of your comparison operator:
struct my_compare
{
__device__ __host__ bool operator()(const float x, const float y) const
{
return !((x<0.0f) && (y>0.0f));
}
};
thrust::sort_by_key(thrust::device_ptr<float> (A),
thrust::device_ptr<float> ( A + N ),
thrust::device_ptr<myStruct> ( B ),
my_compare() );

Resources