Skip to content

Commit

Permalink
Merge pull request #111 from qtzhuang/zqt
Browse files Browse the repository at this point in the history
Add some pre-build circuit templates and tests
  • Loading branch information
Zhaoyilunnn committed Nov 14, 2023
2 parents 7e2a50c + 54b6ba2 commit d175036
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 0 deletions.
57 changes: 57 additions & 0 deletions quafu/algorithms/embedding/angle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# (C) Copyright 2023 Beijing Academy of Quantum Information Sciences
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Angel Embedding in Quantum Data embedding"""
from quafu.circuits import QuantumCircuit
import quafu.elements.element_gates as qeg
import numpy as np

ROT = {"X": qeg.RXGate, "Y": qeg.RYGate, "Z": qeg.RZGate}

class AngleEmbedding:
def __init__(self, features, num_qubits: int, rotation="X"):
"""
Args:
features(np.array): The data to be embedded
num_qubits(int): the number of qubit
rotation(str): type of rotations used
"""
if rotation not in ROT:
raise ValueError(f"Rotation option {rotation} not recognized.")

shape = np.shape(features)[-1:]
n_features = shape[0]
if n_features != num_qubits:
raise ValueError(
"The length of Features must match num_qubits"
)
self.features = features
self.num_qubits = num_qubits
self.op = ROT[rotation]

"""Build the embedding circuit and get the gate_list"""
self.gate_list = self._build()

def _build(self):
gate_list = []
for i in range(self.num_qubits):
gate = self.op(pos=i, paras=self.features[i])
gate_list.append(gate)
return gate_list

def __iter__(self):
return iter(self.gate_list)

def __getitem__(self, index):
return self.gate_list[index]
80 changes: 80 additions & 0 deletions quafu/algorithms/layers/basic_entangle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# (C) Copyright 2023 Beijing Academy of Quantum Information Sciences
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Layers consisting of one-parameter single-qubit rotations on each qubit, followed by a closed chain or ring of CNOT gates"""
from quafu.circuits import QuantumCircuit
import quafu.elements.element_gates as qeg
import numpy as np

ROT = {"X": qeg.RXGate, "Y": qeg.RYGate, "Z": qeg.RZGate}

class BasicEntangleLayers:
def __init__(self, weights, num_qubits, rotation="X"):
"""
Args:
weights(array): Each weight is used as a parameter for the rotation
num_qubits(int): the number of qubit
rotation(str): one-parameter single-qubit gate to use
"""
weights = np.asarray(weights)
"""convert weights to numpy array if weights is list otherwise keep unchanged"""
shape = np.shape(weights)

##TODO(qtzhuang): If weights are batched, i.e. dim>3, additional processing is required
if weights.ndim > 2:
raise ValueError(
f"Weights tensor must be 2-dimensional "
)

if not (len(shape) == 3 or len(shape) == 2): # 3 is when batching, 2 is no batching
raise ValueError(
f"Weights tensor must be 2-dimensional "
f"or 3-dimensional if batching; got shape {shape}"
)

if shape[-1] != num_qubits:
# index with -1 since we may or may not have batching in first dimension
raise ValueError(
f"Weights tensor must have last dimension of length {num_qubits}; got {shape[-1]}"
)
self.weights = weights
self.num_qubits = num_qubits
self.op = ROT[rotation]

"""Build the quantum basic_entangle layer and get the gate_list"""
self.gate_list = self._build()

def _build(self):
repeat = np.shape(self.weights)[-2]
gate_list = []
for layer in range(repeat):
for i in range(self.num_qubits):
gate = self.op(pos=i, paras=self.weights[layer][i])
gate_list.append(gate)

# if num_qubits equals two, it just need to apply CNOT one time
if self.num_qubits == 2:
gate_list.append(qeg.CXGate(0,1))

elif self.num_qubits > 2:
for i in range(self.num_qubits):
gate_list.append(qeg.CXGate(i,(i+1)%self.num_qubits))

return gate_list

def __iter__(self):
return iter(self.gate_list)

def __getitem__(self, index):
return self.gate_list[index]
5 changes: 5 additions & 0 deletions quafu/circuits/quantum_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ def gates(self):
@gates.setter
def gates(self, gates:list):
self._gates = gates

#TODO(qtzhuang): add_gates is just a temporary call function to add gate from gate_list
def add_gates(self, gates: list):
for gate in gates:
self.add_gate(gate)

def add_gate(self, gate: QuantumGate):
pos = np.array(gate.pos)
Expand Down
32 changes: 32 additions & 0 deletions tests/quafu/algorithms/angle_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# (C) Copyright 2023 Beijing Academy of Quantum Information Sciences
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from quafu.circuits import QuantumCircuit
import quafu.elements.element_gates as qeg
from quafu.algorithms.embedding.angle import AngleEmbedding
import numpy as np


class TestAngleEmbedding:
"""Example of angle embedding"""

def test_build(self):
num_qubits = 4
qc = QuantumCircuit(num_qubits)
feature = np.array([[6,-12.5,11.15,7],[8,9.5,-11,-5],[5,0.5,8,-7]])
for i in range(4):
qc.add_gate(qeg.HGate(pos=i))
for i in range(len(feature)):
qc.add_gates(AngleEmbedding(features=feature[i], num_qubits=num_qubits,rotation='Y'))
qc.draw_circuit(width=num_qubits)
43 changes: 43 additions & 0 deletions tests/quafu/algorithms/basic_entangle_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# (C) Copyright 2023 Beijing Academy of Quantum Information Sciences
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from quafu.circuits import QuantumCircuit
import quafu.elements.element_gates as qeg
from quafu.algorithms.layers.basic_entangle import BasicEntangleLayers
import numpy as np

class TestBasicEntangleLayers:
"""Example of building basic_entangle layer"""
def test_build(self):
num_qubits = 3
qc = QuantumCircuit(num_qubits)
weights = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6], [0.7, 0.8, 0.9]])
# weights = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]])
# weights = np.array([[0.1, 0.2], [0.3, 0.4]])
qc.add_gates(BasicEntangleLayers(weights=weights, num_qubits=num_qubits,rotation='Y'))
qc.draw_circuit(width=num_qubits)

##TODO(): if weights are as follows, it need additional processing.
# weights = np.array([
# [
# [1, 2, 3, 4],
# [5, 6, 7, 8],
# [9, 10, 11, 12]
# ],
# [
# [13, 14, 15, 16],
# [17, 18, 19, 20],
# [21, 22, 23, 24]
# ]
# ])

0 comments on commit d175036

Please sign in to comment.