|
13 | 13 | """X, CX, CCX and multi-controlled X gates.""" |
14 | 14 | from __future__ import annotations |
15 | 15 | from typing import Optional, Union, Type |
16 | | -from math import ceil, pi |
| 16 | +from math import pi |
17 | 17 | import numpy |
18 | 18 | from qiskit.circuit.controlledgate import ControlledGate |
19 | 19 | from qiskit.circuit.singleton import SingletonGate, SingletonControlledGate, stdlib_singleton_key |
@@ -1371,47 +1371,12 @@ def inverse(self, annotated: bool = False): |
1371 | 1371 |
|
1372 | 1372 | def _define(self): |
1373 | 1373 | """Define the MCX gate using recursion.""" |
1374 | | - # pylint: disable=cyclic-import |
1375 | | - from qiskit.circuit.quantumcircuit import QuantumCircuit |
1376 | 1374 |
|
1377 | | - q = QuantumRegister(self.num_qubits, name="q") |
1378 | | - qc = QuantumCircuit(q, name=self.name) |
1379 | | - if self.num_qubits == 4: |
1380 | | - qc._append(C3XGate(), q[:], []) |
1381 | | - self.definition = qc |
1382 | | - elif self.num_qubits == 5: |
1383 | | - qc._append(C4XGate(), q[:], []) |
1384 | | - self.definition = qc |
1385 | | - else: |
1386 | | - num_ctrl_qubits = len(q) - 1 |
1387 | | - q_ancilla = q[-1] |
1388 | | - q_target = q[-2] |
1389 | | - middle = ceil(num_ctrl_qubits / 2) |
1390 | | - first_half = [*q[:middle]] |
1391 | | - second_half = [*q[middle : num_ctrl_qubits - 1], q_ancilla] |
1392 | | - |
1393 | | - qc._append( |
1394 | | - MCXVChain(num_ctrl_qubits=len(first_half), dirty_ancillas=True), |
1395 | | - qargs=[*first_half, q_ancilla, *q[middle : middle + len(first_half) - 2]], |
1396 | | - cargs=[], |
1397 | | - ) |
1398 | | - qc._append( |
1399 | | - MCXVChain(num_ctrl_qubits=len(second_half), dirty_ancillas=True), |
1400 | | - qargs=[*second_half, q_target, *q[: len(second_half) - 2]], |
1401 | | - cargs=[], |
1402 | | - ) |
1403 | | - qc._append( |
1404 | | - MCXVChain(num_ctrl_qubits=len(first_half), dirty_ancillas=True), |
1405 | | - qargs=[*first_half, q_ancilla, *q[middle : middle + len(first_half) - 2]], |
1406 | | - cargs=[], |
1407 | | - ) |
1408 | | - qc._append( |
1409 | | - MCXVChain(num_ctrl_qubits=len(second_half), dirty_ancillas=True), |
1410 | | - qargs=[*second_half, q_target, *q[: len(second_half) - 2]], |
1411 | | - cargs=[], |
1412 | | - ) |
| 1375 | + # pylint: disable=cyclic-import |
| 1376 | + from qiskit.synthesis.multi_controlled import synth_mcx_1_clean_b95 |
1413 | 1377 |
|
1414 | | - self.definition = qc |
| 1378 | + qc = synth_mcx_1_clean_b95(self.num_ctrl_qubits) |
| 1379 | + self.definition = qc |
1415 | 1380 |
|
1416 | 1381 |
|
1417 | 1382 | class MCXVChain(MCXGate): |
@@ -1513,92 +1478,21 @@ def get_num_ancilla_qubits(num_ctrl_qubits: int, mode: str = "v-chain"): |
1513 | 1478 |
|
1514 | 1479 | def _define(self): |
1515 | 1480 | """Define the MCX gate using a V-chain of CX gates.""" |
1516 | | - # pylint: disable=cyclic-import |
1517 | | - from qiskit.circuit.quantumcircuit import QuantumCircuit |
1518 | | - |
1519 | | - q = QuantumRegister(self.num_qubits, name="q") |
1520 | | - qc = QuantumCircuit(q, name=self.name) |
1521 | | - q_controls = q[: self.num_ctrl_qubits] |
1522 | | - q_target = q[self.num_ctrl_qubits] |
1523 | | - q_ancillas = q[self.num_ctrl_qubits + 1 :] |
1524 | 1481 |
|
1525 | 1482 | if self._dirty_ancillas: |
1526 | | - if self.num_ctrl_qubits < 3: |
1527 | | - qc.mcx(q_controls, q_target) |
1528 | | - elif not self._relative_phase and self.num_ctrl_qubits == 3: |
1529 | | - qc._append(C3XGate(), [*q_controls, q_target], []) |
1530 | | - else: |
1531 | | - num_ancillas = self.num_ctrl_qubits - 2 |
1532 | | - targets = [q_target] + q_ancillas[:num_ancillas][::-1] |
1533 | | - |
1534 | | - for j in range(2): |
1535 | | - for i in range(self.num_ctrl_qubits): # action part |
1536 | | - if i < self.num_ctrl_qubits - 2: |
1537 | | - if targets[i] != q_target or self._relative_phase: |
1538 | | - # gate cancelling |
1539 | | - |
1540 | | - # cancel rightmost gates of action part |
1541 | | - # with leftmost gates of reset part |
1542 | | - if self._relative_phase and targets[i] == q_target and j == 1: |
1543 | | - qc.cx(q_ancillas[num_ancillas - i - 1], targets[i]) |
1544 | | - qc.t(targets[i]) |
1545 | | - qc.cx(q_controls[self.num_ctrl_qubits - i - 1], targets[i]) |
1546 | | - qc.tdg(targets[i]) |
1547 | | - qc.h(targets[i]) |
1548 | | - else: |
1549 | | - qc.h(targets[i]) |
1550 | | - qc.t(targets[i]) |
1551 | | - qc.cx(q_controls[self.num_ctrl_qubits - i - 1], targets[i]) |
1552 | | - qc.tdg(targets[i]) |
1553 | | - qc.cx(q_ancillas[num_ancillas - i - 1], targets[i]) |
1554 | | - else: |
1555 | | - controls = [ |
1556 | | - q_controls[self.num_ctrl_qubits - i - 1], |
1557 | | - q_ancillas[num_ancillas - i - 1], |
1558 | | - ] |
1559 | | - |
1560 | | - qc.ccx(controls[0], controls[1], targets[i]) |
1561 | | - else: |
1562 | | - # implements an optimized toffoli operation |
1563 | | - # up to a diagonal gate, akin to lemma 6 of arXiv:1501.06911 |
1564 | | - qc.h(targets[i]) |
1565 | | - qc.t(targets[i]) |
1566 | | - qc.cx(q_controls[self.num_ctrl_qubits - i - 2], targets[i]) |
1567 | | - qc.tdg(targets[i]) |
1568 | | - qc.cx(q_controls[self.num_ctrl_qubits - i - 1], targets[i]) |
1569 | | - qc.t(targets[i]) |
1570 | | - qc.cx(q_controls[self.num_ctrl_qubits - i - 2], targets[i]) |
1571 | | - qc.tdg(targets[i]) |
1572 | | - qc.h(targets[i]) |
1573 | | - |
1574 | | - break |
1575 | | - |
1576 | | - for i in range(num_ancillas - 1): # reset part |
1577 | | - qc.cx(q_ancillas[i], q_ancillas[i + 1]) |
1578 | | - qc.t(q_ancillas[i + 1]) |
1579 | | - qc.cx(q_controls[2 + i], q_ancillas[i + 1]) |
1580 | | - qc.tdg(q_ancillas[i + 1]) |
1581 | | - qc.h(q_ancillas[i + 1]) |
1582 | | - |
1583 | | - if self._action_only: |
1584 | | - qc.ccx(q_controls[-1], q_ancillas[-1], q_target) |
1585 | | - |
1586 | | - break |
1587 | | - else: |
1588 | | - qc.rccx(q_controls[0], q_controls[1], q_ancillas[0]) |
1589 | | - i = 0 |
1590 | | - for j in range(2, self.num_ctrl_qubits - 1): |
1591 | | - qc.rccx(q_controls[j], q_ancillas[i], q_ancillas[i + 1]) |
| 1483 | + # pylint: disable=cyclic-import |
| 1484 | + from qiskit.synthesis.multi_controlled import synth_mcx_n_dirty_i15 |
1592 | 1485 |
|
1593 | | - i += 1 |
1594 | | - |
1595 | | - qc.ccx(q_controls[-1], q_ancillas[i], q_target) |
1596 | | - |
1597 | | - for j in reversed(range(2, self.num_ctrl_qubits - 1)): |
1598 | | - qc.rccx(q_controls[j], q_ancillas[i - 1], q_ancillas[i]) |
| 1486 | + qc = synth_mcx_n_dirty_i15( |
| 1487 | + self.num_ctrl_qubits, |
| 1488 | + self._relative_phase, |
| 1489 | + self._action_only, |
| 1490 | + ) |
1599 | 1491 |
|
1600 | | - i -= 1 |
| 1492 | + else: # use clean ancillas |
| 1493 | + # pylint: disable=cyclic-import |
| 1494 | + from qiskit.synthesis.multi_controlled import synth_mcx_n_clean_m15 |
1601 | 1495 |
|
1602 | | - qc.rccx(q_controls[0], q_controls[1], q_ancillas[i]) |
| 1496 | + qc = synth_mcx_n_clean_m15(self.num_ctrl_qubits) |
1603 | 1497 |
|
1604 | 1498 | self.definition = qc |
0 commit comments