add classical if, new teleport and rippleadd examples

This commit is contained in:
Andrew W. Cross 2017-03-27 15:19:59 -04:00
parent 9be253b409
commit 8fc60bb1f3
20 changed files with 162 additions and 41 deletions

View File

@ -28,4 +28,4 @@ class Barrier(Instruction):
if j != len(self.arg) - 1:
s += ","
s += ";"
return s
return s # no c_if on barrier instructions

View File

@ -9,4 +9,6 @@ from ._register import Register
class ClassicalRegister(Register):
"""Implement a classical register."""
pass
def qasm(self):
"""Return OPENQASM string for this register."""
return "creg %s[%d];" % (self.name, self.sz)

View File

@ -21,13 +21,7 @@ class CompositeGate(Gate):
param = list of real parameters
arg = list of pairs (Register, index)
"""
for a in arg:
if not isinstance(a[0], QuantumRegister):
raise QISKitException("argument not (QuantumRegister, int) "
+ "tuple")
self.name = name
self.param = param
self.arg = arg
super(Gate, self).__init__(name, param, arg)
self.data = [] # gate sequence defining the composite unitary
self.inverse_flag = False
@ -36,6 +30,12 @@ class CompositeGate(Gate):
self.data.append(g)
return g
def set_program(self, p):
"""Point back to the program containing this composite gate."""
super(CompositeGate, self).set_program(p)
for g in self.data:
g.set_program(p)
def _check_qubit(self, r):
"""Raise exception if r is not an argument or not qreg."""
if type(r[0]) is not QuantumRegister:
@ -54,14 +54,14 @@ class CompositeGate(Gate):
self.inverse_flag = not self.inverse_flag
return self
def control(self, *qregs):
def q_if(self, *qregs):
"""Add controls to this gate."""
self.seq = [g.control(qregs) for g in self.data]
self.seq = [g.q_if(qregs) for g in self.data]
return self
def doif(self, c, val):
def c_if(self, c, val):
"""Add classical control register."""
self.seq = [g.doif(c, val) for g in self.data]
self.seq = [g.c_if(c, val) for g in self.data]
return self
def u_base(self, tpl, q):

View File

@ -18,8 +18,8 @@ class CXBase(Gate):
"""Return OPENQASM string."""
ctl = self.arg[0]
tgt = self.arg[1]
return "CX %s[%d],%s[%d];" % (ctl[0].name, ctl[1],
tgt[0].name, tgt[1])
return self._qasmif("CX %s[%d],%s[%d];" % (ctl[0].name, ctl[1],
tgt[0].name, tgt[1]))
def inverse(self):
"""Invert this gate."""

View File

@ -4,20 +4,30 @@ Unitary gate.
Author: Andrew Cross
"""
from ._instruction import Instruction
from ._quantumregister import QuantumRegister
from ._qiskitexception import QISKitException
class Gate(Instruction):
"""Unitary gate."""
def __init__(self, name, param, arg):
"""Create a new composite gate.
name = instruction name string
param = list of real parameters
arg = list of pairs (Register, index)
"""
for a in arg:
if not isinstance(a[0], QuantumRegister):
raise QISKitException("argument not (QuantumRegister, int) "
+ "tuple")
super(Gate, self).__init__(name, param, arg)
def inverse(self):
"""Invert this gate."""
raise QISKitException("inverse not implemented")
def control(self, *qregs):
def q_if(self, *qregs):
"""Add controls to this gate."""
raise QISKitException("control not implemented")
def doif(self, c, val):
"""Add classical control register."""
raise QISKitException("doif not implemented")

View File

@ -23,3 +23,25 @@ class Instruction(object):
self.name = name
self.param = param
self.arg = arg
self.control = None
self.program = None
def set_program(self, p):
"""Point back to the program that contains this instruction."""
self.program = p
def c_if(self, c, val):
"""Add classical control on register c and value val."""
if self.program is None:
raise QISKitException("gate is not associated to a program")
self.program._check_creg(c)
if val < 0:
raise QISKitException("control value should be non-negative")
self.control = (c, val)
def _qasmif(self, s):
"""Print an if statement if needed."""
if self.control is None:
return s
else:
return "if(%s==%d) " % (self.control[0].name, self.control[1]) + s

View File

@ -27,14 +27,14 @@ class InstructionSet(object):
g.inverse()
return self
def control(self, *qregs):
def q_if(self, *qregs):
"""Add controls to all instructions."""
for g in self.gs:
g.control(*qregs)
g.q_if(*qregs)
return self
def doif(self, c, val):
def c_if(self, c, val):
"""Add classical control register to all instructions."""
for g in self.gs:
g.doif(c, val)
g.c_if(c, val)
return self

View File

@ -17,5 +17,5 @@ class Measure(Instruction):
"""Return OPENQASM string."""
qubit = self.arg[0]
bit = self.arg[1]
return "measure %s[%d] -> %s[%d];" % (qubit[0].name, qubit[1],
bit[0].name, bit[1])
return self._qasmif("measure %s[%d] -> %s[%d];" % (qubit[0].name,
qubit[1], bit[0].name, bit[1]))

View File

@ -27,6 +27,7 @@ class Program(object):
def _attach(self, g):
"""Attach a gate."""
g.set_program(self)
self.data.append(g)
return g
@ -61,9 +62,10 @@ class Program(object):
s = "OPENQASM 2.0;\n"
# TODO: need to decide how to handle gate definitions
s += "include \"qelib.inc\";\n"
for r in self.regs:
s += r.qasm() + "\n"
for i in self.data:
s += i.qasm()
s += "\n"
s += i.qasm() + "\n"
return s
def measure(self, q, c):

View File

@ -13,6 +13,10 @@ from ._instructionset import InstructionSet
class QuantumRegister(Register):
"""Implement a quantum register."""
def qasm(self):
"""Return OPENQASM string for this register."""
return "qreg %s[%d];" % (self.name, self.sz)
def reset(self, j=-1):
"""Reset the jth qubit of this register (or all)."""
self._check_bound()

View File

@ -16,4 +16,4 @@ class Reset(Instruction):
def qasm(self):
"""Return OPENQASM string."""
qubit = self.arg[0]
return "reset %s[%d];" % (qubit[0].name, qubit[1])
return self._qasmif("reset %s[%d];" % (qubit[0].name, qubit[1]))

View File

@ -3,7 +3,6 @@ Element of SU(2).
Author: Andrew Cross
"""
from ._instruction import Instruction
from ._gate import Gate
from ._qiskitexception import QISKitException
@ -23,8 +22,8 @@ class UBase(Gate):
phi = self.param[1]
lamb = self.param[2]
qubit = self.arg[0]
return "U(%.15f,%.15f,%.15f) %s[%d];" % (theta, phi, lamb,
qubit[0].name, qubit[1])
return self._qasmif("U(%.15f,%.15f,%.15f) %s[%d];" % (theta, phi,
lamb, qubit[0].name, qubit[1]))
def inverse(self):
"""Invert this gate.

View File

@ -21,8 +21,8 @@ class CnotGate(Gate):
"""Return OPENQASM string."""
ctl = self.arg[0]
tgt = self.arg[1]
return "cx %s[%d],%s[%d];" % (ctl[0].name, ctl[1],
tgt[0].name, tgt[1])
return self._qasmif("cx %s[%d],%s[%d];" % (ctl[0].name, ctl[1],
tgt[0].name, tgt[1]))
def inverse(self):
"""Invert this gate."""

View File

@ -20,7 +20,7 @@ class IdGate(Gate):
def qasm(self):
"""Return OPENQASM string."""
qubit = self.arg[0]
return "id %s[%d];" % (qubit[0].name, qubit[1])
return self._qasmif("id %s[%d];" % (qubit[0].name, qubit[1]))
def inverse(self):
"""Invert this gate."""

View File

@ -21,7 +21,8 @@ class U1Gate(Gate):
"""Return OPENQASM string."""
qubit = self.arg[0]
theta = self.param[0]
return "u1(%.15f) %s[%d];" % (theta, qubit[0].name, qubit[1])
return self._qasmif("u1(%.15f) %s[%d];" % (theta, qubit[0].name,
qubit[1]))
def inverse(self):
"""Invert this gate."""

View File

@ -23,7 +23,9 @@ class U2Gate(Gate):
qubit = self.arg[0]
phi = self.param[0]
lam = self.param[1]
return "u2(%.15f,%.15f) %s[%d];" % (phi, lam, qubit[0].name, qubit[1])
return self._qasmif("u2(%.15f,%.15f) %s[%d];" % (phi, lam,
qubit[0].name,
qubit[1]))
def inverse(self):
"""Invert this gate.

View File

@ -23,8 +23,9 @@ class U3Gate(Gate):
theta = self.param[0]
phi = self.param[1]
lam = self.param[2]
return "u3(%.15f,%.15f,%.15f) %s[%d];" % (theta, phi, lam,
qubit[0].name, qubit[1])
return self._qasmif("u3(%.15f,%.15f,%.15f) %s[%d];" % (theta, phi, lam,
qubit[0].name,
qubit[1]))
def inverse(self):
"""Invert this gate.

49
rippleadd.py Executable file
View File

@ -0,0 +1,49 @@
"""
Ripple adder example based on OPENQASM example.
Author: Andrew Cross
"""
from qiskit_sdk import QuantumRegister, ClassicalRegister, Program
from qiskit_sdk.extensions.standard import x, cx, ccx
n = 4
cin = QuantumRegister("cin", 1)
a = QuantumRegister("a", n)
b = QuantumRegister("b", n)
cout = QuantumRegister("cout", 1)
ans = ClassicalRegister("ans", n+1)
p = Program(cin, a, b, cout, ans)
def majority(p, a, b, c):
"""Majority gate."""
p.cx(c, b)
p.cx(c, a)
p.ccx(a, b, c)
def unmajority(p, a, b, c):
"""Unmajority gate."""
p.ccx(a, b, c)
p.cx(c, a)
p.cx(a, b)
# Set the input states
a.x(0) # a = 0...0001
b.x() # b = 1...1111
# Add a to b, storing result in b
majority(p, (cin, 0), (b, 0), (a, 0))
for j in range(n-1):
majority(p, (a, j), (b, j+1), (a, j+1))
p.cx((a, n-1), (cout, 0))
for j in reversed(range(n-1)):
unmajority(p, (a, j), (b, j+1), (a, j+1))
unmajority(p, (cin, 0), (b, 0), (a, 0))
for j in range(n):
p.measure((b, j), (ans, j))
p.measure((cout, 0), (ans, n))
print(p.qasm())

27
teleport.py Executable file
View File

@ -0,0 +1,27 @@
"""
Quantum teleportation example based on OPENQASM example.
Author: Andrew Cross
"""
import math
from qiskit_sdk import QuantumRegister, ClassicalRegister, Program
from qiskit_sdk.extensions.standard import h, cx, u3, x, z
q = QuantumRegister("q", 3)
c0 = ClassicalRegister("c0", 1)
c1 = ClassicalRegister("c1", 1)
c2 = ClassicalRegister("c2", 1)
p = Program(q, c0, c1, c2)
q.u3(0.3, 0.2, 0.1, 0)
q.h(1)
q.cx(1, 2)
q.barrier()
q.cx(0, 1)
q.h(0)
p.measure((q, 0), (c0, 0))
p.measure((q, 1), (c1, 0))
q.z(2).c_if(c0, 1)
q.x(2).c_if(c1, 1)
p.measure((q, 2), (c2, 0))
print(p.qasm())

View File

@ -15,8 +15,7 @@ from qiskit_sdk.extensions.standard import t, ccx
# QASM before transmitting it through the web API.
# Issues
# - .doif is not implemented
# .control is not implemented
# .q_if is not implemented
# What other features do we need?
# - Think about how we run programs and get results.
@ -31,6 +30,9 @@ p = Program(q, c)
pp = Program(q, r, c) # it would be easy to bail here if that's preferred
q.reset()
q.h(0) # this gets applied to q in p and pp
q.h(1).c_if(c, 5)
ppp = Program(q)
#q.h(2).c_if(c, 5) # raise exception
q.u1(math.pi/4.0).inverse().inverse()
q.u2(math.pi/8.0, math.pi/8.0)
q.u3(math.pi/4.0, math.pi/8.0, math.pi/16.0)