diff --git a/src/stim/stabilizers/tableau.pybind.cc b/src/stim/stabilizers/tableau.pybind.cc index da568248..ea562c65 100644 --- a/src/stim/stabilizers/tableau.pybind.cc +++ b/src/stim/stabilizers/tableau.pybind.cc @@ -2130,16 +2130,8 @@ void stim_pybind::pybind_tableau_methods(pybind11::module &m, pybind11::class_> v; - double weight = 0; for (const auto &obj : state_vector) { v.push_back(pybind11::cast>(obj)); - weight += std::norm(v.back()); - } - if (weight != 1.0 && weight > 0.0) { - std::complex scale = (float)sqrt(1.0 / weight); - for (auto &litude : v) { - amplitude *= scale; - } } return circuit_to_tableau( @@ -2155,7 +2147,7 @@ void stim_pybind::pybind_tableau_methods(pybind11::module &m, pybind11::class_ 0.125) { - throw std::invalid_argument( - "The given state vector wasn't a unit vector. It had a length of " + std::to_string(weight) + "."); - } - VectorSimulator sim(num_qubits); sim.state = state_vector; + /* + double weight = 0; + for (const auto &c : sim.state) { + weight += std::norm(c); + } + if (weight == 0.0) { + throw std::invalid_argument("The given state vector has zero length."); + } + */ Circuit recorded; auto apply = [&](GateType gate_type, uint32_t target) { @@ -73,7 +73,7 @@ Circuit stim::stabilizer_state_vector_to_circuit( {}); }; - // Move biggest amplitude to start of state vector.. + // 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) { diff --git a/src/stim/util_top/circuit_vs_amplitudes.h b/src/stim/util_top/circuit_vs_amplitudes.h index be7d59d8..f841d16e 100644 --- a/src/stim/util_top/circuit_vs_amplitudes.h +++ b/src/stim/util_top/circuit_vs_amplitudes.h @@ -8,7 +8,8 @@ namespace stim { /// Synthesizes a circuit to generate the given state vector. /// /// Args: -/// stabilizer_state_vector: The vector of amplitudes to produce using a circuit. +/// stabilizer_state_vector: The vector of amplitudes to produce using a circuit. Must be non-zero and will be +/// normalized if necessary. /// little_endian: Whether the vector is using little endian or big endian ordering. /// inverted_circuit: If false, returns a circuit that sends |000...0> to the state vector. /// If true, returns a circuit that sends the state vector to |000...0> instead of a cir. diff --git a/src/stim/util_top/circuit_vs_amplitudes.test.cc b/src/stim/util_top/circuit_vs_amplitudes.test.cc index cd45c7f3..db60267c 100644 --- a/src/stim/util_top/circuit_vs_amplitudes.test.cc +++ b/src/stim/util_top/circuit_vs_amplitudes.test.cc @@ -8,10 +8,12 @@ using namespace stim; TEST(conversions, stabilizer_state_vector_to_circuit_basic) { + ASSERT_THROW(stabilizer_state_vector_to_circuit({}, false), std::invalid_argument); + ASSERT_THROW( stabilizer_state_vector_to_circuit( { - {0.5}, + {0}, }, false), std::invalid_argument); @@ -175,6 +177,35 @@ TEST(conversions, stabilizer_state_vector_to_circuit_fuzz_round_trip) { } } +TEST(conversions, stabilizer_state_vector_to_circuit_unnormalized_fuzz_round_trip) { + auto rng = INDEPENDENT_TEST_RNG(); + auto little_endian = true; + + for (size_t i = 0; i < 100; i++) { + // Pick a random stabilizer state. + size_t n = i % 5; + TableauSimulator<64> sim(INDEPENDENT_TEST_RNG(), n); + sim.inv_state = Tableau<64>::random(n, rng); + auto desired_vec = sim.to_state_vector(little_endian); + + // Unnormalize by multiplying by a random non-zero factor. + auto scaled_vec = desired_vec; + std::uniform_real_distribution dist(-1000.0, +1000.0); + std::complex scale = {dist(rng), dist(rng)}; + while (std::norm(scale) < 0.01) { + scale = {dist(rng), dist(rng)}; + } + for (auto &c : scaled_vec) { + c *= scale; + } + + // Round trip through a circuit. + auto circuit = stabilizer_state_vector_to_circuit(scaled_vec, little_endian); + auto actual_vec = circuit_to_output_state_vector(circuit, little_endian); + ASSERT_EQ(actual_vec, desired_vec) << " scale=" << scale; + } +} + TEST(conversions, circuit_to_output_state_vector) { ASSERT_EQ(circuit_to_output_state_vector(Circuit(""), false), (std::vector>{{1}})); ASSERT_EQ(