cuda-quantum icon indicating copy to clipboard operation
cuda-quantum copied to clipboard

Inconsistent qubit order for `cudaq.get_state(...)`

Open OliverAh opened this issue 11 months ago • 0 comments

For inspecting a state obtained via state = cudaq.get_state(...), there are basically 3 options.

  1. print(state)
  2. print(state[i])
  3. print(state.amplitude(bit_string))

Given the ususal cudaq-convention of using big-endian bitstrings, the previous option 2 provides a contradicting result as I guess it uses a little-endian ordering of the states. (example big-endian bit string: |q_0 q_1> --> 'q_0 q_1')

In option 2 the bitstring needs to be converted to a single integer index. Following big-endian convention I would expect this to be done via (example 2 qubit case):

  • q_0*2^0 + q_1*2^1 --> index
  • 00 --> 0
  • 10 --> 1
  • 01 --> 2
  • 11 --> 3

Options 1 and 3 seem to stick to this definition, however option 2 does not. In my opinion especially the mismatch between option 1 and 2 are confusing, and I suggest sticking to big-endian throughout.

MWE:

import cudaq

@cudaq.kernel
def kernel():
    q = cudaq.qvector(2)
    x(q[0])


samples = cudaq.sample(kernel, shots_count=1000)
print('samples:', samples)
state = cudaq.get_state(kernel)
print('state:', state)
print('i', '| bs_le:', '| bs_be:', '| state[i]:', '| state.amplitude(bs_be):')
for i in range(2**2):
    bit_string_little_endian = format(i, '0' + str(2) + 'b')
    bit_string_big_endian = bit_string_little_endian[::-1]
    print(i,                        ' ',
          bit_string_little_endian, '     ',
          bit_string_big_endian,    '     ',
          state[i],                 '         ',
          state.amplitude(bit_string_big_endian))

Produces:

samples: { 10:1000 }

state: SV: [(0,0), (1,0), (0,0), (0,0)]    <-- big-endian bit order as second entry of SV holds non-zero amplitude

i | bs_le: | bs_be: | state[i]: | state.amplitude(bs_be):
0   00       00       0j           0j
1   01       10       0j           (1+0j)
2   10       01       (1+0j)           0j    <-- little-endian bit order as only third entry of state (`state[2]`) holds non-zero amplitude
3   11       11       0j           0j

While I expected:

samples: { 10:1000 }

state: SV: [(0,0), (1,0), (0,0), (0,0)]

i | bs_le: | bs_be: | state[i]: | state.amplitude(bs_be):
0   00       00       0j           0j
1   01       10       (1+0j)            (1+0j)    <-- big-endian bit order also for state[i]
2   10       01       0j          0j
3   11       11       0j           0j

Related issues:

  • #978
  • #1107

Environment

  • CUDA-Q Version 0.9.0
  • Python Version 3.11.11
  • C++ compiler: x86_64-conda-linux-gnu-c++ (installed via micromamba following quick start guide)
  • Operating System: Ubuntu 24.04.1 LTS

OliverAh avatar Mar 11 '25 13:03 OliverAh