Skip to content

Commit b39ac31

Browse files
authored
Merge pull request #176 from GenericP3rson/qft_layer
QFT Layer and Algorithm
2 parents 0995612 + dd31bf1 commit b39ac31

File tree

3 files changed

+146
-1
lines changed

3 files changed

+146
-1
lines changed

torchquantum/algorithm/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@
2323
"""
2424

2525
from .vqe import *
26-
from .hamiltonian import *
26+
from .hamiltonian import *
27+
from .qft import *

torchquantum/algorithm/qft.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import torchquantum as tq
2+
from typing import Iterable
3+
4+
__all__ = ["QFT"]
5+
6+
7+
class QFT(object):
8+
def __init__(
9+
self, n_wires: int = None, wires: Iterable = None, do_swaps=True
10+
) -> None:
11+
"""Init function for QFT class
12+
13+
Args:
14+
n_wires (int): Number of wires for the QFT as an integer
15+
wires (Iterable): Wires to perform the QFT as an Iterable
16+
add_swaps (bool): Whether or not to add the final swaps in a boolean format
17+
inverse (bool): Whether to create an inverse QFT layer in a boolean format
18+
"""
19+
super().__init__()
20+
21+
self.n_wires = n_wires
22+
self.wires = wires
23+
self.do_swaps = do_swaps
24+
25+
def construct_qft_circuit(self) -> tq.QuantumModule:
26+
"""Construct the QFT circuit."""
27+
return tq.layer.QFTLayer(
28+
n_wires=self.n_wires, wires=self.wires, do_swaps=self.do_swaps
29+
)
30+
31+
def construct_inverse_qft_circuit(self) -> tq.QuantumModule:
32+
"""Construct the inverse of a QFT circuit."""
33+
return tq.layer.QFTLayer(
34+
n_wires=self.n_wires, wires=self.wires, do_swaps=self.do_swaps, inverse=True
35+
)

torchquantum/layer/layers.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
SOFTWARE.
2323
"""
2424

25+
import torch
2526
import torch.nn as nn
2627
import torchquantum as tq
2728
import torchquantum.functional as tqf
@@ -49,6 +50,7 @@
4950
"CXCXCXLayer",
5051
"SWAPSWAPLayer",
5152
"RXYZCXLayer0",
53+
"QFTLayer",
5254
]
5355

5456

@@ -1467,6 +1469,113 @@ def build_layers(self):
14671469
return layers_all
14681470

14691471

1472+
class QFTLayer(tq.QuantumModule):
1473+
def __init__(
1474+
self,
1475+
n_wires: int = None,
1476+
wires: Iterable = None,
1477+
do_swaps: bool = True,
1478+
inverse: bool = False,
1479+
):
1480+
"""
1481+
Constructs a Quantum Fourier Transform (QFT) layer
1482+
1483+
Args:
1484+
n_wires (int): Number of wires for the QFT as an integer
1485+
wires (Iterable): Wires to perform the QFT as an Iterable
1486+
do_swaps (bool): Whether or not to add the final swaps in a boolean format
1487+
inverse (bool): Whether to create an inverse QFT layer in a boolean format
1488+
"""
1489+
super().__init__()
1490+
1491+
assert n_wires is not None or wires is not None
1492+
1493+
if n_wires is None:
1494+
self.n_wires = len(wires)
1495+
1496+
if wires is None:
1497+
wires = range(n_wires)
1498+
1499+
self.n_wires = n_wires
1500+
self.wires = wires
1501+
self.do_swaps = do_swaps
1502+
1503+
if inverse:
1504+
self.gates_all = self.build_inverse_circuit()
1505+
else:
1506+
self.gates_all = self.build_circuit()
1507+
1508+
def build_circuit(self):
1509+
"""Construct a QFT circuit."""
1510+
1511+
operation_list = []
1512+
1513+
# add the H and CU1 gates
1514+
for top_wire in range(self.n_wires):
1515+
operation_list.append({"name": "hadamard", "wires": self.wires[top_wire]})
1516+
for wire in range(top_wire + 1, self.n_wires):
1517+
lam = torch.pi / (2 ** (wire - top_wire))
1518+
operation_list.append(
1519+
{
1520+
"name": "cu1",
1521+
"params": lam,
1522+
"wires": [self.wires[wire], self.wires[top_wire]],
1523+
}
1524+
)
1525+
1526+
# add swaps if specified
1527+
if self.do_swaps:
1528+
for wire in range(self.n_wires // 2):
1529+
operation_list.append(
1530+
{
1531+
"name": "swap",
1532+
"wires": [
1533+
self.wires[wire],
1534+
self.wires[self.n_wires - wire - 1],
1535+
],
1536+
}
1537+
)
1538+
1539+
return tq.QuantumModule.from_op_history(operation_list)
1540+
1541+
def build_inverse_circuit(self):
1542+
"""Construct the inverse of a QFT circuit."""
1543+
1544+
operation_list = []
1545+
1546+
# add swaps if specified
1547+
if self.do_swaps:
1548+
for wire in range(self.n_wires // 2):
1549+
operation_list.append(
1550+
{
1551+
"name": "swap",
1552+
"wires": [
1553+
self.wires[wire],
1554+
self.wires[self.n_wires - wire - 1],
1555+
],
1556+
}
1557+
)
1558+
1559+
# add the CU1 and H gates
1560+
for top_wire in range(self.n_wires)[::-1]:
1561+
for wire in range(top_wire + 1, self.n_wires)[::-1]:
1562+
lam = -torch.pi / (2 ** (wire - top_wire))
1563+
operation_list.append(
1564+
{
1565+
"name": "cu1",
1566+
"params": lam,
1567+
"wires": [self.wires[wire], self.wires[top_wire]],
1568+
}
1569+
)
1570+
operation_list.append({"name": "hadamard", "wires": self.wires[top_wire]})
1571+
1572+
return tq.QuantumModule.from_op_history(operation_list)
1573+
1574+
@tq.static_support
1575+
def forward(self, q_device: tq.QuantumDevice):
1576+
self.gates_all(q_device)
1577+
1578+
14701579
layer_name_dict = {
14711580
"u3cu3_0": U3CU3Layer0,
14721581
"cu3_0": CU3Layer0,

0 commit comments

Comments
 (0)