29int getLog2(qindex a) {
31 DEMAND( (a & (a - 1)) == 0 );
41qindex getPow2(
int a) {
44 return ((qindex) 1) << a;
48int getBitAt(qindex num,
int ind) {
51 return (num >> ind) & 1;
55vector<int> getBits(qindex num,
int numBits) {
56 DEMAND( numBits > 0 );
59 vector<int> out(numBits);
61 for (
int i=0; i<numBits; i++)
62 out[i] = getBitAt(num, i);
68qindex getBitsAt(qindex num, vector<int> inds) {
73 for (
size_t i=0; i<inds.size(); i++)
74 out |= getBitAt(num, inds[i]) << i;
80qindex setBitAt(qindex num,
int ind,
int bit) {
84 return (num & ~(one << ind)) | (bit << ind);
88qindex setBitsAt(qindex num, vector<int> inds, qindex bits) {
90 for (
size_t i=0; i<inds.size(); i++)
91 num = setBitAt(num, inds[i], getBitAt(bits, i));
97qindex getNumPermutations(
int n,
int k) {
100 constexpr auto max = std::numeric_limits<qindex>::max();
104 for (
int t=n-k+1; t<=n; t++)
105 p *= (p < max / t)? t : 0;
117qcomp getSum(qvector vec) {
119 qcomp sum = qcomp(0,0);
123 for (
auto& x : vec) {
134qreal getSum(vector<qreal> vec) {
137 qvector in = getZeroVector(vec.size());
138 for (
size_t i=0; i<in.size(); i++)
139 in[i] = qcomp(vec[i],0);
141 return std::real(getSum(in));
145qvector getNormalised(qvector vec) {
148 vector<qreal> probs(vec.size());
149 for (
size_t i=0; i<vec.size(); i++)
150 probs[i] = std::norm(vec[i]);
153 qreal norm = getSum(probs);
154 qreal fac = 1 / std::sqrt(norm);
162qvector getDiscreteFourierTransform(qvector in,
bool inverse) {
163 DEMAND( in.size() > 0 );
165 size_t dim = in.size();
166 qvector out = getZeroVector(dim);
169 qreal pi = 3.14159265358979323846;
170 qreal a = 1 / std::sqrt(dim);
171 qreal b = (inverse ? -1 : 1) * 2 * pi / dim;
173 for (
size_t x=0; x<dim; x++)
174 for (
size_t y=0; y<dim; y++)
175 out[x] += a * std::exp(b * x * y * 1_i) * in[y];
181qvector getDiscreteFourierTransform(qvector in, vector<int> targs,
bool inverse) {
182 DEMAND( in.size() > 0 );
184 size_t dim = in.size();
185 qvector out = getZeroVector(dim);
187 qindex len = getPow2(targs.size());
188 qreal pi = 3.14159265358979323846;
189 qreal a = 1 / std::sqrt(len);
190 qreal b = (inverse ? -1 : 1) * 2 * pi / len;
192 for (
size_t i=0; i<dim; i++) {
193 size_t x = getBitsAt(i, targs);
194 for (
size_t y=0; y<len; y++) {
195 qindex j = setBitsAt(i, targs, y);
196 out[j] += a * std::exp(b * x * y * 1_i) * in[i];
210qcomp getInnerProduct(qvector bra, qvector ket) {
211 DEMAND( bra.size() == ket.size() );
215 for (
size_t i=0; i<bra.size(); i++)
216 out += std::conj(bra[i]) * ket[i];
222qmatrix getOuterProduct(qvector ket, qvector bra) {
223 DEMAND( bra.size() == ket.size() );
227 for (
size_t i=0; i<ket.size(); i++)
228 for (
size_t j=0; j<ket.size(); j++)
229 out[i][j] = ket[i] * std::conj(bra[j]);
241bool isDiagonal(qmatrix m) {
243 for (
size_t r=0; r<m.size(); r++)
244 for (
size_t c=0; c<m.size(); c++)
245 if (r!=c && m[r][c] != 0_i)
252bool isApproxUnitary(qmatrix m) {
257 return doMatricesAgree(md,
id);
261qcomp getTrace(qmatrix m) {
264 for (
size_t r=0; r<m.size(); r++)
271qmatrix getTranspose(qmatrix m) {
275 for (
size_t r=0; r<m.size(); r++)
276 for (
size_t c=0; c<m.size(); c++)
283qmatrix getConjugate(qmatrix m) {
286 for (
auto& elem : row)
287 elem = std::conj(elem);
294 DEMAND( m.size() > 0 );
301 qmatrix out(m[0].size(), qvector(m.size()));
303 for (
size_t r=0; r<out.size(); r++)
304 for (
size_t c=0; c<out[0].size(); c++)
305 out[r][c] = std::conj(m[c][r]);
311qmatrix getPowerOfDiagonalMatrix(qmatrix m, qcomp p) {
312 DEMAND( isDiagonal(m) );
322 for (
size_t i=0; i<m.size(); i++) {
323 bool mIsRe = std::imag(m[i][i]) == 0;
324 bool mIsNeg = std::real(m[i][i]) < 0;
325 bool pIsRe = std::imag(p) == 0;
326 bool pIsInt = std::trunc(std::real(p)) == std::real(p);
329 out[i][i] = (mIsRe && mIsNeg && pIsRe && pIsInt)?
330 qcomp(std::pow(std::real(m[i][i]), std::real(p)),0):
331 std::pow(m[i][i], p);
339 DEMAND( isDiagonal(m) );
343 for (
size_t i=0; i<m.size(); i++)
344 out[i][i] = std::exp(m[i][i]);
350qmatrix getExponentialOfPauliMatrix(qcomp arg, qmatrix m) {
354 qmatrix out = std::cos(arg/2)*
id - 1_i*std::sin(arg/2)*m;
359qmatrix getExponentialOfNormalisedPauliVector(qreal arg, qreal x, qreal y, qreal z) {
362 qreal n = std::sqrt(x*x + y*y + z*z);
368 qmatrix out = std::cos(arg/2)*
id - 1_i*std::sin(arg/2)*(
369 x * getPauliMatrix(1) +
370 y * getPauliMatrix(2) +
371 z * getPauliMatrix(3));
377qmatrix getOrthonormalisedRows(qmatrix matr) {
380 for (
size_t i=0; i<matr.size(); i++) {
381 qvector row = matr[i];
384 for (
int k=i-1; k>=0; k--) {
387 qcomp prod = getInnerProduct(matr[k], row);
390 matr[i] -= prod * matr[k];
394 matr[i] = getNormalised(matr[i]);
402qmatrix getProjector(
int outcome) {
403 DEMAND( outcome == 0 || outcome == 1 );
406 out[outcome][outcome] = 1.;
411qmatrix getProjector(vector<int> targets, vector<int> outcomes,
int numQubits) {
412 DEMAND( targets.size() == outcomes.size() );
413 DEMAND( numQubits > *std::max_element(targets.begin(), targets.end()) );
417 for (
size_t i=0; i<targets.size(); i++)
418 matrices[targets[i]] = getProjector(outcomes[i]);
424qmatrix getPartialTrace(qmatrix in, vector<int> targets) {
425 DEMAND( in.size() > getPow2(targets.size()) );
427 auto numTargs = targets.size();
428 auto numQubits = getLog2(in.size());
429 auto numTargVals = getPow2(numTargs);
433 for (qindex v=0; v<numTargVals; v++) {
437 for (
size_t t=0; t<numTargs; t++) {
438 int bit = getBitAt(v, t);
439 matrices[targets[t]] = {
446 out += bra * in * ket;
453qmatrix getControlledMatrix(qmatrix matrix,
int numCtrls) {
455 size_t dim = getPow2(numCtrls) * matrix.size();
456 size_t off = dim - matrix.size();
465qmatrix getMixture(vector<qmatrix> densmatrs, vector<qreal> probs) {
466 DEMAND( densmatrs.size() > 0 );
469 for (
size_t i=0; i<densmatrs.size(); i++)
470 out += probs[i] * densmatrs[i];
476qmatrix getMixture(vector<qvector> statevecs, vector<qreal> probs) {
478 vector<qmatrix> densmatrs(statevecs.size());
479 for (
size_t i=0; i<statevecs.size(); i++)
480 densmatrs[i] = getOuterProduct(statevecs[i], statevecs[i]);
482 return getMixture(densmatrs, probs);
486qmatrix getSuperOperator(vector<qmatrix> matrices) {
487 DEMAND( matrices.size() > 0 );
489 size_t dim = matrices[0].size();
493 for (
auto& matr : matrices)
506qvector operator * (
const qmatrix& m,
const qvector& v) {
507 DEMAND( m.size() == v.size() );
509 qvector out = getZeroVector(v.size());
511 for (
size_t r=0; r<v.size(); r++)
512 for (
size_t c=0; c<v.size(); c++)
513 out[r] += m[r][c] * v[c];
532 size_t aRows = a.size();
533 size_t bRows = b.size();
534 size_t aCols = a[0].size();
535 size_t bCols = b[0].size();
537 qmatrix out(aRows * bRows, qvector(aCols * bCols));
539 for (
size_t r=0; r<bRows; r++)
540 for (
size_t c=0; c<bCols; c++)
541 for (
size_t i=0; i<aRows; i++)
542 for (
size_t j=0; j<aCols; j++)
543 out[r+bRows*i][c+bCols*j] = a[i][j] * b[r][c];
554 for (
auto& m : matrices)
562 DEMAND( count >= 1 );
566 for (
int n=0; n<count; n++)
579bool isApproxCPTP(vector<qmatrix> matrices) {
580 DEMAND( matrices.size() >= 1 );
582 size_t dim = matrices[0].size();
586 for (
auto& m : matrices)
589 return doMatricesAgree(sum,
id);
qmatrix getKroneckerProduct(qmatrix a, qmatrix b)
qmatrix getConjugateTranspose(qmatrix m)
qmatrix getExponentialOfDiagonalMatrix(qmatrix m)
qmatrix getIdentityMatrix(size_t dim)
void setSubMatrix(qmatrix &dest, qmatrix sub, size_t r, size_t c)
qmatrix getZeroMatrix(size_t dim)