Skip to content

Commit 91e5d1d

Browse files
authored
Improve stim.Tableau.from_stabilizers error messages (#761)
- Include examples when failing - Fix some anticommutation cases claiming that the issue is the stabilizers are redundant Fixes #760
1 parent 575f7b7 commit 91e5d1d

File tree

2 files changed

+94
-26
lines changed

2 files changed

+94
-26
lines changed

src/stim/stabilizers/tableau_pybind_test.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,3 +975,31 @@ def test_to_circuit_mpp_unsigned_preserves_stabilizers():
975975
for e in reconstructed:
976976
e.sign = +1
977977
assert original == reconstructed
978+
979+
980+
def test_from_stabilizers_error_messages():
981+
with pytest.raises(ValueError, match="anticommute"):
982+
stim.Tableau.from_stabilizers([
983+
stim.PauliString("Z"),
984+
stim.PauliString("X"),
985+
])
986+
with pytest.raises(ValueError, match="anticommute"):
987+
stim.Tableau.from_stabilizers([
988+
stim.PauliString("Z"),
989+
stim.PauliString("X" + "_"*500),
990+
])
991+
with pytest.raises(ValueError, match="contradict"):
992+
stim.Tableau.from_stabilizers([
993+
stim.PauliString("Z_"),
994+
stim.PauliString("-_Z"),
995+
stim.PauliString("Z" + "_"*500 + "X"),
996+
stim.PauliString("ZZ"),
997+
])
998+
with pytest.raises(ValueError, match="redundant"):
999+
stim.Tableau.from_stabilizers([
1000+
stim.PauliString("-Z_"),
1001+
stim.PauliString("Z" + "_"*500 + "X"),
1002+
stim.PauliString("-__Z"),
1003+
stim.PauliString("_Z_"),
1004+
stim.PauliString("Z_Z"),
1005+
])

src/stim/util_top/stabilizers_to_tableau.inl

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,58 @@ Tableau<W> stabilizers_to_tableau(
2424

2525
Circuit elimination_instructions;
2626

27+
auto fail_due_to_anticommutation = [&]() {
28+
for (size_t k1 = 0; k1 < stabilizers.size(); k1++) {
29+
for (size_t k2 = k1 + 1; k2 < stabilizers.size(); k2++) {
30+
if (!stabilizers[k1].ref().commutes(stabilizers[k2])) {
31+
std::stringstream ss;
32+
ss << "Some of the given stabilizers anticommute.\n";
33+
ss << "For example:";
34+
ss << "\n stabilizers[" << k1 << "] = " << stabilizers[k1];
35+
ss << "\nanticommutes with";
36+
ss << "\n stabilizers[" << k2 << "] = " << stabilizers[k2];
37+
throw std::invalid_argument(ss.str());
38+
}
39+
}
40+
}
41+
throw std::invalid_argument(
42+
"The given stabilizers commute but the solver failed in a way that suggests they anticommute. Please "
43+
"report this as a bug.");
44+
};
45+
46+
auto print_redundant_z_product_parts = [&](size_t stabilizer_index, std::ostream &out) {
47+
PauliString<W> target = stabilizers[stabilizer_index];
48+
target.ensure_num_qubits(num_qubits, 1.0);
49+
target = target.ref().after(elimination_instructions);
50+
if (num_qubits > 0) {
51+
GateTarget t = GateTarget::qubit(num_qubits - 1);
52+
elimination_instructions.safe_append(CircuitInstruction{GateType::X, {}, &t});
53+
elimination_instructions.safe_append(CircuitInstruction{GateType::X, {}, &t});
54+
}
55+
Tableau<W> inverse = circuit_to_tableau<W>(elimination_instructions, false, false, false, true);
56+
target.ref().for_each_active_pauli([&](size_t q) {
57+
out << "\n ";
58+
for (size_t k = 0; k < stabilizers.size(); k++) {
59+
PauliString<W> s = stabilizers[k];
60+
s.ensure_num_qubits(num_qubits, 1.0);
61+
if (s == inverse.zs[q]) {
62+
out << "stabilizers[" << k << "] = " << stabilizers[k];
63+
return;
64+
}
65+
}
66+
out << inverse.zs[q];
67+
});
68+
};
69+
2770
size_t used = 0;
2871
for (size_t k = 0; k < stabilizers.size(); k++) {
2972
// Find a non-identity term in the Pauli string past the region used by other stabilizers.
3073
size_t pivot;
74+
for (size_t q = 0; q < used; q++) {
75+
if (buf_xs[q][k]) {
76+
fail_due_to_anticommutation();
77+
}
78+
}
3179
for (pivot = used; pivot < num_qubits; pivot++) {
3280
if (buf_xs[pivot][k] || buf_zs[pivot][k]) {
3381
break;
@@ -37,12 +85,26 @@ Tableau<W> stabilizers_to_tableau(
3785
// Check for incompatible / redundant stabilizers.
3886
if (pivot == num_qubits) {
3987
if (buf_signs[k]) {
40-
throw std::invalid_argument("Some of the given stabilizers contradict each other.");
88+
std::stringstream ss;
89+
ss << "Some of the given stabilizers contradict each other.\n";
90+
ss << "For example:";
91+
ss << "\n stabilizers[" << k << "] = " << stabilizers[k];
92+
ss << "\nis the negation of the product of the following stabilizers: {";
93+
print_redundant_z_product_parts(k, ss);
94+
ss << "\n}";
95+
throw std::invalid_argument(ss.str());
4196
}
4297
if (!allow_redundant) {
43-
throw std::invalid_argument(
44-
"Didn't specify allow_redundant=True but one of the given stabilizers is a product of the others. "
45-
"To allow redundant stabilizers, pass the argument allow_redundant=True.");
98+
std::stringstream ss;
99+
ss << "Some of the given stabilizers are redundant.";
100+
ss<< "\nTo allow redundant stabilizers, pass the argument allow_redundant=True.";
101+
ss << "\n";
102+
ss << "\nFor example:";
103+
ss << "\n stabilizers[" << k << "] = " << stabilizers[k];
104+
ss << "\nis the product of the following stabilizers: {";
105+
print_redundant_z_product_parts(k, ss);
106+
ss << "\n}";
107+
throw std::invalid_argument(ss.str());
46108
}
47109
continue;
48110
}
@@ -140,28 +202,6 @@ Tableau<W> stabilizers_to_tableau(
140202
used++;
141203
}
142204

143-
// All stabilizers will have been mapped into Z products, if they commuted.
144-
for (size_t q = 0; q < num_qubits; q++) {
145-
if (buf_xs[q].not_zero()) {
146-
for (size_t k1 = 0; k1 < stabilizers.size(); k1++) {
147-
for (size_t k2 = k1 + 1; k2 < stabilizers.size(); k2++) {
148-
if (!stabilizers[k1].ref().commutes(stabilizers[k2])) {
149-
std::stringstream ss;
150-
ss << "Some of the given stabilizers anticommute.\n";
151-
ss << "For example:\n ";
152-
ss << stabilizers[k1];
153-
ss << "\nanticommutes with\n";
154-
ss << stabilizers[k2] << "\n";
155-
throw std::invalid_argument(ss.str());
156-
}
157-
}
158-
}
159-
throw std::invalid_argument(
160-
"The given stabilizers commute but the solver failed in a way that suggests they anticommute. Please "
161-
"report this as a bug.");
162-
}
163-
}
164-
165205
if (used < num_qubits) {
166206
if (!allow_underconstrained) {
167207
throw std::invalid_argument(

0 commit comments

Comments
 (0)