Skip to content

Commit 15595ec

Browse files
Merge pull request #504 from quantumlib/qsim-repeat-samples
Use qsim for repeated sampling
2 parents 8f7f940 + d3fd8dd commit 15595ec

File tree

3 files changed

+50
-19
lines changed

3 files changed

+50
-19
lines changed

pybind_interface/pybind_main.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,15 @@ class SimulatorHelper {
525525
return helper.release_state_to_python();
526526
}
527527

528+
static std::vector<uint64_t> sample_final_state(
529+
const py::dict &options, bool is_noisy, uint64_t num_samples) {
530+
auto helper = SimulatorHelper(options, is_noisy);
531+
if (!helper.is_valid || !helper.simulate(0)) {
532+
return {};
533+
}
534+
return helper.sample(num_samples);
535+
}
536+
528537
template <typename StateType>
529538
static std::vector<std::complex<double>> simulate_expectation_values(
530539
const py::dict &options,
@@ -753,6 +762,11 @@ class SimulatorHelper {
753762
return result;
754763
}
755764

765+
std::vector<uint64_t> sample(uint64_t num_samples) {
766+
StateSpace state_space = factory.CreateStateSpace();
767+
return state_space.Sample(state, num_samples, seed);
768+
}
769+
756770
py::array_t<float> release_state_to_python() {
757771
StateSpace state_space = factory.CreateStateSpace();
758772
state_space.InternalToNormalOrder(state);
@@ -931,6 +945,16 @@ qtrajectory_simulate_moment_expectation_values(
931945

932946
// Methods for sampling.
933947

948+
std::vector<uint64_t> qsim_sample_final(
949+
const py::dict &options, uint64_t num_samples) {
950+
return SimulatorHelper::sample_final_state(options, false, num_samples);
951+
}
952+
953+
std::vector<uint64_t> qtrajectory_sample_final(
954+
const py::dict &options, uint64_t num_samples) {
955+
return SimulatorHelper::sample_final_state(options, true, num_samples);
956+
}
957+
934958
std::vector<unsigned> qsim_sample(const py::dict &options) {
935959
Circuit<Cirq::GateCirq<float>> circuit;
936960
try {

pybind_interface/pybind_main.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ py::array_t<float> qsim_simulate_fullstate(
9090
const py::dict &options, const py::array_t<float> &input_vector);
9191

9292
std::vector<unsigned> qsim_sample(const py::dict &options);
93+
std::vector<uint64_t> qsim_sample_final(
94+
const py::dict &options, uint64_t num_samples);
9395

9496
// Methods for simulating noisy circuits.
9597
std::vector<std::complex<float>> qtrajectory_simulate(const py::dict &options);
@@ -100,6 +102,8 @@ py::array_t<float> qtrajectory_simulate_fullstate(
100102
const py::dict &options, const py::array_t<float> &input_vector);
101103

102104
std::vector<unsigned> qtrajectory_sample(const py::dict &options);
105+
std::vector<uint64_t> qtrajectory_sample_final(
106+
const py::dict &options, uint64_t num_samples);
103107

104108
// As above, but returning expectation values instead.
105109
std::vector<std::complex<double>> qsim_simulate_expectation_values(
@@ -200,8 +204,12 @@ std::vector<std::complex<float>> qsimh_simulate(const py::dict &options);
200204
\
201205
/* Methods for returning samples */ \
202206
m.def("qsim_sample", &qsim_sample, "Call the qsim sampler"); \
207+
m.def("qsim_sample_final", &qsim_sample_final, \
208+
"Call the qsim final-state sampler"); \
203209
m.def("qtrajectory_sample", &qtrajectory_sample, \
204210
"Call the qtrajectory sampler"); \
211+
m.def("qtrajectory_sample_final", &qtrajectory_sample_final, \
212+
"Call the qtrajectory final-state sampler"); \
205213
\
206214
using GateCirq = qsim::Cirq::GateCirq<float>; \
207215
using OpString = qsim::OpString<GateCirq>; \
@@ -400,8 +408,12 @@ std::vector<std::complex<float>> qsimh_simulate(const py::dict &options);
400408
\
401409
/* Methods for returning samples */ \
402410
m.def("qsim_sample", &qsim_sample, "Call the qsim sampler"); \
411+
m.def("qsim_sample_final", &qsim_sample_final, \
412+
"Call the qsim final-state sampler"); \
403413
m.def("qtrajectory_sample", &qtrajectory_sample, \
404414
"Call the qtrajectory sampler"); \
415+
m.def("qtrajectory_sample_final", &qtrajectory_sample_final, \
416+
"Call the qtrajectory final-state sampler"); \
405417
\
406418
using GateCirq = qsim::Cirq::GateCirq<float>; \
407419
using OpString = qsim::OpString<GateCirq>; \

qsimcirq/qsim_simulator.py

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -349,19 +349,7 @@ def _sample_measure_results(
349349
)
350350

351351
noisy = _needs_trajectories(program)
352-
if noisy:
353-
translator_fn_name = "translate_cirq_to_qtrajectory"
354-
sampler_fn = self._sim_module.qtrajectory_sample
355-
else:
356-
translator_fn_name = "translate_cirq_to_qsim"
357-
sampler_fn = self._sim_module.qsim_sample
358-
359-
if (
360-
not noisy
361-
and program.are_all_measurements_terminal()
362-
and repetitions > 1
363-
and num_qubits <= 32 # max length of ndarray.shape
364-
):
352+
if not noisy and program.are_all_measurements_terminal() and repetitions > 1:
365353
# Measurements must be replaced with identity gates to sample properly.
366354
# Simply removing them may omit qubits from the circuit.
367355
for i in range(len(program.moments)):
@@ -378,12 +366,12 @@ def _sample_measure_results(
378366
cirq.QubitOrder.DEFAULT,
379367
)
380368
options["s"] = self.get_seed()
381-
final_state = self._sim_module.qsim_simulate_fullstate(options, 0)
382-
full_results = cirq.sample_state_vector(
383-
final_state.view(np.complex64),
384-
range(num_qubits),
385-
repetitions=repetitions,
386-
seed=self._prng,
369+
raw_results = self._sim_module.qsim_sample_final(options, repetitions)
370+
full_results = np.array(
371+
[
372+
[bool(result & (1 << q)) for q in reversed(range(num_qubits))]
373+
for result in raw_results
374+
]
387375
)
388376

389377
for key, op in meas_ops.items():
@@ -393,6 +381,13 @@ def _sample_measure_results(
393381
results[key] = full_results[:, meas_indices] ^ invert_mask
394382

395383
else:
384+
if noisy:
385+
translator_fn_name = "translate_cirq_to_qtrajectory"
386+
sampler_fn = self._sim_module.qtrajectory_sample
387+
else:
388+
translator_fn_name = "translate_cirq_to_qsim"
389+
sampler_fn = self._sim_module.qsim_sample
390+
396391
options["c"], _ = self._translate_circuit(
397392
program,
398393
translator_fn_name,

0 commit comments

Comments
 (0)