Skip to content

Commit

Permalink
CheckMap analysis pass (Qiskit#1317)
Browse files Browse the repository at this point in the history
* layout object

* layout object

* getitem None

* lint

* get_physical

* set length

* idle_wires

* docstring in _layout.py

* docstrings in test

* doc

* Update qiskit/mapper/_layout.py

Co-Authored-By: 1ucian0 <[email protected]>

* swap error

* Update qiskit/mapper/_layout.py

Co-Authored-By: 1ucian0 <[email protected]>

* key error if gettin a None

* get_logical -> get_bits. get_physical -> get_wires

* length -> set_length

* logical is not a good name

* physical no more

* QuantumRegister instead of strings

* add_register

* style

* get_cnot_nodes

* check map analysis pass

* style

* no-effect stmt

* style

* lint

* docstring

* no expand_gates=False

* Coupling(couplingdict=...
  • Loading branch information
1ucian0 authored and ajavadia committed Nov 26, 2018
1 parent bed0b0a commit 613e250
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 0 deletions.
10 changes: 10 additions & 0 deletions qiskit/dagcircuit/_dagcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,16 @@ def get_named_nodes(self, name):
return {node_id for node_id, data in self.multi_graph.nodes(data=True)
if data["type"] == "op" and data["name"] == name}

def get_cnot_nodes(self):
"""Get the set of Cnot."""
cx_names = ['cx', 'CX']
cxs_nodes = []
for cx_name in cx_names:
if cx_name in self.basis:
for cx_id in self.get_named_nodes(cx_name):
cxs_nodes.append(self.multi_graph.node[cx_id])
return cxs_nodes

def _remove_op_node(self, n):
"""Remove an operation node n.
Expand Down
1 change: 1 addition & 0 deletions qiskit/transpiler/passes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@

from .cx_cancellation import CXCancellation
from .fixed_point import FixedPoint
from .check_map import CheckMap
54 changes: 54 additions & 0 deletions qiskit/transpiler/passes/check_map.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-

# Copyright 2018, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

"""
This pass checks if a DAG is mapped to a coupling map.
"""

from qiskit.transpiler._basepasses import AnalysisPass
from qiskit.mapper import Layout


class CheckMap(AnalysisPass):
"""
Checks if a DAGCircuit is mapped to `coupling_map`.
"""

def __init__(self, coupling_map, initial_layout=None):
"""
Checks if a DAGCircuit is mapped to `coupling_map`.
Args:
coupling_map (Coupling): Directed graph represented a coupling map.
initial_layout (Layout): The initial layout of the DAG to analyze.
"""
super().__init__()
self.layout = initial_layout
self.coupling_map = coupling_map

def run(self, dag):
"""
If `dag` is mapped to coupling_map, the property `is_mapped` is
set to True (or to False otherwise).
Args:
dag (DAGCircuit): DAG to map.
"""
if self.layout is None:
self.layout = Layout()
for qreg in dag.qregs.values():
self.layout.add_register(qreg)

self.property_set['is_mapped'] = None
for layer in dag.serial_layers():
subdag = layer['graph']

for a_cx in subdag.get_cnot_nodes():
physical_q0 = ('q', self.layout[a_cx['op'].qargs[0]])
physical_q1 = ('q', self.layout[a_cx['op'].qargs[1]])
if self.coupling_map.distance(physical_q0, physical_q1) != 1:
self.property_set['is_mapped'] = False
return
self.property_set['is_mapped'] = True
109 changes: 109 additions & 0 deletions test/python/transpiler/test_check_map.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# -*- coding: utf-8 -*-

# Copyright 2018, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

"""Test the Check Map pass"""

import unittest

from qiskit import QuantumRegister, QuantumCircuit
from qiskit.transpiler.passes import CheckMap
from qiskit.mapper import Coupling
from qiskit.dagcircuit import DAGCircuit
from ..common import QiskitTestCase


class TestCheckMap(QiskitTestCase):
""" Tests the CheckMap pass."""

def test_trivial_map(self):
""" Trivial map in a circuit without entanglement
qr0:---[H]---
qr1:---[H]---
qr2:---[H]---
Coupling map: None
"""
qr = QuantumRegister(3, 'qr')
circuit = QuantumCircuit(qr)
circuit.h(qr)
coupling = Coupling()
dag = DAGCircuit.fromQuantumCircuit(circuit)
pass_ = CheckMap(coupling)
pass_.run(dag)
self.assertTrue(pass_.property_set['is_mapped'])

def test_true_map(self):
""" Mapped is easy to check
qr0:--(+)-[H]-(+)-
| |
qr1:---.-------|--
|
qr2:-----------.--
Coupling map: [1]--[0]--[2]
"""
qr = QuantumRegister(3, 'qr')
circuit = QuantumCircuit(qr)
circuit.cx(qr[0], qr[1])
circuit.h(qr[0])
circuit.cx(qr[0], qr[2])
coupling = Coupling(couplingdict={0: [1, 2]})
dag = DAGCircuit.fromQuantumCircuit(circuit)

pass_ = CheckMap(coupling)
pass_.run(dag)

self.assertTrue(pass_.property_set['is_mapped'])

def test_true_map_in_same_layer(self):
""" Two CXs distance 1 to each other, in the same layer
qr0:--(+)--
|
qr1:---.---
qr2:--(+)--
|
qr3:---.---
Coupling map: [0]--[1]--[2]--[3]
"""
qr = QuantumRegister(4, 'qr')
circuit = QuantumCircuit(qr)
circuit.cx(qr[0], qr[1])
circuit.cx(qr[2], qr[3])
coupling = Coupling(couplingdict={0: [1], 1: [2], 2: [3]})
dag = DAGCircuit.fromQuantumCircuit(circuit)

pass_ = CheckMap(coupling)
pass_.run(dag)

self.assertTrue(pass_.property_set['is_mapped'])

def test_false_map(self):
""" Needs [0]-[1] in a [0]--[2]--[1]
qr0:--(+)--
|
qr1:---.---
Coupling map: [0]--[2]--[1]
"""
qr = QuantumRegister(2, 'qr')
circuit = QuantumCircuit(qr)
circuit.cx(qr[0], qr[1])
coupling = Coupling(couplingdict={0: [2], 2: [1]})
dag = DAGCircuit.fromQuantumCircuit(circuit)

pass_ = CheckMap(coupling)
pass_.run(dag)

self.assertFalse(pass_.property_set['is_mapped'])


if __name__ == '__main__':
unittest.main()

0 comments on commit 613e250

Please sign in to comment.