Skip to content

Commit

Permalink
Merge branch 'main' into oxidize-commutative-analysis
Browse files Browse the repository at this point in the history
  • Loading branch information
Cryoris committed Sep 2, 2024
2 parents e19f7c6 + f4ca088 commit 52ba2e0
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 9 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ license = "Apache-2.0"
# Each crate can add on specific features freely as it inherits.
[workspace.dependencies]
bytemuck = "1.17"
indexmap.version = "2.4.0"
indexmap.version = "2.5.0"
hashbrown.version = "0.14.5"
num-bigint = "0.4"
num-complex = "0.4"
Expand Down
17 changes: 17 additions & 0 deletions crates/circuit/src/circuit_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use pyo3::types::{IntoPyDict, PyDict, PyList, PySet, PyTuple, PyType};
use pyo3::{import_exception, intern, PyTraverseError, PyVisit};

use hashbrown::{HashMap, HashSet};
use indexmap::IndexMap;
use smallvec::SmallVec;

import_exception!(qiskit.circuit.exceptions, CircuitError);
Expand Down Expand Up @@ -983,6 +984,22 @@ impl CircuitData {
self.param_table.clear();
}

/// Counts the number of times each operation is used in the circuit.
///
/// # Parameters
/// - `self` - A mutable reference to the CircuitData struct.
///
/// # Returns
/// An IndexMap containing the operation names as keys and their respective counts as values.
pub fn count_ops(&self) -> IndexMap<&str, usize, ::ahash::RandomState> {
let mut ops_count: IndexMap<&str, usize, ::ahash::RandomState> = IndexMap::default();
for instruction in &self.data {
*ops_count.entry(instruction.op.name()).or_insert(0) += 1;
}
ops_count.par_sort_by(|_k1, v1, _k2, v2| v2.cmp(v1));
ops_count
}

// Marks this pyclass as NOT hashable.
#[classattr]
const __hash__: Option<Py<PyAny>> = None;
Expand Down
6 changes: 2 additions & 4 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -3516,10 +3516,8 @@ def count_ops(self) -> "OrderedDict[Instruction, int]":
Returns:
OrderedDict: a breakdown of how many operations of each kind, sorted by amount.
"""
count_ops: dict[Instruction, int] = {}
for instruction in self._data:
count_ops[instruction.operation.name] = count_ops.get(instruction.operation.name, 0) + 1
return OrderedDict(sorted(count_ops.items(), key=lambda kv: kv[1], reverse=True))
ops_dict = self._data.count_ops()
return OrderedDict(ops_dict)

def num_nonlocal_gates(self) -> int:
"""Return number of non-local gates (i.e. involving 2+ qubits).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def run(self, dag: DAGCircuit):
):
continue

decomp = TwoQubitWeylDecomposition(node.op, fidelity=self.requested_fidelity)
decomp = TwoQubitWeylDecomposition(node.matrix, fidelity=self.requested_fidelity)
if (
decomp._inner_decomposition.specialization
== TwoQubitWeylDecomposition._specializations.IdEquiv
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
fixes:
- |
Fixed a bug in :class:`.Split2QUnitaries` where it would fail to run on circuits
with custom gates that didn't implement :meth:`__array__`.
See `#12984 <https://github.com/Qiskit/qiskit/issues/12970>`__.
5 changes: 5 additions & 0 deletions releasenotes/notes/port-countops-method-3ad362c20b13182c.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
features_circuits:
- |
The :meth:`~.QuantumCircuit.count_ops` method in :class:`.QuantumCircuit`
has been re-written in Rust. It now runs between 3 and 9 times faster.
39 changes: 38 additions & 1 deletion test/python/transpiler/test_split_2q_unitaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from qiskit import QuantumCircuit, QuantumRegister, transpile
from qiskit.circuit.library import UnitaryGate, XGate, ZGate, HGate
from qiskit.circuit import Parameter, CircuitInstruction
from qiskit.circuit import Parameter, CircuitInstruction, Gate
from qiskit.providers.fake_provider import GenericBackendV2
from qiskit.quantum_info import Operator
from qiskit.transpiler import PassManager
Expand Down Expand Up @@ -223,3 +223,40 @@ def test_split_qft(self):
pm.append(Split2QUnitaries())
qc_split = pm.run(qc)
self.assertEqual(26, qc_split.num_nonlocal_gates())

def test_gate_no_array(self):
"""
Test that the pass doesn't fail when the circuit contains a custom gate
with no ``__array__`` implementation.
Reproduce from: https://github.com/Qiskit/qiskit/issues/12970
"""

class MyGate(Gate):
"""Custom gate"""

def __init__(self):
super().__init__("mygate", 2, [])

def to_matrix(self):
return np.eye(4, dtype=complex)
# return np.eye(4, dtype=float)

def mygate(self, qubit1, qubit2):
return self.append(MyGate(), [qubit1, qubit2], [])

QuantumCircuit.mygate = mygate

qc = QuantumCircuit(2)
qc.mygate(0, 1)

pm = PassManager()
pm.append(Collect2qBlocks())
pm.append(ConsolidateBlocks())
pm.append(Split2QUnitaries())
qc_split = pm.run(qc)

self.assertTrue(Operator(qc).equiv(qc_split))
self.assertTrue(
matrix_equal(Operator(qc).data, Operator(qc_split).data, ignore_phase=False)
)

0 comments on commit 52ba2e0

Please sign in to comment.