Skip to content

Commit

Permalink
Merge pull request #12 from qDNA-yonsei/ae_feature_map
Browse files Browse the repository at this point in the history
Amplitude encoding feature map
  • Loading branch information
israelferrazaraujo authored Mar 24, 2024
2 parents ef38133 + 4d1f9dd commit 9ef4424
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 34 deletions.
14 changes: 12 additions & 2 deletions qdna/embedding/ae_feature_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,17 @@ def _build(self) -> None:
# the global phase only depends on the first coordinate of the
# state vector.
if self._set_global_phase:
circuit.global_phase = ((_sign(params[0])-1) / -2) * pi
circuit.global_phase += ((_sign(params[0])-1) / -2) * pi

for _ in range(self._reps):
self.compose(circuit, self.qubits, inplace=True, wrap=False)
# Due to a bug introduced in Qiskit 1.0, it is necessary to use
# `wrap=True` when `self._set_global_phase=True`.
# The `global_phase` of `circuit` is not taking effect
# when `wrap=False`. In future, test whether this is still
# necessary. Using the `wrap=True` parameter causes slowdowns.
self.compose(
circuit,
self.qubits,
inplace=True,
wrap=self._set_global_phase
)
4 changes: 3 additions & 1 deletion qdna/embedding/nqe_ae_feature_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def __init__(
insert_barriers: bool = False,
name: str = "NqeAeFeatureMap",
nn = None,
set_global_phase: bool = False
) -> None:

super().__init__(
Expand All @@ -44,5 +45,6 @@ def __init__(
'reps':reps,
'parameter_prefix':parameter_prefix,
'insert_barriers':insert_barriers,
'name':name
'name':name,
'set_global_phase':set_global_phase
}
95 changes: 67 additions & 28 deletions qdna/embedding/nqe_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
from qiskit import QuantumCircuit
from qiskit_machine_learning.connectors import TorchConnector
from qiskit_machine_learning.neural_networks import SamplerQNN
from qiskit_machine_learning.exceptions import QiskitMachineLearningError

import torch
import torch.optim as optim
from torch import optim
from torch.nn import (
Module,
Linear,
Expand All @@ -28,6 +29,7 @@
ReLU
)

# pylint: disable=maybe-no-member

class _Transform(Module):
def __init__(self, nn):
Expand Down Expand Up @@ -61,14 +63,33 @@ def __init__(self, nn) -> None:
self._transform = None


def fit(self, X, Y, batch_size=25, iters=100, optimizer=None, loss_func=None, distance='fidelity', sampler=None, verbose=1):
def fit(
self,
x, y,
batch_size=25,
iters=100,
optimizer=None,
loss_func=None,
distance='fidelity',
sampler=None,
verbose=1
):
if self.nn is None:
self.nn = Sequential(
Linear(self.num_parameters_settable, self.num_parameters_settable*3),
Linear(
self.num_parameters_settable,
self.num_parameters_settable*3
),
ReLU(),
Linear(self.num_parameters_settable*3, self.num_parameters_settable*3),
Linear(
self.num_parameters_settable*3,
self.num_parameters_settable*3
),
ReLU(),
Linear(self.num_parameters_settable*3, self.num_parameters_settable)
Linear(
self.num_parameters_settable*3,
self.num_parameters_settable
)
)

qnn = self.create_qnn(distance, sampler)
Expand All @@ -85,15 +106,19 @@ def fit(self, X, Y, batch_size=25, iters=100, optimizer=None, loss_func=None, di
model.train() # Set model to training mode

for i in range(iters):
X1_batch, X2_batch, Y_batch = self.new_data(batch_size, X, Y) # Random sampling of data.
# Random sampling of data.
x1_batch, x2_batch, y_batch = self.new_data(batch_size, x, y)

optimizer.zero_grad(set_to_none=True) # Initialize gradient
output = model(X1_batch, X2_batch) # Forward pass
loss = loss_func(output, Y_batch) # Calculate loss
loss.backward() # Backward pass
optimizer.step() # Optimize weights
try:
optimizer.zero_grad(set_to_none=True) # Initialize gradient
output = model(x1_batch, x2_batch) # Forward pass
loss = loss_func(output, y_batch) # Calculate loss
loss.backward() # Backward pass
optimizer.step() # Optimize weights

loss_list.append(loss.item()) # Store loss
loss_list.append(loss.item()) # Store loss
except QiskitMachineLearningError:
loss_list.append(loss_list[-1])

if verbose:
print(
Expand Down Expand Up @@ -133,13 +158,27 @@ def create_qnn(self, distance, sampler):
if distance == 'hs':
qc = QuantumCircuit(self.num_qubits + 1)
qc.h(0)
qc.compose(feature_map.control(1, label='map'), range(self.num_qubits+1), inplace=True)
qc.compose(feature_map_inv.control(1, label='map_inv'), range(self.num_qubits+1), inplace=True)
qc.compose(
feature_map.control(1, label='map'),
range(self.num_qubits+1),
inplace=True
)
qc.compose(
feature_map_inv.control(1, label='map_inv'),
range(self.num_qubits+1),
inplace=True
)
qc.h(0)
else:
qc = QuantumCircuit(self.num_qubits)
qc.compose(feature_map, inplace=True)
qc.compose(feature_map_inv, inplace=True)
qc.compose(
feature_map,
inplace=True
)
qc.compose(
feature_map_inv,
inplace=True
)

qnn = SamplerQNN(
sampler=sampler,
Expand All @@ -152,19 +191,19 @@ def create_qnn(self, distance, sampler):


@staticmethod
def new_data(batch_size, X, Y):
X1_new, X2_new, Y_new = [], [], []
for i in range(batch_size):
n, m = np.random.randint(len(X)), np.random.randint(len(X))
X1_new.append(X[n])
X2_new.append(X[m])
if Y[n] == Y[m]:
Y_new.append(1)
def new_data(batch_size, x, y):
x1_new, x2_new, y_new = [], [], []
for _ in range(batch_size):
n, m = np.random.randint(len(x)), np.random.randint(len(x))
x1_new.append(x[n])
x2_new.append(x[m])
if y[n] == y[m]:
y_new.append(1)
else:
Y_new.append(0)
y_new.append(0)

return (
torch.tensor(np.array(X1_new), dtype=torch.float32),
torch.tensor(np.array(X2_new), dtype=torch.float32),
torch.tensor(np.array(Y_new), dtype=torch.float32)
torch.tensor(np.array(x1_new), dtype=torch.float32),
torch.tensor(np.array(x2_new), dtype=torch.float32),
torch.tensor(np.array(y_new), dtype=torch.float32)
)
3 changes: 0 additions & 3 deletions test/embedding/test_ae_feature_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,6 @@ def test_fixed_state(self):
-0.14796486, 0.00971746, -0.15238775, 0.12996466,
-0.19630254, -0.08859373, -0.12830557, 0.12446281]

# state_vector = state_vector / np.linalg.norm(state_vector)

feature_map = AeFeatureMap(n_qubits, normalize=False, set_global_phase=True)

circuit = QuantumCircuit(n_qubits)
Expand All @@ -111,5 +109,4 @@ def test_fixed_state(self):

state = Statevector(circuit)

state_vector = state_vector / np.linalg.norm(state_vector)
self.assertTrue(np.allclose(state_vector, state, rtol=1e-03, atol=1e-05))

0 comments on commit 9ef4424

Please sign in to comment.