【代码贡献】Fix QPCA crash on 4-feature input and k=2 returning 0 - #43
Open
mnn31 wants to merge 1 commit into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题 / Problem
Three of the four
qpca()entry points are broken. Onlyqpca(A, 1)on a2-feature input, the case in the docstring and the demo notebook, works.
原因 / Root cause
taoandqmare only assigned inside theA.shape[0] == 2branch. TheA.shape[0] == 4branch assignsqmbut nevertao, so the next lineraises
UnboundLocalError. This is specific to 4 features: other featurecounts fail earlier and more clearly at
A.reshape(1, 2 ** n), since thecovariance matrix has n² entries and the reshape asks for 2ⁿ, which agree
only at n=2 and n=4.
data = 0is initialised and only overwritten insideif k == 1, soqpca(A, 2)falls through and returns the integer 0.Invalid
kcallssys.exit(), which terminates the caller's processinstead of raising.
The k=1 projection vector takes
np.sqrttwice.result_circuitAisalready the amplitude vector, and on a non-degenerate spectrum the
post-selection leaves two outcomes, so dividing by
sum_Aalready makes itunit norm. Taking its square root again gives a vector of norm 2^(1/4) =
1.1892, so every projected coordinate came out 18.9% too large.
I also checked the n=4 circuit code before deciding what to do with it. Wiring
tao/qmby hand is not enough to make it work:|00000000>with probability 1, so the ancilla the algorithm post-selects onnever flips and there is no output to read.
get_prob_dictsits inside
if A.shape[0] == 2._init_cirignores itsstate_vectorargument, so nothing is amplitudeencoded and the register the n=4 path would need is never populated.
Finishing that path means writing the state preparation and the extraction
step, which is a feature, not a bugfix. I left the n=4 circuit code in place
and gated the entry point instead.
修改 / Fix
NotImplementedErrorwith the count in the message,
koutside {1, 2} raisesValueError. Nomore
UnboundLocalError, no moresys.exit().k=2returns the actual PCA scores.tao = min(lambda) - 1puts thethreshold below every eigenvalue, and the circuit confirms this: the
post-selection succeeds with probability 1, so the algorithm reports that
nothing is filtered out. The retained subspace is therefore the whole
feature space, and the basis for it is taken from the eigendecomposition the
module already computes. Output is
norm_x @ V.np.linalg.eigtonp.linalg.eigh. Thecovariance matrix is symmetric by construction, so this guarantees real
eigenvalues and an orthonormal basis, and the components are sorted
descending.
taois unaffected, it only readsmin,maxandsum.np.sqrton the k=1 projection direction.result_idealAblock, which was computed and then neverread, and the now unused
import sys.sorted()order socomponent assignment does not lean on dict insertion order. On this circuit
the two keys already came back sorted and at equal probability, so nothing
observable changes.
数值验证 / Numerical validation
Compared against classical PCA, numpy eigendecomposition of the same
covariance matrix, on the docstring example. Eigenvalues are 30.4194 and
7.7472.
k=1, quantum output averaged over 20 runs (the circuit samples 8192 shots, so
it carries sampling noise of about 0.01 per coordinate):
Max absolute error against classical drops from 0.5716 to 0.0229, which is
19.4% down to 0.78% of the largest coordinate. Correlation with the classical
projection is 0.99998. The recovered projection direction has norm 0.99997
against 1.1892 before, and sits 0.74 degrees off the classical principal
component.
k=2, previously the integer 0, now a (6, 2) array:
The scores are decorrelated and their column variances are the eigenvalues in
descending order, which is what distinguishes PCA output from the centred
input sitting in the original feature basis.
测试 / Tests
test/QPCA/Test_qpca.py, 8 tests, up from 1. The originaltest_qpca_normalis untouched, the diff against develop is pure insertion. Added: k=1 against
classical PCA, k=1 projection direction is unit norm on the documented
example, k=2 decorrelation plus column variances plus per-column equality with
the classical scores, invalid k raises
ValueError(parametrised over 0, 3,-1), 4-feature input raises
NotImplementedErrorfor both k=1 and k=2.Ran the QPCA file 10 times in a row to check the tolerances hold against shot
noise. The demo notebook
pyqpanda-algorithm/test/07-QPCA/demo01-QPCA-qpca.ipynbuses k=1 and stillruns.
已知限制(既有行为,本 PR 未改动) / Known limitation (pre-existing, unchanged by this PR)
This is existing upstream behaviour; this PR neither introduces nor changes
it. Flagging it so the numbers above are not read as more than they are.
The phase estimation gates are constants and
_init_cirnever encodesstate_vector, so the input matrix only reaches the circuit through thetaobranch comparison. The k=1 direction the circuit returns is therefore always
[1/sqrt(2), 1/sqrt(2)], which coincides with the principal component of the
docstring example but is not correct for general input. On
[[-3,3],[-2,2],[-1,1],[1,-1],[2,-2],[3,-3]], whose principal component is[0.7071, -0.7071], classical PCA gives projections up to 4.24 while
qpcareturns about 0.02.
The extraction is also sign-blind by construction: amplitudes are recovered as
square roots of measured probabilities, which are non-negative, so a principal
component with mixed signs can never be reproduced no matter what the circuit
does. Fixing this needs real state preparation and a data dependent evolution,
so I kept it out of this PR. Happy to open a separate one if that is wanted.