diff --git a/src/stim/simulators/tableau_simulator.inl b/src/stim/simulators/tableau_simulator.inl index de872532b..bdc739495 100644 --- a/src/stim/simulators/tableau_simulator.inl +++ b/src/stim/simulators/tableau_simulator.inl @@ -1170,7 +1170,7 @@ std::vector> TableauSimulator::to_state_vector(bool littl auto sim = to_vector_sim(); if (!little_endian && inv_state.num_qubits > 0) { for (size_t q = 0; q < inv_state.num_qubits - q - 1; q++) { - sim.apply("SWAP", q, inv_state.num_qubits - q - 1); + sim.apply(GateType::SWAP, q, inv_state.num_qubits - q - 1); } } return sim.state; diff --git a/src/stim/simulators/tableau_simulator.test.cc b/src/stim/simulators/tableau_simulator.test.cc index 41e7f35c0..aa5f39872 100644 --- a/src/stim/simulators/tableau_simulator.test.cc +++ b/src/stim/simulators/tableau_simulator.test.cc @@ -391,19 +391,19 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, to_vector_sim, { ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true)); sim_tab.do_X(OpDat(0)); - sim_vec.apply("X", 0); + sim_vec.apply(GateType::X, 0); ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true)); sim_tab.do_H_XZ(OpDat(0)); - sim_vec.apply("H_XZ", 0); + sim_vec.apply(GateType::H, 0); ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true)); sim_tab.do_SQRT_Z(OpDat(0)); - sim_vec.apply("SQRT_Z", 0); + sim_vec.apply(GateType::S, 0); ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true)); sim_tab.do_ZCX(OpDat({0, 1})); - sim_vec.apply("ZCX", 0, 1); + sim_vec.apply(GateType::CX, 0, 1); ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true)); sim_tab.inv_state = Tableau::random(10, rng); @@ -411,7 +411,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, to_vector_sim, { ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true)); sim_tab.do_gate({GateType::XCX, {}, qubit_targets({4, 7})}); - sim_vec.apply("XCX", 4, 7); + sim_vec.apply(GateType::XCX, 4, 7); ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true)); }) @@ -432,8 +432,8 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, to_state_vector, { TEST_EACH_WORD_SIZE_W(TableauSimulator, to_state_vector_endian, { VectorSimulator sim_vec0(3); VectorSimulator sim_vec2(3); - sim_vec0.apply("H", 0); - sim_vec2.apply("H", 2); + sim_vec0.apply(GateType::H, 0); + sim_vec2.apply(GateType::H, 2); TableauSimulator sim_tab(INDEPENDENT_TEST_RNG(), 3); sim_tab.do_H_XZ(OpDat(2)); diff --git a/src/stim/simulators/vector_simulator.cc b/src/stim/simulators/vector_simulator.cc index 31891c590..adc81c185 100644 --- a/src/stim/simulators/vector_simulator.cc +++ b/src/stim/simulators/vector_simulator.cc @@ -71,19 +71,21 @@ void VectorSimulator::apply( } } -void VectorSimulator::apply(const std::string &gate, size_t qubit) { +void VectorSimulator::apply(GateType gate, size_t qubit) { try { - apply(GATE_DATA.at(gate).unitary(), {qubit}); + apply(GATE_DATA[gate].unitary(), {qubit}); } catch (const std::out_of_range &) { - throw std::out_of_range("Single qubit gate isn't supported by VectorSimulator: " + gate); + throw std::out_of_range( + "Single qubit gate isn't supported by VectorSimulator: " + std::string(GATE_DATA[gate].name)); } } -void VectorSimulator::apply(const std::string &gate, size_t qubit1, size_t qubit2) { +void VectorSimulator::apply(GateType gate, size_t qubit1, size_t qubit2) { try { - apply(GATE_DATA.at(gate).unitary(), {qubit1, qubit2}); + apply(GATE_DATA[gate].unitary(), {qubit1, qubit2}); } catch (const std::out_of_range &) { - throw std::out_of_range("Two qubit gate isn't supported by VectorSimulator: " + gate); + throw std::out_of_range( + "Two qubit gate isn't supported by VectorSimulator: " + std::string(GATE_DATA[gate].name)); } } diff --git a/src/stim/simulators/vector_simulator.h b/src/stim/simulators/vector_simulator.h index 56a1649b3..89aa54f00 100644 --- a/src/stim/simulators/vector_simulator.h +++ b/src/stim/simulators/vector_simulator.h @@ -85,9 +85,9 @@ struct VectorSimulator { void apply(const std::vector>> &matrix, const std::vector &qubits); /// Helper method for applying named single qubit gates. - void apply(const std::string &gate, size_t qubit); + void apply(GateType gate, size_t qubit); /// Helper method for applying named two qubit gates. - void apply(const std::string &gate, size_t qubit1, size_t qubit2); + void apply(GateType gate, size_t qubit1, size_t qubit2); /// Helper method for applying the gates in a Pauli string. template @@ -102,11 +102,11 @@ struct VectorSimulator { bool z = gate.zs[k]; size_t q = qubit_offset + k; if (x && z) { - apply("Y", q); + apply(GateType::Y, q); } else if (x) { - apply("X", q); + apply(GateType::X, q); } else if (z) { - apply("Z", q); + apply(GateType::Z, q); } } } @@ -132,9 +132,9 @@ struct VectorSimulator { for (size_t k = 0; k < observable.num_qubits; k++) { if (observable.xs[k]) { if (observable.zs[k]) { - apply("H_YZ", k); + apply(GateType::H_YZ, k); } else { - apply("H_XZ", k); + apply(GateType::H, k); } } } diff --git a/src/stim/simulators/vector_simulator.test.cc b/src/stim/simulators/vector_simulator.test.cc index f99834e9d..3e8d4c9f2 100644 --- a/src/stim/simulators/vector_simulator.test.cc +++ b/src/stim/simulators/vector_simulator.test.cc @@ -31,8 +31,8 @@ static float complex_distance(std::complex a, std::complex b) { TEST(vector_sim, qubit_order) { VectorSimulator sim(2); - sim.apply("H_XZ", 0); - sim.apply("ZCX", 0, 1); + sim.apply(GateType::H, 0); + sim.apply(GateType::CX, 0, 1); ASSERT_NEAR_C(sim.state[0], sqrtf(0.5)); ASSERT_NEAR_C(sim.state[1], 0); ASSERT_NEAR_C(sim.state[2], 0); @@ -41,27 +41,27 @@ TEST(vector_sim, qubit_order) { TEST(vector_sim, h_squared) { VectorSimulator sim(1); - sim.apply("H_XZ", 0); - sim.apply("H_XZ", 0); + sim.apply(GateType::H, 0); + sim.apply(GateType::H, 0); ASSERT_NEAR_C(sim.state[0], 1); ASSERT_NEAR_C(sim.state[1], 0); } TEST(vector_sim, sqrt_x_squared) { VectorSimulator sim(1); - sim.apply("SQRT_X_DAG", 0); - sim.apply("SQRT_X_DAG", 0); + sim.apply(GateType::SQRT_X_DAG, 0); + sim.apply(GateType::SQRT_X_DAG, 0); ASSERT_NEAR_C(sim.state[0], 0); ASSERT_NEAR_C(sim.state[1], 1); } TEST(vector_sim, state_channel_duality_cnot) { VectorSimulator sim(4); - sim.apply("H_XZ", 0); - sim.apply("H_XZ", 1); - sim.apply("ZCX", 0, 2); - sim.apply("ZCX", 1, 3); - sim.apply("ZCX", 2, 3); + sim.apply(GateType::H, 0); + sim.apply(GateType::H, 1); + sim.apply(GateType::CX, 0, 2); + sim.apply(GateType::CX, 1, 3); + sim.apply(GateType::CX, 2, 3); auto u = GATE_DATA.at("ZCX").unitary(); for (size_t row = 0; row < 4; row++) { for (size_t col = 0; col < 4; col++) { @@ -72,9 +72,9 @@ TEST(vector_sim, state_channel_duality_cnot) { TEST(vector_sim, state_channel_duality_y) { VectorSimulator sim(2); - sim.apply("H_XZ", 0); - sim.apply("ZCX", 0, 1); - sim.apply("Y", 1); + sim.apply(GateType::H, 0); + sim.apply(GateType::CX, 0, 1); + sim.apply(GateType::Y, 1); auto u = GATE_DATA.at("Y").unitary(); for (size_t row = 0; row < 2; row++) { for (size_t col = 0; col < 2; col++) { diff --git a/src/stim/stabilizers/conversions.cc b/src/stim/stabilizers/conversions.cc index cb83c0b41..caf7eba86 100644 --- a/src/stim/stabilizers/conversions.cc +++ b/src/stim/stabilizers/conversions.cc @@ -110,14 +110,16 @@ bool stim::try_disjoint_to_independent_xyz_errors_approx( double stim::depolarize1_probability_to_independent_per_channel_probability(double p) { if (p > 0.75) { - throw std::invalid_argument("depolarize1_probability_to_independent_per_channel_probability with p>0.75; p=" + std::to_string(p)); + throw std::invalid_argument( + "depolarize1_probability_to_independent_per_channel_probability with p>0.75; p=" + std::to_string(p)); } return 0.5 - 0.5 * sqrt(1 - (4 * p) / 3); } double stim::depolarize2_probability_to_independent_per_channel_probability(double p) { if (p > 0.9375) { - throw std::invalid_argument("depolarize2_probability_to_independent_per_channel_probability with p>15.0/16.0; p=" + std::to_string(p)); + throw std::invalid_argument( + "depolarize2_probability_to_independent_per_channel_probability with p>15.0/16.0; p=" + std::to_string(p)); } return 0.5 - 0.5 * pow(1 - (16 * p) / 15, 0.125); } diff --git a/src/stim/stabilizers/conversions.inl b/src/stim/stabilizers/conversions.inl index b37c24fd7..611ed8ad4 100644 --- a/src/stim/stabilizers/conversions.inl +++ b/src/stim/stabilizers/conversions.inl @@ -51,25 +51,31 @@ Circuit stabilizer_state_vector_to_circuit(const std::vector sim.state = state_vector; Circuit recorded; - auto apply = [&](const std::string &name, uint32_t target) { - sim.apply(name, target); - recorded.safe_append_u(name, {little_endian ? target : (num_qubits - target - 1)}); + auto apply = [&](GateType gate_type, uint32_t target) { + sim.apply(gate_type, target); + recorded.safe_append( + gate_type, + std::vector{ + GateTarget::qubit(little_endian ? target : (num_qubits - target - 1)), + }, + {}); }; - auto apply2 = [&](const std::string &name, uint32_t target, uint32_t target2) { - sim.apply(name, target, target2); - recorded.safe_append_u( - name, - { - little_endian ? target : (num_qubits - target - 1), - little_endian ? target2 : (num_qubits - target2 - 1), - }); + auto apply2 = [&](GateType gate_type, uint32_t target, uint32_t target2) { + sim.apply(gate_type, target, target2); + recorded.safe_append( + gate_type, + std::vector{ + GateTarget::qubit(little_endian ? target : (num_qubits - target - 1)), + GateTarget::qubit(little_endian ? target2 : (num_qubits - target2 - 1)), + }, + {}); }; // Move biggest amplitude to start of state vector.. size_t pivot = biggest_index(state_vector); for (size_t q = 0; q < num_qubits; q++) { if ((pivot >> q) & 1) { - apply("X", q); + apply(GateType::X, q); } } sim.smooth_stabilizer_state(sim.state[0]); @@ -96,7 +102,7 @@ Circuit stabilizer_state_vector_to_circuit(const std::vector if (base_qubit == SIZE_MAX) { base_qubit = q; } else { - apply2("CNOT", base_qubit, q); + apply2(GateType::CX, base_qubit, q); } } } @@ -104,13 +110,13 @@ Circuit stabilizer_state_vector_to_circuit(const std::vector auto s = sim.state[1 << base_qubit]; assert(s != (std::complex{0, 0})); if (s == std::complex{-1, 0}) { - apply("Z", base_qubit); + apply(GateType::Z, base_qubit); } else if (s == std::complex{0, 1}) { - apply("S_DAG", base_qubit); + apply(GateType::S_DAG, base_qubit); } else if (s == std::complex{0, -1}) { - apply("S", base_qubit); + apply(GateType::S, base_qubit); } - apply("H", base_qubit); + apply(GateType::H, base_qubit); sim.smooth_stabilizer_state(sim.state[0]); if (compute_occupation(sim.state) * 2 != occupation) { @@ -214,13 +220,13 @@ Circuit tableau_to_circuit(const Tableau &tableau, const std::string &method) Tableau remaining = tableau.inverse(); Circuit recorded_circuit; - auto apply = [&](const std::string &name, uint32_t target) { - remaining.inplace_scatter_append(GATE_DATA.at(name).tableau(), {target}); - recorded_circuit.safe_append_u(name, {target}); + auto apply = [&](GateType gate_type, uint32_t target) { + remaining.inplace_scatter_append(GATE_DATA[gate_type].tableau(), {target}); + recorded_circuit.safe_append(gate_type, std::vector{GateTarget::qubit(target)}, {}); }; - auto apply2 = [&](const std::string &name, uint32_t target, uint32_t target2) { - remaining.inplace_scatter_append(GATE_DATA.at(name).tableau(), {target, target2}); - recorded_circuit.safe_append_u(name, {target, target2}); + auto apply2 = [&](GateType gate_type, uint32_t target, uint32_t target2) { + remaining.inplace_scatter_append(GATE_DATA[gate_type].tableau(), {target, target2}); + recorded_circuit.safe_append(gate_type, std::vector{GateTarget::qubit(target), GateTarget::qubit(target2)}, {}); }; auto x_out = [&](size_t inp, size_t out) { const auto &p = remaining.xs[inp]; @@ -246,53 +252,53 @@ Circuit tableau_to_circuit(const Tableau &tableau, const std::string &method) // Move the pivot to the diagonal. if (pivot_row != col) { - apply2("CNOT", pivot_row, col); - apply2("CNOT", col, pivot_row); - apply2("CNOT", pivot_row, col); + apply2(GateType::CX, pivot_row, col); + apply2(GateType::CX, col, pivot_row); + apply2(GateType::CX, pivot_row, col); } // Transform the pivot to XZ. if (z_out(col, col) == 3) { - apply("S", col); + apply(GateType::S, col); } if (z_out(col, col) != 2) { - apply("H", col); + apply(GateType::H, col); } if (x_out(col, col) != 1) { - apply("S", col); + apply(GateType::S, col); } // Use the pivot to remove all other terms in the X observable. for (size_t row = col + 1; row < n; row++) { if (x_out(col, row) == 3) { - apply("S", row); + apply(GateType::S, row); } } for (size_t row = col + 1; row < n; row++) { if (x_out(col, row) == 2) { - apply("H", row); + apply(GateType::H, row); } } for (size_t row = col + 1; row < n; row++) { if (x_out(col, row)) { - apply2("CX", col, row); + apply2(GateType::CX, col, row); } } // Use the pivot to remove all other terms in the Z observable. for (size_t row = col + 1; row < n; row++) { if (z_out(col, row) == 3) { - apply("S", row); + apply(GateType::S, row); } } for (size_t row = col + 1; row < n; row++) { if (z_out(col, row) == 1) { - apply("H", row); + apply(GateType::H, row); } } for (size_t row = col + 1; row < n; row++) { if (z_out(col, row)) { - apply2("CX", row, col); + apply2(GateType::CX, row, col); } } } @@ -301,30 +307,30 @@ Circuit tableau_to_circuit(const Tableau &tableau, const std::string &method) simd_bits signs_copy = remaining.zs.signs; for (size_t col = 0; col < n; col++) { if (signs_copy[col]) { - apply("H", col); + apply(GateType::H, col); } } for (size_t col = 0; col < n; col++) { if (signs_copy[col]) { - apply("S", col); - apply("S", col); + apply(GateType::S, col); + apply(GateType::S, col); } } for (size_t col = 0; col < n; col++) { if (signs_copy[col]) { - apply("H", col); + apply(GateType::H, col); } } for (size_t col = 0; col < n; col++) { if (remaining.xs.signs[col]) { - apply("S", col); - apply("S", col); + apply(GateType::S, col); + apply(GateType::S, col); } } if (recorded_circuit.count_qubits() < n) { - apply("H", n - 1); - apply("H", n - 1); + apply(GateType::H, n - 1); + apply(GateType::H, n - 1); } return recorded_circuit; } @@ -379,13 +385,13 @@ Tableau unitary_to_tableau(const std::vector> sim.do_unitary_circuit(recorded_circuit); sim.smooth_stabilizer_state(sim.state[0]); - auto apply = [&](const std::string &name, uint32_t target) { - sim.apply(name, target); - recorded_circuit.safe_append_u(name, {target}); + auto apply = [&](GateType gate_type, uint32_t target) { + sim.apply(gate_type, target); + recorded_circuit.safe_append(gate_type, std::vector{GateTarget::qubit(target)}, {}); }; - auto apply2 = [&](const std::string &name, uint32_t target, uint32_t target2) { - sim.apply(name, target, target2); - recorded_circuit.safe_append_u(name, {target, target2}); + auto apply2 = [&](GateType gate_type, uint32_t target, uint32_t target2) { + sim.apply(gate_type, target, target2); + recorded_circuit.safe_append(gate_type, std::vector{GateTarget::qubit(target), GateTarget::qubit(target2)}, {}); }; // Undo the permutation and also single-qubit phases. @@ -402,21 +408,21 @@ Tableau unitary_to_tableau(const std::vector> size_t pivot = first_set_bit(r, q); for (size_t b = 0; b < num_qubits; b++) { if (((r >> b) & 1) != 0 && b != pivot) { - apply2("CX", pivot, b); + apply2(GateType::CX, pivot, b); } } if (pivot != q) { - apply2("SWAP", q, pivot); + apply2(GateType::SWAP, q, pivot); } } // Undo phasing on this qubit. if (ratio.real() == -1) { - apply("Z", q); + apply(GateType::Z, q); } else if (ratio.imag() == -1) { - apply("S", q); + apply(GateType::S, q); } else if (ratio.imag() == +1) { - apply("S_DAG", q); + apply(GateType::S_DAG, q); } break; } @@ -429,7 +435,7 @@ Tableau unitary_to_tableau(const std::vector> size_t v = (1 << q1) | (1 << q2); size_t d = v * num_amplitudes + v; if (sim.state[d].real() == -1) { - apply2("CZ", q1, q2); + apply2(GateType::CZ, q1, q2); } } } diff --git a/src/stim/stabilizers/tableau.test.cc b/src/stim/stabilizers/tableau.test.cc index b3c804ddf..c224bf253 100644 --- a/src/stim/stabilizers/tableau.test.cc +++ b/src/stim/stabilizers/tableau.test.cc @@ -72,8 +72,8 @@ bool tableau_agrees_with_unitary( VectorSimulator sim(n * 2); // Create EPR pairs to test all possible inputs via state channel duality. for (size_t q = 0; q < n; q++) { - sim.apply("H_XZ", q); - sim.apply("ZCX", q, q + n); + sim.apply(GateType::H, q); + sim.apply(GateType::CX, q, q + n); } // Apply input-side observable. sim.apply(input_side_obs, n);