28int getLog2(qindex a) {
30 DEMAND( (a & (a - 1)) == 0 );
40qindex getPow2(
int a) {
43 return ((qindex) 1) << a;
47int getBitAt(qindex num,
int ind) {
50 return (num >> ind) & 1;
54vector<int> getBits(qindex num,
int numBits) {
55 DEMAND( numBits > 0 );
58 vector<int> out(numBits);
60 for (
int i=0; i<numBits; i++)
61 out[i] = getBitAt(num, i);
67qindex getBitsAt(qindex num, vector<int> inds) {
72 for (
size_t i=0; i<inds.size(); i++)
73 out |= getBitAt(num, inds[i]) << i;
79qindex setBitAt(qindex num,
int ind,
int bit) {
83 return (num & ~(one << ind)) | (bit << ind);
87qindex setBitsAt(qindex num, vector<int> inds, qindex bits) {
89 for (
size_t i=0; i<inds.size(); i++)
90 num = setBitAt(num, inds[i], getBitAt(bits, i));
96int getNumPermutations(
int n,
int k) {
102 for (
int t=n-k+1; t<=n; t++)
115qcomp getSum(qvector vec) {
117 qcomp sum = qcomp(0,0);
121 for (
auto& x : vec) {
132qreal getSum(vector<qreal> vec) {
135 qvector in = getZeroVector(vec.size());
136 for (
size_t i=0; i<in.size(); i++)
137 in[i] = qcomp(vec[i],0);
139 return std::real(getSum(in));
143qvector getNormalised(qvector vec) {
146 vector<qreal> probs(vec.size());
147 for (
size_t i=0; i<vec.size(); i++)
148 probs[i] = std::norm(vec[i]);
151 qreal norm = getSum(probs);
152 qreal fac = 1 / std::sqrt(norm);
160qvector getDisceteFourierTransform(qvector in) {
161 DEMAND( in.size() > 0 );
163 size_t dim = in.size();
164 qvector out = getZeroVector(dim);
167 qreal pi = 3.14159265358979323846;
168 qreal a = 1 / std::sqrt(dim);
169 qreal b = 2 * pi / dim;
171 for (
size_t x=0; x<dim; x++)
172 for (
size_t y=0; y<dim; y++)
173 out[x] += a * std::exp(b * x * y * 1_i) * in[y];
179qvector getDisceteFourierTransform(qvector in, vector<int> targs) {
180 DEMAND( in.size() > 0 );
182 size_t dim = in.size();
183 qvector out = getZeroVector(dim);
185 qindex len = getPow2(targs.size());
186 qreal pi = 3.14159265358979323846;
187 qreal a = 1 / std::sqrt(len);
188 qreal b = 2 * pi / len;
190 for (
size_t i=0; i<dim; i++) {
191 size_t x = getBitsAt(i, targs);
192 for (
size_t y=0; y<len; y++) {
193 qindex j = setBitsAt(i, targs, y);
194 out[j] += a * std::exp(b * x * y * 1_i) * in[i];
208qcomp getInnerProduct(qvector bra, qvector ket) {
209 DEMAND( bra.size() == ket.size() );
213 for (
size_t i=0; i<bra.size(); i++)
214 out += std::conj(bra[i]) * ket[i];
220qmatrix getOuterProduct(qvector ket, qvector bra) {
221 DEMAND( bra.size() == ket.size() );
225 for (
size_t i=0; i<ket.size(); i++)
226 for (
size_t j=0; j<ket.size(); j++)
227 out[i][j] = ket[i] * std::conj(bra[j]);
239bool isDiagonal(qmatrix m) {
241 for (
size_t r=0; r<m.size(); r++)
242 for (
size_t c=0; c<m.size(); c++)
243 if (r!=c && m[r][c] != 0_i)
250bool isApproxUnitary(qmatrix m) {
255 return doMatricesAgree(md,
id);
259qcomp getTrace(qmatrix m) {
262 for (
size_t r=0; r<m.size(); r++)
269qmatrix getTranspose(qmatrix m) {
273 for (
size_t r=0; r<m.size(); r++)
274 for (
size_t c=0; c<m.size(); c++)
281qmatrix getConjugate(qmatrix m) {
284 for (
auto& elem : row)
285 elem = std::conj(elem);
292 DEMAND( m.size() > 0 );
299 qmatrix out(m[0].size(), qvector(m.size()));
301 for (
size_t r=0; r<out.size(); r++)
302 for (
size_t c=0; c<out[0].size(); c++)
303 out[r][c] = std::conj(m[c][r]);
309qmatrix getPowerOfDiagonalMatrix(qmatrix m, qcomp p) {
310 DEMAND( isDiagonal(m) );
320 for (
size_t i=0; i<m.size(); i++) {
321 bool mIsRe = std::imag(m[i][i]) == 0;
322 bool mIsNeg = std::real(m[i][i]) < 0;
323 bool pIsRe = std::imag(p) == 0;
324 bool pIsInt = std::trunc(std::real(p)) == std::real(p);
327 out[i][i] = (mIsRe && mIsNeg && pIsRe && pIsInt)?
328 qcomp(std::pow(std::real(m[i][i]), std::real(p)),0):
329 std::pow(m[i][i], p);
337 DEMAND( isDiagonal(m) );
341 for (
size_t i=0; i<m.size(); i++)
342 out[i][i] = std::exp(m[i][i]);
352 qmatrix out = std::cos(arg/2)*
id - 1_i*std::sin(arg/2)*m;
357qmatrix getExponentialOfNormalisedPauliVector(qreal arg, qreal x, qreal y, qreal z) {
360 qreal n = std::sqrt(x*x + y*y + z*z);
366 qmatrix out = std::cos(arg/2)*
id - 1_i*std::sin(arg/2)*(
367 x * getPauliMatrix(1) +
368 y * getPauliMatrix(2) +
369 z * getPauliMatrix(3));
375qmatrix getOrthonormalisedRows(qmatrix matr) {
378 for (
size_t i=0; i<matr.size(); i++) {
379 qvector row = matr[i];
382 for (
int k=i-1; k>=0; k--) {
385 qcomp prod = getInnerProduct(matr[k], row);
388 matr[i] -= prod * matr[k];
392 matr[i] = getNormalised(matr[i]);
400qmatrix getProjector(
int outcome) {
401 DEMAND( outcome == 0 || outcome == 1 );
404 out[outcome][outcome] = 1.;
409qmatrix getProjector(vector<int> targets, vector<int> outcomes,
int numQubits) {
410 DEMAND( targets.size() == outcomes.size() );
411 DEMAND( numQubits > *std::max_element(targets.begin(), targets.end()) );
415 for (
size_t i=0; i<targets.size(); i++)
416 matrices[targets[i]] = getProjector(outcomes[i]);
422qmatrix getPartialTrace(qmatrix in, vector<int> targets) {
423 DEMAND( in.size() > getPow2(targets.size()) );
425 auto numTargs = targets.size();
426 auto numQubits = getLog2(in.size());
427 auto numTargVals = getPow2(numTargs);
431 for (qindex v=0; v<numTargVals; v++) {
435 for (
size_t t=0; t<numTargs; t++) {
436 int bit = getBitAt(v, t);
437 matrices[targets[t]] = {
444 out += bra * in * ket;
451qmatrix getControlledMatrix(qmatrix matrix,
int numCtrls) {
453 size_t dim = getPow2(numCtrls) * matrix.size();
454 size_t off = dim - matrix.size();
463qmatrix getMixture(vector<qmatrix> densmatrs, vector<qreal> probs) {
464 DEMAND( densmatrs.size() > 0 );
467 for (
size_t i=0; i<densmatrs.size(); i++)
468 out += probs[i] * densmatrs[i];
474qmatrix getMixture(vector<qvector> statevecs, vector<qreal> probs) {
476 vector<qmatrix> densmatrs(statevecs.size());
477 for (
size_t i=0; i<statevecs.size(); i++)
478 densmatrs[i] = getOuterProduct(statevecs[i], statevecs[i]);
480 return getMixture(densmatrs, probs);
484qmatrix getSuperOperator(vector<qmatrix> matrices) {
485 DEMAND( matrices.size() > 0 );
487 size_t dim = matrices[0].size();
491 for (
auto& matr : matrices)
504qvector operator * (
const qmatrix& m,
const qvector& v) {
505 DEMAND( m.size() == v.size() );
507 qvector out = getZeroVector(v.size());
509 for (
size_t r=0; r<v.size(); r++)
510 for (
size_t c=0; c<v.size(); c++)
511 out[r] += m[r][c] * v[c];
530 size_t aRows = a.size();
531 size_t bRows = b.size();
532 size_t aCols = a[0].size();
533 size_t bCols = b[0].size();
535 qmatrix out(aRows * bRows, qvector(aCols * bCols));
537 for (
size_t r=0; r<bRows; r++)
538 for (
size_t c=0; c<bCols; c++)
539 for (
size_t i=0; i<aRows; i++)
540 for (
size_t j=0; j<aCols; j++)
541 out[r+bRows*i][c+bCols*j] = a[i][j] * b[r][c];
552 for (
auto& m : matrices)
560 DEMAND( count >= 1 );
564 for (
int n=0; n<count; n++)
577bool isApproxCPTP(vector<qmatrix> matrices) {
578 DEMAND( matrices.size() >= 1 );
580 size_t dim = matrices[0].size();
584 for (
auto& m : matrices)
587 return doMatricesAgree(sum,
id);
qmatrix getKroneckerProduct(qmatrix a, qmatrix b)
qmatrix getConjugateTranspose(qmatrix m)
qmatrix getExponentialOfDiagonalMatrix(qmatrix m)
qmatrix getExponentialOfPauliMatrix(qreal arg, qmatrix m)
qmatrix getIdentityMatrix(size_t dim)
void setSubMatrix(qmatrix &dest, qmatrix sub, size_t r, size_t c)
qmatrix getZeroMatrix(size_t dim)