Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Fix issue #6185 #7100

Closed
wants to merge 2 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Added get_instance method and tests
Abby-Mitchell committed Oct 5, 2021

Verified

This commit was signed with the committer’s verified signature.
addaleax Anna Henningsen
commit 9de113e9dbc76e42dfe554646d8a833f139540ef
108 changes: 33 additions & 75 deletions qiskit/circuit/library/n_local/two_local.py
Original file line number Diff line number Diff line change
@@ -12,38 +12,13 @@

"""The two-local gate circuit."""

from typing import Union, Optional, List, Callable, Any
from typing import Union, Optional, List, Callable, Any, Type

from qiskit.circuit.quantumcircuit import QuantumCircuit
from qiskit.circuit import Gate, Instruction, Parameter
from qiskit.circuit.library import standard_gates as gates

from .n_local import NLocal
from ..standard_gates import (
IGate,
XGate,
YGate,
ZGate,
RXGate,
RYGate,
RZGate,
HGate,
SGate,
SdgGate,
TGate,
TdgGate,
RXXGate,
RYYGate,
RZXGate,
RZZGate,
SwapGate,
CXGate,
CYGate,
CZGate,
CRXGate,
CRYGate,
CRZGate,
CHGate,
)


class TwoLocal(NLocal):
@@ -235,55 +210,11 @@ def _convert_to_block(self, layer: Union[str, type, Gate, QuantumCircuit]) -> Qu
if isinstance(layer, QuantumCircuit):
return layer

# check the list of valid layers
# this could be a lot easier if the standard layers would have `name` and `num_params`
# as static types, which might be something they should have anyways
theta = Parameter("θ")
valid_layers = {
"ch": CHGate(),
"cx": CXGate(),
"cy": CYGate(),
"cz": CZGate(),
"crx": CRXGate(theta),
"cry": CRYGate(theta),
"crz": CRZGate(theta),
"h": HGate(),
"i": IGate(),
"id": IGate(),
"iden": IGate(),
"rx": RXGate(theta),
"rxx": RXXGate(theta),
"ry": RYGate(theta),
"ryy": RYYGate(theta),
"rz": RZGate(theta),
"rzx": RZXGate(theta),
"rzz": RZZGate(theta),
"s": SGate(),
"sdg": SdgGate(),
"swap": SwapGate(),
"x": XGate(),
"y": YGate(),
"z": ZGate(),
"t": TGate(),
"tdg": TdgGate(),
}

# try to exchange `layer` from a string to a gate instance
if isinstance(layer, str):
try:
layer = valid_layers[layer]
except KeyError as ex:
raise ValueError(f"Unknown layer name `{layer}`.") from ex

# try to exchange `layer` from a type to a gate instance
if isinstance(layer, type):
# iterate over the layer types and look for the specified layer
instance = None
for gate in valid_layers.values():
if isinstance(gate, layer):
instance = gate
# try to exchange `layer` from a string/type to a gate instance
if isinstance(layer, (str, type)):
instance = self._get_gate_instance(layer)
if instance is None:
raise ValueError(f"Unknown layer type`{layer}`.")
raise ValueError(f"Unknown layer `{layer}`.")
layer = instance

if isinstance(layer, Instruction):
@@ -302,3 +233,30 @@ def get_entangler_map(
if self.num_qubits <= 1:
return []
return super().get_entangler_map(rep_num, block_num, num_block_qubits)

def _get_gate_instance(self, val: Union[str, Type[Gate]]) -> Gate:
"""Iterate over the standard gates library and return an instance of required gate"""
instance = None
# dictionary of standard gates
gates_dict = {
cls_name: cls for (cls_name, cls) in gates.__dict__.items() if isinstance(cls, type)
}

for gate in gates_dict.values():
params = []
# Check if gate is in standard gate library and has required static attributes
if (hasattr(gate, "name") and gate.name == val) or (gate == val):
if hasattr(gate, "num_params"):
for i in range(gate.num_params):
params.append(Parameter(f"θ{i}"))
if hasattr(gate, "num_int_params"):
for _ in range(gate.num_int_params):
params.append(1)
# instantiate gate with appropriate params
try:
instance = gate(*params)
except TypeError as ex:
raise ValueError(
f"Unable to instantiate {val}. Failed with error: {ex}"
) from ex
return instance
28 changes: 28 additions & 0 deletions test/python/circuit/library/test_nlocal.py
Original file line number Diff line number Diff line change
@@ -37,6 +37,7 @@
RXXGate,
RYYGate,
CXGate,
standard_gates,
)
from qiskit.circuit.random.utils import random_circuit
from qiskit.converters.circuit_to_dag import circuit_to_dag
@@ -783,6 +784,33 @@ def test_circuit_with_numpy_integers(self):
self.assertEqual(two_np32.decompose().count_ops()["cx"], expected_cx)
self.assertEqual(two_np64.decompose().count_ops()["cx"], expected_cx)

def test_unknown_layer_error(self):
"""Test if TwoLocal throws error with unknown layer name"""
with self.assertRaisesRegex(ValueError, "Unknown layer `abc`"):
TwoLocal(3, "ry", "abc", "linear", reps=2)

def test_unsupported_layer_error(self):
"""Test if TwoLocal throws error with unsupported gate"""
with self.assertRaisesRegex(ValueError, f"Unable to instantiate {standard_gates.MSGate}"):
TwoLocal(3, "ry", standard_gates.MSGate, "linear", reps=2)

def test_all_standard_gates(self):
"""Test TwoLocal works with every standard gate"""
gates_dict = {
cls_name: cls
for (cls_name, cls) in standard_gates.__dict__.items()
if isinstance(cls, type)
}
unsupported_gates = ["MSGate", "MCXGate", "MCXGrayCode", "MCXRecursive", "MCXVChain"]

for key in unsupported_gates:
del gates_dict[key]

for gate in gates_dict.values():
two = TwoLocal(4, "ry", gate, "linear", reps=2)
print(gate)
self.assertIsInstance(two.entanglement_blocks[0].data[0][0], gate)


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