Skip to content

bugfix(grover): Initialise MatMultMapBody::contains_zero_val - #10

Open
endaytrer wants to merge 1 commit into
trishullab:mainfrom
endaytrer:patch-1
Open

bugfix(grover): Initialise MatMultMapBody::contains_zero_val#10
endaytrer wants to merge 1 commit into
trishullab:mainfrom
endaytrer:patch-1

Conversation

@endaytrer

Copy link
Copy Markdown
Contributor

Summary

MatMultMapBody::contains_zero_val is never initialised. Its indeterminate value is read in MatrixMultiplyV4WithInfoNode, where a stray true makes matrix multiplication silently drop path multiplicities. The visible consequence is that testGroversAlgo returns wrong answers from 16 qubits up — 0 of 10 seeds correct at 16, 32 and 64 qubits.

The defect

CFLOBDD/matmult_map.cpp:39 initialises two of the three flags:

MatMultMapBody::MatMultMapBody()
	: refCount(0), isCanonical(false)      // contains_zero_val left indeterminate
{
	hashCheck = NULL;
}

The field is only ever assigned in MatMultMapHandle::ForceAdd (matmult_map.cpp:217), when the (-1,-1) zero-sentinel pair is inserted. Every map that never goes through that path carries whatever was in memory — I have observed it reading as 208.

It is consumed twice in MatrixMultiplyV4WithInfoNode (CFLOBDD/matrix1234_node.cpp:5776 and :5785):

if (!(new_bb_return.Size() == 1 &&
      new_bb_return[0].mapContents->contains_zero_val))
    bb = MkLeftScalarTimesTopNode<MatMultMapHandle, VAL_TYPE>(v.second, bb);

v.second is the path count contributed by the A-connection. When the flag reads true the scaling is skipped and that multiplicity is lost. The second use, a few lines below, replaces the accumulator instead of adding into it, dropping terms outright.

Because the value is indeterminate rather than merely wrong, the failure is order-dependent: canonicalMatMultMapBodySet interns bodies by map contents alone — MatMultMapBody::operator== and Hash() do not include this flag — so a body interned by one multiply supplies the flag that a later, unrelated multiply reads. In a run of testGroversAlgo, U_s * U_s is exactly I when computed on its own and stops being I as soon as M * psi0 has run first.

Fix

--- a/CFLOBDD/matmult_map.cpp
+++ b/CFLOBDD/matmult_map.cpp
@@ -37,7 +37,7 @@
 
 // Constructor
 MatMultMapBody::MatMultMapBody()
-	: refCount(0), isCanonical(false)
+	: refCount(0), isCanonical(false), contains_zero_val(false)
 {
 	hashCheck = NULL;
 }

Once initialised, the flag is a pure function of the map contents — true exactly when (-1,-1) is present — so its omission from operator== and Hash() becomes harmless and needs no change.

Verification

cd CFLOBDD && make -j$(nproc)
for s in $(seq 1 10); do ./cflobdd testGroversAlgo 4 $s | grep '^equal: '; done

Ten seeds per size through 128 qubits, three at 256 and 512:

qubits before after time before time after nodes+edges before after
4 10/10 10/10 2 ms 2 ms 74 47
8 7/10 10/10 4.5 ms 2 ms 128 73
16 0/10 10/10 26.5 ms 3 ms 212 110
32 0/10 10/10 430 ms 4 ms 161 161
64 0/10 10/10 10.8 s 6 ms 809 250
128 10/10 10 ms 388
256 3/3 30 ms 617
512 3/3 115 ms 1,028

The speedup is a side effect of the same defect: dropped multiplicities were splitting entries that should have coincided, inflating the diagrams.

testGHZAlgo, testBVAlgo, testDJAlgo and testSimonsAlgo are unchanged and still correct.

Notes

  • Measured on the sequitur branch, since main's Makefile passes the Windows-only -lpsapi and -Wl,--stack and does not build on Linux as-is. The constructor is byte-identical on both branches.
  • The weighted-CFLOBDD multiplies (wmatrix1234_fb_mul_node.cpp, wmatrix1234_complex_fb_mul_node.cpp, wmatrix1234_fourier_mul_node.cpp) read this same field, several of them testing contains_zero_val == false explicitly. They were not exercised here — that arm was not built — but they rely on the same default.
  • Separately and not addressed here: with this fix applied, testGroversAlgo 10 (1024 qubits) terminates with SIGSEGV on every seed after roughly 2 s. That looks like an unrelated second issue.

Initialize contains_zero_val to make Grover's algorithm work properly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant