diff --git a/doc/python_api_reference_vDev.md b/doc/python_api_reference_vDev.md index 784cb9e9..106ac282 100644 --- a/doc/python_api_reference_vDev.md +++ b/doc/python_api_reference_vDev.md @@ -11665,7 +11665,7 @@ def from_state_vector( Args: state_vector: A list of complex amplitudes specifying a superposition. The vector must correspond to a state that is reachable using Clifford - operations, and must be normalized (i.e. it must be a unit vector). + operations, and can be unnormalized. endian: "little": state vector is in little endian order, where higher index qubits correspond to larger changes in the state index. diff --git a/doc/stim.pyi b/doc/stim.pyi index c629b71e..c6279d9e 100644 --- a/doc/stim.pyi +++ b/doc/stim.pyi @@ -9169,7 +9169,7 @@ class Tableau: Args: state_vector: A list of complex amplitudes specifying a superposition. The vector must correspond to a state that is reachable using Clifford - operations, and must be normalized (i.e. it must be a unit vector). + operations, and can be unnormalized. endian: "little": state vector is in little endian order, where higher index qubits correspond to larger changes in the state index. diff --git a/glue/python/src/stim/__init__.pyi b/glue/python/src/stim/__init__.pyi index c629b71e..c6279d9e 100644 --- a/glue/python/src/stim/__init__.pyi +++ b/glue/python/src/stim/__init__.pyi @@ -9169,7 +9169,7 @@ class Tableau: Args: state_vector: A list of complex amplitudes specifying a superposition. The vector must correspond to a state that is reachable using Clifford - operations, and must be normalized (i.e. it must be a unit vector). + operations, and can be unnormalized. endian: "little": state vector is in little endian order, where higher index qubits correspond to larger changes in the state index. diff --git a/src/stim/stabilizers/tableau.pybind.cc b/src/stim/stabilizers/tableau.pybind.cc index e3dcd32e..ea562c65 100644 --- a/src/stim/stabilizers/tableau.pybind.cc +++ b/src/stim/stabilizers/tableau.pybind.cc @@ -2147,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; @@ -73,7 +64,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..f9b38148 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. Does not need to be a unit vector, +/// but must be non-zero. /// 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(