/********************************************************************** This file is part of the Quantum Computation Language QCL. (c) Copyright by Bernhard Oemer , 1998 This program comes without any warranty; without even the implied warranty of merchantability or fitness for any particular purpose. This program is free software under the terms of the GNU General Public Licence (GPL) version 2 or higher ************************************************************************/ #pragma implementation #include "quheap.h" #include "error.h" #include #include int isStateModified=1; term string2term(const string& s,int l) { term t(l); istringstream buf(s.c_str()); buf >> t; return t; } string term2string(const term& t,int binary) { ostringstream buf; buf << t; return string(buf.str()); } class opFANOUT : public opGate { int inv; public: opFANOUT(int n,int i) : opGate(2*n) { inv=i; } virtual term funct(const bitvec& v) const { bitvec a(v.getbits(0,bits()/2)); bitvec b(v.getbits(bits()/2,bits()/2)); b^=a; a+=b; return term(a,1.0); }; virtual opOperator *newclone() const { return new opFANOUT(bits()/2,inv); } }; QuHeap::QuHeap(int n,int d) { bs=new quBaseState(n); delbs=1; nbits=n; mbits=bitvec(n).qnot(); nfree=n; mfree=bitvec(n).qnot(); ndirty=0; mdirty=bitvec(n); parent=0; delayed=d; init(); } QuHeap::QuHeap(quState *s,int d) { int n; bs=s; delbs=0; n=s->mapbits(); nbits=n; mbits=bitvec(n).qnot(); nfree=n; mfree=bitvec(n).qnot(); ndirty=0; mdirty=bitvec(n); parent=0; delayed=d; init(); } QuHeap::QuHeap(QuHeap *h,int d) { bs=h->bs; delbs=0; nbits=h->nbits; mbits=h->mbits; nfree=h->nfree; mfree=h->mfree; ndirty=h->ndirty; mdirty=h->mdirty; parent=h; delayed=d; regs=h->regs; init(); } void QuHeap::init() { ignore=0; qconds=0; } QuHeap::~QuHeap() { while(!ql.empty()) { if(ql.back().s) delete ql.back().s; ql.pop_back(); } while(!cd.empty()) { centry c=cd.back(); if(c.ev) delete c.ev; if(c.reg) delete c.reg; if(c.reg0) delete c.reg0; cd.pop_back(); } while(!regs.empty()) { regs.pop_back(); } if(bs && delbs) qcl_delete(bs); } tValue QuHeap::qualloc(int n,BaseType t) { int i,o=0,l,ll; quState *ss; if(n==0) return tValue(new quEmpty(*bs),t); if(n>nfree) throw tError(errMEM,"out of quantum memory"); while(o+n<=nbits) { for(i=o;i=o) break; }; if(o+n<=nbits) { ss=bs->newsubstring(n,o); nfree-=n; mfree&=~ ss->mapmask(); return tValue(ss); }; o=l=0; ss=0; while(on) ll=n-l; if(ss) { ss=new quCombState(ss,bs->newsubstring(l,o),1); } else { ss=bs->newsubstring(l,o); }; l+=ll; } if(!ss || l!=n || ss->mapbits()!=n) { if(ss) qcl_delete(ss); throw tError(errMEM,"register allocation failed"); } nfree-=n; mfree&=~ ss->mapmask(); return tValue(ss,t); } void QuHeap::qufree(tValue var) { int n; bitvec m; quState *ss; if(!var.isQuExpr()) throw tError(errINVTYP); ss=var.qustate(); n=ss->mapbits(); m=ss->mapmask(); if(n>nbits-nfree-ndirty || !zero(m & mdirty) || !zero(m & mfree)) throw tError(errMEM,"qufree: overlapping registers"); nfree+=n; mfree|=m; } tValue QuHeap::measure(tValue var) { bitvec m; if(!var.isQuExpr()) throw tError(errINVTYP); if(var.qustate()->mapbits()>8*(int)sizeof(tInt)) throw tError(errRANGE,"register loo long to measure"); m=var.qustate()->measure(); return(tValue((tInt)m.getword())); } void QuHeap::reset() { bs->reset(); } void QuHeap::qcond(quState *s,SymTable *gl) { QuCond qc=s; qconds++; qif(qc,gl); } int QuHeap::qif(QuCond qc,SymTable *gl,int has_else) { centry c; if(ignore) { int i=ncond(); fmask.push(0); if(fmask.length()==oldfmask.length() && oldfmask==fmask) { if((int)cd.size()!=ncond()) throw tError(errINT,"qucond stack mismatch"); return 0; } if(ncond(); for(v=qc.first();v.length();v=qc.next()) { quentry q; q=makeentry(CNOTID,gl,0,0,c.tmp,tValue(new quMask(*bs,v),tQUCONST)); callentry(q,gl); q=makeentry(CNOTID,gl,1,0,c.tmp,tValue(new quMask(*bs,v),tQUCONST)); c.ev->push_back(q); } } catch(...) { qufree(c.tmp); throw; } v=c.tmp.qustate()->mapmask(); } c.reg=new quMask(*bs,v); if(ncond()) v|=cd.back().reg0->mapmask(); c.reg0=new quMask(*bs,v); fmask.push(0); cd.push_back(c); return !c.qc0.isFalse(); } int QuHeap::qelse(QuCond qc,SymTable *gl) { if(ncond()==0 || fmask.top()!=0) throw tError(errINT,"unexpected else-statement"); if(fmask.length()==oldfmask.length() && oldfmask==fmask) { if((int)cd.size()!=ncond()) throw tError(errINT,"qucond stack mismatch"); ignore=0; } fmask.pop(); if(ignore) { fmask.push(1); return 1; } centry c=cd.back(); cd.pop_back(); if(qc!=c.qc) throw tError(errINT,"if- and else-conditions don't match"); c.qc=~qc; if(ncond()) { c.qc0=cd.back().qc0 & qc; } else { c.qc0=qc; } if(c.reg) { if(!c.ev) c.ev=new vector; callentry(makeentry(NOTID,gl,0,0,*c.reg),gl); c.ev->push_back(makeentry(NOTID,gl,1,0,*c.reg)); } c.inv^=c.reg->mapmask(); fmask.push(1); cd.push_back(c); return !c.qc0.isFalse(); } void QuHeap::qendif(SymTable *gl) { if(fmask.length()==0) throw tError(errINT,"unexpected endif"); fmask.pop(); centry c=cd.back(); cd.pop_back(); while(c.ev && !c.ev->empty()) { callentry(c.ev->back(),gl); c.ev->pop_back(); } if(c.tmp.isQuExpr()) qufree(c.tmp); if(c.ev) delete c.ev; if(c.reg) delete c.reg; if(c.reg0) delete c.reg0; } int QuHeap::qendfork(SymTable *gl) { while(ncond() && fmask.top()) { qendif(gl); } oldfmask=fmask; ignore=(ncond()>qconds); if(ignore) fmask=bitvec(qconds); else while(ncond()) qendif(gl); return ignore; } void QuHeap::add(sRoutDef *d,SymTable *s,int inv) { quentry q; if(ignore) return; q.d=d; q.s=s; q.i=inv; ql.push_back(q); } void QuHeap::apply(SymTable *gl,int inv) { int i; if(inv) { for(i=ql.size()-1;i>=0;i--) { ql[i].d->invoke(ql[i].s,gl,this,!ql[i].i); } } else { for(i=0;i<(int)ql.size();i++) { ql[i].d->invoke(ql[i].s,gl,this,ql[i].i); } } } void QuHeap::call(tId op,SymTable *gl,int inv,int cnd,tValue a,tValue b,tValue c) { callentry(makeentry(op,gl,inv,cnd,a,b,c),gl); } void QuHeap::call(sRoutDef *d,SymTable *loc,SymTable *gl,int inv,int cnd) { quentry q; q.d=d; q.s=loc; q.i=inv; if(q.d->isCondDef()) { if(cond() && cnd) q.s->put(&CONDDEF,tValue(*cond(),tQUCONST)); else q.s->put(&CONDDEF,tValue(new quEmpty(*state()),tQUCONST)); } callentry(q,gl); } void QuHeap::callentry(const quentry& q,SymTable *gl) { if(ignore) return; if(delayed) { ql.push_back(q); } else { try { q.d->invoke(q.s,gl,this,q.i); } catch (...) { delete q.s; throw; } delete q.s; } } QuHeap::quentry QuHeap::makeentry(tId op,SymTable *gl,int inv,int cnd, tValue a,tValue b,tValue c) { quentry q; void *cc; sDef *dd; q.d=(sRoutDef*)gl->getDef(op); if(!q.d || !q.d->isQuDef()) throw tError(errSYMBOL,"cannot find operator "+op); if(cond() && !q.d->isCondDef()) throw tError(errSYMBOL,"operator "+op+" is not conditional"); q.s=new SymTab(); if(a.isDefined() && (dd=q.d->args()->first(cc))) q.s->put(dd,a); if(b.isDefined() && (dd=q.d->args()->next(cc))) q.s->put(dd,b); if(c.isDefined() && (dd=q.d->args()->next(cc))) q.s->put(dd,c); if(q.d->isCondDef()) { if(cond() && cnd) q.s->put(&CONDDEF,tValue(*cond(),tQUCONST)); else q.s->put(&CONDDEF,tValue(new quEmpty(*state()),tQUCONST)); } q.i=inv; return q; } string QuHeap::prtstr() { string ostr; int i; if(parent) ostr+=parent->prtstr(); ostr+="{ "; for(i=0;i<(int)ql.size();i++) { if(ql[i].i) ostr+="!"; ostr+=ql[i].d->id(); ostr+=ql[i].s->prtstr(); ostr+=" "; } ostr+="}"; return ostr; } int QuHeap::load(ifstream& f) { int l=-1; term t; string s; char buf[1024]; //f.scan("QCL begin state %d qubits\n",&l); f.getline(buf,1024); sscanf(buf,"QCL begin state %d qubits\n",&l); if(l!=nbits) return 2; bs->opbegin(); while(!f.eof()) { f.getline(buf,1024); s=buf; if(s=="QCL end state") break; t=string2term(s,l); if(t.nbits()==0) { return 1; } bs->opadd(t); } bs->opend(); return 0; } int QuHeap::save(ofstream& f) { int i; string s; f << "QCL begin state " << bs->basebits() << " qubits\n"; if(!f) return 1; bs->normalize(); for(i=0;ibaseterms();i++) { f << bs->baseterm(i) << "\n"; if(!f) return 1; } f << "QCL end state\n"; if(!f) return 1; return 0; }