ADD: Rippleadd Example

fix create circuit arguments
This commit is contained in:
ismael faro 2017-05-08 00:50:44 -04:00
parent 3aa9efda38
commit 73aed08c81
3 changed files with 211 additions and 3 deletions

View File

@ -305,12 +305,17 @@ class QuantumProgram(object):
qregisters=quantumr["name"],
cregisters=classicalr["name"])
def create_circuit(self, name, qregisters, cregisters):
def create_circuit(self, name, qregisters=None, cregisters=None):
"""Create a new Quantum Circuit into the Quantum Program
name is a string, the name of the circuit
qregisters is a Array of Quantum Registers, can be String, by name or the object reference
cregisters is a Array of Classical Registers, can be String, by name or the object reference
"""
if not qregisters:
qregisters = []
if not cregisters:
cregisters = []
self.__circuits[name] = QuantumCircuit()
for register in qregisters:
if isinstance(register, str):

205
rippleadd_obj.py Normal file
View File

@ -0,0 +1,205 @@
"""
Ripple adder example based on OPENQASM example.
Author: Andrew Cross
"""
from qiskit import QuantumProgram
n = 4
QPSpecs = {
"name": "Program",
"circuits": [{
"name": "rippleadd",
"quantum_registers": [
{"name":"a",
"size":n},
{"name":"b",
"size":n},
{"name":"cin",
"size":1},
{"name":"cout",
"size":1}
],
"classical_registers": [
{"name":"ans",
"size":n+1},
]}]
}
QP_program = QuantumProgram(specs=QPSpecs)
qc = QP_program.circuit("rippleadd")
a = QP_program.quantum_registers("a")
b = QP_program.quantum_registers("b")
cin = QP_program.quantum_registers("cin")
cout = QP_program.quantum_registers("cout")
ans = QP_program.classical_registers("ans")
def print_2x8(layout):
"""Print a 2x8 layout."""
rev_layout = {b: a for a, b in layout.items()}
print("")
for i in range(8):
qubit = ("q", i)
if qubit in rev_layout:
print("%s[%d] " % (rev_layout[qubit][0], rev_layout[qubit][1]),
end="")
else:
print("XXXX ", end="")
print("")
for i in range(8, 16):
qubit = ("q", i)
if qubit in rev_layout:
print("%s[%d] " % (rev_layout[qubit][0], rev_layout[qubit][1]),
end="")
else:
print("XXXX ", end="")
print("")
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)
# Build subcircuit to add a to b, storing result in b
adder_subcircuit = QP_program.create_circuit("adder_subcircuit", [cin, a, b, cout])
majority(adder_subcircuit, cin[0], b[0], a[0])
for j in range(n-1):
majority(adder_subcircuit, a[j], b[j+1], a[j+1])
adder_subcircuit.cx(a[n-1], cout[0])
for j in reversed(range(n-1)):
unmajority(adder_subcircuit, a[j], b[j+1], a[j+1])
unmajority(adder_subcircuit, cin[0], b[0], a[0])
# Build the adder example
qc.x(a[0]) # Set input a = 0...0001
qc.x(b) # Set input b = 1...1111
qc += adder_subcircuit
for j in range(n):
qc.measure(b[j], ans[j]) # Measure the output register
qc.measure(cout[0], ans[n])
######################################################################
# Work in progress to map the QuantumCircuit to the 2x8 device
######################################################################
print("QuantumCircuit OPENQASM")
print("-----------------------")
print(qc.qasm())
######################################################################
# First pass: expand subroutines to a basis of 1 and 2 qubit gates.
######################################################################
source, C = QP_program.unroller_code(qc)
print("Unrolled OPENQASM to [u1, u2, u3, cx] basis")
print("-------------------------------------------")
print(C.qasm(qeflag=True))
print("")
print("size = %d" % C.size())
print("depth = %d" % C.depth())
print("width = %d" % C.width())
print("bits = %d" % C.num_cbits())
print("factors = %d" % C.num_tensor_factors())
######################################################################
# Second pass: choose a layout on the coupling graph and add SWAPs.
######################################################################
# This is the 2 by 8 array of 16 qubits
couplingdict = {0: [1, 8], 1: [2, 9], 2: [3, 10], 3: [4, 11], 4: [5, 12],
5: [6, 13], 6: [7, 14], 7: [15], 8: [9], 9: [10], 10: [11],
11: [12], 12: [13], 13: [14], 14: [15]}
coupling = QP_program.mapper.Coupling(couplingdict)
C_mapped, layout = QP_program.mapper.swap_mapper(C, coupling)
print("")
print("Initial qubit positions on 2x8 layout")
print("-------------------------------------------")
print_2x8(layout)
print("")
print("Inserted SWAP gates for 2x8 layout")
print("-------------------------------------------")
print(C_mapped.qasm(qeflag=True))
print("")
print("size = %d" % C_mapped.size())
print("depth = %d" % C_mapped.depth())
print("width = %d" % C_mapped.width())
print("bits = %d" % C_mapped.num_cbits())
print("factors = %d" % C_mapped.num_tensor_factors())
######################################################################
# Third pass: expand SWAP subroutines and adjust cx gate orientations.
######################################################################
source, C_mapped_unrolled = QP_program.unroller_code(C_mapped)
C_directions = QP_program.mapper.direction_mapper(C_mapped_unrolled, coupling)
print("")
print("Changed CNOT directions")
print("-------------------------------------------")
print(C_directions.qasm(qeflag=True))
print("")
print("size = %d" % C_directions.size())
print("depth = %d" % C_directions.depth())
print("width = %d" % C_directions.width())
print("bits = %d" % C_directions.num_cbits())
print("factors = %d" % C_directions.num_tensor_factors())
######################################################################
# Fourth pass: collect runs of cx gates and cancel them.
######################################################################
# We assume there are no double edges in the connectivity graph, so
# we don't need to check the direction of the cx gates in a run.
runs = C_directions.collect_runs(["cx"])
for r in runs:
if len(r) % 2 == 0:
for n in r:
C_directions._remove_op_node(n)
else:
for j in range(len(r)-1):
C_directions._remove_op_node(r[j])
print("")
print("Cancelled redundant CNOT gates")
print("-------------------------------------------")
print(C_directions.qasm(qeflag=True))
print("")
print("size = %d" % C_directions.size())
print("depth = %d" % C_directions.depth())
print("width = %d" % C_directions.width())
print("bits = %d" % C_directions.num_cbits())
print("factors = %d" % C_directions.num_tensor_factors())
######################################################################
# Fifth pass: expand single qubit gates to u1, u2, u3 and simplify.
######################################################################
source, C_directions_unrolled = QP_program.unroller_code(C_directions)
runs = C_directions_unrolled.collect_runs(["u1", "u2", "u3"])
print(runs)
# TODO: complete this pass
# TODO: add Circuit method to tally each type of gate so we can see costs
# TODO: test on examples using simulator
# TODO: simple unit tests for qasm, mapper, unroller, circuit

View File

@ -7,10 +7,8 @@ from qiskit import QuantumProgram
QPSpecs = {
"name": "Program",
# "importmodule": "",
"circuits": [{
"name": "teleport",
#"importqasm": "chemisty.qjson",
"quantum_registers": [{
"name":"q",
"size":3