Skip to content

Commit

Permalink
autoformat
Browse files Browse the repository at this point in the history
  • Loading branch information
Strilanc committed Apr 11, 2024
1 parent 4291faf commit 26f4387
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 137 deletions.
3 changes: 2 additions & 1 deletion src/stim/circuit/circuit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,8 @@ void Circuit::safe_append_u(
safe_append(gate.id, converted, args);
}

void Circuit::safe_append(GateType gate_type, SpanRef<const GateTarget> targets, SpanRef<const double> args, bool block_fusion) {
void Circuit::safe_append(
GateType gate_type, SpanRef<const GateTarget> targets, SpanRef<const double> args, bool block_fusion) {
auto flags = GATE_DATA[gate_type].flags;
if (flags & GATE_IS_BLOCK) {
throw std::invalid_argument("Can't append a block like a normal operation.");
Expand Down
3 changes: 2 additions & 1 deletion src/stim/circuit/circuit.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ struct Circuit {
void safe_append_u(
std::string_view gate_name, const std::vector<uint32_t> &targets, const std::vector<double> &args = {});
/// Safely adds an operation at the end of the circuit, copying its data into the circuit's jagged data as needed.
void safe_append(GateType gate_type, SpanRef<const GateTarget> targets, SpanRef<const double> args, bool block_fusion = false);
void safe_append(
GateType gate_type, SpanRef<const GateTarget> targets, SpanRef<const double> args, bool block_fusion = false);
/// Safely copies a repeat block to the end of the circuit.
void append_repeat_block(uint64_t repeat_count, const Circuit &body);
/// Safely moves a repeat block to the end of the circuit.
Expand Down
62 changes: 29 additions & 33 deletions src/stim/util_top/circuit_inverse_qec.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,42 +32,39 @@ void CircuitFlowReverser::recompute_active_terms() {

void CircuitFlowReverser::do_rp_mrp_instruction(const CircuitInstruction &inst) {
Gate g = GATE_DATA[inst.gate_type];
for_each_disjoint_target_segment_in_instruction_reversed(
inst, qubit_workspace, [&](CircuitInstruction segment) {
// Each reset effect becomes a measurement effect in the inverted circuit. Index these
// measurements.
for (size_t k = inst.targets.size(); k-- > 0;) {
auto q = inst.targets[k].qubit_value();
for (auto d : rev.xs[q]) {
d2ms[d].insert(num_new_measurements);
}
for (auto d : rev.zs[q]) {
d2ms[d].insert(num_new_measurements);
}
num_new_measurements++;
for_each_disjoint_target_segment_in_instruction_reversed(inst, qubit_workspace, [&](CircuitInstruction segment) {
// Each reset effect becomes a measurement effect in the inverted circuit. Index these
// measurements.
for (size_t k = inst.targets.size(); k-- > 0;) {
auto q = inst.targets[k].qubit_value();
for (auto d : rev.xs[q]) {
d2ms[d].insert(num_new_measurements);
}
for (auto d : rev.zs[q]) {
d2ms[d].insert(num_new_measurements);
}
num_new_measurements++;
}

// Undo the gate, ignoring measurement noise.
rev.undo_gate(segment);
inverted_circuit.safe_append_reversed_targets(
g.best_candidate_inverse_id, segment.targets, {}, false);
// Undo the gate, ignoring measurement noise.
rev.undo_gate(segment);
inverted_circuit.safe_append_reversed_targets(g.best_candidate_inverse_id, segment.targets, {}, false);

// Measurement noise becomes noise-after-reset in the reversed circuit.
if (!inst.args.empty()) {
GateType ejected_noise;
if (inst.gate_type == GateType::MRX) {
ejected_noise = GateType::Z_ERROR;
} else if (inst.gate_type == GateType::MRY) {
ejected_noise = GateType::Z_ERROR;
} else if (inst.gate_type == GateType::MR) {
ejected_noise = GateType::X_ERROR;
} else {
throw std::invalid_argument("Don't know how to invert " + inst.str());
}
inverted_circuit.safe_append_reversed_targets(
ejected_noise, segment.targets, segment.args, false);
// Measurement noise becomes noise-after-reset in the reversed circuit.
if (!inst.args.empty()) {
GateType ejected_noise;
if (inst.gate_type == GateType::MRX) {
ejected_noise = GateType::Z_ERROR;
} else if (inst.gate_type == GateType::MRY) {
ejected_noise = GateType::Z_ERROR;
} else if (inst.gate_type == GateType::MR) {
ejected_noise = GateType::X_ERROR;
} else {
throw std::invalid_argument("Don't know how to invert " + inst.str());
}
});
inverted_circuit.safe_append_reversed_targets(ejected_noise, segment.targets, segment.args, false);
}
});
}

void CircuitFlowReverser::do_m2r_instruction(const CircuitInstruction &inst) {
Expand Down Expand Up @@ -169,7 +166,6 @@ void CircuitFlowReverser::flush_detectors_and_observables() {
}

void CircuitFlowReverser::do_instruction(const CircuitInstruction &inst) {

switch (inst.gate_type) {
case GateType::DETECTOR: {
rev.undo_gate(inst);
Expand Down
2 changes: 1 addition & 1 deletion src/stim/util_top/circuit_inverse_qec.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ struct CircuitFlowReverser {
Circuit &&build_and_move_final_inverted_circuit();
};

} // namespace stim::internal
} // namespace internal
} // namespace stim

#include "stim/util_top/circuit_inverse_qec.inl"
Expand Down
202 changes: 101 additions & 101 deletions src/stim/util_top/circuit_inverse_qec.inl
Original file line number Diff line number Diff line change
Expand Up @@ -4,128 +4,128 @@
namespace stim {

namespace internal {
template <size_t W>
void CircuitFlowReverser::xor_pauli_string_into_tracker_as_target(const PauliString<W> &pauli_string, DemTarget target) {
pauli_string.ref().for_each_active_pauli([&](size_t q) {
bool x = pauli_string.xs[q];
bool z = pauli_string.zs[q];
if (x) {
rev.xs[q].xor_item(target);
}
if (z) {
rev.zs[q].xor_item(target);
}
});
}

template <size_t W>
void CircuitFlowReverser::xor_flow_ends_into_tracker(std::span<const Flow<W>> flows) {
for (size_t k = 0; k < flows.size(); k++) {
const auto &flow = flows[k];
DemTarget flow_target = DemTarget::observable_id(stats.num_observables + k);
xor_pauli_string_into_tracker_as_target(flow.output, flow_target);
template <size_t W>
void CircuitFlowReverser::xor_pauli_string_into_tracker_as_target(
const PauliString<W> &pauli_string, DemTarget target) {
pauli_string.ref().for_each_active_pauli([&](size_t q) {
bool x = pauli_string.xs[q];
bool z = pauli_string.zs[q];
if (x) {
rev.xs[q].xor_item(target);
}
if (z) {
rev.zs[q].xor_item(target);
}
});
}

template <size_t W>
void CircuitFlowReverser::xor_flow_ends_into_tracker(std::span<const Flow<W>> flows) {
for (size_t k = 0; k < flows.size(); k++) {
const auto &flow = flows[k];
DemTarget flow_target = DemTarget::observable_id(stats.num_observables + k);
xor_pauli_string_into_tracker_as_target(flow.output, flow_target);
}
}

template <size_t W>
void CircuitFlowReverser::xor_flow_measurements_into_tracker(std::span<const Flow<W>> flows) {
for (size_t k = 0; k < flows.size(); k++) {
const auto &flow = flows[k];
DemTarget flow_target = DemTarget::observable_id(stats.num_observables + k);
template <size_t W>
void CircuitFlowReverser::xor_flow_measurements_into_tracker(std::span<const Flow<W>> flows) {
for (size_t k = 0; k < flows.size(); k++) {
const auto &flow = flows[k];
DemTarget flow_target = DemTarget::observable_id(stats.num_observables + k);

for (int32_t m : flow.measurements) {
if (m < 0) {
m += stats.num_measurements;
}
if (m < 0 || (uint64_t)m >= stats.num_measurements) {
std::stringstream ss;
ss << "Out of range measurement in one of the flows: " << flow;
throw std::invalid_argument(ss.str());
}
rev.rec_bits[m].sorted_items.push_back(flow_target);
for (int32_t m : flow.measurements) {
if (m < 0) {
m += stats.num_measurements;
}
if (m < 0 || (uint64_t)m >= stats.num_measurements) {
std::stringstream ss;
ss << "Out of range measurement in one of the flows: " << flow;
throw std::invalid_argument(ss.str());
}
rev.rec_bits[m].sorted_items.push_back(flow_target);
}
}
}

template <size_t W>
void CircuitFlowReverser::xor_flow_starts_into_tracker(std::span<const Flow<W>> flows) {
for (size_t k = 0; k < flows.size(); k++) {
const auto &flow = flows[k];
DemTarget flow_target = DemTarget::observable_id(stats.num_observables + k);
xor_pauli_string_into_tracker_as_target(flow.input, flow_target);
}
template <size_t W>
void CircuitFlowReverser::xor_flow_starts_into_tracker(std::span<const Flow<W>> flows) {
for (size_t k = 0; k < flows.size(); k++) {
const auto &flow = flows[k];
DemTarget flow_target = DemTarget::observable_id(stats.num_observables + k);
xor_pauli_string_into_tracker_as_target(flow.input, flow_target);
}
}

template <size_t W>
void CircuitFlowReverser::verify_flow_observables_disappeared(std::span<const Flow<W>> flows) {
bool failed = false;
DemTarget example{};
for (size_t q = 0; q < stats.num_qubits; q++) {
for (auto &e : rev.xs[q]) {
failed = true;
example = e;
}
for (auto &e : rev.zs[q]) {
failed = true;
example = e;
}
template <size_t W>
void CircuitFlowReverser::verify_flow_observables_disappeared(std::span<const Flow<W>> flows) {
bool failed = false;
DemTarget example{};
for (size_t q = 0; q < stats.num_qubits; q++) {
for (auto &e : rev.xs[q]) {
failed = true;
example = e;
}
if (failed) {
if (example.is_relative_detector_id() ||
(example.is_observable_id() && example.raw_id() < stats.num_observables)) {
std::stringstream ss;
ss << "The detecting region of " << example << " reached the start of the circuit.\n";
ss << "Only flows given as arguments are permitted to touch the start or end of the circuit.\n";
ss << "There are four potential ways to fix this issue, depending on what's wrong:\n";
ss << "- If " + example.str() +
" was relying on implicit initialization into |0> at the start of the circuit, add explicit "
"resets to the circuit.\n";
ss << "- If " + example.str() + " shouldn't be reaching the start of the circuit, fix its declaration.\n";
ss << "- If " + example.str() + " isn't needed, delete it from the circuit.\n";
ss << "- If the given circuit is a partial circuit, and " << example
<< " is reaching outside of it, refactor " << example << "into a flow argument.";
throw std::invalid_argument(ss.str());
} else {
std::stringstream ss;
const auto &flow = flows[example.raw_id() - stats.num_observables];
ss << "The circuit didn't satisfy one of the given flows (ignoring sign): ";
ss << flow;
auto v = rev.current_error_sensitivity_for<W>(example);
v.xs ^= flow.input.xs;
v.zs ^= flow.input.zs;
ss << "\nChanging the flow to '"
<< Flow<W>{.input = v, .output = flow.output, .measurements = flow.measurements}
<< "' would make it a valid flow.";
throw std::invalid_argument(ss.str());
}
for (auto &e : rev.zs[q]) {
failed = true;
example = e;
}
}
if (failed) {
if (example.is_relative_detector_id() ||
(example.is_observable_id() && example.raw_id() < stats.num_observables)) {
std::stringstream ss;
ss << "The detecting region of " << example << " reached the start of the circuit.\n";
ss << "Only flows given as arguments are permitted to touch the start or end of the circuit.\n";
ss << "There are four potential ways to fix this issue, depending on what's wrong:\n";
ss << "- If " + example.str() +
" was relying on implicit initialization into |0> at the start of the circuit, add explicit "
"resets to the circuit.\n";
ss << "- If " + example.str() + " shouldn't be reaching the start of the circuit, fix its declaration.\n";
ss << "- If " + example.str() + " isn't needed, delete it from the circuit.\n";
ss << "- If the given circuit is a partial circuit, and " << example
<< " is reaching outside of it, refactor " << example << "into a flow argument.";
throw std::invalid_argument(ss.str());
} else {
std::stringstream ss;
const auto &flow = flows[example.raw_id() - stats.num_observables];
ss << "The circuit didn't satisfy one of the given flows (ignoring sign): ";
ss << flow;
auto v = rev.current_error_sensitivity_for<W>(example);
v.xs ^= flow.input.xs;
v.zs ^= flow.input.zs;
ss << "\nChanging the flow to '"
<< Flow<W>{.input = v, .output = flow.output, .measurements = flow.measurements}
<< "' would make it a valid flow.";
throw std::invalid_argument(ss.str());
}
}
}

template <size_t W>
std::vector<Flow<W>> CircuitFlowReverser::build_inverted_flows(std::span<const Flow<W>> flows) {
std::vector<Flow<W>> inverted_flows;
for (size_t k = 0; k < flows.size(); k++) {
const auto &f = flows[k];
inverted_flows.push_back(Flow<W>{
.input = f.output,
.output = f.input,
.measurements = {},
});
auto &f2 = inverted_flows.back();
f2.input.sign = false;
f2.output.sign = false;
for (auto &m : d2ms[DemTarget::observable_id(k + stats.num_observables)]) {
f2.measurements.push_back((int32_t)m - (int32_t)num_new_measurements);
}
template <size_t W>
std::vector<Flow<W>> CircuitFlowReverser::build_inverted_flows(std::span<const Flow<W>> flows) {
std::vector<Flow<W>> inverted_flows;
for (size_t k = 0; k < flows.size(); k++) {
const auto &f = flows[k];
inverted_flows.push_back(Flow<W>{
.input = f.output,
.output = f.input,
.measurements = {},
});
auto &f2 = inverted_flows.back();
f2.input.sign = false;
f2.output.sign = false;
for (auto &m : d2ms[DemTarget::observable_id(k + stats.num_observables)]) {
f2.measurements.push_back((int32_t)m - (int32_t)num_new_measurements);
}
return inverted_flows;
}
return inverted_flows;
}
} // namespace internal

template <size_t W>
std::pair<Circuit, std::vector<Flow<W>>> circuit_inverse_qec(
const Circuit &circuit, std::span<const Flow<W>> flows, bool dont_turn_measurements_into_resets) {

size_t max_flow_qubit = 0;
for (const auto &flow : flows) {
max_flow_qubit = std::max(max_flow_qubit, flow.input.num_qubits);
Expand Down

0 comments on commit 26f4387

Please sign in to comment.