Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions pyqpanda-algorithm/pyqpanda_alg/QSVD/QSVD.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,15 @@ def loss(self, ls, return_type=True):
machine.run(prog, 1000)
re = machine.result().get_prob_list(qvec0 + qvec1)
re = np.array(parse_quantum_result_list(re, qvec0+qvec1, select_max=-1))
stv = StateVector(self.q0 + self.q1)
phase = stv.evolve(cir).ndarray().real
phase = phase.reshape(2**self.q1, 2**self.q0)
prob = np.diagonal(re.reshape(2**self.q1, 2**self.q0))
same_p = np.sum(prob)
if return_type:
return 1-same_p
else:
# state vector is only needed for the singular vectors, not for the loss
stv = StateVector(self.q0 + self.q1)
phase = stv.evolve(cir).ndarray().real
phase = phase.reshape(2**self.q1, 2**self.q0)
return phase, np.argmax(abs(phase))

def QSVD_min(self):
Expand Down
59 changes: 59 additions & 0 deletions test/QAlgBase/Test_QSVD_SVD.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import time

import pytest
import numpy as np
from pyqpanda_alg.QSVD import SVD
from pyqpanda_alg.QSVD import QSVD as qsvd_module
import warnings


Expand Down Expand Up @@ -30,6 +33,62 @@ def test_orthogonality_properties(self):
assert np.all(np.diff(q_sorted) <= 0), "QSVD奇异值应该降序排列"
assert np.all(np.diff(np_sorted) <= 0), "NumPy奇异值应该降序排列"

def test_singular_values_against_numpy(self):
matrix = np.random.random(16).reshape([4, 4])

qsvd_instance = SVD(matrix_in=matrix)
para = qsvd_instance.QSVD_min()
q_singular = np.sort(np.diag(qsvd_instance.return_diag(para)))[::-1]

np_singular = np.linalg.svd(matrix, compute_uv=False)

rel_err = np.max(np.abs(q_singular - np_singular) / np_singular)
assert rel_err < 1e-2, f"singular value relative error too large: {rel_err}"

def test_singular_vectors_against_numpy(self):
matrix = np.random.random(32).reshape([4, 8])

qsvd_instance = SVD(matrix_in=matrix)
para = qsvd_instance.QSVD_min()
# loss() reports the index the dominant singular value ended up on
max_index = qsvd_instance.loss(para, return_type=False)[1]
left = qsvd_instance.max_eig('0', para, max_index)
right = qsvd_instance.max_eig('1', para, max_index)

u_np, s_np, v_np = np.linalg.svd(matrix)

cos_left = abs(np.dot(left, u_np[:, 0])) / (np.linalg.norm(left) * np.linalg.norm(u_np[:, 0]))
cos_right = abs(np.dot(right, v_np[0])) / (np.linalg.norm(right) * np.linalg.norm(v_np[0]))
assert cos_left > 0.99, f"left singular vector overlap too low: {cos_left}"
assert cos_right > 0.99, f"right singular vector overlap too low: {cos_right}"

def test_loss_skips_state_vector_on_scalar_path(self, monkeypatch):
# the scalar loss is the optimizer inner loop, it must not simulate the state vector
built = []
real_state_vector = qsvd_module.StateVector

def counting_state_vector(*args, **kwargs):
built.append(1)
return real_state_vector(*args, **kwargs)

monkeypatch.setattr(qsvd_module, 'StateVector', counting_state_vector)

qsvd_instance = SVD(matrix_in=np.random.random(16).reshape([4, 4]))
qsvd_instance.loss(qsvd_instance.parameter)
assert len(built) == 0, "scalar loss built a state vector"

qsvd_instance.loss(qsvd_instance.parameter, return_type=False)
assert len(built) == 1, "matrix loss did not build a state vector"

def test_qsvd_min_runtime(self):
matrix = np.random.random(64).reshape([8, 8])

start = time.perf_counter()
SVD(matrix_in=matrix).QSVD_min()
elapsed = time.perf_counter() - start

assert elapsed < 20, f"QSVD_min on an 8x8 matrix took {elapsed:.1f}s"


if __name__ == "__main__":
# 运行测试
Expand Down