Skip to content

Conversation

@rniczh
Copy link

@rniczh rniczh commented Jan 6, 2026

Context:

from catalyst import *
import pennylane as qml

qml.capture.enable()

@qjit
@qml.qnode(qml.device("lightning.qubit", wires=3, shots=10))
def circuit():
    with qml.allocate(2) as qs:
        qml.X(qs[1])

    return qml.sample(wires=[0, 1])

print(circuit())

It get unexpected result due to the aux wires involved.

[[0 0]
 [0 1]
 [0 0]
 [1 0]
 [0 0]
 [0 0]
 [0 1]
 [0 0]
 [1 0]
 [0 0]]

Description of the Change:

Only take the device wires for generating samples
Compact state vector before measurement.

For state vector normalization:

$|\psi| = \sqrt{\sum_i |\psi_i|^2}$
$normalized_i = \psi_i / |\psi|$

Benefits:

Possible Drawbacks:

Related GitHub Issues:

PennyLaneAI/catalyst#2339
[[sc-107206]]

@github-actions
Copy link
Contributor

github-actions bot commented Jan 6, 2026

Hello. You may have forgotten to update the changelog!
Please edit .github/CHANGELOG.md with:

  • A one-to-two sentence description of the change. You may include a small working example for new features.
  • A link back to this PR.
  • Your name (or GitHub username) in the contributors section.

@blacksmith-sh

This comment has been minimized.

Copy link
Contributor

@dime10 dime10 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @rniczh !

const std::vector<std::size_t> &wires, const std::string &kernelname,
std::size_t num_burnin, std::size_t num_samples) {
std::uniform_real_distribution<PrecisionT> distrib(0.0, 1.0);
std::size_t num_qubits = wires.size();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we know that this is sufficient to identify which wires should be selected in a more complex dynamic (de)allocation scheme, or does it rely on the assumption that the selected wires are always the bottom n wires?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mentioned this offline but I think we'd be better off providing a universal solution that we never got around to implementing (see #1254 (comment)).

Copy link
Author

@rniczh rniczh Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the PR, basically removed the original solution that only pass the device_wires to GenerateSample. Now, it will compact the state vector before the measurement process to ensure the erased qubits are erased from state vector as well.
ca0ff43 Edit: 77fbbe9

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow that was fast! 🤩
@maliasadi are you able to look this over?

@blacksmith-sh

This comment has been minimized.

@codecov
Copy link

codecov bot commented Jan 7, 2026

Codecov Report

❌ Patch coverage is 82.55814% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.22%. Comparing base (e7d82a2) to head (5bac5ae).

Files with missing lines Patch % Lines
..._lightning/core/catalyst/LightningQubitManager.hpp 0.00% 12 Missing ⚠️
...rs/lightning_qubit/catalyst/LightningSimulator.cpp 94.82% 3 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (e7d82a2) and HEAD (5bac5ae). Click for more details.

HEAD has 6 uploads less than BASE
Flag BASE (e7d82a2) HEAD (5bac5ae)
unit_tests 13 7
Additional details and impacted files
@@              Coverage Diff               @@
##           v0.44.0_rc    #1321      +/-   ##
==============================================
- Coverage       96.01%   89.22%   -6.80%     
==============================================
  Files             307      187     -120     
  Lines           46923    29012   -17911     
==============================================
- Hits            45055    25886   -19169     
- Misses           1868     3126    +1258     
Flag Coverage Δ
unit_tests 89.22% <82.55%> (-6.80%) ⬇️

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@blacksmith-sh

This comment has been minimized.

@maliasadi maliasadi self-requested a review January 8, 2026 15:06
Copy link
Member

@maliasadi maliasadi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @rniczh! A few things:

  • If we need this to go out with the release, you will need to rebase it against #1317 and sync ASAP with @jzaia18
  • Update Lighnting-Kokkos and Lightning-GPU catalyst impl similar to Lightning-Qubit
  • Please add a changelog entry for this fix

@rniczh rniczh changed the base branch from master to v0.44.0_rc January 8, 2026 15:19
@jzaia18 jzaia18 added this to the 0.44.0 milestone Jan 8, 2026
@rniczh rniczh force-pushed the rniczh/fix-dynamic-wires-with-samples branch from d3abf70 to 6e9f177 Compare January 8, 2026 15:32
@rniczh rniczh changed the base branch from v0.44.0_rc to master January 8, 2026 15:37
@rniczh rniczh changed the base branch from master to v0.44.0_rc January 8, 2026 15:37
Copy link
Contributor

@jzaia18 jzaia18 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work Hongsheng! Just a few questions and comments. Is there any reason we're implementing this for lightning.qubit but not the other devices? Does this issue exist for the others as well? nvm, just saw Ali already addressed this

Comment on lines -420 to +505
// get device wires
auto &&dev_wires = getDeviceWires(wires);

auto li_samples = this->GenerateSamples(device_shots);

// Get device wires
auto &&dev_wires = getDeviceWires(wires);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for switching the order of these steps?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's because the getMeasurements() is within the GenerateSamples. The getMeasurements() will compact the state vector to get the measurement object, that means if the getDeviceWires happens before GenerateSamples may not get the correct device wires.

std::vector<size_t> LightningSimulator::GenerateSamples(size_t shots) {
    auto m = getMeasurements();
    // ... rest of code ...

Comment on lines +178 to +187
std::unordered_set<DeviceQubitID> new_free_qubits;
for (auto old_device_id : this->free_device_qubits) {
auto it = old_to_new_mapping.find(old_device_id);
if (it != old_to_new_mapping.end()) {
new_free_qubits.insert(it->second);
} else {
new_free_qubits.insert(old_device_id);
}
}
this->free_device_qubits = std::move(new_free_qubits);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How often do we expect this section to be run? Will it be expensive to create and free the free_device_qubits set each time this is run as we currently do?

Comment on lines +185 to +198
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];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This outer loop goes over the entire statevector, we probably want to use parallelism to prevent this from being a very expensive operation. Unsure if it's worth doing here or fixing in a follow-up PR. @maliasadi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants