Skip to content

Commit

Permalink
Fixed documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcDrudis committed Oct 10, 2024
1 parent fca4710 commit be25ef2
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 101 deletions.
50 changes: 50 additions & 0 deletions qiskit/circuit/_standard_gates_commutations.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,53 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2023.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Dictionary containing commutation relations of unparameterizable standard gates. The dictionary key
is defined by a pair of gates and, optionally, their relative placement to each other, i.e.:
┌───┐┌───┐
q: ┤ X ├┤ Z ├ -> standard_gates_commutations["x", "z"] = False
└───┘└───┘
or
┌───┐
q_0: ──■──┤ X ├
┌─┴─┐└─┬─┘ -> standard_gates_commutations["cx", "cy"][1, 0] = False
q_1: ┤ Y ├──■──
└───┘
or
q_0: ──■───────
┌─┴─┐
q_1: ┤ X ├──■── -> standard_gates_commutations['cx', 'cx'][None, 0] = False
└───┘┌─┴─┐
q_2: ─────┤ X ├
└───┘
Note that the commutation of a pair of gates is only stored in one specific order, i.e. the commutation
of a pair of cy and cx gates is only stored in standard_gates_commutations["cx", "cy"]. The order of the
gates is derived from the number of qubits in each gate and the value of the integer representation of
the gate name.
The values of standard_gates_commutations can be a Boolean value denoting whether the pair of gates
commute or another dictionary if the relative placement of the pair of gates has an impact on the
commutation. The relative placement is defined by the gate qubit arrangements as q2^{-1}[q1[i]] where
q1[i] is the ith qubit of the first gate and q2^{-1}[q] returns the qubit index of qubit q in the second
gate (possibly 'None'). In the second example, the zeroth qubit of cy overlaps with qubit 1 of cx. Non-
overlapping qubits are specified as 'None' in the dictionary key, e.g. example 3, there is no overlap
on the zeroth qubit of the first cx but the zeroth qubit of the second gate overlaps with qubit 1 of the
first cx.
"""


standard_gates_commutations = {
("id", "id"): True,
("id", "sx"): True,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
---
features_circuits:
- |
Improved the functionality of :class:`.CommutationChecker` to include support for
the following parameterized gates ... with free parameters. Before these were only
supported with bound parameters.
Improved the functionality of :class:`.CommutationChecker` to include
support for the following parameterized gates with free parameters:
:class:`.RXXGate`,:class:`.RYYGate`,:class:`.RZZGate`,:class:`.RZXGate`,
:class:`.RXGate`,:class:`.RYGate`,:class:`.RZGate`,:class:`.PhaseGate`,
:class:`.U1Gate`,:class:`.CRXGate`,:class:`.CRYGate`,:class:`.CRZGate`,
:class:`.CPhaseGate`.
Before these were only supported with bound parameters.
49 changes: 11 additions & 38 deletions test/python/circuit/test_commutation_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,48 +13,21 @@
"""Test commutation checker class ."""

import unittest
from test import QiskitTestCase # pylint: disable=wrong-import-order

import numpy as np
from ddt import ddt, data, unpack

from qiskit import ClassicalRegister, transpile
from qiskit.circuit import (
QuantumRegister,
Parameter,
Qubit,
AnnotatedOperation,
InverseModifier,
ControlModifier,
Gate,
QuantumCircuit,
)
from ddt import data, ddt

from qiskit import ClassicalRegister
from qiskit.circuit import (AnnotatedOperation, ControlModifier, Gate,
InverseModifier, Parameter, QuantumRegister, Qubit)
from qiskit.circuit.commutation_library import SessionCommutationChecker as scc
from qiskit.circuit.library import (Barrier, CCXGate, CPhaseGate, CRXGate,
CRYGate, CRZGate, CXGate, LinearFunction,
MCXGate, Measure, PhaseGate, Reset, RXGate,
RXXGate, RYGate, RYYGate, RZGate, RZXGate,
RZZGate, SGate, XGate, ZGate)
from qiskit.dagcircuit import DAGOpNode
from qiskit.circuit.library import (
ZGate,
XGate,
CXGate,
CCXGate,
MCXGate,
RXGate,
RYGate,
RZGate,
PhaseGate,
Measure,
Barrier,
Reset,
LinearFunction,
SGate,
CRXGate,
CRYGate,
CRZGate,
CPhaseGate,
RXXGate,
RYYGate,
RZZGate,
RZXGate,
)
from test import QiskitTestCase # pylint: disable=wrong-import-order


class NewGateCX(Gate):
Expand Down
62 changes: 2 additions & 60 deletions tools/build_standard_commutations.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
import itertools
from functools import lru_cache
from typing import List
from qiskit.circuit import Gate, CommutationChecker

import qiskit.circuit.library.standard_gates as stdg
from qiskit.circuit import CommutationChecker, Gate
from qiskit.circuit.library import PauliGate
from qiskit.dagcircuit import DAGOpNode

Expand All @@ -32,65 +33,6 @@
}


@lru_cache(maxsize=10**3)
def _persistent_id(op_name: str) -> int:
"""Returns an integer id of a string that is persistent over different python executions (note that
hash() can not be used, i.e. its value can change over two python executions)
Args:
op_name (str): The string whose integer id should be determined.
Return:
The integer id of the input string.
"""
return int.from_bytes(bytes(op_name, encoding="utf-8"), byteorder="big", signed=True)


def _order_operations(op1, qargs1, cargs1, op2, qargs2, cargs2):
"""Orders two operations in a canonical way that is persistent over
@different python versions and executions
Args:
op1: first operation.
qargs1: first operation's qubits.
cargs1: first operation's clbits.
op2: second operation.
qargs2: second operation's qubits.
cargs2: second operation's clbits.
Return:
The input operations in a persistent, canonical order.
"""
op1_tuple = (op1, qargs1, cargs1)
op2_tuple = (op2, qargs2, cargs2)
least_qubits_op, most_qubits_op = (
(op1_tuple, op2_tuple) if op1.num_qubits < op2.num_qubits else (op2_tuple, op1_tuple)
)
# prefer operation with the least number of qubits as first key as this results in shorter keys
if op1.num_qubits != op2.num_qubits:
return least_qubits_op, most_qubits_op
else:
return (
(op1_tuple, op2_tuple)
if _persistent_id(op1.name) < _persistent_id(op2.name)
else (op2_tuple, op1_tuple)
)


def _get_relative_placement(first_qargs, second_qargs) -> tuple:
"""Determines the relative qubit placement of two gates. Note: this is NOT symmetric.
Args:
first_qargs (DAGOpNode): first gate
second_qargs (DAGOpNode): second gate
Return:
A tuple that describes the relative qubit placement: E.g.
_get_relative_placement(CX(0, 1), CX(1, 2)) would return (None, 0) as there is no overlap on
the first qubit of the first gate but there is an overlap on the second qubit of the first gate,
i.e. qubit 0 of the second gate. Likewise,
_get_relative_placement(CX(1, 2), CX(0, 1)) would return (1, None)
"""
qubits_g2 = {q_g1: i_g1 for i_g1, q_g1 in enumerate(second_qargs)}
return tuple(qubits_g2.get(q_g0, None) for q_g0 in first_qargs)


@lru_cache(maxsize=10**3)
def _persistent_id(op_name: str) -> int:
"""Returns an integer id of a string that is persistent over different python executions (note that
Expand Down

0 comments on commit be25ef2

Please sign in to comment.