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

Fix bug in bit flip noise channel #528

Merged
merged 8 commits into from
Aug 9, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
168 changes: 153 additions & 15 deletions python/tests/unittests/test_NoiseModel.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@
import cudaq


def test_Depol():

def test_depolarization_channel():
"""Tests the depolarization channel in the case of a non-zero probability."""
cudaq.set_target('density-matrix-cpu')

circuit = cudaq.make_kernel()
q = circuit.qalloc()
circuit.x(q)
Expand All @@ -42,10 +41,150 @@ def test_Depol():
assert ('1' in counts)


def test_Kraus():

def test_depolarization_channel_simple():
"""Tests the depolarization channel in the case of `probability = 1.0`"""
cudaq.set_target('density-matrix-cpu')
kernel = cudaq.make_kernel()
qubit = kernel.qalloc()
noise = cudaq.NoiseModel()

# Depolarization channel with `1.0` probability of the qubit state
# being scrambled.
depolarization_channel = cudaq.DepolarizationChannel(1.0)
# Channel applied to any Y-gate on the depolarization channel.
noise.add_channel('y', [0], depolarization_channel)

# Bring the qubit to the |1> state, where it will remain
# with a probability of `1 - p = 0.0`.
kernel.y(qubit)
kernel.mz(qubit)

# Without noise, the qubit should still be in the |1> state.
counts = cudaq.sample(kernel)
want_counts = 1000
got_counts = counts["1"]
assert got_counts == want_counts

# With noise, the measurements should be a roughly 50/50
# mix between the |0> and |1> states.
noisy_counts = cudaq.sample(kernel, noise_model=noise)
want_probability = 0.5
got_zero_probability = noisy_counts.probability("0")
got_one_probability = noisy_counts.probability("1")
assert np.isclose(got_zero_probability, want_probability, atol=.2)
assert np.isclose(got_one_probability, want_probability, atol=.2)


def test_amplitude_damping_simple():
"""Tests the amplitude damping channel in the case of `probability = 1.0`"""
cudaq.set_target('density-matrix-cpu')
noise = cudaq.NoiseModel()
# Amplitude damping channel with `1.0` probability of the qubit
# decaying to the ground state.
amplitude_damping = cudaq.AmplitudeDampingChannel(1.0)
# Applied to any Hadamard gate on the qubit.
noise.add_channel('h', [0], amplitude_damping)

kernel = cudaq.make_kernel()
qubit = kernel.qalloc()
# This will bring qubit to `1/sqrt(2) (|0> + |1>)`, where it will remain
# with a probability of `1 - p = 0.0`.
kernel.h(qubit)
kernel.mz(qubit)

# Without noise, the qubit will now have a 50/50 mix of measurements
# between |0> and |1>.
counts = cudaq.sample(kernel)
want_probability = 0.5
got_zero_probability = counts.probability("0")
got_one_probability = counts.probability("1")
assert np.isclose(got_zero_probability, want_probability, atol=.1)
assert np.isclose(got_one_probability, want_probability, atol=.1)

# With noise, all measurements should be in the |0> state,
noisy_counts = cudaq.sample(kernel, noise_model=noise)
want_counts = 1000
got_counts = noisy_counts["0"]
assert (got_counts == want_counts)


def test_phase_flip_simple():
"""Tests the phase flip channel in the case of `probability = 1.0`"""
cudaq.set_target('density-matrix-cpu')
noise = cudaq.NoiseModel()
# Phase flip channel with `1.0` probability of the qubit
# undergoing a phase rotation of 180 degrees (π).
phase_flip = cudaq.PhaseFlipChannel(1.0)
noise.add_channel('z', [0], phase_flip)

kernel = cudaq.make_kernel()
qubit = kernel.qalloc()

# Place qubit in superposition state.
kernel.h(qubit)
# Rotate the phase around Z by 180 degrees (π).
kernel.z(qubit)
# Apply another hadamard and measure.
kernel.h(qubit)
kernel.mz(qubit)

# Without noise, we'd expect the qubit to end in the |1>
# state due to the phase rotation between the two hadamard
# gates.
counts = cudaq.sample(kernel)
want_counts = 1000
got_one_counts = counts["1"]
assert got_one_counts == want_counts

# With noise, should be in the |0> state.
noisy_counts = cudaq.sample(kernel, noise_model=noise)
got_zero_counts = noisy_counts["0"]
assert got_zero_counts == want_counts


def test_bit_flip_simple():
"""
Tests the bit flip channel with the probability at `0.0` on qubit 0,
and `1.0` on qubit 1.
"""
cudaq.set_target('density-matrix-cpu')
noise = cudaq.NoiseModel()
# Bit flip channel with `0.0` probability of the qubit flipping 180 degrees.
bit_flip_zero = cudaq.BitFlipChannel(0.0)
noise.add_channel('x', [0], bit_flip_zero)
# Bit flip channel with `1.0` probability of the qubit flipping 180 degrees.
bit_flip_one = cudaq.BitFlipChannel(1.0)
noise.add_channel('x', [1], bit_flip_one)

# Now we may define our simple kernel function and allocate a register
# of qubits to it.
kernel = cudaq.make_kernel()
qubits = kernel.qalloc(2)
# This will bring the qubit to the |1> state.
# Remains with a probability of `1 - p = 1.0`.
kernel.x(qubits[0])
# Now we apply an X-gate to qubit 1.
# Remains in the |1> state with a probability of `1 - p = 0.0`.
kernel.x(qubits[1])
kernel.mz(qubits)

# Without noise, both qubits in the |1> state.
counts = cudaq.sample(kernel)
counts.dump()
want_counts = 1000
got_one_one_counts = counts["11"]
assert got_one_one_counts == want_counts

# With noise, the state should be |1>|0> == |10>
noisy_counts = cudaq.sample(kernel, noise_model=noise)
noisy_counts.dump()
got_one_zero_counts = noisy_counts["10"]
assert got_one_zero_counts == want_counts


def test_kraus_channel():
"""Tests the Kraus Channel with a series of custom Kraus Operators."""
cudaq.set_target('density-matrix-cpu')
k0 = np.array([[0.05773502691896258, 0.0], [0., -0.05773502691896258]],
dtype=np.complex128)
k1 = np.array([[0., 0.05773502691896258], [0.05773502691896258, 0.]],
Expand All @@ -55,28 +194,27 @@ def test_Kraus():
k3 = np.array([[0.99498743710662, 0.0], [0., 0.99498743710662]],
dtype=np.complex128)

depol = cudaq.KrausChannel([k0, k1, k2, k3])
depolarization = cudaq.KrausChannel([k0, k1, k2, k3])

assert ((depol[0] == k0).all())
assert ((depol[1] == k1).all())
assert ((depol[2] == k2).all())
assert ((depol[3] == k3).all())
assert ((depolarization[0] == k0).all())
assert ((depolarization[1] == k1).all())
assert ((depolarization[2] == k2).all())
assert ((depolarization[3] == k3).all())

noise = cudaq.NoiseModel()
noise.add_channel('x', [0], depol)
noise.add_channel('x', [0], depolarization)
cudaq.set_noise(noise)
circuit = cudaq.make_kernel()
q = circuit.qalloc()
circuit.x(q)

counts = cudaq.sample(circuit)
assert (len(counts) == 2)
want_count_length = 2
got_count_length = len(counts)
assert (got_count_length == want_count_length)
assert ('0' in counts)
assert ('1' in counts)

cudaq.unset_noise()
cudaq.reset_target()


# leave for gdb debugging
if __name__ == "__main__":
Expand Down
1 change: 1 addition & 0 deletions python/tests/unittests/test_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def assert_close(want, got, tolerance=1.e-5) -> bool:


def test_simple_statevector():
cudaq.set_target('default')

circuit = cudaq.make_kernel()
q = circuit.qalloc(2)
Expand Down
5 changes: 0 additions & 5 deletions runtime/nvqir/CircuitSimulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -858,11 +858,6 @@ class CircuitSimulatorBase : public CircuitSimulator {
QuantumOperation gate;
cudaq::info(gateToString(gate.name(), controls, angles, targets));
enqueueGate(gate.name(), gate.getGate(angles), controls, targets, angles);
if (executionContext && executionContext->noiseModel) {
std::vector<std::size_t> noiseQubits{controls.begin(), controls.end()};
noiseQubits.insert(noiseQubits.end(), targets.begin(), targets.end());
applyNoiseChannel(gate.name(), noiseQubits);
}
}

#define CIRCUIT_SIMULATOR_ONE_QUBIT(NAME) \
Expand Down
57 changes: 56 additions & 1 deletion unittests/integration/noise_tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,18 @@ CUDAQ_TEST(NoiseTest, checkDepolType) {
EXPECT_EQ(2, counts.size());
}

CUDAQ_TEST(NoiseTest, checkDepolTypeSimple) {
cudaq::depolarization_channel depol(1.);
cudaq::noise_model noise;
noise.add_channel<cudaq::types::x>({0}, depol);
cudaq::set_noise(noise);
auto counts = cudaq::sample(xOp{});
counts.dump();
EXPECT_EQ(2, counts.size());
EXPECT_NEAR(counts.probability("0"), .50, .2);
EXPECT_NEAR(counts.probability("1"), .50, .2);
}

CUDAQ_TEST(NoiseTest, checkAmpDampType) {
cudaq::amplitude_damping_channel ad(.25);
cudaq::noise_model noise;
Expand All @@ -187,8 +199,19 @@ CUDAQ_TEST(NoiseTest, checkAmpDampType) {
EXPECT_NEAR(counts.probability("1"), .75, .1);
}

CUDAQ_TEST(NoiseTest, checkAmpDampTypeSimple) {
cudaq::amplitude_damping_channel ad(1.);
cudaq::noise_model noise;
noise.add_channel<cudaq::types::x>({0}, ad);
cudaq::set_noise(noise);
auto counts = cudaq::sample(xOp{});
counts.dump();
EXPECT_EQ(1, counts.size());
EXPECT_NEAR(counts.probability("0"), 1., .1);
}

CUDAQ_TEST(NoiseTest, checkBitFlipType) {
cudaq::amplitude_damping_channel bf(.1);
cudaq::bit_flip_channel bf(.1);
cudaq::noise_model noise;
noise.add_channel<cudaq::types::x>({0}, bf);
cudaq::set_noise(noise);
Expand All @@ -198,4 +221,36 @@ CUDAQ_TEST(NoiseTest, checkBitFlipType) {
EXPECT_NEAR(counts.probability("0"), .1, .1);
EXPECT_NEAR(counts.probability("1"), .9, .1);
}

CUDAQ_TEST(NoiseTest, checkBitFlipTypeSimple) {
cudaq::bit_flip_channel bf(1.);
cudaq::noise_model noise;
noise.add_channel<cudaq::types::x>({0}, bf);
cudaq::set_noise(noise);
auto counts = cudaq::sample(xOp{});
counts.dump();
EXPECT_EQ(1, counts.size());
EXPECT_NEAR(counts.probability("0"), 1., .1);
}

CUDAQ_TEST(NoiseTest, checkPhaseFlipType) {

auto kernel = []() __qpu__ {
cudaq::qubit q;
h(q);
z(q);
h(q);
mz(q);
};

cudaq::phase_flip_channel pf(1.);
cudaq::noise_model noise;
noise.add_channel<cudaq::types::z>({0}, pf);
cudaq::set_noise(noise);
auto counts = cudaq::sample(kernel);
counts.dump();
EXPECT_EQ(1, counts.size());
EXPECT_NEAR(counts.probability("0"), 1., .1);
}

#endif
Loading