// This file implements the classes for quantum states // and quantum operators. This includes the member functions // that allow the operators to act on the states, and the // functions that give binary operations. // // The classes are: qstate // qmatrix // qoperator // // The operators are: qoperator: tensor,*,*(scalar),+,- // qstate: tensor,*(scalar),+,>>,<< // qmatrix: tensor,*,*(scalar),+ // // general: qoperator*qstate, // qoperator*qmatrix, // qmatrix*qoperator // #include "qobjects.h" // Note: This class library includes code to use one of five external fft libraries. // This code is currently commented out, so that the user can use qobjects without // having to install an fft library. In this case the meamber functions which // invoke the fft's simply do nothing. Comments are included which direct // the user as to which segments to uncomment so as to use one of the fft // libraries. The current supported libraries are: GNU's GSL, netlibs Fftpack, // SCS's Library (zzfft), FFTW and an fft written in f90 by Daniel Steck. This // last one can be requested from the author. // -KJ // To use GNU's GSL uncomment: // #include // int fft(std::vector< std::complex >& x, gsl_fft_direction); // To use netlibs Fftpack uncomment: // ------------------------------------------ // extern "C" { // // void zffti_(int* n, double* wsave); // // void zfftf_(int* n, double* x, double* wsave); // // void zfftb_(int* n, double* x, double* wsave); // // } //------------------------------------------- // To use the SCS FFT uncomment: // ------------------------------------------- //#include // ------------------------------------------- // To use Dan Steck's fft1d uncomment: // ------------------------------------------ //extern "C" { void ffts1d_( int* fftsign, double* data, int* n ); } // ------------------------------------------ // To use FFTW (Fastest FT in the West) uncomment the indicated lines in qobjects.h // and the lines indicated in this file (below). To find them search for "FFTW" // Diagonalisation using netlibs LAPACK // This not yet implemented here, but for future use, the calling interface is as follows // extern "C" { // // void ZHBEVD(char* JOBZ, char* UPLO, int* N, int* KD, double* AB, int* LDAB, // double* W, double* Z, int* LDZ, double* WORK, int* LWORK, double* RWORK, // int* LRWORK, int* IWORK, int* LIWORK, int* INFO); // // // note: DOUBLE COMPLEX AB(LDAB,*), Z(LDZ,*), WORK(*) // } // **************************** // definitions for class qstate // **************************** qstate::qstate() { qcoeff.push_back(1); dims.push_back(1); } qstate::qstate(unsigned int dim) { if (dim>0) { for (unsigned int i=0;i0) { bool match = false; if (sname == "down") { match = true; for (unsigned int i=1;i<=dim;++i) { if (i==dim) { qcoeff.push_back(1); } else { qcoeff.push_back(0); } } dims.push_back(dim); } if (sname == "up") { match = true; for (unsigned int i=1;i<=dim;++i) { if (i==1) { qcoeff.push_back(1); } else { qcoeff.push_back(0); } } dims.push_back(dim); } if (sname == "+") { match = true; for (unsigned int i=1;i<=dim;++i) { qcoeff.push_back(1/std::sqrt(1.0*dim)); } dims.push_back(dim); } if (sname == "-") { match = true; int sign = 1; for (unsigned int i=1;i<=dim;++i) { qcoeff.push_back(sign/std::sqrt(1.0*dim)); sign *= -1; } dims.push_back(dim); } if (sname == "y+") { match = true; dim = 2; std::complex ei(0,1); qcoeff.push_back(-ei*std::sqrt(0.5)); qcoeff.push_back(std::sqrt(0.5)); dims.push_back(dim); } if (sname == "y-") { match = true; dim = 2; std::complex ei(0,1); qcoeff.push_back(ei*std::sqrt(0.5)); qcoeff.push_back(std::sqrt(0.5)); dims.push_back(dim); } if (!match) { std::cout << "Error in qstate contructor: requested state not found " << std::endl; } } } qstate::qstate(std::string sname, std::complex alpha, unsigned int dim) { if (dim>0) { if (sname == "coherent") { std::complex f_n(1.0,0.0); for (unsigned int i=0;inormalise(); } if (sname == "number") { unsigned int number = static_cast(std::floor(alpha.real())); for (unsigned int i=0;i0)&&(dims.size()==0)) { std::cout << "Could not create state: requested state unknown" << std::endl; } } // std::vector< std::complex > hermites(std::complex x, int n) { // std::vector< std::complex > h(n+1); // h[0] = 1.0; if (n==0) {return h;} // h[1] = x; if (n==1) {return h;} // if (n>1) { for (unsigned int m=2;m<=n;m++) { h[m] = x*h[m-1] - 2.0*(m-1.0)*h[m-2]; std::cout << h[m] << std::endl; } } // return h; // } // // std::vector factorial(int n) { // std::vector fac(n+1); // fac[0] = 1; if (n==0) {return fac;} // if (n>0) { for (unsigned int m=1;m<=n;m++) { fac[m] = m*fac[m-1]; std::cout << fac[m] << std::endl;} } // return fac; // } std::vector< std::complex > HOSFSP(std::complex x, std::complex p, int n) { // First n Hermites * Sqrt( P^n / n! ) std::vector< std::complex > hof(n+1); hof[0] = 1.0; if (n==0) {return hof;} hof[1] = x*std::sqrt(p); if (n==1) {return hof;} if (n>1) { for (unsigned int m=2;m<=n;m++) { hof[m] = x*std::sqrt(p/(1.0*m))*hof[m-1] - 2.0*p*(m-1.0)*hof[m-2]/( std::sqrt(1.0*m*(m-1)) ); } } return hof; } qstate::qstate(std::string sname, std::complex alpha, std::complex squeeze, unsigned int dim) { if (dim>0) { // Formula is in AJP 58, 1003 (1990) if (sname == "squeezed" && std::abs(squeeze)>0.0) { std::complex ei(0,1); double r = std::abs(squeeze); double theta = std::arg(squeeze); std::complex gamma = alpha*std::cosh(r) + std::conj(alpha)*std::exp(ei*theta)*std::sinh(r); std::complex x = gamma*std::exp(-ei*theta/2.0)/std::sqrt(std::sinh(2*r)); std::vector< std::complex > hof = HOSFSP(x, std::exp(ei*theta)*std::tanh(r), dim-1); for (int m=0;m0)&&(dims.size()==0)) { std::cout << "Could not create state: requested state unknown or parameter out of bounds" << std::endl; } } qstate::qstate( std::vector< std::complex >& vec ) { dims.push_back(vec.size()); qcoeff = vec; } qstate::qstate(std::string sname, unsigned int nx, const double& L, const double& hbar, const double& Vx0, const double& Vp0, const double& meanx0, const double& meanp0 ) { if (nx>0) { if (sname == "Gaussian") { double dx = L/nx; double pi = 3.1415927; //double e = 2.7182818; std::complex ei(0,1); double xi = 0; double norm0 = std::pow((2*pi*Vx0),-0.25)*std::sqrt(dx); double zeta0 = std::sqrt(std::fabs(Vp0 - hbar*hbar/(4*Vx0))); for (unsigned int i=0;i0)&&(dims.size()==0)) { std::cout << "Could not create state: requested state unknown" << std::endl; } } int qstate::clear() { for (unsigned int i=0;i >& vec) { dims.assign(1,vec.size()); qcoeff = vec; return 0; } int qstate::assign( std::complex* start, std::complex* finish) { qcoeff.assign(start,finish); dims.assign(1,qcoeff.size()); return 0; } int qstate::writeblock(int block) const { if (dims.size()>1) { for (unsigned int i=0;i new_dims(dims.size()-1); for (int i=0;i sys-1) { new_dims[i-1] = dims[i]; } } int new_size(1); for (int i=0;i qstate::get_elem( unsigned int i ) const { return qcoeff[i]; } int qstate::addto_elem( unsigned int i, std::complex val ) { qcoeff[i] += val; return 0; } void* qstate::get_array() { //return reinterpret_cast(&(qcoeff[0])); return &(qcoeff[0]); } std::vector qstate::get_dims() const { return dims; } int qstate::normalise() { double scale = std::sqrt((*this).norm()); // std::cout << "Cannot normalise state: norm is zero" << std::endl; for (unsigned int i=0;i qstate::inner_prod(const qstate& psi) const { std::complex result = 0; if (qcoeff.size() == psi.qcoeff.size()) { for (unsigned int i=0;i inner_prod(const qstate& psi, const qstate& chi) { return psi.inner_prod(chi); } int qstate::apply(const qoperator& op) { qstate temp(*this); clear(); if (op.matdim()==temp.qcoeff.size()) { for (unsigned int i=0;i cx) { qstate temp(*this); clear(); if (op.matdim()==temp.qcoeff.size()) { for (unsigned int i=0;iqcoeff.size()==psi.qcoeff.size()) { for (unsigned int i=0;iqcoeff[i] += psi.qcoeff[i]; } } else { std::cout << "Cannot add to (+=) the state: size mismatch\n"; } return *this; } const qstate qstate::operator*(const std::complex& cx) const { qstate result = *this; for (unsigned int i=0;i& cx, const qstate& psi) { return psi*cx; } const qstate qstate::operator*(const double& cx) const { qstate result = *this; for (unsigned int i=0;i0)&&(psi.qcoeff.size()>0)){ for (unsigned int i=0;i1) {result.dims.push_back(psi.dims[i]);} // dims[0] is the fastest index } for (unsigned int i=0;i1) {result.dims.push_back(chi.dims[i]);} } } *this = result; return 0; } qstate tensor(const qstate& psi, const qstate& chi) { qstate result = psi; result.tensor(chi); return result; } qstate tensor(const qstate& psi1, const qstate& psi2, const qstate& psi3) { qstate result = tensor(psi1,psi2); result.tensor(psi3); return result; } int qstate::shift( const int nn ) { if (nn!=0) { unsigned int nx = qcoeff.size(); if (nn>0) { unsigned int n = static_cast(nn); if (n>nx) {std::cout << " shift too big! " << std::endl;} if (n==nx) {std::cout << " warning: shifted the full length -> all elements are now zero" << std::endl;} for (unsigned int j=0;j<(nx-n);++j) {qcoeff[j] = qcoeff[j+n];} for (unsigned int j=(nx-n);j(-nn); if (n>nx) {std::cout << " shift too big! " << std::endl;} if (n==nx) {std::cout << " warning: shifted the full length -> result is the zero vector" << std::endl;} for (unsigned int j=nx-1;j>=n;j--) { qcoeff[j] = qcoeff[j-n];} for (unsigned int j=n;j>=1;j--) { qcoeff[j-1] = 0;} // cant condition on 0) { unsigned int n = static_cast(nn); if (n>nx) {std::cout << " rotation too big! " << std::endl;} std::vector< std::complex > temp; for (unsigned int j=0;j(-nn); if (n>nx) {std::cout << " rotation too big! " << std::endl;} std::vector< std::complex > temp; for (unsigned int j=nx-n;j=n;--j) {qcoeff[j] = qcoeff[j-n];} for (unsigned int j=0;j ztemp; int t_stride = static_cast(std::ceil(std::pow(2.0,target))); int t_blocks = qcoeff.size()/(2*t_stride); std::vector targetbits(qcoeff.size()); for (int i=0;i(std::ceil(std::pow(2.0,control))); int c_blocks = qcoeff.size()/(2*c_stride); for (int i=0;i ztemp; int t_stride = static_cast(std::ceil(std::pow(2.0,target))); int t_blocks = qcoeff.size()/(2*t_stride); std::vector targetbits(qcoeff.size()); for (int i=0;i(dims[0]); // void* itt = &qcoeff[0]; // // std::vector< std::complex > temp = qcoeff; // // plan1 = fftw_plan_many_dft(1, &n, chunknum, reinterpret_cast(itt), &n, 1, n, // reinterpret_cast(itt), &n, 1, n, // -1, FFTW_MEASURE); // plan2 = fftw_plan_many_dft(1, &n, chunknum, reinterpret_cast(itt), &n, 1, n, // reinterpret_cast(itt), &n, 1, n, // 1, FFTW_MEASURE); // // for (int i=0;i >::iterator itt; int chunknum = qcoeff.size()/dims[0]; int n = static_cast(dims[0]); // -----to use netlibs Fftpack uncoment: ---------------------------------- // *init_array = new double[4*n + 15]; // zffti_(&n, *init_array); //------------------------------------------------------------------------- // -----to use SCS uncomment: ----------------------------------------------------------- // itt = qcoeff.begin(); // double scale = sqrt(1.0/n); // int isys[2]; isys[0] = 1; // *init_array = new double[2*n + 256]; // double* work = new double[2*n]; // zzfft(0, n, scale, reinterpret_cast(itt), // reinterpret_cast(itt), *init_array, work, isys); // // delete[] work; // -------------------------------------------------------------------------------------- // -----Note: to use GNU's GSL nothing needs to be uncommented here ------- // -----Note: to use Steck's FFT nothing needs to be uncommented here ----- return 0; } int qstate::fft_ss1b(int sign, double* init_array) { std::vector< std::complex >::iterator itt; int chunknum = qcoeff.size()/dims[0]; int n = static_cast(dims[0]); for (int i=0;i(itt), init_array); // } else { // zfftb_(&n, reinterpret_cast(itt), init_array); // } //------------------------------------------------------------------------- // -----to use SCS uncomment: ----------------------------------------------------------- // double scale = sqrt(1.0/n); // int isys[2]; isys[0] = 1; // double* work = new double[2*n]; // zzfft(-sign, n, scale, reinterpret_cast(itt), // reinterpret_cast(itt), init_array, work, isys); // delete[] work; // -------------------------------------------------------------------------------------- // -----to use GNU's GSL uncomment: ----------------------------------------------------- // gsl_fft_complex_radix2_transform(reinterpret_cast(itt), // 1,dims[0],static_cast(sign)); // -------------------------------------------------------------------------------------- // -----to use Dan Steck's fft1d uncomment:---------------------------------------------- // sign = -sign; // ffts1d_(&sign, reinterpret_cast(itt), &n); // -------------------------------------------------------------------------------------- } return 0; } int qstate::fft_subsys1(int sign) { std::vector< std::complex >::iterator itt; int chunknum = qcoeff.size()/dims[0]; int n = static_cast(dims[0]); for (int i=0;i(itt), wsave); // } else { // zfftb_(&n, reinterpret_cast(itt), wsave); // } // delete[] wsave; //------------------------------------------------------------------------- // -----to use SCS uncomment: ----------------------------------------------------------- // double scale = sqrt(1.0/n); // int isys[2]; isys[0] = 1; // double* table = new double[2*n + 256]; // double* work = new double[2*n]; // zzfft(0, n, scale, reinterpret_cast(itt), // reinterpret_cast(itt), table, work, isys); // zzfft(-sign, n, scale, reinterpret_cast(itt), // reinterpret_cast(itt), table, work, isys); // delete[] work; // delete[] table; // -------------------------------------------------------------------------------------- // ----to use GNU's GSL uncomment: ------------------------------------------------------ // gsl_fft_complex_radix2_transform(reinterpret_cast(itt), // 1,dims[0],static_cast(sign)); // -------------------------------------------------------------------------------------- // -----to use Dan Steck's fft1d uncomment:---------------------------------------------- // sign = -sign; // ffts1d_(&sign, reinterpret_cast(itt), &n); // -------------------------------------------------------------------------------------- } return 0; } std::ostream& qstate::output(std::ostream& s) const { s << dims.size() << std::endl; for (unsigned int i=0;i(qcoeff.size()),static_cast(elems_per_line)); unsigned int fullrows = static_cast(qr.quot); unsigned int lastrown = static_cast(qr.rem); for (unsigned int i=0;i> dims_size; for (unsigned int i=0;i> dims_elem; dims.push_back(dims_elem); } unsigned int qcoeff_size; std::complex qcoeff_elem; s >> qcoeff_size; for (unsigned int i=0;i> qcoeff_elem; qcoeff.push_back(qcoeff_elem); } return s; } std::istream& operator>>(std::istream& s, qstate& psi) { psi.input(s); return s; } int qstate::output(std::ofstream& out_real, std::ofstream& out_imag) const { for (int i=0;i0)) { int chunksize = 1; for (unsigned int i=0;i<(subsys-1);++i) { chunksize = chunksize*dims[i]; } int chunknum = 1; for (unsigned int i=subsys;i zval; double val; for (unsigned int i=0;i2) { int blocktotal = 1; for (unsigned int i=2;i0) { std::vector< std::complex > temp; for (unsigned int i=0;i dims_vec ) { if (dim>0) { std::vector< std::complex > temp; for (unsigned int i=0;i > temp; temp.push_back(p); temp.push_back(std::sqrt(p*(1-p))*std::polar(1.0,phi)); elements.push_back(temp); temp[0] = std::conj(temp[1]); temp[1] = (1-p); elements.push_back(temp); dims.push_back(2); } qmatrix::qmatrix(double p, double q, double phi) { std::vector< std::complex > temp; std::complex corner = std::sqrt(p*q)*std::polar(1.0,phi); temp.push_back(p); temp.push_back(corner); elements.push_back(temp); temp[0] = std::conj(corner); temp[1] = q; elements.push_back(temp); dims.push_back(2); } qmatrix::qmatrix(std::string sname, unsigned int dim ) { if (dim>0) { std::vector< std::complex > temp; // *** should call qmatrix(dim) here for (unsigned int i=0;i psi_dims = psi.get_dims(); unsigned int size = 1; for (unsigned int i=0;i > temp; // *** should call qmatrix(dim) here for (unsigned int i=0;i0) { std::vector< std::complex > temp; // *** should call qmatrix(dim) here for (unsigned int i=0;i qmatrix::get_elem( unsigned int row, unsigned int col ) const { return elements[col][row]; } int qmatrix::addto_elem( unsigned int row, unsigned int col, std::complex val ) { elements[col][row] += val; return 0; } std::vector qmatrix::get_dims( ) const { return dims; } int qmatrix::display(std::string name, unsigned int prec ) const { std::cout << name << std::endl; for (unsigned int j=0;j std::fabs(zi)*1000) || ((std::fabs(zr)==0.0) && (std::fabs(zi)==0.0))) { std::cout << std::setw(prec) << std::setprecision(prec) << zr << " "; } if (std::fabs(zi) > std::fabs(zr)*1000) { std::cout << std::setw(prec) << std::setprecision(prec) << zi << "i "; } else { if (std::fabs(zr) < std::fabs(zi)*1000) { std::cout << std::setw(prec) << std::setprecision(prec) << zr << "+" << zi << "i "; } } } std::cout << " "; } std::cout << std::endl; } std::cout << std::endl; } return 0; } std::complex qmatrix::trace() const { std::complex temp(0); for (unsigned int i=0;i new_dims(dims.size()-1); for (int i=0;i sys-1) { new_dims[i-1] = dims[i]; } } int new_size(1); for (int i=0;i trace( const qmatrix& rho) { return rho.trace(); } int qmatrix::normalise() { *this = (1.0/this->trace())**this; return 0; } std::complex qmatrix::inner_prod(const qmatrix& sigma) const { std::complex result = 0; if (elements.size() == sigma.elements.size()) { for (unsigned int i=0;i temp(0); for (unsigned int k=0;k inner_prod(const qmatrix& rho, const qmatrix& sigma) { return rho.inner_prod(sigma); } double qmatrix::fidelity( const qstate& psi) const { qoperator op(*this); // note: not efficient return std::sqrt(op.expect(psi).real()); } int qmatrix::apply(const qoperator& op) // A \rho A^\dagger { qmatrix temp(elements.size()); if (op.matdim()==temp.elements.size()) { for (unsigned int i=0;i cx) { apply(op); *this = cx**this; return 0; } const qmatrix qmatrix::operator+(const qmatrix& rho) const { qmatrix result(*this); unsigned int size = result.elements.size(); if (size==rho.elements.size()) { for (unsigned int i=0;ielements.size()); unsigned int size = this->elements.size(); unsigned int sigsize = sig.elements.size(); if (size == sigsize) { for (unsigned int i=0;ielements[j][i]*sig.elements[k][j]; } } } } else { std::cout << "Cannot multiply density matricies: size missmatch" << std::endl; } return rho; } const qmatrix qmatrix::operator*(const std::complex& cx) const { qmatrix result = *this; unsigned int size = elements.size(); for (unsigned int i=0;i& cx, const qmatrix& rho) { return rho*cx; } const qmatrix operator*(const double& c, const qmatrix& rho) { return rho*c; } int qmatrix::tensor(const qmatrix& sig) { unsigned int rhosize = this->elements.size(), sigsize = sig.elements.size(); qmatrix result(rhosize*sigsize); if ((rhosize>0)&&(sigsize>0)) { for (unsigned int coli=0;colielements[colj][j]*sig.elements[coli][i]; } } } } result.dims = this->dims; for (unsigned int i=0;i* z_ptr ) // { // if (dims.size()==2) { // if (dims[1]!=2) { // std::cout << "Error (matrix::fftw): matrix::fftw only works if the second subsystem has dimension 2" << std::endl; // } // } // if (dims.size()>2) { // std::cout << "Error (matrix::fftw): matrix::fftw only works for density matrices with 2 subsystems" << std::endl; // } // else { // void *v_ptr; v_ptr = z_ptr; // fftw_complex *ptr = reinterpret_cast(v_ptr); // // int dim1 = dims[0]; // int dim2; // if (dims.size()==2) { dim2 = dims[1]; } else { dim2 = 1; } // int howmany_cols = dim1*dim2*dim2; // // // collumn transform, forward and back // plan1c = fftw_plan_many_dft(1, &dim1, howmany_cols, ptr, &dim1, 1, dim1, ptr, &dim1, 1, dim1, -1, FFTW_MEASURE); // plan2c = fftw_plan_many_dft(1, &dim1, howmany_cols, ptr, &dim1, 1, dim1, ptr, &dim1, 1, dim1, 1, FFTW_MEASURE); // // // row transform, forward and back // fftw_iodim row_layout; // row_layout.n = dim1; // row_layout.is = row_layout.os = dim1*dim2; // // fftw_iodim howmany_rows[1]; // howmany_rows[0].n = dim1*dim2; // howmany_rows[0].is = howmany_rows[0].os = 1; // //howmany_rows[1].n = dim2; // //howmany_rows[1].is = howmany_rows[0].os = dim1*dim1*dim2; // // plan1r[0] = fftw_plan_guru_dft(1, &row_layout, 1, howmany_rows, ptr, ptr, 1, FFTW_MEASURE); // plan1r[1] = fftw_plan_guru_dft(1, &row_layout, 1, howmany_rows, ptr + dim1*dim1*dim2, ptr + dim1*dim1*dim2, 1, FFTW_MEASURE); // plan2r[0] = fftw_plan_guru_dft(1, &row_layout, 1, howmany_rows, ptr, ptr, -1, FFTW_MEASURE); // plan2r[1] = fftw_plan_guru_dft(1, &row_layout, 1, howmany_rows, ptr + dim1*dim1*dim2, ptr + dim1*dim1*dim2, -1, FFTW_MEASURE); // } // return 0; // } // // int qmatrix::fftw_fin( fftw_plan* plan1, fftw_plan& plan2, fftw_plan* plan3, fftw_plan& plan4 ) // { // fftw_destroy_plan(plan1[0]); // fftw_destroy_plan(plan1[1]); // fftw_destroy_plan(plan2); // fftw_destroy_plan(plan3[0]); // fftw_destroy_plan(plan3[1]); // fftw_destroy_plan(plan4); // return 0; // } // // int qmatrix::fftw( fftw_plan* plan1, fftw_plan& plan2 ) // { // fftw_execute(plan1[0]); // fftw_execute(plan1[1]); // fftw_execute(plan2); // return 0; // } // ---------------------------------------------------------------------- int qmatrix::copy_to_array_col( std::complex * ptr, unsigned int len) { if (len != elements.size()*elements[0].size()) { std::cout << "Error (qmatrix::copy_to_array): length mismatch" << std::endl; } else { unsigned int side = elements.size(); for (unsigned int j=0;j * ptr, unsigned int len) { if (len != elements.size()*elements[0].size()) { std::cout << "Error (qmatrix::copy_to_array): length mismatch" << std::endl; } else { unsigned int side = elements.size(); for (unsigned int j=0;j * ptr, unsigned int len) { if (len != elements.size()*elements[0].size()) { std::cout << "Error (qmatrix::copy_to_array): length mismatch" << std::endl; } else { unsigned int side = elements.size(); for (unsigned int j=0;j * ptr, unsigned int len) { if (len != elements.size()*elements[0].size()) { std::cout << "Error (qmatrix::copy_to_array): length mismatch" << std::endl; } else { unsigned int side = elements.size(); for (unsigned int j=0;j0)) { int chunksize = 1; for (unsigned int i=0;i<(subsys-1);++i) { chunksize = chunksize*dims[i]; } int chunknum = 1; for (unsigned int i=subsys;i dim_vec = rho.get_dims(); dimension = 1; for (unsigned int i=0;i elem; double tol(1e-7/dimension); for (unsigned int i=0;i tol) { row.push_back(i); col.push_back(j); val.push_back(elem); } } } } qoperator::qoperator(std::string opname, unsigned int size ) { dimension = size; if (size>0) { if (opname=="identity") { for (unsigned int i=0;i ei(0,1); row.push_back(0); col.push_back(1); val.push_back(-ei); row.push_back(1); col.push_back(0); val.push_back(ei); } if ((opname=="spinZ")&&(size==2)) { row.push_back(0); col.push_back(0); val.push_back(1.0); row.push_back(1); col.push_back(1); val.push_back(-1.0); } if ((opname=="destroy")&&(size>1)) { for (unsigned int i=0;i<(size-1);++i) { row.push_back(i); col.push_back(i+1); val.push_back(sqrt(1.0*(i+1))); } } if ((opname=="create")&&(size>1)) { for (unsigned int i=0;i<(size-1);++i) { row.push_back(i+1); col.push_back(i); val.push_back(sqrt(1.0*(i+1))); } } if ((opname=="Hadamard")&&(size==2)) { for (unsigned int i=0;ix")&&(size==2)) { row.push_back(0); col.push_back(0); val.push_back(std::sqrt(0.5)); row.push_back(0); col.push_back(1); val.push_back(std::sqrt(0.5)); row.push_back(1); col.push_back(0); val.push_back(std::sqrt(0.5)); row.push_back(1); col.push_back(1); val.push_back(-std::sqrt(0.5)); } if ((opname=="rotate:z->y")&&(size==2)) { std::complex ei(0,1); row.push_back(0); col.push_back(0); val.push_back(-ei*std::sqrt(0.5)); row.push_back(0); col.push_back(1); val.push_back( ei*std::sqrt(0.5)); row.push_back(1); col.push_back(0); val.push_back(std::sqrt(0.5)); row.push_back(1); col.push_back(1); val.push_back(std::sqrt(0.5)); } if ((opname=="rotate:z->x+z")&&(size==2)) { row.push_back(0); col.push_back(0); val.push_back(-0.92387953); row.push_back(0); col.push_back(1); val.push_back( 0.38268343); row.push_back(1); col.push_back(0); val.push_back(-0.38268343); row.push_back(1); col.push_back(1); val.push_back(-0.92387953); } if ((opname=="rotate:z->x-z")&&(size==2)) { row.push_back(0); col.push_back(0); val.push_back( 0.38268343); row.push_back(0); col.push_back(1); val.push_back(-0.92387953); row.push_back(1); col.push_back(0); val.push_back( 0.92387953); row.push_back(1); col.push_back(1); val.push_back( 0.38268343); } if ((opname=="rotate:z->x+y")&&(size==2)) { std::complex ei(0,1); row.push_back(0); col.push_back(0); val.push_back(0.5 - 0.5*ei); row.push_back(0); col.push_back(1); val.push_back(0.5 - 0.5*ei); row.push_back(1); col.push_back(0); val.push_back( std::sqrt(0.5)); row.push_back(1); col.push_back(1); val.push_back(-std::sqrt(0.5)); } if ((opname=="rotate:z->x-y")&&(size==2)) { std::complex ei(0,1); row.push_back(0); col.push_back(0); val.push_back(0.5 + 0.5*ei); row.push_back(0); col.push_back(1); val.push_back(0.5 + 0.5*ei); row.push_back(1); col.push_back(0); val.push_back( std::sqrt(0.5)); row.push_back(1); col.push_back(1); val.push_back(-std::sqrt(0.5)); } if ((opname=="lineig")&&(size>1)) { for (unsigned int i=0;i1)&&(val.size()==0)) { std::cout << "Error creating operator. You requested: " << opname << std::endl; } } qoperator::qoperator(std::string opname, std::vector & x, double beta, unsigned int n ) { dimension = x.size(); if (n>dimension) { std::cout << "Warning: new basis cannot be larger than current dimension" << std::endl; n = dimension; } if (((opname=="transform:x->Fock")||(opname=="transform:p->Fock"))&&(dimension>1)&&(n>1)) { // generate the first n Hermite polynomials std::vector one(x.size(),1.0); std::vector< std::vector > HO_eigs(0), HO_imag(0); HO_eigs.push_back(one); std::vector poly(0); for (unsigned int i=0;i base_func(dimension); for (unsigned int i=0;i n_func(n); n_func[0] = 1; for (unsigned int m=1;m0;--l) { // orthogonalise inprod = 0.0; for (unsigned int i=0;iFock qstate psi; std::vector< std::complex > temp(dimension); HO_imag = HO_eigs; if (opname=="transform:p->Fock") { for (unsigned int m = 0;m iu(0,1); // the HO-eigenfunctions are the rows of the transform operator for (unsigned int i=0;iFock (currently done above) // if (opname=="transform:p->Fock") { // for (unsigned int i=0;i0)&&(dimension>0)&&(val.size()==0)) { std::cout << "Error creating transform. You requested: " << opname << std::endl; } } qoperator::qoperator( std::string opname, const qstate& psi) { if (opname=="swap") { std::vector sys_dims = psi.get_dims(); if ((sys_dims.size() == 2) && (sys_dims[0]==sys_dims[1])) { for (unsigned int i=0;i >& Fx) { dimension = Fx.size(); for (unsigned int i=0;i& Fx) { dimension = Fx.size(); for (unsigned int i=0;i cx) const { qstate result(psi); result.apply(*this,cx); return result; } std::complex qoperator::expect(const qstate& psi) const { qstate temp(psi); temp.apply(*this); return inner_prod(psi,temp); } void qoperator::normalize() { double opnorm = 0; for (unsigned int i=0;i temp(row); row = col; col = temp; for (unsigned int i=0;i t ) { for (unsigned int i=0;i ei(0,1); for (unsigned int i=0;i qoperator::op_inner_prod( const qoperator& qopin) const { std::complex result = 0; for (unsigned int i=0;i& cx) const { qoperator op = *this; for (unsigned int i=0;i& cx, const qoperator& op) { return op*cx; } const qoperator operator*(const double& c, const qoperator& op) { return op*c; } const qoperator& qoperator::operator+=(const qoperator& op1) { qoperator op2 = *this; if (op1.dimension!=op2.dimension) { std::cout << "cannot add operators: different dimensions\n"; } bool exists; for (unsigned int i=0;i a,b,c,d; a = rho.get_elem(0,0); b = rho.get_elem(0,1); c = rho.get_elem(1,0); d = rho.get_elem(1,1); std::complex lam1 = (a+d)/2.0 + std::sqrt( (a+d)*(a+d)/4.0 + b*c - a*d ); std::complex lam2 = (a+d)/2.0 - std::sqrt( (a+d)*(a+d)/4.0 + b*c - a*d ); std::complex y1 = std::sqrt( (lam1-a)*std::conj(lam1-a) / ( (lam1-a)*std::conj(lam1-a) + b*std::conj(b) ) ); std::complex x1 = y1*b/(lam1-a); std::complex y2 = std::sqrt( x1*std::conj(x1) / ( x1*std::conj(x1) + y1*std::conj(y1) ) ); std::complex x2 = -y2*std::conj(y1)/std::conj(x1); val[0] = x1; row.push_back(1); col.push_back(0); val.push_back( y1 ); row.push_back(0); col.push_back(1); val.push_back( x2 ); row.push_back(1); col.push_back(1); val.push_back( y2 ); dimension = 2; } int qoperator::display( std::string name, unsigned int prec ) const { qmatrix rho(*this); rho.display(name, prec); return 0; } int qoperator::displaylist() const { for (unsigned int i=0;i& noise) { int ns = noise.size()/2; double tn1,tn2,rn; for (unsigned int i=0;i= 1 || rn == 0) { tn1 = 2*static_cast(rand())/static_cast(RAND_MAX) - 1; tn2 = 2*static_cast(rand())/static_cast(RAND_MAX) - 1; rn = tn1*tn1 + tn2*tn2; } rn = std::sqrt((-2*std::log(rn)/rn)); noise[2*i] = tn1*rn; noise[2*i+1] = tn2*rn; } return 0; } // ******************* // auxillary functions // ******************* // the following requires GNU's gsl // int fft(std::vector< std::complex >& x, gsl_fft_direction sign) // { // std::vector< std::complex >::iterator itt = x.begin(); // return gsl_fft_complex_radix2_transform(reinterpret_cast(itt), // 1,x.size(),sign); // }