-
Notifications
You must be signed in to change notification settings - Fork 50
Fix dynamic wires with samples #1321
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
base: master
Are you sure you want to change the base?
Changes from 37 commits
e5cc327
769aae4
7b5bdd0
22d3c17
e7d82a2
79451be
7078d0e
ddfdb53
9d19fa9
7ae4e5e
b3e806f
d365d2d
6771882
0e11617
635370d
aa98ec9
a8367bd
6e9f177
5bac5ae
54a87e1
14a351e
e0033de
90d9300
bf6ff01
203a53b
1ed47be
81c4859
6eb8caa
a5e2132
43a1b6a
9fc0cc0
abd373d
60511a8
128dfff
57b3a61
0ec104f
fcc5229
2b784c7
0f53498
6c8cdb2
5689741
e0bc81f
c99af27
eebcc7f
1edd945
214128b
11b7a5b
61f6fa1
c3c8daf
8aae477
854b0a4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,4 +16,4 @@ | |
| Version number (major.minor.patch[-label]) | ||
| """ | ||
|
|
||
| __version__ = "0.44.0-dev26" | ||
| __version__ = "0.44.0-rc3" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,7 @@ | |
| #include <unordered_set> | ||
|
|
||
| #include "LightningGPUSimulator.hpp" | ||
| #include "Util.hpp" | ||
|
|
||
| namespace Catalyst::Runtime::Simulator { | ||
|
|
||
|
|
@@ -82,9 +83,14 @@ auto LightningGPUSimulator::AllocateQubits(std::size_t num_qubits) | |
| } | ||
|
|
||
| void LightningGPUSimulator::ReleaseQubit(QubitIdType q) { | ||
| // We do not deallocate physical memory in the statevector for this | ||
| // operation, instead we just mark the qubits as released. | ||
| RT_FAIL_IF(!this->qubit_manager.isValidQubitId(q), | ||
| "Invalid qubit to release"); | ||
|
|
||
| // Mark the qubit as released in the qubit manager | ||
| this->qubit_manager.Release(q); | ||
|
|
||
| // Mark that compaction is needed | ||
| this->needs_compaction = true; | ||
| } | ||
|
|
||
| void LightningGPUSimulator::ReleaseQubits(const std::vector<QubitIdType> &ids) { | ||
|
|
@@ -101,19 +107,95 @@ void LightningGPUSimulator::ReleaseQubits(const std::vector<QubitIdType> &ids) { | |
| if (deallocate_all) { | ||
| this->qubit_manager.ReleaseAll(); | ||
| this->device_sv = std::make_unique<StateVectorT>(0); | ||
| this->needs_compaction = false; | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| for (auto id : ids) { | ||
| this->qubit_manager.Release(id); | ||
| this->ReleaseQubit(id); | ||
| } | ||
| } | ||
|
|
||
| auto LightningGPUSimulator::GetNumQubits() const -> std::size_t { | ||
| return this->qubit_manager.getNumQubits(); | ||
| } | ||
|
|
||
| auto LightningGPUSimulator::getMeasurements() | ||
| -> Pennylane::LightningGPU::Measures::Measurements<StateVectorT> { | ||
| CompactStateVector(); | ||
| return Pennylane::LightningGPU::Measures::Measurements<StateVectorT>{ | ||
| *(this->device_sv)}; | ||
| } | ||
|
|
||
| void LightningGPUSimulator::CompactStateVector() { | ||
|
||
| if (!this->needs_compaction) { | ||
| return; | ||
| } | ||
|
|
||
| // Get active qubits | ||
| auto all_qubits = this->qubit_manager.getAllQubitIds(); | ||
| std::vector<std::pair<size_t, QubitIdType>> wire_id_pairs; | ||
|
|
||
| for (auto qid : all_qubits) { | ||
| size_t device_wire = this->qubit_manager.getDeviceId(qid); | ||
| wire_id_pairs.push_back({device_wire, qid}); | ||
| } | ||
|
|
||
| // Sort by device wire index | ||
| std::sort(wire_id_pairs.begin(), wire_id_pairs.end()); | ||
|
|
||
| // Extract compacted state vector - need to copy from GPU first | ||
| auto old_data = this->device_sv->getDataVector(); | ||
| size_t num_qubits_after = wire_id_pairs.size(); | ||
| size_t new_size = 1UL << num_qubits_after; | ||
|
|
||
| std::vector<std::complex<double>> new_data(new_size); | ||
|
|
||
| // state[idx] = |q0 q1 ... q_{n-1}> | ||
| // where q_i = (idx >> (n-1-i)) & 1 | ||
| // So device wire 0 corresponds to the MSB (bit n-1) | ||
| size_t old_num_qubits = this->device_sv->getNumQubits(); | ||
|
|
||
| for (size_t old_idx = 0; old_idx < old_data.size(); old_idx++) { | ||
| size_t new_idx = 0; | ||
| for (size_t i = 0; i < num_qubits_after; i++) { | ||
| size_t old_wire = wire_id_pairs[i].first; | ||
| size_t old_bit_pos = old_num_qubits - 1 - old_wire; | ||
| size_t new_bit_pos = num_qubits_after - 1 - i; | ||
|
|
||
| if ((old_idx >> old_bit_pos) & 1) { | ||
| new_idx |= (1UL << new_bit_pos); | ||
| } | ||
| } | ||
|
|
||
| new_data[new_idx] += old_data[old_idx]; | ||
| } | ||
|
|
||
| // Normalize the state vector | ||
| Pennylane::Util::normalizeStateVector(new_data); | ||
|
|
||
| // Replace the state vector | ||
| this->device_sv = | ||
| std::make_unique<StateVectorT>(new_data.data(), new_data.size()); | ||
|
|
||
| // Remap device ids | ||
| std::unordered_map<size_t, size_t> old_to_new_device_id; | ||
| for (size_t new_idx = 0; new_idx < wire_id_pairs.size(); new_idx++) { | ||
| size_t old_device_id = wire_id_pairs[new_idx].first; | ||
| size_t new_device_id = new_idx; | ||
| if (old_device_id != new_device_id) { | ||
| old_to_new_device_id[old_device_id] = new_device_id; | ||
| } | ||
| } | ||
|
|
||
| if (!old_to_new_device_id.empty()) { | ||
| this->qubit_manager.RemapDeviceIds(old_to_new_device_id); | ||
| } | ||
|
|
||
| this->needs_compaction = false; | ||
| } | ||
|
|
||
| void LightningGPUSimulator::StartTapeRecording() { | ||
| RT_FAIL_IF(this->tape_recording, "Cannot re-activate the cache manager"); | ||
| this->tape_recording = true; | ||
|
|
@@ -264,9 +346,7 @@ auto LightningGPUSimulator::Expval(ObsIdType obsKey) -> double { | |
|
|
||
| auto &&obs = this->obs_manager.getObservable(obsKey); | ||
|
|
||
| Pennylane::LightningGPU::Measures::Measurements<StateVectorT> m{ | ||
| *(this->device_sv)}; | ||
|
|
||
| auto m = getMeasurements(); | ||
| m.setSeed(this->generateSeed()); | ||
|
|
||
| return device_shots ? m.expval(*obs, device_shots, {}) : m.expval(*obs); | ||
|
|
@@ -283,9 +363,7 @@ auto LightningGPUSimulator::Var(ObsIdType obsKey) -> double { | |
|
|
||
| auto &&obs = this->obs_manager.getObservable(obsKey); | ||
|
|
||
| Pennylane::LightningGPU::Measures::Measurements<StateVectorT> m{ | ||
| *(this->device_sv)}; | ||
|
|
||
| auto m = getMeasurements(); | ||
| m.setSeed(this->generateSeed()); | ||
|
|
||
| return device_shots ? m.var(*obs, device_shots) : m.var(*obs); | ||
|
|
@@ -307,9 +385,7 @@ void LightningGPUSimulator::State(DataView<std::complex<double>, 1> &state) { | |
| } | ||
|
|
||
| void LightningGPUSimulator::Probs(DataView<double, 1> &probs) { | ||
| Pennylane::LightningGPU::Measures::Measurements<StateVectorT> m{ | ||
| *(this->device_sv)}; | ||
|
|
||
| auto m = getMeasurements(); | ||
| m.setSeed(this->generateSeed()); | ||
|
|
||
| auto &&dv_probs = device_shots ? m.probs(device_shots) : m.probs(); | ||
|
|
@@ -328,12 +404,11 @@ void LightningGPUSimulator::PartialProbs( | |
| RT_FAIL_IF(numWires > numQubits, "Invalid number of wires"); | ||
| RT_FAIL_IF(!isValidQubits(wires), "Invalid given wires to measure"); | ||
|
|
||
| auto dev_wires = getDeviceWires(wires); | ||
| Pennylane::LightningGPU::Measures::Measurements<StateVectorT> m{ | ||
| *(this->device_sv)}; | ||
|
|
||
| auto m = getMeasurements(); | ||
| m.setSeed(this->generateSeed()); | ||
|
|
||
| auto dev_wires = getDeviceWires(wires); | ||
|
|
||
| auto &&dv_probs = | ||
| device_shots ? m.probs(dev_wires, device_shots) : m.probs(dev_wires); | ||
|
|
||
|
|
@@ -344,10 +419,7 @@ void LightningGPUSimulator::PartialProbs( | |
| } | ||
|
|
||
| std::vector<size_t> LightningGPUSimulator::GenerateSamples(size_t shots) { | ||
| // generate_samples is a member function of the Measures class. | ||
| Pennylane::LightningGPU::Measures::Measurements<StateVectorT> m{ | ||
| *(this->device_sv)}; | ||
|
|
||
| auto m = getMeasurements(); | ||
| m.setSeed(this->generateSeed()); | ||
|
|
||
| return m.generate_samples(shots); | ||
|
|
@@ -383,11 +455,11 @@ void LightningGPUSimulator::PartialSample( | |
| RT_FAIL_IF(samples.size() != device_shots * numWires, | ||
| "Invalid size for the pre-allocated partial-samples"); | ||
|
|
||
| // get device wires | ||
| auto &&dev_wires = getDeviceWires(wires); | ||
|
|
||
| auto li_samples = this->GenerateSamples(device_shots); | ||
|
|
||
| // Get device wires | ||
| auto &&dev_wires = getDeviceWires(wires); | ||
|
|
||
| // The lightning samples are layed out as a single vector of size | ||
| // shots*qubits, where each element represents a single bit. The | ||
| // corresponding shape is (shots, qubits). Gather the desired bits | ||
|
|
@@ -444,11 +516,11 @@ void LightningGPUSimulator::PartialCounts( | |
| RT_FAIL_IF((eigvals.size() != numElements || counts.size() != numElements), | ||
| "Invalid size for the pre-allocated partial-counts"); | ||
|
|
||
| // get device wires | ||
| auto &&dev_wires = getDeviceWires(wires); | ||
|
|
||
| auto li_samples = this->GenerateSamples(device_shots); | ||
|
|
||
| // Get device wires | ||
| auto &&dev_wires = getDeviceWires(wires); | ||
|
|
||
| // Fill the eigenvalues with the integer representation of the | ||
| // corresponding computational basis bitstring. In the future, | ||
| // eigenvalues can also be obtained from an observable, hence the | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.