Calculating Probabilities for Specific Basis States in CuQuantum when Ancilla Qubits are Present in Qiskit To Einsum Conversion. "

I am using the Function CircuitToEinsum to convert my Qiskit circuit to a Tensor. The circuit is a variational one with ancilla qubits, also known as auxiliary qubits. When using the Qiskit qasm_simulator to obtain results, it provides probabilities for all possible basis states, excluding the ancilla qubits. For instance, in the attached image, there are 12 total qubits, but only 8 are system qubits. Consequently, I obtain probabilities for 256 possible basis states, which is what I aim to implement in CuQuantum. I use the function myconverter.amplitudes(bitstring) to find the respective probabilities for these basis states.

However, I encountered an issue when attempting to calculate probabilities for only the 8-qubit basis states. The error message states: âValueError: bitstring must be of the same length as the number of qubits (12)â. My objective is to calculate probabilities for the specific 8-qubit basis states corresponding to the original circuit.

In the provided code snippet, I am generating all 2^12 basis states, which works fine. My question is: How can I modify this to generate and calculate probabilities for only the 8-qubit basis states, as shown in the first image (2^8 = 256 states)?

circuit.measure([self.ancilla_size + _ for _ in range(self.n_qubits)],
[_ for _ in range(self.n_qubits)])

myconverter = CircuitToEinsum(circuit, dtype='complex128', backend=cp)
bitstrings = self.generate_bit_strings(self.tot_qubits)
x = list()
for btstr in bitstrings:
expression, operands = myconverter.amplitude(btstr)
amplitude = contract(expression, *operands)
probability = abs(amplitude) ** 2
print(probability)
'''
Recreation of x by binning the eigen values.
'''
old_keys = [self.convert_bin(_, self.n_qubits)
for _ in range(2**self.n_qubits)]


Hello,

Letâs start with a simpler example assuming 3 physical qubits followed by 2 ancilla qubits:

For the probability of the first 3 physical qubits, youâre looking at:
prob_physical[â000â] = \sum_{x,y=0,1} prob_all_qubits[â000xyâ] = \sum_{x,y} | amp_all_qubits[â000xyâ] | ** 2
Where x, y denotes the state of the ancilla qubits. This means youâll need to iterate over all possible ancilla qubit states and perform an absolute squared sums on the amplitudes (bitstring of size 5) to compute the total probability for a particular bitstring of the physical qubits (size 3).

In certain cases the computation can be easier. For instance, if you know that all your ancillas will collaps into a single state, e.g, |11>, meaning amp_all_qubits[âabcxyâ] will be zero unless xy = 11, then all prob_physical[âabcâ] is going to be equal to prob_all_qubits[âabc11â] and then you donât need to iterate over other xy state.

BTW, are you computing the probability of all bitstrings? If so, is there a reason why you didnât want to use the âCircuitToEinsum.state_vectorâ method which gives the amplitudes of all bitstrings? You may also take advantage of the âCircuitToEinsum.batched_amplitudesâ method to slice over the ancilla qubits if you donât want to store the SV for all the 12 qubits amplitudes. I would encourage you to check out our sample notebook for these features if you havenât already.

Hello, thank you for your swift response!

In my scenario, I am dealing with ancillary qubits followed by system qubits (i.e. ancilla is placed at the top or starting of the circuit and then system qubits). To clarify, I am attempting to calculate the probability of the bit strings for all system qubits, excluding the ancillary ones. For instance, the list provided represents the desired basis states for which I want to calculate the probabilities. Itâs worth noting that my code is designed to be generalized, accommodating cases where the total qubits may vary, such as having 9 qubits with 4 ancilla and 5 system qubits.

As a follow-up question, the state_vector() function currently returns the state vector for all 12 qubits in the circuit. However, my expectation is to obtain the state vector specifically for the system qubits. This will allow me to calculate the probabilities of all basis states for the system qubits, as illustrated in the code snippet provided.

system qubits:  8
ancilla qubits:  4
total qubits: 12

['00000000', '10000000', '01000000', '11000000', '00100000', '10100000', '01100000', '11100000', '00010000', '10010000', '01010000', '11010000', '00110000', '10110000', '01110000', '11110000', '00001000', '10001000', '01001000', '11001000', '00101000', '10101000', '01101000', '11101000', '00011000', '10011000', '01011000', '11011000', '00111000', '10111000', '01111000', '11111000', '00000100', '10000100', '01000100', '11000100', '00100100', '10100100', '01100100', '11100100', '00010100', '10010100', '01010100', '11010100', '00110100', '10110100', '01110100', '11110100', '00001100', '10001100', '01001100', '11001100', '00101100', '10101100', '01101100', '11101100', '00011100', '10011100', '01011100', '11011100', '00111100', '10111100', '01111100', '11111100', '00000010', '10000010', '01000010', '11000010', '00100010', '10100010', '01100010', '11100010', '00010010', '10010010', '01010010', '11010010', '00110010', '10110010', '01110010', '11110010', '00001010', '10001010', '01001010', '11001010', '00101010', '10101010', '01101010', '11101010', '00011010', '10011010', '01011010', '11011010', '00111010', '10111010', '01111010', '11111010', '00000110', '10000110', '01000110', '11000110', '00100110', '10100110', '01100110', '11100110', '00010110', '10010110', '01010110', '11010110', '00110110', '10110110', '01110110', '11110110', '00001110', '10001110', '01001110', '11001110', '00101110', '10101110', '01101110', '11101110', '00011110', '10011110', '01011110', '11011110', '00111110', '10111110', '01111110', '11111110', '00000001', '10000001', '01000001', '11000001', '00100001', '10100001', '01100001', '11100001', '00010001', '10010001', '01010001', '11010001', '00110001', '10110001', '01110001', '11110001', '00001001', '10001001', '01001001', '11001001', '00101001', '10101001', '01101001', '11101001', '00011001', '10011001', '01011001', '11011001', '00111001', '10111001', '01111001', '11111001', '00000101', '10000101', '01000101', '11000101', '00100101', '10100101', '01100101', '11100101', '00010101', '10010101', '01010101', '11010101', '00110101', '10110101', '01110101', '11110101', '00001101', '10001101', '01001101', '11001101', '00101101', '10101101', '01101101', '11101101', '00011101', '10011101', '01011101', '11011101', '00111101', '10111101', '01111101', '11111101', '00000011', '10000011', '01000011', '11000011', '00100011', '10100011', '01100011', '11100011', '00010011', '10010011', '01010011', '11010011', '00110011', '10110011', '01110011', '11110011', '00001011', '10001011', '01001011', '11001011', '00101011', '10101011', '01101011', '11101011', '00011011', '10011011', '01011011', '11011011', '00111011', '10111011', '01111011', '11111011', '00000111', '10000111', '01000111', '11000111', '00100111', '10100111', '01100111', '11100111', '00010111', '10010111', '01010111', '11010111', '00110111', '10110111', '01110111', '11110111', '00001111', '10001111', '01001111', '11001111', '00101111', '10101111', '01101111', '11101111', '00011111', '10011111', '01011111', '11011111', '00111111', '10111111', '01111111', '11111111']


In this case I would encourage you to try the CircuitToEinsum.batched_amplitudes method which can compute the probability of all system qubits with ancillas at certain fixed state (Then sum over all ancilla state). Iâm attaching a code snippet below to show the two approaches for computing all probs, one using CircuitToEinsum.amplitude method and the other using CircuitToEinsum.batched_amplitudes method.

Note that the snippet is assuming 6 qubits in total with the first 2 being ancilla and the last 4 being system qubits. It can be extended to any system configuration and order.


from qiskit.circuit.random import random_circuit
from cuquantum import CircuitToEinsum, contract

num_qubits = 6
depth = 4
# create a random circuit
circuit = random_circuit(num_qubits, depth, seed=0)
converter = CircuitToEinsum(circuit)

# assuming first 2 qubits being ancilla and last 4 being system qubits
ancilla_qubits = converter.qubits[:2]
system_qubits = converter.qubits[2:]
num_ancilla_qubits = len(ancilla_qubits)
num_system_qubits = num_qubits - num_ancilla_qubits

# format specifier for bitstring manipulation
system_specifier = f"0{num_system_qubits}b"
ancilla_specifier = f"0{num_ancilla_qubits}b"

print("With CircuitToEinsum.amplitude")
for system_bitstring in range(2**num_system_qubits):
# iterate over all system qubits
system_bitstring = format(system_bitstring, system_specifier)
prob = 0
for ancilla_state in range(2**num_ancilla_qubits):
# iterate over all ancilla state
ancilla_state = format(ancilla_state, ancilla_specifier)
# Construct the full bistring including both ancilla and system qubits.
# Note this must be consistent with the orders of ancilla and system qubits
full_bitstring = ancilla_state + system_bitstring
expr, operands = converter.amplitude(full_bitstring)
amp = contract(expr, *operands)
prob += abs(amp) ** 2
print(f"prob for system bitstring {system_bitstring}: {prob}")

print("With CircuitToEinsum.batched_amplitudes")
full_prob = 0
for ancilla_state in range(2**num_ancilla_qubits):
# iterate over all ancilla state
ancilla_state = format(ancilla_state, ancilla_specifier)
fixed = dict(zip(ancilla_qubits, ancilla_state))
expr, operands = converter.batched_amplitudes(fixed)
# compute the batched amplitudes for system qubits with ancillas at fixed state
batched_amp = contract(expr, *operands)
full_prob += abs(batched_amp) ** 2
print(f"full prob shape {full_prob.shape}")

for system_bitstring in range(2**num_system_qubits):
system_bitstring = format(system_bitstring, system_specifier)
system_index = tuple(int(i) for i in system_bitstring)
print(f"prob for system bitstring {system_bitstring}: {full_prob[system_index]}")



Let me know if this solves your question.

1 Like

Thanks You, This is more helpful!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.