Skip to content

Instantly share code, notes, and snippets.

@simonlindholm
Last active June 10, 2018 18:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save simonlindholm/e31b68fccd66a140a6d49a6f81db4c8a to your computer and use it in GitHub Desktop.
Save simonlindholm/e31b68fccd66a140a6d49a6f81db4c8a to your computer and use it in GitHub Desktop.
#include <message.h>
#include "kenneth.h"
#include <bits/stdc++.h>
using namespace std;
#define rep(i, from, to) for (int i = from; i < (to); ++i)
#define trav(a, x) for (auto& a : x)
#define all(x) x.begin(), x.end()
#define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int nnodes = NumberOfNodes();
const int nodeid = MyNodeId();
typedef unsigned long long H;
static H C = 123891739; // arbitrary
static H CR = 3985654725013410664ULL; // inverse
// Arithmetic mod 2^64-1. 5x slower than mod 2^64 and more
// code, but works on evil test data (e.g. Thue-Morse).
// typedef H K;
struct K {
typedef __uint128_t H2;
H x; K(H x=0) : x(x) {}
K operator+(K o){ return x + o.x + H(((H2)x + o.x)>>64); }
K operator*(K o){ return K(x*o.x)+ H(((H2)x * o.x)>>64); }
H operator-(K o) { K a = *this + ~o.x; return a.x + !~a.x; }
};
vi positions;
int n;
vector<int> active1;
vector<int> active2;
vector<H> fwdHashes, revHashes;
set<int> hasSentTo;
int myBasePos, myEndPos;
int totalLength;
struct Work {
bool done = false;
vi remaining;
vector<H> myhashes;
int size;
int pos;
bool rev;
int dataUsed = 0;
int iter = 0;
int otherParty;
int sent = 0, received = 0;
Work(int pos, int rev) : pos(pos), rev(rev) {
size = positions[pos+1] - positions[pos];
otherParty = rev ? active1[pos] : active2[pos];
rep(i,positions[pos], positions[pos+1]) {
if (rev)
myhashes.push_back(revHashes[myEndPos-myBasePos-1 - (totalLength-1 - i - myBasePos)]);
else
myhashes.push_back(fwdHashes[i - myBasePos]);
}
rep(i,0,size) remaining.push_back(i);
}
void prework() {
if (done) return;
if (iter == 6) {
trav(i, remaining) {
PutLL(otherParty, myhashes[i]);
}
}
else {
int ind = 0;
H chunk = 0;
trav(i, remaining) {
bool bit = myhashes[i] & (1ULL << (63 - iter));
if (bit) chunk |= 1ULL << ind;
ind++;
if (ind == 64) {
PutLL(otherParty, chunk);
ind = 0;
chunk = 0;
sent++;
}
dataUsed++;
}
PutLL(otherParty, chunk);
sent++;
}
hasSentTo.insert(otherParty);
}
void postwork() {
if (done) return;
vi rem2;
if (iter == 6) {
trav(i, remaining) {
if ((H)GetLL(otherParty) == myhashes[i])
rem2.push_back(i);
}
done = true;
}
else {
int ind = 0;
H chunk = GetLL(otherParty);
received++;
trav(i, remaining) {
bool bit = myhashes[i] & (1ULL << (63 - iter));
bool recvBit = chunk & (1ULL << ind);
if (bit == recvBit) rem2.push_back(i);
ind++;
if (ind == 64) {
chunk = GetLL(otherParty);
received++;
ind = 0;
}
}
assert(sent == received);
sent = received = 0;
if (dataUsed + (iter == 5 ? sz(rem2) * 64 : 0) > size * 3.8 + 7000) {
// There are short cycles, quit to avoid sending too much data
done = true;
}
iter++;
}
remaining = move(rem2);
if (remaining.empty()) done = true;
}
};
int main() {
C = K(C) * C * C - 0; // larger C
CR = K(CR) * CR * CR - 0;
assert(K(C) * CR - 0 == 1);
srand(2);
int cur = 0;
set<int> markers;
markers.insert(0);
vi before, after, before2, after2;
rep(i,0,nnodes) {
before.push_back(cur);
cur += (int)GetPieceLength(i);
after.push_back(cur);
markers.insert(cur);
}
myBasePos = before[nodeid];
myEndPos = after[nodeid];
totalLength = cur;
rep(i,0,nnodes) {
before2.push_back(cur);
cur -= (int)GetPieceLength(i);
after2.push_back(cur);
markers.insert(cur);
}
// COMPUTE HASHES
K h = 0, pw = 1;
K hR = 0, pwR = 1;
K beforeH = 0, beforeHR = 0;
vector<H> localHashes, localHashesR;
rep(i,myBasePos,myEndPos) {
h = h * C + GetSignalCharacter(i);
localHashes.push_back(h - 0);
pw = pw * C;
}
for (int i = myEndPos-1; i >= myBasePos; i--) {
hR = hR * CR + GetSignalCharacter(i);
localHashesR.push_back(hR - 0);
pwR = pwR * CR;
}
K cor = 1;
rep(i,0,nnodes) {
PutLL(i, h-0);
PutLL(i, pw-0);
PutLL(i, hR-0);
PutLL(i, pwR-0);
Send(i);
}
rep(i,0,nnodes) {
Receive(i);
K h2 = GetLL(i);
K pw2 = GetLL(i);
if (i < nodeid) {
beforeH = beforeH * pw2 + h2;
}
if (i > nodeid) {
cor = cor * pw2;
}
}
for (int i = nnodes-1; i >= 0; i--) {
K hR2 = GetLL(i);
K pwR2 = GetLL(i);
if (i > nodeid) {
beforeHR = beforeHR * pwR2 + hR2;
}
}
pw = K(1);
pwR = K(1);
trav(x, localHashes) {
pw = pw * C;
x = (beforeH * pw + K(x)) - 0;
}
trav(x, localHashesR) {
pwR = pwR * CR;
x = (beforeHR * pwR + K(x)) * cor - 0;
cor = cor * C;
}
fwdHashes = localHashes;
revHashes = localHashesR;
// END HASHES
/* rep(i,0,myEndPos-myBasePos)
cerr << "hash[" << i << "] = " << fwdHashes[i] << endl;
rep(i,0,myEndPos-myBasePos)
cerr << "hashr[" << i << "] = " << revHashes[i] << endl; */
// We want a chunk with only short cycles, which doesn't abort early.
if (totalLength >= 1000) markers.insert(totalLength - 1000);
positions.assign(all(markers));
n = sz(positions) - 1;
active1.assign(n, -1);
active2.assign(n, -1);
rep(i,0,nnodes) {
int it1 = (int)(find(all(positions), before[i]) - positions.begin());
int it2 = (int)(find(all(positions), after[i]) - positions.begin());
rep(j,it1,it2) {
assert(active1[j] == -1);
active1[j] = i;
}
}
rep(i,0,nnodes) {
int it1 = (int)(find(all(positions), after2[i]) - positions.begin());
int it2 = (int)(find(all(positions), before2[i]) - positions.begin());
rep(j,it1,it2) {
assert(active2[j] == -1);
active2[j] = i;
}
}
trav(x, active1) assert(x != -1);
trav(x, active2) assert(x != -1);
vector<Work> myactive;
myactive.reserve(n*2);
vector<Work*> myactiveRecv;
rep(i,0,n) {
Work *a, *b;
if (active1[i] == nodeid) myactive.emplace_back(i, 0), a = &myactive.back();
if (active2[i] == nodeid) myactive.emplace_back(i, 1), b = &myactive.back();
if (active2[i] == nodeid) myactiveRecv.push_back(b);
if (active1[i] == nodeid) myactiveRecv.push_back(a);
}
for (;;) {
bool ready = true;
trav(w, myactive) if (!w.done) ready = false;
if (ready) break;
trav(w, myactive) w.prework();
trav(x, hasSentTo)
Send(x);
trav(x, hasSentTo)
Receive(x);
hasSentTo.clear();
trav(w, myactiveRecv) w->postwork();
}
int best = totalLength;
trav(w, myactive) if (!w.rev) {
trav(x, w.remaining) {
auto y = totalLength - (x + positions[w.pos] + 1);
if (y) {
best = min(best, y);
}
}
}
PutInt(0, best);
Send(0);
if (nodeid == 0) {
rep(i,0,nnodes) {
Receive(i);
best = min(best, GetInt(i));
}
cout << best << endl;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment