Skip to content

Commit

Permalink
fix depolarizing channel and test case
Browse files Browse the repository at this point in the history
  • Loading branch information
dsdsdshe committed Aug 25, 2023
1 parent 22ac6c6 commit 021b478
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 30 deletions.
60 changes: 50 additions & 10 deletions ccsrc/include/simulator/vector/vector_state.tpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,17 +408,57 @@ template <typename qs_policy_t_>
void VectorState<qs_policy_t_>::ApplyDepolarizingChannel(const std::shared_ptr<BasicGate>& gate) {
auto g = static_cast<DepolarizingChannel*>(gate.get());
double p = g->prob_;
for (qbit_t obj_qubit : gate->obj_qubits_) {
double r = static_cast<double>(rng_());
if (r < p * 3.0 / 4.0) {
qbits_t obj{obj_qubit};
size_t n_qubits = gate->obj_qubits_.size();
double r = static_cast<double>(rng_());
if (r < p) {
if (p <= 1) {
for (qbit_t obj_qubit : gate->obj_qubits_) {
qbits_t obj{obj_qubit};
double p_i = static_cast<double>(rng_());
if (p_i > 3.0 / 4.0) {
qs_policy_t::ApplyX(&qs, obj, gate->ctrl_qubits_, dim);
} else if (p_i > 1.0 / 2.0) {
qs_policy_t::ApplyY(&qs, obj, gate->ctrl_qubits_, dim);
} else if (p_i > 1.0 / 4.0) {
qs_policy_t::ApplyZ(&qs, obj, gate->ctrl_qubits_, dim);
}
}
} else {
double s = static_cast<double>(rng_());
if (s < p / pow(4, n_qubits) + (1 - p)) {
return;
}
std::string pauli_string;
std::vector<std::string> pauli_string_list = {"I", "X", "Y", "Z"};
std::vector<std::string> pauli_word = {"I", "X", "Y", "Z"};
for (size_t i = 1; i < n_qubits; i++) {
std::vector<std::string> tmp_list;
for (size_t j = 0; j < pauli_string_list.size(); j++) {
for (size_t k = 0; k < 4; k++) {
pauli_string = pauli_string_list[j] + pauli_word[k];
tmp_list.push_back(pauli_string);
}
}
pauli_string_list = tmp_list;
}
pauli_string = "";
auto denominator = pow(4, n_qubits) - 1;
double p_i = static_cast<double>(rng_());
if (p_i < 1.0 / 3.0) {
qs_policy_t::ApplyX(&qs, obj, gate->ctrl_qubits_, dim);
} else if (p_i < 2.0 / 3.0) {
qs_policy_t::ApplyY(&qs, obj, gate->ctrl_qubits_, dim);
} else {
qs_policy_t::ApplyZ(&qs, obj, gate->ctrl_qubits_, dim);
for (size_t i = 1; i < denominator + 1; i++) {
if (p_i > 1 - i / denominator) {
pauli_string = pauli_string_list[i];
break;
}
}
for (size_t i = 0; i < n_qubits; i++) {
qbits_t obj{gate->obj_qubits_[i]};
if (pauli_string[i] == 'X') {
qs_policy_t::ApplyX(&qs, obj, gate->ctrl_qubits_, dim);
} else if (pauli_string[i] == 'Y') {
qs_policy_t::ApplyY(&qs, obj, gate->ctrl_qubits_, dim);
} else if (pauli_string[i] == 'Z') {
qs_policy_t::ApplyZ(&qs, obj, gate->ctrl_qubits_, dim);
}
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions tests/st/test_core/test_gates/test_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
# limitations under the License.
# ============================================================================
"""Test channel."""
import numpy as np
from math import sqrt
import numpy as np
import pytest

import mindquantum.core.gates.channel as C
Expand All @@ -32,7 +32,9 @@ def test_pauli_channel():
Expectation: success.
"""
px, py, pz = np.random.rand(3) / 3
assert np.allclose(C.PauliChannel(px, py, pz).matrix(), [sqrt(1 - px - py - pz) * I, sqrt(px) * X, sqrt(py) * Y, sqrt(pz) * Z])
assert np.allclose(
C.PauliChannel(px, py, pz).matrix(), [sqrt(1 - px - py - pz) * I, sqrt(px) * X, sqrt(py) * Y, sqrt(pz) * Z]
)
assert np.allclose(C.BitFlipChannel(px).matrix(), [sqrt(1 - px) * I, sqrt(px) * X])
assert np.allclose(C.PhaseFlipChannel(pz).matrix(), [sqrt(1 - pz) * I, sqrt(pz) * Z])
assert np.allclose(C.BitPhaseFlipChannel(py).matrix(), [sqrt(1 - py) * I, sqrt(py) * Y])
Expand Down
20 changes: 10 additions & 10 deletions tests/st/test_simulator/test_basic_gate_with_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ def test_none_parameter_gate(config, gate):
m = np.block([[np.eye(dim), np.zeros((dim, dim))], [np.zeros((dim, dim)), g.matrix()]])
c_ref_qs = m @ (c_init_state / np.linalg.norm(c_init_state))
if virtual_qc.startswith("mqmatrix"):
assert np.allclose(c_sim.get_qs(), np.outer(c_ref_qs, c_ref_qs.conj()), atol=1.0e-6)
assert np.allclose(c_sim.get_qs(), np.outer(c_ref_qs, c_ref_qs.conj()), atol=1e-6)
else:
assert np.allclose(c_sim.get_qs(), c_ref_qs)
assert np.allclose(c_sim.get_qs(), c_ref_qs, atol=1e-6)


@pytest.mark.level0
Expand All @@ -118,9 +118,9 @@ def test_single_parameter_gate(config, gate):
sim.apply_gate(g)
ref_qs = g.matrix() @ (init_state / np.linalg.norm(init_state))
if virtual_qc.startswith("mqmatrix"):
assert np.allclose(sim.get_qs(), np.outer(ref_qs, ref_qs.conj()))
assert np.allclose(sim.get_qs(), np.outer(ref_qs, ref_qs.conj()), atol=1e-6)
else:
assert np.allclose(sim.get_qs(), ref_qs)
assert np.allclose(sim.get_qs(), ref_qs, atol=1e-6)

c_g = g.on(list(range(g.n_qubits)), g.n_qubits)
c_init_state = np.random.rand(2 * dim) + np.random.rand(2 * dim) * 1j
Expand All @@ -130,9 +130,9 @@ def test_single_parameter_gate(config, gate):
m = np.block([[np.eye(dim), np.zeros((dim, dim))], [np.zeros((dim, dim)), g.matrix()]])
c_ref_qs = m @ (c_init_state / np.linalg.norm(c_init_state))
if virtual_qc.startswith("mqmatrix"):
assert np.allclose(c_sim.get_qs(), np.outer(c_ref_qs, c_ref_qs.conj()), atol=1.0e-6)
assert np.allclose(c_sim.get_qs(), np.outer(c_ref_qs, c_ref_qs.conj()), atol=1e-6)
else:
assert np.allclose(c_sim.get_qs(), c_ref_qs)
assert np.allclose(c_sim.get_qs(), c_ref_qs, atol=1e-6)


@pytest.mark.level0
Expand Down Expand Up @@ -161,9 +161,9 @@ def test_multi_parameter_gate(config, gate):
sim.apply_gate(g)
ref_qs = g.matrix() @ (init_state / np.linalg.norm(init_state))
if virtual_qc.startswith("mqmatrix"):
assert np.allclose(sim.get_qs(), np.outer(ref_qs, ref_qs.conj()))
assert np.allclose(sim.get_qs(), np.outer(ref_qs, ref_qs.conj()), atol=1e-6)
else:
assert np.allclose(sim.get_qs(), ref_qs)
assert np.allclose(sim.get_qs(), ref_qs, atol=1e-6)

c_g = g.on(list(range(g.n_qubits)), g.n_qubits)
c_init_state = np.random.rand(2 * dim) + np.random.rand(2 * dim) * 1j
Expand All @@ -173,9 +173,9 @@ def test_multi_parameter_gate(config, gate):
m = np.block([[np.eye(dim), np.zeros((dim, dim))], [np.zeros((dim, dim)), g.matrix()]])
c_ref_qs = m @ (c_init_state / np.linalg.norm(c_init_state))
if virtual_qc.startswith("mqmatrix"):
assert np.allclose(c_sim.get_qs(), np.outer(c_ref_qs, c_ref_qs.conj()), atol=1.0e-6)
assert np.allclose(c_sim.get_qs(), np.outer(c_ref_qs, c_ref_qs.conj()), atol=1e-6)
else:
assert np.allclose(c_sim.get_qs(), c_ref_qs)
assert np.allclose(c_sim.get_qs(), c_ref_qs, atol=1e-6)


@pytest.mark.level0
Expand Down
23 changes: 15 additions & 8 deletions tests/st/test_simulator/test_channel_with_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

"""Test channel with simulator."""
import numpy as np
from scipy.stats import entropy
import pytest

import mindquantum as mq
Expand All @@ -31,6 +32,8 @@
G.PhaseDampingChannel,
]

shots = 100000


@pytest.mark.level0
@pytest.mark.platform_x86_gpu_training
Expand Down Expand Up @@ -58,8 +61,9 @@ def test_flip_and_damping_channel(config, channel):
sim.apply_gate(c)
assert np.allclose(sim.get_qs(), ref_qs)
else:
res = sim.sampling(Circuit([c, G.Measure().on(0)]), shots=100000)
assert np.allclose(res.data['0'] / 100000, ref_qs[0][0], atol=1e-2)
res = sim.sampling(Circuit([c, G.Measure().on(0)]), shots=shots)
difference = entropy(np.array(list(res.data.values())) / shots, ref_qs.diagonal().real)
assert difference < 1e-4


@pytest.mark.level0
Expand Down Expand Up @@ -87,8 +91,9 @@ def test_pauli_channel(config):
sim.apply_gate(c)
assert np.allclose(sim.get_qs(), ref_qs)
else:
res = sim.sampling(Circuit([c, G.Measure().on(0)]), shots=100000)
assert np.allclose(res.data['0'] / 100000, ref_qs[0][0], atol=1e-2)
res = sim.sampling(Circuit([c, G.Measure().on(0)]), shots=shots)
difference = entropy(np.array(list(res.data.values())) / shots, ref_qs.diagonal().real)
assert difference < 1e-4


@pytest.mark.level0
Expand Down Expand Up @@ -118,8 +123,9 @@ def test_depolarizing_channel(config):
sim.apply_gate(c)
assert np.allclose(sim.get_qs(), ref_qs)
else:
res = sim.sampling(Circuit(c).measure_all(), shots=100000)
assert np.allclose(res.data[n * '0'] / 100000, ref_qs[0][0], atol=1e-2)
res = sim.sampling(Circuit(c).measure_all(), shots=shots)
difference = entropy(np.array(list(res.data.values())) / shots, ref_qs.diagonal().real)
assert difference < 1e-4


@pytest.mark.level0
Expand Down Expand Up @@ -148,5 +154,6 @@ def test_kraus_channel(config):
sim.apply_gate(c)
assert np.allclose(sim.get_qs(), ref_qs)
else:
res = sim.sampling(Circuit([c, G.Measure().on(0)]), shots=100000)
assert np.allclose(res.data['0'] / 100000, ref_qs[0][0], atol=1e-2)
res = sim.sampling(Circuit([c, G.Measure().on(0)]), shots=shots)
difference = entropy(np.array(list(res.data.values())) / shots, ref_qs.diagonal().real)
assert difference < 1e-4

0 comments on commit 021b478

Please sign in to comment.