Skip to content

Commit c827537

Browse files
authored
Follow-up to #333 - fix tests for public repo (#335)
This PR will restore the per-PR CI back to a state where all the tests should pass. (The cause for the failures is that the public repo doesn't have all the same test resources available as the private repo.)
1 parent 075193c commit c827537

File tree

10 files changed

+123
-267
lines changed

10 files changed

+123
-267
lines changed

libs/qec/python/tests/test_decoders_yaml.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@
1111
import cudaq_qec as qec
1212

1313

14+
def is_nv_qldpc_decoder_available():
15+
"""
16+
Helper function to check if the NV-QLDPC decoder is available.
17+
"""
18+
try:
19+
H_list = [[1, 0, 0, 1, 0, 1, 1], [0, 1, 0, 1, 1, 0, 1],
20+
[0, 0, 1, 0, 1, 1, 1]]
21+
22+
H_np = np.array(H_list, dtype=np.uint8)
23+
nv_dec_gpu_and_cpu = qec.get_decoder("nv-qldpc-decoder", H_np)
24+
return True
25+
except Exception as e:
26+
return False
27+
28+
1429
def check_decoder_yaml_roundtrip(multi_config):
1530
"""
1631
Helper function to test that a decoder configuration can be serialized to
@@ -119,6 +134,8 @@ def test_single_decoder():
119134
"""
120135
Test YAML serialization/deserialization and creation of a single NV-QLDPC decoder.
121136
"""
137+
if not is_nv_qldpc_decoder_available():
138+
pytest.skip("NV-QLDPC decoder is not available, skipping test")
122139
multi_config = qec.multi_decoder_config()
123140
config = create_test_decoder_config_nv_qldpc(0)
124141
multi_config.decoders = [config]
@@ -131,6 +148,8 @@ def test_multi_decoder():
131148
"""
132149
Test YAML serialization/deserialization and creation of multiple NV-QLDPC decoders.
133150
"""
151+
if not is_nv_qldpc_decoder_available():
152+
pytest.skip("NV-QLDPC decoder is not available, skipping test")
134153
multi_config = qec.multi_decoder_config()
135154
config1 = create_test_decoder_config_nv_qldpc(0)
136155
config2 = create_test_decoder_config_nv_qldpc(1)

libs/qec/python/tests/test_decoding_config.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,12 +307,14 @@ def test_configure_valid_decoders():
307307

308308
dc = qec.decoder_config()
309309
dc.id = 0
310-
dc.type = "nv-qldpc-decoder"
310+
dc.type = "multi_error_lut"
311311
dc.block_size = 10
312312
dc.syndrome_size = 3
313313
dc.num_syndromes_per_round = 3
314314
dc.H_sparse = [1, 2, 3, -1, 6, 7, 8, -1, -1]
315-
dc.set_decoder_custom_args(nv)
315+
lut_config = qec.multi_error_lut_config()
316+
lut_config.lut_error_depth = 2
317+
dc.set_decoder_custom_args(lut_config)
316318

317319
mdc = qec.multi_decoder_config()
318320
mdc.decoders = [dc]

libs/qec/python/tests/test_sliding_window.py

Lines changed: 2 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
import cudaq
1111
import cudaq_qec as qec
1212
import pytest
13-
import os
14-
import tempfile
1513

1614

1715
@pytest.fixture(scope="function", autouse=True)
@@ -22,16 +20,6 @@ def setTarget():
2220
cudaq.set_target(old_target)
2321

2422

25-
@pytest.mark.parametrize("decoder_name",
26-
["multi_error_lut", "nv-qldpc-decoder"])
27-
@pytest.mark.parametrize("batched", [True, False])
28-
@pytest.mark.parametrize("num_rounds", [5, 10])
29-
@pytest.mark.parametrize("num_windows", [1, 2, 3])
30-
def test_sliding_window_multi_error_lut_and_nv_qldpc_decoder(
31-
decoder_name, batched, num_rounds, num_windows):
32-
test_sliding_window_1(decoder_name, batched, num_rounds, num_windows)
33-
34-
3523
@pytest.mark.parametrize("decoder_name", ["single_error_lut"])
3624
@pytest.mark.parametrize("batched", [True, False])
3725
@pytest.mark.parametrize("num_rounds", [5, 10])
@@ -61,27 +49,9 @@ def test_sliding_window_1(decoder_name, batched, num_rounds, num_windows):
6149
# First compare the results of the full decoder to the sliding window
6250
# decoder using an inner decoder of the full window size. The results should
6351
# be the same.
64-
if decoder_name == "nv-qldpc-decoder":
65-
# nv-qldpc-decoder requires use_sparsity=True for batched decoding
66-
full_decoder = qec.get_decoder(decoder_name,
67-
dem.detector_error_matrix,
68-
use_sparsity=True,
69-
error_rate_vec=np.array(dem.error_rates))
70-
else:
71-
full_decoder = qec.get_decoder(decoder_name, dem.detector_error_matrix)
52+
full_decoder = qec.get_decoder(decoder_name, dem.detector_error_matrix)
7253
num_syndromes_per_round = dem.detector_error_matrix.shape[0] // num_rounds
7354

74-
# Set up inner decoder parameters based on decoder type
75-
if decoder_name == "nv-qldpc-decoder":
76-
inner_decoder_params = {
77-
"use_sparsity": True,
78-
"error_rate_vec": np.array(dem.error_rates)
79-
}
80-
elif decoder_name == "multi_error_lut":
81-
inner_decoder_params = {"lut_error_depth": 2}
82-
else:
83-
inner_decoder_params = {}
84-
8555
sw_as_full_decoder = qec.get_decoder(
8656
"sliding_window",
8757
dem.detector_error_matrix,
@@ -92,28 +62,7 @@ def test_sliding_window_1(decoder_name, batched, num_rounds, num_windows):
9262
straddle_end_round=True,
9363
error_rate_vec=np.array(dem.error_rates),
9464
inner_decoder_name=decoder_name,
95-
inner_decoder_params=inner_decoder_params)
96-
97-
# Save sliding window configuration to YAML file for verification
98-
config_filename = save_sliding_window_config_to_yaml(
99-
n_rounds=num_rounds,
100-
n_errs_per_round=dem.detector_error_matrix.shape[1] // num_rounds,
101-
n_syndromes_per_round=num_syndromes_per_round,
102-
window_size=num_rounds - num_windows + 1,
103-
step_size=1,
104-
simplified_pcm=np.array(dem.detector_error_matrix),
105-
simplified_weights=np.array(dem.error_rates),
106-
inner_decoder_name=decoder_name)
107-
108-
# ============================================================================
109-
# PROVE END-TO-END SERIALIZATION: Load and configure decoders from the saved YAML
110-
# ============================================================================
111-
config_result = qec.configure_decoders_from_file(config_filename)
112-
assert config_result == 0, f"Failed to configure decoders from saved YAML file: {config_filename}"
113-
print(
114-
f"✅ Successfully configured decoders from saved YAML file: {config_filename}"
115-
)
116-
print("End-to-end YAML serialization and decoder configuration verified!")
65+
inner_decoder_params={'dummy_param': 1})
11766

11867
if batched:
11968
full_results = full_decoder.decode_batch(syndromes)
@@ -134,127 +83,3 @@ def test_sliding_window_1(decoder_name, batched, num_rounds, num_windows):
13483
if r1.result != r2.result:
13584
num_mismatches += 1
13685
assert num_mismatches == 0
137-
138-
# Cleanup: Finalize decoders after testing configuration
139-
qec.qecrt.config.finalize_decoders()
140-
141-
# Clean up the generated YAML file
142-
#if os.path.exists(config_filename):
143-
# os.unlink(config_filename)
144-
145-
146-
def save_sliding_window_config_to_yaml(n_rounds, n_errs_per_round,
147-
n_syndromes_per_round, window_size,
148-
step_size, simplified_pcm,
149-
simplified_weights, inner_decoder_name):
150-
"""
151-
Save sliding window decoder configuration to YAML (Python version of C++ function)
152-
"""
153-
# Create a sliding_window_config struct with concrete inner decoder configs
154-
sw_config = qec.qecrt.config.sliding_window_config()
155-
sw_config.window_size = window_size
156-
sw_config.step_size = step_size
157-
sw_config.num_syndromes_per_round = n_syndromes_per_round
158-
sw_config.straddle_start_round = False # Default value from sliding_window.cpp
159-
sw_config.straddle_end_round = True # Default value from sliding_window.cpp
160-
sw_config.error_rate_vec = simplified_weights.tolist()
161-
sw_config.inner_decoder_name = inner_decoder_name
162-
163-
# Set the appropriate concrete inner decoder config based on decoder name
164-
if inner_decoder_name == "single_error_lut":
165-
single_config = qec.qecrt.config.single_error_lut_config()
166-
# single_error_lut_config is intentionally empty (no configuration parameters)
167-
sw_config.single_error_lut_params = single_config
168-
elif inner_decoder_name == "multi_error_lut":
169-
multi_config = qec.qecrt.config.multi_error_lut_config()
170-
multi_config.lut_error_depth = 2
171-
# Note: error_rate_vec not supported in multi_error_lut_config for real-time decoding
172-
sw_config.multi_error_lut_params = multi_config
173-
elif inner_decoder_name == "nv-qldpc-decoder":
174-
nv_config = qec.qecrt.config.nv_qldpc_decoder_config()
175-
nv_config.use_sparsity = True
176-
nv_config.error_rate_vec = simplified_weights.tolist()
177-
nv_config.use_osd = True
178-
nv_config.max_iterations = 50
179-
nv_config.osd_order = 60
180-
nv_config.osd_method = 3
181-
sw_config.nv_qldpc_decoder_params = nv_config
182-
183-
# Create a decoder_config for the sliding window decoder
184-
config = qec.qecrt.config.decoder_config()
185-
config.id = 0
186-
config.type = "sliding_window"
187-
config.block_size = simplified_pcm.shape[1] # Number of columns
188-
config.syndrome_size = simplified_pcm.shape[0] # Number of rows
189-
config.num_syndromes_per_round = n_syndromes_per_round
190-
191-
# Convert PCM to sparse format for H_sparse and create empty O_sparse
192-
H_sparse = []
193-
for row in range(simplified_pcm.shape[0]):
194-
for col in range(simplified_pcm.shape[1]):
195-
if simplified_pcm[row, col] == 1:
196-
H_sparse.append(int(col))
197-
H_sparse.append(-1) # End of row marker
198-
199-
config.H_sparse = H_sparse
200-
config.O_sparse = [] # Empty for this test
201-
# D_sparse is optional, leave unset
202-
203-
# Set the sliding_window_config directly
204-
config.decoder_custom_args = sw_config
205-
206-
# Create multi_decoder_config and add our sliding window decoder
207-
multi_config = qec.qecrt.config.multi_decoder_config()
208-
multi_config.decoders = [config]
209-
210-
# Generate YAML string using native serialization (no concatenation needed!)
211-
config_str = multi_config.to_yaml_str(200) # 200 char line wrap
212-
213-
# Create a unique filename based on test parameters
214-
filename = f"sliding_window_config_r{n_rounds}_e{n_errs_per_round}_s{n_syndromes_per_round}_w{window_size}_st{step_size}_{inner_decoder_name}.yml"
215-
216-
with open(filename, 'w') as config_file:
217-
config_file.write(config_str)
218-
219-
print(
220-
f"Saved sliding window config (with native YAML inner decoder params) to file: {filename}"
221-
)
222-
223-
# Verify the config can be loaded back (inner decoder params should be natively serialized)
224-
loaded_multi_config = qec.qecrt.config.multi_decoder_config.from_yaml_str(
225-
config_str)
226-
assert len(loaded_multi_config.decoders) == 1
227-
assert loaded_multi_config.decoders[0].type == "sliding_window"
228-
assert loaded_multi_config.decoders[0].id == 0
229-
230-
# Verify the YAML contains the expected structure and parameters
231-
assert "decoder_custom_args:" in config_str
232-
assert f"window_size: {window_size}" in config_str
233-
assert f"step_size: {step_size}" in config_str
234-
assert f"num_syndromes_per_round: {n_syndromes_per_round}" in config_str
235-
assert f"inner_decoder_name: {inner_decoder_name}" in config_str
236-
237-
# Verify that inner decoder parameters are preserved in the loaded config
238-
print("Successfully verified sliding window YAML config round-trip!")
239-
print(
240-
"Sliding window parameters and inner decoder configs natively serialized!"
241-
)
242-
243-
if inner_decoder_name == "single_error_lut":
244-
# single_error_lut_config is intentionally empty (no configuration parameters)
245-
print("Single error LUT config parameters successfully verified!")
246-
elif inner_decoder_name == "multi_error_lut":
247-
assert "inner_decoder_params:" in config_str
248-
assert "lut_error_depth: 2" in config_str
249-
print("Multi error LUT config parameters successfully verified!")
250-
elif inner_decoder_name == "nv-qldpc-decoder":
251-
assert "inner_decoder_params:" in config_str
252-
assert "use_sparsity: true" in config_str
253-
assert "use_osd: true" in config_str
254-
assert "max_iterations: 50" in config_str
255-
assert "osd_order: 60" in config_str
256-
assert "osd_method: 3" in config_str
257-
print("NV QLDPC decoder config parameters successfully verified!")
258-
259-
# Return the filename for end-to-end verification
260-
return filename

libs/qec/unittests/realtime/app_examples/CMakeLists.txt

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,19 @@ add_test(
3838
${CMAKE_BINARY_DIR}/lib
3939
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
4040
)
41-
add_test(
42-
NAME app_examples.surface_code-1-local-test-distance-5
43-
COMMAND
44-
bash "${CMAKE_CURRENT_SOURCE_DIR}/surface_code-1-test.sh"
45-
${CMAKE_CURRENT_BINARY_DIR}/surface_code-1-local
46-
${CMAKE_CURRENT_BINARY_DIR}/surface_code-1-local
47-
5 40 40 NULL 20 10
48-
${CMAKE_BINARY_DIR}/lib
49-
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
50-
)
41+
# This must be disabled for now because the multi_error_lut decoder is not
42+
# powerful enough to pass this test. The nv-qldpc-decoder can pass this test,
43+
# but that is not available on the GitHub repo.
44+
# add_test(
45+
# NAME app_examples.surface_code-1-local-test-distance-5
46+
# COMMAND
47+
# bash "${CMAKE_CURRENT_SOURCE_DIR}/surface_code-1-test.sh"
48+
# ${CMAKE_CURRENT_BINARY_DIR}/surface_code-1-local
49+
# ${CMAKE_CURRENT_BINARY_DIR}/surface_code-1-local
50+
# 5 40 40 NULL 20 10
51+
# ${CMAKE_BINARY_DIR}/lib
52+
# WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
53+
# )
5154

5255
# Surface code 1 Python test
5356
add_test(
@@ -151,16 +154,19 @@ add_test(
151154
${CMAKE_BINARY_DIR}/lib
152155
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
153156
)
154-
add_test(
155-
NAME app_examples.surface_code-2-local-test-distance-5
156-
COMMAND
157-
bash "${CMAKE_CURRENT_SOURCE_DIR}/surface_code-2-test.sh"
158-
${CMAKE_CURRENT_BINARY_DIR}/surface_code-2-local
159-
${CMAKE_CURRENT_BINARY_DIR}/surface_code-2-local
160-
5 10 10 NULL
161-
${CMAKE_BINARY_DIR}/lib
162-
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
163-
)
157+
# This must be disabled for now because the multi_error_lut decoder is not
158+
# powerful enough to pass this test. The nv-qldpc-decoder can pass this test,
159+
# but that is not available on the GitHub repo.
160+
# add_test(
161+
# NAME app_examples.surface_code-2-local-test-distance-5
162+
# COMMAND
163+
# bash "${CMAKE_CURRENT_SOURCE_DIR}/surface_code-2-test.sh"
164+
# ${CMAKE_CURRENT_BINARY_DIR}/surface_code-2-local
165+
# ${CMAKE_CURRENT_BINARY_DIR}/surface_code-2-local
166+
# 5 10 10 NULL
167+
# ${CMAKE_BINARY_DIR}/lib
168+
# WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
169+
# )
164170

165171
# End of surface code 2, fully local, regular Stim simulator
166172
#------------------------------------------------------------------------------#
@@ -226,7 +232,10 @@ add_test(
226232

227233

228234
macro(add_surface_code_test base_name exe_local exe_remote dist server)
229-
foreach(err_rate IN ITEMS 0.010 0.015)
235+
# For now, disable 0.015 error rate because the multi_error_lut decoder is not
236+
# powerful enough to pass this test. The nv-qldpc-decoder can pass this test,
237+
# but that is not available on the GitHub repo.
238+
foreach(err_rate IN ITEMS 0.010)
230239
foreach(prep IN ITEMS prep0 prepp)
231240
add_test(
232241
NAME ${base_name}-dist-${dist}-${prep}-err-${err_rate}

libs/qec/unittests/realtime/app_examples/surface_code-1-test.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,22 @@
3333
"number_of_corrections_decoder_threshold": 40
3434
},
3535
id="d3-local"),
36-
pytest.param(
37-
{
38-
"distance": 5,
39-
"p_spam": 0.01,
40-
"num_rounds": 20,
41-
"decoder_window": 10,
42-
"num_shots": 1000,
43-
"target": "stim",
44-
"number_of_non_zero_values_threshold": 40,
45-
"number_of_corrections_decoder_threshold": 40
46-
},
47-
id="d5-local",
48-
),
36+
# This must be disabled for now because the multi_error_lut decoder is not
37+
# powerful enough to pass this test. The nv-qldpc-decoder can pass this test,
38+
# but that is not available on the GitHub repo.
39+
# pytest.param(
40+
# {
41+
# "distance": 5,
42+
# "p_spam": 0.01,
43+
# "num_rounds": 20,
44+
# "decoder_window": 10,
45+
# "num_shots": 1000,
46+
# "target": "stim",
47+
# "number_of_non_zero_values_threshold": 40,
48+
# "number_of_corrections_decoder_threshold": 40
49+
# },
50+
# id="d5-local",
51+
# ),
4952
pytest.param(
5053
{
5154
"distance": 3,

0 commit comments

Comments
 (0)