Skip to content

Commit 706649b

Browse files
committed
v0.7.1: LLR-based physical weight formalism for surface decoders
1 parent 90cc45c commit 706649b

17 files changed

+419
-26
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ add_executable(lidmas
1919
src/models/NeuralWeightModel.cpp
2020
src/UniformWeightField.cpp
2121
src/NeuralWeightField.cpp
22+
src/LLRWeightField.cpp
2223
include/core/DecoderConfig.h
2324
include/core/IDecoderPlugin.h
2425
include/core/PluginRegistry.h

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ Adaptive-threshold flags:
143143
- `--target_ci_halfwidth=<x>`
144144
- `--target_rel_ci=<x>`
145145
- `--monotonic_smooth`
146+
- `--weight_mode=uniform|neural|llr`
147+
- `--llr_p_data=<x> --llr_p_meas=<x> --llr_p_idle=<x>`
148+
- `--llr_clamp_min=<x> --llr_clamp_max=<x>`
149+
- `--mwpm_weight_scale=<x>`
146150

147151
CSV header:
148152

@@ -152,6 +156,14 @@ distance,p,trials,ler,ci_low,ci_high,defect_mean,weight_mean,decoder_fail_rate
152156

153157
Per-point console output includes Wilson 95% CI and decoder fail rate.
154158

159+
Quick v0.7.1 smoke commands:
160+
161+
```bash
162+
./lidmas --surface_threshold --decoder=uf --weight_mode=uniform --threads=8 --trials=2000 --d=5 --p_start=0.01 --p_end=0.03 --p_step=0.01
163+
./lidmas --surface_threshold --decoder=uf --weight_mode=llr --threads=8 --trials=2000 --d=5 --p_start=0.01 --p_end=0.03 --p_step=0.01
164+
./lidmas --surface_threshold --decoder=mwpm --weight_mode=llr --threads=8 --trials=2000 --d=5 --p_start=0.01 --p_end=0.03 --p_step=0.01
165+
```
166+
155167
## Run: Smoke Checks
156168

157169
```bash

include/LLRWeightField.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#pragma once
2+
3+
#include "WeightField.h"
4+
5+
class LLRWeightField : public WeightField {
6+
public:
7+
LLRWeightField(double p_data,
8+
double p_meas,
9+
double p_idle,
10+
double clamp_min = 1e-12,
11+
double clamp_max = 1.0 - 1e-12);
12+
13+
double edge_weight(int u, int v) const override;
14+
15+
private:
16+
double p_data_ = 0.01;
17+
double p_meas_ = 0.01;
18+
double p_idle_ = 0.01;
19+
double clamp_min_ = 1e-12;
20+
double clamp_max_ = 1.0 - 1e-12;
21+
};

include/plugins/mwpm/MWPMPlugin.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
#pragma once
22

3+
#include <memory>
4+
#include <string>
5+
6+
#include "WeightField.h"
37
#include "core/DecoderConfig.h"
48
#include "surface/ISurfaceDecoderPlugin.h"
9+
#include "surface/MWPMDecoder.h"
510

611
class MWPMPlugin : public ISurfaceDecoderPlugin {
712
public:
@@ -12,4 +17,16 @@ class MWPMPlugin : public ISurfaceDecoderPlugin {
1217

1318
private:
1419
DecoderConfig cfg_;
20+
const SurfaceCode* cached_code_ = nullptr;
21+
std::string cached_weight_mode_ = "uniform";
22+
uint64_t cached_seed_ = 0;
23+
double cached_p_error_ = -1.0;
24+
double cached_weight_scale_ = 1000.0;
25+
double cached_llr_p_data_ = -1.0;
26+
double cached_llr_p_meas_ = -1.0;
27+
double cached_llr_p_idle_ = -1.0;
28+
double cached_llr_clamp_min_ = 1e-12;
29+
double cached_llr_clamp_max_ = 1.0 - 1e-12;
30+
std::unique_ptr<WeightField> cached_weight_field_;
31+
std::unique_ptr<MWPMDecoder> cached_decoder_;
1532
};

include/plugins/uf/UnionFindPlugin.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ class UnionFindPlugin : public ISurfaceDecoderPlugin {
2424
std::string cached_weight_mode_ = "uniform";
2525
uint64_t cached_seed_ = 0;
2626
double cached_p_error_ = -1.0;
27+
double cached_llr_p_data_ = -1.0;
28+
double cached_llr_p_meas_ = -1.0;
29+
double cached_llr_p_idle_ = -1.0;
30+
double cached_llr_clamp_min_ = 1e-12;
31+
double cached_llr_clamp_max_ = 1.0 - 1e-12;
2732
std::unique_ptr<WeightField> cached_weight_field_;
2833
std::unique_ptr<UnionFindDecoder> cached_decoder_;
2934
std::unique_ptr<lidmas_v07::UnionFindDecoder> cached_weighted_decoder_;

include/sim/SurfaceSimulation.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ struct SurfaceSweepConfig {
1414
std::string decoder_name = "stub";
1515
std::string weight_mode = "uniform";
1616
bool uf_weighted = false;
17+
double llr_p_data = -1.0; // <0 => use point p
18+
double llr_p_meas = -1.0; // <0 => use point p
19+
double llr_p_idle = -1.0; // <0 => use point p
20+
double llr_clamp_min = 1e-12;
21+
double llr_clamp_max = 1.0 - 1e-12;
22+
double mwpm_weight_scale = 1000.0;
1723
std::string neural_weights_path;
1824
std::string neural_model_path;
1925
};

include/sim/SurfaceThresholdRunner.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ struct SurfaceThresholdConfig {
1919
bool monotonic_smooth = false;
2020
std::string weight_mode = "uniform";
2121
bool uf_weighted = false;
22+
double llr_p_data = -1.0; // <0 => use sweep point p
23+
double llr_p_meas = -1.0; // <0 => use sweep point p
24+
double llr_p_idle = -1.0; // <0 => use sweep point p
25+
double llr_clamp_min = 1e-12;
26+
double llr_clamp_max = 1.0 - 1e-12;
27+
double mwpm_weight_scale = 1000.0;
2228
std::string neural_weights_path;
2329
std::string neural_model_path;
2430
int min_trials = 200;

include/surface/MWPMDecoder.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#pragma once
22

33
#include <vector>
4+
#include "WeightField.h"
5+
#include "UniformWeightField.h"
46
#include "core/BinaryMatrix.h"
57
#include "surface/BlossomMWPM.h"
68
#include "surface/ISurfaceDecoder.h"
@@ -23,11 +25,16 @@ class MWPMDecoder : public ISurfaceDecoder {
2325
};
2426

2527
explicit MWPMDecoder(const SurfaceCode& code);
28+
MWPMDecoder(const SurfaceCode& code, const WeightField* weight_field, double weight_scale = 1000.0);
2629
std::vector<int> decode(const SurfaceSyndrome& syn) override;
2730

2831
private:
2932
const SurfaceCode& code_;
3033
int d_ = 0;
34+
UniformWeightField uniform_weight_field_;
35+
const WeightField* weight_field_ = nullptr;
36+
bool weighted_mode_ = false;
37+
double weight_scale_ = 1000.0;
3138

3239
int hIndex(int x, int y) const;
3340
int vIndex(int x, int y) const;
@@ -37,6 +44,8 @@ class MWPMDecoder : public ISurfaceDecoder {
3744
std::vector<Defect> defectsFromPlaquetteSyndrome(const std::vector<int>& sz) const;
3845
std::vector<Defect> defectsFromStarSyndrome(const std::vector<int>& sx) const;
3946
int manhattan(const Defect& a, const Defect& b) const;
47+
int weightedCost(const Defect& a, const Defect& b, bool plaquette_mode) const;
48+
int weightedBoundaryCost(const Defect& d, bool plaquette_mode) const;
4049
int DistToBoundaryZ(LatticeCoord zdef, int d) const;
4150
int DistToBoundaryX(LatticeCoord xdef, int d) const;
4251
int boundaryDistance(const Defect& d, bool plaquette_mode) const;

src/LLRWeightField.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include "LLRWeightField.h"
2+
3+
#include <algorithm>
4+
#include <cmath>
5+
6+
namespace {
7+
8+
double clampProb(double p, double lo, double hi) {
9+
return std::clamp(p, lo, hi);
10+
}
11+
12+
double llrFromProb(double p) {
13+
const double w = std::log((1.0 - p) / p);
14+
if (!std::isfinite(w)) return 0.0;
15+
return std::max(0.0, w);
16+
}
17+
18+
} // namespace
19+
20+
LLRWeightField::LLRWeightField(double p_data,
21+
double p_meas,
22+
double p_idle,
23+
double clamp_min,
24+
double clamp_max)
25+
: p_data_(p_data),
26+
p_meas_(p_meas),
27+
p_idle_(p_idle),
28+
clamp_min_(std::max(1e-18, clamp_min)),
29+
clamp_max_(std::min(1.0 - 1e-18, clamp_max)) {
30+
if (clamp_min_ > clamp_max_) std::swap(clamp_min_, clamp_max_);
31+
}
32+
33+
double LLRWeightField::edge_weight(int u, int v) const {
34+
// No explicit time dimension in current surface graph: default all non-self edges to data errors.
35+
// Self-edge is used as boundary/idle proxy where needed by decoder plugins.
36+
double p_e = p_data_;
37+
if (u == v) {
38+
p_e = p_idle_;
39+
}
40+
41+
// Future-proof hook for time-like edges when time index is encoded in node IDs.
42+
if (u < 0 || v < 0) {
43+
p_e = p_meas_;
44+
}
45+
46+
const double p = clampProb(p_e, clamp_min_, clamp_max_);
47+
return llrFromProb(p);
48+
}

src/decoders/UnionFindDecoder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
#pragma once
23

34
#include <atomic>

0 commit comments

Comments
 (0)