Skip to content

[BUG] default.clifford ignores shot-vector partitions and returns malformed QNode results #9671

Description

@YujinSong-hep

Expected behavior

When a QNode is configured with a shot vector such as qml.set_shots([10, 20]), its result
should preserve one independent result for each shot quantity.

The qml.set_shots documentation explicitly demonstrates this behavior:

new_circ = qml.set_shots(circuit_sample, shots=(4, 10))
result = new_circ()
a, b = result

a.shape  # (4,)
b.shape  # (10,)

In addition, default.clifford declares that its shots argument accepts Sequence[int].
Therefore, for [10, 20]:

  • qml.counts should return two dictionaries whose counts sum to 10 and 20;
  • qml.sample should return two arrays containing 10 and 20 samples;
  • qml.expval should return two independently estimated scalar values.

Actual behavior

On default.clifford, the shot partitions are not preserved:

  • qml.counts returns a tuple of outcome labels instead of two count dictionaries;
  • qml.sample returns one flattened tuple containing 30 samples;
  • qml.expval raises TypeError: 'numpy.float64' object is not iterable.

The same QNodes return correctly partitioned results on default.qubit.

Example output:

default.qubit
counts:  ({'0': 3, '1': 7}, {'0': 8, '1': 12})
sample shapes: ((10, 1), (20, 1))
expval:  (-0.2, 0.2)

default.clifford
counts:  ('0', '1')
sample length: 30
expval:  TypeError: 'numpy.float64' object is not iterable

The numerical values vary because these are finite-shot measurements, but their result structures
consistently differ as shown above.

Additional information

qml.set_shots correctly constructs and passes the partitioned shot configuration:

Shots([10, 20]).shot_vector
# (ShotCopies(10 shots x 1), ShotCopies(20 shots x 1))

The issue appears to be in DefaultClifford.measure_statistical. It uses only the total number of
shots:

num_shots = circuit.shots.total_shots

For Shots([10, 20]), this produces num_shots == 30. The implementation then performs a single
30-shot measurement and does not reconstruct separate results for the two shot-vector entries.

By comparison, other simulation paths explicitly check circuit.shots.has_partitioned_shots,
execute each shot partition separately, and return a tuple containing one result per partition.

Source code

import pennylane as qml


dev = qml.device("default.clifford", wires=1)


@qml.set_shots([10, 20])
@qml.qnode(dev)
def counts_circuit():
    qml.Hadamard(0)
    return qml.counts(wires=[0])


@qml.set_shots([10, 20])
@qml.qnode(dev)
def sample_circuit():
    qml.Hadamard(0)
    return qml.sample(wires=[0])


@qml.set_shots([10, 20])
@qml.qnode(dev)
def expval_circuit():
    qml.Hadamard(0)
    return qml.expval(qml.Z(0))


print(counts_circuit())
print(sample_circuit())
print(expval_circuit())

Tracebacks

TypeError: 'numpy.float64' object is not iterable

System information

Version: 0.45.0
Platform info: macOS
Python version: 3.13.13

Existing GitHub issues

  • I have searched existing GitHub issues to make sure the issue does not already exist.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug 🐛Something isn't workingcommunity-botIssue suspected to be found by a bot

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions