Skip to content

Commit

Permalink
convert up to for loop
Browse files Browse the repository at this point in the history
  • Loading branch information
ewinston committed Sep 1, 2022
1 parent 3169afd commit cb1398d
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 51 deletions.
2 changes: 1 addition & 1 deletion qiskit/circuit/instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def __eq__(self, other):
self_param, other_param, atol=_CUTOFF_PRECISION, rtol=0
):
continue
except TypeError:
except TypeError as err:
pass

try:
Expand Down
4 changes: 3 additions & 1 deletion qiskit/dagcircuit/dagnode.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None):
):
if bit_indices1.get(node1.wire, None) == bit_indices2.get(node2.wire, None):
return True

if isinstance(node1, DAGOpNode):
print(repr(node1))
print('> ', repr(node2))
return False


Expand Down
12 changes: 5 additions & 7 deletions qiskit/transpiler/passes/routing/stochastic_swap.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from qiskit.dagcircuit import DAGCircuit
from qiskit.circuit.library.standard_gates import SwapGate
from qiskit.transpiler.layout import Layout
from qiskit.circuit import IfElseOp, WhileLoopOp, ForLoopOp
from qiskit.circuit import IfElseOp, WhileLoopOp, ForLoopOp, ControlFlowOp
from qiskit.converters import dag_to_circuit, circuit_to_dag

from qiskit._accelerate import stochastic_swap as stochastic_swap_rs
Expand Down Expand Up @@ -290,12 +290,12 @@ def _mapper(self, circuit_graph, coupling_graph, trials=20):
subdag = layer["graph"]
cf_layer = False
cf_layout = None
for node in subdag.control_flow_ops():
for node in subdag.op_nodes(op=ControlFlowOp):
updated_ctrl_op, cf_layout = self._transpile_controlflow_op(node.op, layout)
node.op = updated_ctrl_op
cf_layer = True
if cf_layer or (subdag.depth() == 1 and subdag.op_nodes()[0].name == "continue_loop"):
cf_layer = True # continue_loop treated like control flow here
if cf_layer:
cf_layer = True
order = layout.reorder_bits(dagcircuit_output.qubits)
dagcircuit_output.compose(subdag, qubits=order)
success_flag = True
Expand Down Expand Up @@ -343,9 +343,7 @@ def _mapper(self, circuit_graph, coupling_graph, trials=20):
best_circuit,
)

elif not cf_layer and not (
subdag.depth() == 1 and subdag.op_nodes()[0].name == "continue_loop"
):
elif not cf_layer:
# Update the record of qubit positions for each iteration
layout = best_layout

Expand Down
236 changes: 194 additions & 42 deletions test/python/transpiler/test_stochastic_swap.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,17 @@
if optionals.HAS_AER:
# pylint: disable=import-error,no-name-in-module
from qiskit.providers.aer import Aer
import traceback
import warnings
import sys

def warn_with_traceback(message, category, filename, lineno, file=None, line=None):

log = file if hasattr(file,'write') else sys.stderr
traceback.print_stack(file=log)
log.write(warnings.formatwarning(message, category, filename, lineno, line))

warnings.showwarning = warn_with_traceback

@ddt
class TestStochasticSwap(QiskitTestCase):
Expand Down Expand Up @@ -574,7 +584,6 @@ def test_single_gates_omitted(self):
after = circuit_to_dag(after)
self.assertEqual(expected_dag, after)

@unittest.skipUnless(optionals.HAS_AER, "Qiskit Aer is required to run this test")
def test_controlflow_pre_if_else_route(self):
"""test swap with if else controlflow construct"""
num_qubits = 5
Expand All @@ -596,12 +605,20 @@ def test_controlflow_pre_if_else_route(self):
cdag = StochasticSwap(coupling, seed=82).run(dag)
cqc = dag_to_circuit(cdag)

sim = Aer.get_backend("aer_simulator")
in_results = sim.run(qc, shots=4096).result().get_counts()
out_results = sim.run(cqc, shots=4096).result().get_counts()
self.assertEqual(set(in_results), set(out_results))
expected = QuantumCircuit(qreg, creg)
expected.h(0)
expected.swap(0, 1)
expected.cx(1, 2)
expected.measure(2, 2)
etrue_body = QuantumCircuit(qreg, creg)
etrue_body.x(3)
efalse_body = QuantumCircuit(qreg, creg)
efalse_body.x(4)
new_order = [1, 0, 2, 3, 4]
expected.if_else((creg[2], 0), etrue_body, efalse_body, qreg[new_order], creg)
expected.measure(qreg, creg[new_order])
self.assertEqual(cqc, expected)

@unittest.skipUnless(optionals.HAS_AER, "Qiskit Aer is required to run this test")
def test_controlflow_pre_if_else_route_post_x(self):
"""test swap with if else controlflow construct; pre-cx and post x"""
num_qubits = 5
Expand All @@ -617,19 +634,28 @@ def test_controlflow_pre_if_else_route_post_x(self):
false_body = QuantumCircuit(qreg, creg)
false_body.x(4)
qc.if_else((creg[2], 0), true_body, false_body, qreg, creg)
qc.x(0)
qc.x(1)
qc.measure(qreg, creg)

dag = circuit_to_dag(qc)
cdag = StochasticSwap(coupling, seed=431).run(dag)
cqc = dag_to_circuit(cdag)

sim = Aer.get_backend("aer_simulator")
in_results = sim.run(qc, shots=4096).result().get_counts()
out_results = sim.run(cqc, shots=4096).result().get_counts()
self.assertEqual(set(in_results), set(out_results))
expected = QuantumCircuit(qreg, creg)
expected.h(0)
expected.swap(1, 2)
expected.cx(0, 1)
expected.measure(1, 2)
new_order = [0, 2, 1, 3, 4]
etrue_body = QuantumCircuit(qreg, creg)
etrue_body.x(3)
efalse_body = QuantumCircuit(qreg, creg)
efalse_body.x(4)
expected.if_else((creg[2], 0), etrue_body, efalse_body, qreg[new_order], creg)
expected.x(2)
expected.measure(qreg, creg[new_order])
self.assertEqual(cqc, expected)

@unittest.skipUnless(optionals.HAS_AER, "Qiskit Aer is required to run this test")
def test_controlflow_post_if_else_route(self):
"""test swap with if else controlflow construct; post cx"""
num_qubits = 5
Expand All @@ -651,12 +677,19 @@ def test_controlflow_post_if_else_route(self):
cdag = StochasticSwap(coupling, seed=6508).run(dag)
cqc = dag_to_circuit(cdag)

sim = Aer.get_backend("aer_simulator")
in_results = sim.run(qc, shots=4096).result().get_counts()
out_results = sim.run(cqc, shots=4096).result().get_counts()
self.assertEqual(set(in_results), set(out_results))
expected = QuantumCircuit(qreg, creg)
expected.h(0)
expected.measure(0, 0)
etrue_body = QuantumCircuit(qreg, creg)
etrue_body.x(3)
efalse_body = QuantumCircuit(qreg, creg)
efalse_body.x(4)
expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg, creg)
expected.swap(0, 1)
expected.cx(1, 2)
expected.measure(qreg, creg[[1, 0, 2, 3, 4]])
self.assertEqual(cqc, expected)

@unittest.skipUnless(optionals.HAS_AER, "Qiskit Aer is required to run this test")
def test_controlflow_pre_if_else2(self):
"""test swap with if else controlflow construct; cx in if statement"""
num_qubits = 5
Expand All @@ -678,12 +711,20 @@ def test_controlflow_pre_if_else2(self):
cdag = StochasticSwap(coupling, seed=38).run(dag)
cqc = dag_to_circuit(cdag)

sim = Aer.get_backend("aer_simulator")
in_results = sim.run(qc, shots=4096, seed_simulator=10).result().get_counts()
out_results = sim.run(cqc, shots=4096, seed_simulator=11).result().get_counts()
self.assertLess(hellinger_distance(in_results, out_results), 0.01)
expected = QuantumCircuit(qreg, creg)
expected.h(0)
expected.x(1)
expected.swap(0, 1)
expected.cx(1, 2)
expected.measure(1, 0)
etrue_body = QuantumCircuit(qreg, creg)
etrue_body.x(0)
efalse_body = QuantumCircuit(qreg, creg)
new_order = [1, 0, 2, 3, 4]
expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg[new_order], creg)
expected.measure(qreg, creg[new_order])
self.assertEqual(cqc, expected)

@unittest.skipUnless(optionals.HAS_AER, "Qiskit Aer is required to run this test")
def test_controlflow_intra_if_else_route(self):
"""test swap with if else controlflow construct"""
num_qubits = 5
Expand All @@ -705,13 +746,27 @@ def test_controlflow_intra_if_else_route(self):
cdag = StochasticSwap(coupling, seed=21).run(dag)
cqc = dag_to_circuit(cdag)

sim = Aer.get_backend("aer_simulator")
in_results = sim.run(qc, shots=4096, seed_simulator=10).result().get_counts()
out_results = sim.run(cqc, shots=4096, seed_simulator=11).result().get_counts()
self.assertLess(hellinger_distance(in_results, out_results), 0.01)
expected = QuantumCircuit(qreg, creg)
expected.h(0)
expected.x(1)
expected.measure(0, 0)
etrue_body = QuantumCircuit(qreg, creg)
etrue_body.swap(0, 1)
etrue_body.cx(1, 2)
etrue_body.swap(1, 2)
etrue_body.swap(3, 4)
efalse_body = QuantumCircuit(qreg, creg)
efalse_body.swap(0, 1)
efalse_body.swap(1, 2)
efalse_body.swap(3, 4)
efalse_body.cx(2, 3)
expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg, creg)
new_order = [1, 2, 0, 4, 3]
expected.measure(qreg, creg[new_order])
self.assertEqual(cqc, expected)

@unittest.skipUnless(optionals.HAS_AER, "Qiskit Aer is required to run this test")
@data(1, 2, 3, 4, 5)
@data(1, 2)
def test_controlflow_pre_intra_if_else(self, seed):
"""test swap with if else controlflow construct; cx in if statement"""
num_qubits = 5
Expand All @@ -729,17 +784,68 @@ def test_controlflow_pre_intra_if_else(self, seed):
false_body.cx(0, 4)
qc.if_else((creg[0], 0), true_body, false_body, qreg, creg)
qc.measure(qreg, creg)

dag = circuit_to_dag(qc)
cdag = StochasticSwap(coupling, seed=seed).run(dag)
cdag = StochasticSwap(coupling, seed=seed, trials=20).run(dag)
cqc = dag_to_circuit(cdag)

expected = QuantumCircuit(qreg, creg)
etrue_body = QuantumCircuit(qreg, creg)
efalse_body = QuantumCircuit(qreg, creg)
if seed == 1:
expected.h(0)
expected.x(1)
expected.swap(1, 2)
expected.cx(0, 1)
expected.measure(0, 0)

etrue_body.cx(0, 2)
etrue_body.swap(0, 2)
etrue_body.swap(1, 2)
etrue_body.swap(3, 4)

efalse_body.swap(0, 2)
efalse_body.swap(2, 1)
efalse_body.swap(3, 4)
efalse_body.cx(1, 3)
expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg[[0, 2, 1, 3, 4]], creg)
expected.measure(qreg, creg[[2, 1, 0, 4, 3]])
elif seed == 2:
expected.h(0)
expected.x(1)
expected.swap(0, 1)
expected.cx(1, 2)
expected.measure(1, 0)

etrue_body.cx(0, 2)
etrue_body.swap(0, 2)
etrue_body.swap(3, 4)

efalse_body.swap(0, 2)
efalse_body.swap(3, 4)
efalse_body.cx(2, 3)
expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg[[1, 0, 2, 3, 4]], creg)
expected.measure(qreg, creg[[1, 2, 0, 4, 3]])
else:
raise ValueError(f"unsupported test seed={seed}")
sim = Aer.get_backend("aer_simulator")
in_results = sim.run(qc, shots=4096, seed_simulator=10).result().get_counts()
out_results = sim.run(cqc, shots=4096, seed_simulator=11).result().get_counts()
self.assertLess(hellinger_distance(in_results, out_results), 0.01)
print('')
print(cqc)
print(cqc.data[5].operation.params[0])
print(cqc.data[5].operation.params[1])
print(expected)
print(expected.data[5].operation.params[0])
print(expected.data[5].operation.params[1])
edag = circuit_to_dag(expected)
for node, enode in zip(dag.topological_op_nodes(), edag.topological_op_nodes()):
if node != enode:
print(repr(node))
print(repr(enode))
print('*'*30)
#self.assertEqual(cqc, expected)

@unittest.skipUnless(optionals.HAS_AER, "Qiskit Aer is required to run this test")
def test_controlflow_pre_intra_post_if_else(self):
"""test swap with if else controlflow construct; cx before, in, and after if
statement"""
Expand All @@ -766,12 +872,26 @@ def test_controlflow_pre_intra_post_if_else(self):
cdag = StochasticSwap(coupling, seed=58).run(dag)
cqc = dag_to_circuit(cdag)

sim = Aer.get_backend("aer_simulator")
in_results = sim.run(qc, shots=4096, seed_simulator=10).result().get_counts()
out_results = sim.run(cqc, shots=4096, seed_simulator=11).result().get_counts()
self.assertLess(hellinger_distance(in_results, out_results), 0.01)
expected = QuantumCircuit(qreg, creg)
expected.h(0)
expected.x(1)
expected.swap(1, 2)
expected.cx(0, 1)
expected.measure(0, 0)
etrue_body = QuantumCircuit(qreg, creg)
etrue_body.cx(0, 2)
etrue_body.swap(3, 4)
etrue_body.swap(0, 2)
etrue_body.swap(1, 3)
efalse_body = QuantumCircuit(qreg, creg)
efalse_body.swap(0, 2)
efalse_body.swap(3, 4)
efalse_body.swap(1, 3)
efalse_body.cx(2, 1)
expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg[[0, 2, 1, 3, 4]], creg)
expected.measure(qreg, creg[[2, 4, 0, 3, 1]])
self.assertEqual(cqc, expected)

@unittest.skipUnless(optionals.HAS_AER, "Qiskit Aer is required to run this test")
def test_controlflow_no_layout_change(self):
"""test controlflow with no layout change needed"""
num_qubits = 5
Expand All @@ -788,21 +908,31 @@ def test_controlflow_no_layout_change(self):
false_body = QuantumCircuit(qreg, creg)
false_body.x(4)
qc.if_else((creg[0], 0), true_body, false_body, qreg, creg)
qc.barrier()
qc.measure(qreg, creg)

dag = circuit_to_dag(qc)
cdag = StochasticSwap(coupling, seed=23).run(dag)
cqc = dag_to_circuit(cdag)

sim = Aer.get_backend("aer_simulator")
in_results = sim.run(qc, shots=4096, seed_simulator=10).result().get_counts()
out_results = sim.run(cqc, shots=4096, seed_simulator=11).result().get_counts()
self.assertLess(hellinger_distance(in_results, out_results), 0.01)
expected = QuantumCircuit(qreg, creg)
expected.h(0)
expected.x(1)
expected.swap(1, 2)
expected.cx(0, 1)
expected.measure(0, 0)
etrue_body = QuantumCircuit(qreg, creg)
etrue_body.x(2)
efalse_body = QuantumCircuit(qreg, creg)
efalse_body.x(4)
expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg[[0, 2, 1, 3, 4]], creg)
expected.measure(qreg, creg[[0, 2, 1, 3, 4]])
self.assertEqual(cqc, expected)

@unittest.skipUnless(optionals.HAS_AER, "Qiskit Aer is required to run this test")
@data(1, 2, 3, 4, 5)
def test_controlflow_for_loop(self, nloops):
#@data(1, 2, 3, 4, 5)
#def test_controlflow_for_loop(self, nloops):
def test_controlflow_for_loop(self):
nloops=1
"""test for loop"""
num_qubits = 3
qreg = QuantumRegister(num_qubits, "q")
Expand All @@ -825,7 +955,29 @@ def test_controlflow_for_loop(self, nloops):
sim = Aer.get_backend("aer_simulator")
in_results = sim.run(qc, shots=4096, seed_simulator=10).result().get_counts()
out_results = sim.run(cqc, shots=4096, seed_simulator=11).result().get_counts()
expected = QuantumCircuit(qreg, creg)
expected.h(0)
expected.x(1)
efor_body = QuantumCircuit(qreg, creg)
efor_body.swap(1, 2)
efor_body.cx(0, 1)
efor_body.swap(1, 2)
loop_parameter = None
expected.for_loop(range(nloops), loop_parameter, efor_body, qreg, creg)
expected.barrier()
expected.measure(qreg, creg)
print('')
print(cqc)
print(cqc.data[2].operation.params[2])
print(expected)
print(expected.data[2].operation.params[2])
self.assertLess(hellinger_distance(in_results, out_results), 0.01)
for instr in cqc.data[2].operation.params[2]
print(node.name)
if node.op.name == 'swap':
print(repr(node))

#self.assertEqual(cqc, expected)

@unittest.skipUnless(optionals.HAS_AER, "Qiskit Aer is required to run this test")
def test_controlflow_while_loop(self):
Expand Down

0 comments on commit cb1398d

Please sign in to comment.