qgame++.cpp

00001 /***************************************************************************
00002  *   QGame++                                                               *
00003  *   =======                                                               *
00004  *   A Quantum Gate And Measurement Emulator.                              *
00005  *                                                                         *
00006  *   Copyright (C) 2003/04 by Manuel Nickschas                             *
00007  *   <qgame-devel@nickschas.de>                                            *
00008  *                                                                         *
00009  *   This program is free software; you can redistribute it and/or modify  *
00010  *   it under the terms of the GNU General Public License as published by  *
00011  *   the Free Software Foundation; either version 2 of the License, or     *
00012  *   (at your option) any later version.                                   *
00013  *                                                                         *
00014  *   This program is distributed in the hope that it will be useful,       *
00015  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017  *   GNU General Public License for more details.                          *
00018  *                                                                         *
00019  *   You should have received a copy of the GNU General Public License     *
00020  *   along with this program; if not, write to the                         *
00021  *   Free Software Foundation, Inc.,                                       *
00022  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00023  ***************************************************************************/
00024 
00025 #include "qgame++.h"
00026 
00027 using namespace std;
00028 using namespace qgame;
00029 
00030 ostream & qgame::operator<<(ostream &o, const Result &r) {
00031   o << "Misses: " << r.misses << endl;
00032   o << "Max error: " << r.maxError << endl;
00033   o << "Average error: " << r.avgError << endl;
00034   o << "Max expected oracles: " << r.maxExpOracles << endl;
00035   o << "Average expected oracles: " << r.avgExpOracles << endl;
00036   return o;
00037 }
00038   
00039 
00040 QSys::QSys() {
00041   prg = NULL;
00042   numQubits = 0;
00043   oracleTT = "";
00044 }
00045 
00046 QSys::~QSys() {
00047   delete prg;
00048 }
00049 
00050 void QSys::init (int numqb, QProgram *p, const string &tt) {
00051   prg = p;
00052   instrPnt = 0;
00053   oracleTT = tt;
00054   prob = 1;
00055   numQubits = numqb;
00056   reg = Qureg(numqb);
00057   prg->installOracle(tt);
00058   oracleCount = 0;
00059   execInstr.clear();
00060   measureHistory.clear();
00061   execInstr = vector<bool>(p->length(), true);
00062 };
00063 
00064 void QSys::setReg(const Qureg &r) {
00065   reg = r;
00066 }
00067 
00068 Qureg QSys::getReg() {
00069   return reg;
00070 }
00071 
00072 double QSys::getProb() {
00073   return prob;
00074 }
00075 
00076 void QSys::setProb(double p) {
00077   prob = p;
00078 }
00079 
00080 int QSys::getOracleCount() {
00081   return oracleCount;
00082 }
00083 
00084 void QSys::appendMeasurement(QubitList q, int outcome, double prob) {
00085   Measurement m;
00086   m.qubit = q[0];
00087   m.result = outcome;
00088   m.prob = prob;
00089   measureHistory.push_back(m);
00090 }
00091 
00092 QSys *QSys::clone(double p) {
00093   QSys *res = new QSys;
00094   res->prob      = p;
00095   res->instrPnt  = instrPnt;
00096   res->prg       = prg;
00097   res->oracleTT  = oracleTT;
00098   res->numQubits = numQubits;
00099   res->reg       = reg;
00100   res->oracleCount = oracleCount;
00101   res->execInstr = execInstr;
00102   res->measureHistory = measureHistory;
00103   return res;
00104 }
00105 
00106 void QSys::apply(QGate *gate, const QubitList &qubits) throw(Error) {
00107   if(gate->numQb() != qubits.size()) throw(Error(E_MISMATCH));
00108   vector<QuSubReg> subregs = reg.getSubRegs(qubits);
00109   for(int sr = 0; sr < subregs.size(); sr++) {
00110     gate->apply(subregs[sr]);
00111   }
00112 }
00113 
00114 void QSys::apply(const QInstr &instr) throw(Error) {
00115   if(!instr.gate) return;
00116   if(instr.type == ORACLE) oracleCount++;
00117   else if(instr.type == LIMITED_ORACLE) {
00118     if(oracleCount >= instr.extra) return;
00119     else oracleCount++;
00120   }
00121   apply(instr.gate, instr.qubits);
00122 }
00123 
00124 vector<QSys*> QSys::execute(int numqb, QProgram *p, const string &tt) throw(Error) {
00125   QSys *sys = new QSys;
00126   sys->init(numqb, p, tt);
00127   return sys->exec();
00128 }
00129 
00130 vector<QSys*> QSys::exec() throw(Error) {
00131   vector<QSys*> result;
00132   bool term = false;
00133   while(!term && instrPnt<prg->length()) {
00134     if(!execInstr[instrPnt]) { instrPnt++; continue; }
00135     QInstr *instr = (*prg)[instrPnt];
00136     if(instr->gate) {
00137       //cerr << "\napplying: "<< *instr;
00138       apply(*instr);
00139       instrPnt++;
00140     } else {
00141       instrPnt++;
00142       switch(instr->type) {
00143         case MEASURE: {
00144           vector<double> probs = reg.getProbabilities(instr->qubits);
00145           QSys *ifsys = NULL;
00146           QSys *elsys = NULL;
00147           if(probs[0]>0) elsys = this;
00148           if(probs[1]>0) {
00149             if(elsys) ifsys = clone(prob);
00150             else ifsys = this;
00151           }
00152           if(ifsys) { 
00153             ifsys->reg.collapse(instr->qubits, 1);
00154             ifsys->setProb(ifsys->getProb() * probs[1]);
00155             ifsys->appendMeasurement(instr->qubits, 1, probs[1]);
00156           }
00157           if(elsys) {
00158             elsys->reg.collapse(instr->qubits, 0);
00159             elsys->setProb(elsys->getProb() * probs[0]);
00160             elsys->appendMeasurement(instr->qubits, 0, probs[0]);
00161           }
00162           /* mark the appropriate branches as invalid by setting the execInstr[] flag to false */
00163           int i = instrPnt;
00164           int d = 0; 
00165           bool flg = false; bool branch = true;
00166           QSys *curSys = elsys;
00167           while(!flg && i<prg->length()) {
00168             if(curSys) curSys->execInstr[i] = false;
00169             switch((*prg)[i]->type) {
00170             case MEASURE:   // handle nested measurements
00171               d+=2; break;
00172             case END:
00173               if(d>0) d--;  // belongs to a nested measurement -> ignore
00174               else {
00175                 if(branch) {
00176                   if(elsys) elsys->instrPnt = i+1;
00177                   if(!ifsys) flg = true;
00178                   else { branch = false; curSys = ifsys; }
00179                 } else flg = true;  // we are done with marking...
00180               }
00181               break;
00182             }
00183             i++;
00184           }
00185           if(ifsys && elsys) {
00186             vector<QSys*> ifRes = ifsys->exec();  // execute if-branch
00187             for(int r = 0; r<ifRes.size(); r++) result.push_back(ifRes[r]);
00188           }
00189           break;
00190         }
00191         case HALT:
00192           term = true;
00193           break;
00194           
00195         case ORACLE:
00196           throw(Error(E_NOORACLE));
00197           break;
00198         
00199         case PRINTAMPS:
00200           //cout << "\nQuReg contents after measuring";
00201           //for(int i = 0; i<measureHistory.size(); i++) {
00202           //  cout << "\n  q" <<measureHistory[i].qubit << " = " << measureHistory[i].result
00203           //       << " (p = " << measureHistory[i].prob << ")";
00204           //}
00205           //cout << "\n" << reg;
00206           cout << *this;
00207           break;
00208         //default:
00209           
00210       }   
00211     }
00212   }
00213   result.push_back(this);
00214   return result;
00215 }
00216 
00217 Result QSys::testProgram(int numqb, QProgram *p, const std::vector<TestCase> &cases, 
00218                     const QubitList &finm, double thresh) throw(Error) {
00219   Result res;
00220   res.misses = 0;
00221   res.avgError = res.avgExpOracles = res.maxError = res.maxExpOracles = 0;
00222   double totalErr = 0;
00223   double totalExpOracles = 0;
00224   for(int c = 0; c < cases.size(); c++) {
00225     TestCase tcase = cases[c];
00226     vector<QSys*> systems = execute(numqb, p, tcase.oracleTT);
00227     double expOracles = 0;
00228     double rawerr = 1.0;
00229     for(int s=0; s<systems.size(); s++) {
00230       rawerr -= systems[s]->getReg().getProbabilities(finm)[tcase.desiredRes] * systems[s]->getProb();
00231       expOracles += systems[s]->getProb() * systems[s]->getOracleCount();  
00232     }
00233     if(rawerr<-0.000000001) { cerr << "\nWARNING: rawerr = "<<rawerr; } // DEBUG
00234     if(rawerr>thresh) res.misses++;
00235     totalErr += rawerr;
00236     if(rawerr > res.maxError) res.maxError = rawerr;
00237     totalExpOracles += expOracles;
00238     if(expOracles > res.maxExpOracles) res.maxExpOracles = expOracles;
00239   }
00240   res.avgError = totalErr / cases.size();
00241   res.avgExpOracles = totalExpOracles / cases.size();
00242   return res;
00243 }
00244 
00245 ostream& qgame::operator<<(std::ostream &o, const QSys &s) {
00246   o << "\n========================================================================";
00247   o << "\nQSys ("<<s.numQubits<<" qubits, prior prob = "<<s.prob<<")\n";
00248   o << "\nMeasurement History:";
00249   
00250   for(int i = 0; i<s.measureHistory.size(); i++) {
00251     o << "\n   q" <<s.measureHistory[i].qubit << " = " << s.measureHistory[i].result 
00252          << " (p = " << s.measureHistory[i].prob << ")";
00253   }
00254   o << "\nRegister:" << s.reg << "\n";
00255   
00256   return o;
00257 
00258 }
00259 
00260 /*****************************************************************************
00261  * Documentation - To be used by Doxygen. Please see the autogenerated
00262  * docs in the doc/ subdir for a formatted version of this ;-)
00263  *****************************************************************************/
00264 

Generated on Sat Apr 3 18:42:27 2004 for QGame++ by doxygen 1.3.5