Skip to content

Commit e214a38

Browse files
committed
Fix issues flagged by linters/formatters
1 parent 5f770d6 commit e214a38

10 files changed

+118
-106
lines changed

.pre-commit-config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ repos:
5858
args: ['--score=n']
5959
# This is a slow hook, so only run this if --hook-stage manual is passed
6060
stages: [manual]
61-
additional_dependencies: ['pybind11>=2.6', 'numpy', 'requests', 'boto3', 'matplotlib', 'networkx']
61+
additional_dependencies: ['pybind11>=2.6', 'numpy', 'requests', 'boto3', 'matplotlib', 'networkx', 'qiskit-terra', 'pyparsing']
6262

6363
- repo: https://github.com/mgedmin/check-manifest
6464
rev: "0.46"

projectq/backends/_qasm.py

+30-41
Original file line numberDiff line numberDiff line change
@@ -45,54 +45,43 @@
4545
# ==============================================================================
4646

4747

48-
class OpenQASMBackend(BasicEngine):
48+
class OpenQASMBackend(BasicEngine): # pylint: disable=too-many-instance-attributes
4949
"""
50-
Engine to convert ProjectQ commands to OpenQASM format (either string or
51-
file)
50+
Engine to convert ProjectQ commands to OpenQASM format (either string or file)
5251
"""
5352

5453
def __init__(
5554
self,
56-
collate=True,
5755
collate_callback=None,
58-
qubit_callback=lambda qubit_id: 'q{}'.format(qubit_id),
59-
bit_callback=lambda qubit_id: 'c{}'.format(qubit_id),
56+
qubit_callback='q{}'.format,
57+
bit_callback='c{}'.format,
6058
qubit_id_mapping_redux=True,
6159
):
6260
"""
6361
Initialize an OpenQASMBackend object.
6462
65-
Contrary to OpenQASM, ProjectQ does not impose the restriction that a
66-
programm must start with qubit/bit allocations and end with some
67-
measurements.
63+
Contrary to OpenQASM, ProjectQ does not impose the restriction that a programm must start with qubit/bit
64+
allocations and end with some measurements.
6865
69-
The user can configure what happens each time a FlushGate() is
70-
encountered by setting the `collate` and `collate_func` arguments to
71-
an OpenQASMBackend constructor,
66+
The user can configure what happens each time a FlushGate() is encountered by setting the `collate` and
67+
`collate_func` arguments to an OpenQASMBackend constructor,
7268
7369
Args:
7470
output (list,file):
75-
collate (bool): If True, simply append commands to the exisiting
76-
file/string list when a FlushGate is received. If False, you
77-
need to specify `collate_callback` arguments as well.
78-
collate (function): Only has an effect if `collate` is False. Each
79-
time a FlushGate is received, this callback function will be
80-
called.
71+
collate (function): Each time a FlushGate is received, this callback function will be called. If let
72+
unspecified, the commands are appended to the existing file/string.
8173
Function signature: Callable[[Sequence[str]], None]
82-
qubit_callback (function): Callback function called upon create of
83-
each qubit to generate a name for the qubit.
74+
qubit_callback (function): Callback function called upon create of each qubit to generate a name for the
75+
qubit.
8476
Function signature: Callable[[int], str]
85-
bit_callback (function): Callback function called upon create of
86-
each qubit to generate a name for the qubit.
77+
bit_callback (function): Callback function called upon create of each qubit to generate a name for the
78+
qubit.
8779
Function signature: Callable[[int], str]
88-
qubit_id_mapping_redux (bool): If True, try to allocate new Qubit
89-
IDs to the next available qreg/creg (if any), otherwise create
90-
a new qreg/creg. If False, simply create a new qreg/creg for
91-
each new Qubit ID
80+
qubit_id_mapping_redux (bool): If True, try to allocate new Qubit IDs to the next available qreg/creg (if
81+
any), otherwise create a new qreg/creg. If False, simply create a new qreg/creg for each new Qubit ID
9282
"""
9383
super().__init__()
94-
self._collate = collate
95-
self._collate_callback = None if collate else collate_callback
84+
self._collate_callback = collate_callback
9685
self._gen_qubit_name = qubit_callback
9786
self._gen_bit_name = bit_callback
9887
self._qubit_id_mapping_redux = qubit_id_mapping_redux
@@ -107,6 +96,9 @@ def __init__(
10796

10897
@property
10998
def qasm(self):
99+
"""
100+
Access to the QASM representation of the circuit.
101+
"""
110102
return self._output
111103

112104
def is_available(self, cmd):
@@ -150,8 +142,7 @@ def is_available(self, cmd):
150142
return False
151143
if not self.is_last_engine:
152144
return self.next_engine.is_available(cmd)
153-
else:
154-
return True
145+
return True
155146

156147
def receive(self, command_list):
157148
"""
@@ -170,12 +161,11 @@ def receive(self, command_list):
170161
if not self.is_last_engine:
171162
self.send(command_list)
172163

173-
def _store(self, cmd):
164+
def _store(self, cmd): # pylint: disable=too-many-branches,too-many-statements
174165
"""
175166
Temporarily store the command cmd.
176167
177-
Translates the command and stores it the _openqasm_circuit attribute
178-
(self._openqasm_circuit)
168+
Translates the command and stores it the _openqasm_circuit attribute (self._openqasm_circuit)
179169
180170
Args:
181171
cmd: Command to store
@@ -223,9 +213,8 @@ def _format_angle(angle):
223213
if gate == Allocate:
224214
add = True
225215

226-
# Perform qubit index reduction if possible. This typically means
227-
# that existing qubit keep their indices between FlushGates but
228-
# that qubit indices of deallocated qubit may be reused.
216+
# Perform qubit index reduction if possible. This typically means that existing qubit keep their indices
217+
# between FlushGates but that qubit indices of deallocated qubit may be reused.
229218
if self._qubit_id_mapping_redux and self._available_indices:
230219
add = False
231220
index = self._available_indices.pop()
@@ -263,8 +252,8 @@ def _format_angle(angle):
263252

264253
try:
265254
self._output.append('{} {};'.format(_ccontrolled_gates_func[gate], ','.join(controls + targets)))
266-
except KeyError:
267-
raise RuntimeError('Unable to perform {} gate with n=2 control qubits'.format(gate))
255+
except KeyError as err:
256+
raise RuntimeError('Unable to perform {} gate with n=2 control qubits'.format(gate)) from err
268257

269258
elif n_controls == 1:
270259
target_qureg = [self._qreg_dict[qb.id] for qureg in cmd.qubits for qb in qureg]
@@ -300,8 +289,8 @@ def _format_angle(angle):
300289
_controlled_gates_func[gate], self._qreg_dict[cmd.control_qubits[0].id], *target_qureg
301290
)
302291
)
303-
except KeyError:
304-
raise RuntimeError('Unable to perform {} gate with n=1 control qubits'.format(gate))
292+
except KeyError as err:
293+
raise RuntimeError('Unable to perform {} gate with n=1 control qubits'.format(gate)) from err
305294
else:
306295
target_qureg = [self._qreg_dict[qb.id] for qureg in cmd.qubits for qb in qureg]
307296
if isinstance(gate, Ph):
@@ -323,7 +312,7 @@ def _reset_after_flush(self):
323312
"""
324313
Reset the internal quantum circuit after a FlushGate
325314
"""
326-
if self._collate:
315+
if not self._collate_callback:
327316
self._output.append('# ' + '=' * 80)
328317
else:
329318
self._collate_callback(deepcopy(self._output))

projectq/backends/_qasm_test.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -346,9 +346,7 @@ def test_qasm_no_collate():
346346
def _process(output):
347347
qasm_list.append(output)
348348

349-
eng = MainEngine(
350-
backend=OpenQASMBackend(collate=False, collate_callback=_process, qubit_id_mapping_redux=False), engine_list=[]
351-
)
349+
eng = MainEngine(backend=OpenQASMBackend(collate_callback=_process, qubit_id_mapping_redux=False), engine_list=[])
352350
qubit = eng.allocate_qubit()
353351
ctrls = eng.allocate_qureg(2)
354352

projectq/libs/qasm/__init__.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,22 @@
2121
except ImportError: # pragma: no cover
2222
try:
2323
from ._parse_qasm_pyparsing import read_qasm_file, read_qasm_str
24-
except ImportError as e:
25-
err = (
24+
except ImportError:
25+
ERROR_MSG = (
2626
'Unable to import either qiskit or pyparsing\nPlease install either of them if you want to use '
2727
'projectq.libs.qasm (e.g. using the command python -m pip install projectq[qiskit])'
2828
)
2929

3030
def read_qasm_file(eng, filename):
31+
"""
32+
Dummy implementation
33+
"""
3134
# pylint: disable=unused-argument
32-
raise RuntimeError(err)
35+
raise RuntimeError(ERROR_MSG)
3336

3437
def read_qasm_str(eng, qasm_str):
38+
"""
39+
Dummy implementation
40+
"""
3541
# pylint: disable=unused-argument
36-
raise RuntimeError(err)
42+
raise RuntimeError(ERROR_MSG)

projectq/libs/qasm/_parse_qasm_pyparsing.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -434,18 +434,15 @@ def __init__(self, s, loc, toks):
434434
self.params = param_str[param_str.find('(') + 1 : param_str.rfind(')')].split(',') # noqa: E203
435435
self.qubits = [QubitProxy(qubit) for qubit in toks[2]]
436436

437-
def eval(self, eng):
437+
def eval(self, eng): # pylint: disable=too-many-branches
438438
"""
439439
Evaluate a GateOp
440440
441441
Args:
442442
eng (projectq.BasicEngine): ProjectQ MainEngine to use
443443
"""
444444
if self.name in gates_conv_table:
445-
if self.params:
446-
gate = gates_conv_table[self.name](*[parse_expr(p) for p in self.params])
447-
else:
448-
gate = gates_conv_table[self.name]
445+
gate = gates_conv_table[self.name](*[parse_expr(p) for p in self.params])
449446

450447
qubits = []
451448
for qureg in [qubit.eval(eng) for qubit in self.qubits]:

projectq/libs/qasm/_parse_qasm_qiskit.py

+12-23
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
# limitations under the License.
1515
""" Define function to read OpenQASM file format (using Qiskit). """
1616

17-
from projectq.ops import All, Measure
18-
1917
from qiskit.circuit import QuantumCircuit, Clbit
2018

19+
from projectq.ops import All, Measure
20+
2121
from ._qiskit_conv import gates_conv_table
2222
from ._utils import apply_gate
2323

@@ -28,9 +28,8 @@ def apply_op(eng, gate, qubits, bits, bits_map):
2828
"""
2929
Apply a qiskit operation.
3030
31-
This function takes care of converting between qiskit gates and ProjectQ
32-
gates, as well as handling the translation between qiskit's and ProjectQ's
33-
qubit and bits.
31+
This function takes care of converting between qiskit gates and ProjectQ gates, as well as handling the
32+
translation between qiskit's and ProjectQ's qubit and bits.
3433
3534
Args:
3635
eng (MainEngine): MainEngine to use to the operation(s)
@@ -64,10 +63,7 @@ def apply_op(eng, gate, qubits, bits, bits_map):
6463
eng, gate_sub, [gate_args[qubit.register.name][qubit.index] for qubit in quregs_sub], [], bits_map
6564
)
6665
else:
67-
if gate.params:
68-
gate_projectq = gates_conv_table[gate.name](*gate.params)
69-
else:
70-
gate_projectq = gates_conv_table[gate.name]
66+
gate_projectq = gates_conv_table[gate.name](*gate.params)
7167

7268
if gate.condition:
7369
# OpenQASM 2.0
@@ -100,8 +96,7 @@ def _convert_qiskit_circuit(eng, circuit):
10096
circuit (qiskit.QuantumCircuit): Quantum circuit to process
10197
10298
Note:
103-
At this time, we support most of OpenQASM 2.0 and some of 3.0,
104-
although the latter is still experimental.
99+
At this time, we support most of OpenQASM 2.0 and some of 3.0, although the latter is still experimental.
105100
"""
106101
# Create maps between qiskit and ProjectQ for qubits and bits
107102
qubits_map = {qureg.name: eng.allocate_qureg(qureg.size) for qureg in circuit.qregs}
@@ -119,19 +114,16 @@ def _convert_qiskit_circuit(eng, circuit):
119114

120115
def read_qasm_str(eng, qasm_str):
121116
"""
122-
Read an OpenQASM (2.0, 3.0 is experimental) string and convert it to
123-
ProjectQ commands.
117+
Read an OpenQASM (2.0, 3.0 is experimental) string and convert it to ProjectQ commands.
124118
125-
This version of the function uses Qiskit in order to parse the *.qasm
126-
file.
119+
This version of the function uses Qiskit in order to parse the *.qasm file.
127120
128121
Args:
129122
eng (MainEngine): MainEngine to use for creating qubits and commands.
130123
filename (string): Path to *.qasm file
131124
132125
Note:
133-
At this time, we support most of OpenQASM 2.0 and some of 3.0,
134-
although the latter is still experimental.
126+
At this time, we support most of OpenQASM 2.0 and some of 3.0, although the latter is still experimental.
135127
"""
136128
circuit = QuantumCircuit.from_qasm_str(qasm_str)
137129
return _convert_qiskit_circuit(eng, circuit)
@@ -142,19 +134,16 @@ def read_qasm_str(eng, qasm_str):
142134

143135
def read_qasm_file(eng, filename):
144136
"""
145-
Read an OpenQASM (2.0, 3.0 is experimental) file and convert it to
146-
ProjectQ commands.
137+
Read an OpenQASM (2.0, 3.0 is experimental) file and convert it to ProjectQ commands.
147138
148-
This version of the function uses Qiskit in order to parse the *.qasm
149-
file.
139+
This version of the function uses Qiskit in order to parse the *.qasm file.
150140
151141
Args:
152142
eng (MainEngine): MainEngine to use for creating qubits and commands.
153143
filename (string): Path to *.qasm file
154144
155145
Note:
156-
At this time, we support most of OpenQASM 2.0 and some of 3.0,
157-
although the latter is still experimental.
146+
At this time, we support most of OpenQASM 2.0 and some of 3.0, although the latter is still experimental.
158147
"""
159148

160149
circuit = QuantumCircuit.from_qasm_file(filename)

projectq/libs/qasm/_qiskit_conv.py

+46-24
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,61 @@
1212
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
15-
from projectq.ops import Barrier, H, S, Sdagger, T, Tdagger, X, Y, Z, Rx, Ry, Rz, Swap, Toffoli, C, CNOT, U2, U3
15+
16+
"""Contains some helper variables for the Qiskit conversion functions"""
17+
18+
from projectq.ops import (
19+
Barrier,
20+
HGate,
21+
SGate,
22+
Sdagger,
23+
TGate,
24+
Tdagger,
25+
XGate,
26+
YGate,
27+
ZGate,
28+
Rx,
29+
Ry,
30+
Rz,
31+
SwapGate,
32+
Toffoli,
33+
C,
34+
CNOT,
35+
U2,
36+
U3,
37+
)
1638

1739
# ==============================================================================
1840
# Conversion map between Qiskit gate names and ProjectQ gates
1941

2042
gates_conv_table = {
21-
'barrier': Barrier,
22-
'h': H,
23-
's': S,
24-
'sdg': Sdagger,
25-
't': T,
26-
'tdg': Tdagger,
27-
'x': X,
28-
'y': Y,
29-
'z': Z,
30-
'swap': Swap,
31-
'rx': lambda a: Rx(a),
32-
'ry': lambda a: Ry(a),
33-
'rz': lambda a: Rz(a),
34-
'u1': lambda a: Rz(a),
35-
'u2': lambda p, l: U2(p, l),
36-
'u3': lambda t, p, l: U3(t, p, l),
37-
'phase': lambda a: Rz(a),
43+
'barrier': lambda: Barrier,
44+
'h': HGate,
45+
's': SGate,
46+
'sdg': lambda: Sdagger,
47+
't': TGate,
48+
'tdg': lambda: Tdagger,
49+
'x': XGate,
50+
'y': YGate,
51+
'z': ZGate,
52+
'swap': SwapGate,
53+
'rx': Rx,
54+
'ry': Ry,
55+
'rz': Rz,
56+
'u1': Rz,
57+
'u2': U2,
58+
'u3': U3,
59+
'phase': Rz,
3860
# Controlled gates
39-
'ch': C(H),
40-
'cx': CNOT,
41-
'cy': C(Y),
42-
'cz': C(Z),
43-
'cswap': C(Swap),
61+
'ch': lambda: C(HGate()),
62+
'cx': lambda: CNOT,
63+
'cy': lambda: C(YGate()),
64+
'cz': lambda: C(ZGate()),
65+
'cswap': lambda: C(SwapGate()),
4466
'crz': lambda a: C(Rz(a)),
4567
'cu1': lambda a: C(Rz(a)),
4668
'cu2': lambda p, l: C(U2(p, l)),
4769
'cu3': lambda t, p, l: C(U3(t, p, l)),
4870
# Doubly-controlled gates
49-
"ccx": Toffoli,
71+
"ccx": lambda: Toffoli,
5072
}

0 commit comments

Comments
 (0)