Skip to content

Commit

Permalink
Remove deepcopy usage from dag/circuit converters
Browse files Browse the repository at this point in the history
In Qiskit#1816 as part of the larger restructure the dag_to_circuit() and
circuit_to_dag() converter were modified to use a copy.deepcopy()
instead of native Instruction/Gate constructors. This caused a large
performance regressions (around 3x in the worst case) in certain
transpile calls. To avoid this performance penalty this commit
reintroduces a private function to call the class constructor for each
input gate to create a new instance of the object to append to the
output. This removes the deepcopy usage and should fix the performance
regression.

Fixes Qiskit#2131
  • Loading branch information
mtreinish committed Apr 15, 2019
1 parent f6cfde6 commit cbe8aec
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 7 deletions.
34 changes: 30 additions & 4 deletions qiskit/converters/circuit_to_dag.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

"""Helper function for converting a circuit to a dag"""

import copy

from qiskit.circuit import Gate
from qiskit.circuit import Instruction
from qiskit.dagcircuit.dagcircuit import DAGCircuit


Expand All @@ -35,7 +35,33 @@ def circuit_to_dag(circuit):
else:
control = (instruction.control[0], instruction.control[1])

instruction = copy.deepcopy(instruction)
dagcircuit.apply_operation_back(instruction, qargs, cargs, control)
def duplicate_instruction(inst):
"""Create a fresh instruction from an input instruction."""
if issubclass(inst.__class__,
Instruction) and inst.__class__ not in [
Instruction, Gate]:
if inst.name == 'barrier':
new_inst = inst.__class__(inst.num_qubits)
elif inst.name == 'initialize':
params = getattr(inst, 'params', [])
new_inst = inst.__class__(params)
elif inst.name == 'snapshot':
label = inst.params[0]
snap_type = inst.params[1]
new_inst = inst.__class__(inst.num_qubits, inst.num_clbits,
label, snap_type)
else:
params = getattr(inst, 'params', [])
new_inst = inst.__class__(*params)
else:
new_inst = Instruction(name=inst.name,
num_qubits=inst.num_qubits,
num_clbits=inst.num_clbits,
params=inst.params)
new_inst.definition = inst.definition
return new_inst

dagcircuit.apply_operation_back(duplicate_instruction(instruction),
qargs, cargs, control)

return dagcircuit
34 changes: 31 additions & 3 deletions qiskit/converters/dag_to_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
# the LICENSE.txt file in the root directory of this source tree.

"""Helper function for converting a dag to a circuit"""
import copy
import collections

from qiskit.circuit import QuantumCircuit
from qiskit.circuit import ClassicalRegister
from qiskit.circuit import Instruction
from qiskit.circuit import Gate
from qiskit.circuit import QuantumCircuit
from qiskit.circuit import QuantumRegister


Expand Down Expand Up @@ -51,7 +52,34 @@ def dag_to_circuit(dag):
else:
control = (node.condition[0], node.condition[1])

inst = copy.deepcopy(node.op)
def duplicate_instruction(inst):
"""Create a fresh instruction from an input instruction."""
if issubclass(inst.__class__,
Instruction) and inst.__class__ not in [
Instruction, Gate]:
if inst.name == 'barrier':
new_inst = inst.__class__(inst.num_qubits)
elif inst.name == 'initialize':
params = getattr(inst, 'params', [])
new_inst = inst.__class__(params)
elif inst.name == 'snapshot':
label = inst.params[0]
snap_type = inst.params[1]
new_inst = inst.__class__(inst.num_qubits,
inst.num_clbits,
label, snap_type)
else:
params = getattr(inst, 'params', [])
new_inst = inst.__class__(*params)
else:
new_inst = Instruction(name=inst.name,
num_qubits=inst.num_qubits,
num_clbits=inst.num_clbits,
params=inst.params)
new_inst.definition = inst.definition
return new_inst

inst = duplicate_instruction(node.op)
inst.control = control
circuit.append(inst, qubits, clbits)

Expand Down

0 comments on commit cbe8aec

Please sign in to comment.