Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove the constraint that stim.Tableau.from_state_vector inputs must be normalized #840

Merged
merged 4 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/stim/stabilizers/tableau.pybind.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2147,7 +2147,7 @@ void stim_pybind::pybind_tableau_methods(pybind11::module &m, pybind11::class_<T
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.
Expand Down
14 changes: 14 additions & 0 deletions src/stim/stabilizers/tableau_pybind_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,20 @@ def test_from_named_gate():
stim.Tableau.from_named_gate("X_ERROR")


def test_from_state_vector():
drqec marked this conversation as resolved.
Show resolved Hide resolved
t = stim.Tableau.from_state_vector([
0.5**0.5,
0,
0,
0.5**0.5,
], endian='little')
assert len(t) == 2
assert t.x_output(0) == stim.PauliString("Z_")
assert t.x_output(1) == stim.PauliString("_X")
assert t.z_output(0) == stim.PauliString("XX")
assert t.z_output(1) == stim.PauliString("ZZ")


def test_identity():
t = stim.Tableau(3)
assert len(t) == 3
Expand Down
11 changes: 1 addition & 10 deletions src/stim/util_top/circuit_vs_amplitudes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,6 @@ Circuit stim::stabilizer_state_vector_to_circuit(
}

uint8_t num_qubits = floor_lg2(state_vector.size());
double weight = 0;
drqec marked this conversation as resolved.
Show resolved Hide resolved
for (const auto &c : state_vector) {
weight += std::norm(c);
}
if (abs(weight - 1) > 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;

Expand All @@ -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) {
Expand Down
3 changes: 2 additions & 1 deletion src/stim/util_top/circuit_vs_amplitudes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
33 changes: 32 additions & 1 deletion src/stim/util_top/circuit_vs_amplitudes.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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<float> dist(-1000.0, +1000.0);
std::complex<float> 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<std::complex<float>>{{1}}));
ASSERT_EQ(
Expand Down
Loading