Program Listing for File permute.hpp¶
↰ Return to documentation for file (/home/docs/checkouts/readthedocs.org/user_builds/intel-qs/checkouts/docs/include/permute.hpp
)
#ifndef PERMUTE_HPP
#define PERMUTE_HPP
#include <map>
#include <numeric>
#include <vector>
#include "utils.hpp"
#include "conversion.hpp"
inline std::size_t perm(std::size_t v, std::size_t *map, std::size_t num_qubits)
{
std::size_t v_ = 0;
for (std::size_t i = 0; i < num_qubits; i++) v_ = v_ | (((v & (1 << map[i])) >> map[i]) << i);
return v_;
}
// declaration and definition of class Permutation
class Permutation
{
public:
std::vector<std::size_t> map, imap;
std::size_t num_qubits;
unsigned operator[](std::size_t i)
{
assert(i <= num_qubits);
return (unsigned) map[i];
}
unsigned operator[](unsigned i)
{
assert(i <= num_qubits);
return map[i];
}
int operator[](int i)
{
assert(i <= num_qubits);
return (int)map[i];
}
std::size_t size() {return map.size();}
std::string GetMapStr()
{
std::string s;
for (std::size_t i = 0; i < map.size(); i++) s += " " + qhipster::toString(map[i]);
return s;
}
std::string GetImapStr()
{
std::string s;
for (std::size_t i = 0; i < imap.size(); i++) s += " " + qhipster::toString(imap[i]);
return s;
}
Permutation(std::size_t num_qubits)
{
this->num_qubits = num_qubits;
std::vector<std::size_t> m(num_qubits);
iota(m.begin(), m.end(), 0);
// for(auto i:m) printf("%d ", i); printf("\n");
// exit(0);
SetNewPermutation(m);
}
Permutation(std::vector<std::size_t> m)
{
num_qubits = m.size();
SetNewPermutation(m);
}
std::size_t Find(std::size_t position)
{
bool found = false;
std::size_t i;
for (i = 0; i < map.size(); i++)
{
if (map[i] == position)
{
found = true;
break;
}
}
assert(found);
return i;
}
void SetNewPermutation(std::vector<std::size_t> m)
{
map = m;
// check consistency of map
std::vector<bool> exist(map.size(), 0);
for (auto &m : map) exist[m] = 1;
for (auto e : exist) assert(e > 0);
// compute inverse map
imap = map;
for (std::size_t i = 0; i < map.size(); i++) imap[map[i]] = i;
}
std::string dec2bin(std::size_t in, std::size_t num_bits)
{
std::string s;
s.resize(num_bits);
for (std::size_t i = 0; i < num_bits; i++)
{
s[i] = (in & 0x1) == 0 ? '0' : '1';
in = in >> 1;
}
return s;
}
std::size_t bin2dec(std::string in)
{
std::size_t v = 0;
for (std::size_t i = 0; i < in.size(); i++)
v += UL(1 << i) * UL(in[i] - '0');
return v;
}
inline std::size_t lin2perm_(std::size_t v)
{
std::size_t v_ = 0;
for (std::size_t i = 0; i < num_qubits; i++)
v_ = v_ | (((v & (1 << map[i])) >> map[i]) << i);
return v_;
}
inline std::size_t perm2lin_(std::size_t v)
{
std::size_t v_ = 0;
for (std::size_t i = 0; i < num_qubits; i++)
v_ = v_ | (((v & (((std::size_t)1) << imap[i])) >> imap[i]) << i);
return v_;
}
std::string lin2perm(std::size_t v)
{
std::string s = dec2bin(v, num_qubits), sp(s);
for (std::size_t i = 0; i < s.size(); i++) sp[i] = s[map[i]];
if (0)
{
std::size_t v_ = 0;
for (std::size_t i = 0; i < num_qubits; i++)
v_ = v_ | (((v & (((std::size_t)1) << map[i])) >> map[i]) << i);
printf("sp=%s new:%s\n", sp.c_str(), dec2bin(v_, num_qubits).c_str());
}
return sp;
}
std::string lin2perm(std::string s)
{
std::string sp(s);
for (std::size_t i = 0; i < s.size(); i++)
sp[i] = s[map[i]];
return sp;
}
std::string perm2lin(std::size_t v)
{
std::string s = dec2bin(v, num_qubits), sp(s);
for (std::size_t i = 0; i < s.size(); i++)
sp[i] = s[imap[i]];
return sp;
}
std::string perm2lin(std::string s)
{
std::string sp(s);
for (std::size_t i = 0; i < s.size(); i++)
sp[i] = s[imap[i]];
return sp;
}
void prange()
{
#if 0
printf("map: ");
for(auto & i : map) printf("%d", i);
printf("\n");
printf("imap: ");
for(auto & i : imap) printf("%d", i);
printf("\n");
for(std::size_t i = 0; i < (1 << num_qubits); i++)
{
printf("%s(%lld)\n", dec2bin(i, num_qubits).c_str(), i);
}
printf("\n");
for(std::size_t i = 0; i < (1 << num_qubits); i++)
{
printf("%s(%lld)\n", lin2perm(i).c_str(), bin2dec(lin2perm(i)));
}
printf("\n");
#endif
for (std::size_t i = 0; i < (UL(1) << num_qubits); i++)
{
#if 0
printf("%s ==> %s\n", lin2perm(i).c_str(),
perm2lin(lin2perm(i)).c_str());
#else
printf("map(%3lu) = %3lu\n", i, bin2dec(lin2perm(i)));
#endif
}
}
};
// FIXME FIXME: the code below was probably written by Misha to test the permutation class.
// The MPI part has not been stripped from it.
#if defined(MAIN)
class State
{
public:
std::string name;
Permutation p;
std::vector<ComplexType> state;
State(Permutation p_, std::string name_) : p(p_), name(name_)
{
state.resize(1 << p.num_qubits);
#pragma omp parallel for
for (std::size_t i = 0; i < state.size(); i++) state[i] = {D(i % 3), D(i % 7)};
}
void permute(Permutation pnew)
{
Permutation pold = p;
assert(pnew.num_qubits == pold.num_qubits);
std::vector<ComplexType> state_new(state.size(), 0);
// printf("map: %s imap: %s\n", pnew.GetMapStr().c_str(), pold.GetImapStr().c_str());
std::vector<std::size_t> map(pnew.num_qubits, 0);
for (std::size_t i = 0; i < pnew.num_qubits; i++) {
map[i] = pold.map[pnew.imap[i]];
// printf("%d ", map[i]);
}
// printf("\n");
__int64 t0 = __rdtsc();
double s0 = sec();
#pragma omp parallel for
for (std::size_t i = 0; i < state.size(); i++) {
#if 0
std::size_t to1 = perm(i, &(map[0]), p.num_qubits);
std::size_t to2 = pnew.perm2lin_(pold.lin2perm_(i));
std::size_t to = pold.bin2dec(pnew.perm2lin(pold.lin2perm(i)));
assert(to == to1);
assert(to == to2);
state_new[to] = state[i];
#else
std::size_t to_ = perm(i, &(map[0]), p.num_qubits); // pnew.perm2lin_(pold.lin2perm_(i));
state_new[to_] = state[i];
#endif
}
__int64 t1 = __rdtsc();
double s1 = sec();
double bw = D(state.size()) * D(sizeof(state[0])) * 2.0 / D(s1 - s0);
printf("cycles per shuffle: %.2lf bw=%.2lf GB/s\n", D(t1 - t0) / D(state.size()), bw / 1e9);
p = pnew;
state = state_new;
}
void print()
{
printf("name::%s %s\n", name.c_str(), p.GetMapStr().c_str());
for (std::size_t i = 0; i < state.size(); i++) {
printf("%s {%lf %lf}\n", p.lin2perm(i).c_str(), real(state[i]), imag(state[i]));
}
}
bool operator==(const State &rhs)
{
assert((const std::size_t)state.size() == rhs.state.size());
for (std::size_t i = 0; i < state.size(); i++) {
if (state[i] != rhs.state[i]) return false;
}
return true;
}
};
std::size_t main(std::size_t argc, char **argv)
{
std::size_t num_qubits = 3, num_threads = 1;
if (argc != 3)
{
fprintf(stderr, "usage: %s <num_qubits> <num_threads>\n", argv[0]);
exit(1);
}
else
{
num_qubits = atoi(argv[1]);
num_threads = atoi(argv[2]);
}
initomp(num_threads);
#if 1
Permutation p({2, 0, 1});
p.prange();
State s(Permutation({0, 1, 2}), "s");
s.print();
s.permute(p);
s.print();
s.permute(Permutation({0, 1, 2}));
s.print();
#else
#if 0
State s1(Permutation({2, 1, 0}), "s"), s2(s1);
s1.permute(Permutation({2,0,1}));
s2.permute(Permutation({2,0,1}));
assert(s1 == s2);
printf("SUCCESS!\n");
#else
std::vector<std::size_t> map(num_qubits, 0);
iota(map.begin(), map.end(), 0);
State s1(Permutation(map), "s1"), s2(s1);
s2.permute(Permutation(map));
s2.permute(Permutation(map));
s2.permute(Permutation(map));
#endif
#endif
}
#endif
#endif // header guard PERMUTE_HPP