Skip to content

random_clifford function distribution is not uniform #13855

Open
@Connorpl

Description

Environment

qiskit 1.3.1
python 3.13.1
Ubuntu 20.04.6

What is happening?

The distribution of Cliffords produced by the quantum_info.random_clifford() function is not uniform

How can we reproduce the issue?

import numpy as np
from scipy.stats import chisquare
import stim  ###required to canonicalise tableaus

#Count number of n qubit stabilizers
num_qubits_stab_test=2
iter_count_stabstate = [(2**(num_qubits_stab_test-k)) + 1 for k in range(0,num_qubits_stab_test)]
print("num_stabilizers = ",(2**num_qubits_stab_test)*np.prod(iter_count_stabstate))


#generate 10000 random cliffords, use stim to reduce to a unique canonical form for each stabilizer state and store each unique clifford tableau found on produced_cliffs
produced_cliffs = []
for n in range(10000):
    rand_cliff = random_clifford(num_qubits_stab_test)
    reduced_stab_matrix=[list(str(x).replace("_","I"))[1:] + [-1 if y=="-" else 1 for y in list(str(x))[0]]  for x in stim.Tableau.from_stabilizers([stim.PauliString(x) for x in  rand_cliff.to_labels(mode="S")]).to_stabilizers(canonicalize=True)]
    in_produced_cliffs = [np.array_equal(np.array(reduced_stab_matrix),x) for x in produced_cliffs]
    if True not in in_produced_cliffs:
        produced_cliffs.append(np.array(reduced_stab_matrix)) 
print(len(produced_cliffs))

#check we found all cliffords
assert(len(produced_cliffs) == (2**num_qubits_stab_test)*np.prod(iter_count_stabstate))  

#generate set of samples from random_clifford and reduce to canonical form with stim and store
all_produced_cliffs = []
for n in range(400000):
    rand_cliff = random_clifford(num_qubits_stab_test,seed=np.random.randint(1e12))
    reduced_stab_matrix=[list(str(x).replace("_","I"))[1:] + [-1 if y=="-" else 1 for y in list(str(x))[0]]  for x in stim.Tableau.from_stabilizers([stim.PauliString(x) for x in  rand_cliff.to_labels(mode="S")]).to_stabilizers(canonicalize=True)]
    all_produced_cliffs.append(np.array(reduced_stab_matrix))    


#count number of samples generated for each unique clifford, also split into two sets of samples for comparative bar plot
stab_counts= [0]*len(produced_cliffs)
stab_counts1= [0]*len(produced_cliffs)
stab_counts2= [0]*len(produced_cliffs)

for m in range(len(all_produced_cliffs)):
    for n in range(len(produced_cliffs)):
        if np.array_equal(produced_cliffs[n],all_produced_cliffs[m]):
            stab_counts[n]+=1

            ###split into two seperate sets of counts for comparison
            if m<len(all_produced_cliffs)//2:
                stab_counts1[n]+=1
            else:
                stab_counts2[n]+=1    
            
            break

print("counts of stabilizers produced: ",stab_counts) 

#perform chi square test for uniform randomness


# Example: Observed frequencies from a histogram (e.g., dice rolls)
observed_counts = stab_counts
# Expected frequencies assuming uniformity
expected_counts = np.array([(sum(observed_counts)/len(stab_counts))]*len(stab_counts))

# Perform chi-square test
chi_stat, p_value = chisquare(observed_counts, expected_counts)

# Print results
print(f"Chi-Square Statistic: {chi_stat:.8f}")
print(f"P-Value: {p_value:.8f}")

# Interpretation
alpha = 0.05  # Significance level
if p_value < alpha:
    print("Reject the null hypothesis: The data is NOT uniformly random.")
else:
    print("Fail to reject the null hypothesis: The data is consistent with uniform randomness.")
    

#optionally plot bar chart for independent set of samples
# import matplotlib.pyplot as plt
# X_axis = np.arange(len(stab_counts1)) 

# plt.bar(X_axis-0.2,stab_counts1,0.4,alpha=1.)
# plt.bar(X_axis+0.2,stab_counts2,0.4,alpha=1.)         ```

### What should happen?

The distribution produced should pass the chi-squared test for uniform randomness, for an example of expected behaviour the random Clifford generation can be performed with stim:  

``` rand_cliff = stim.Tableau.random(num_qubits_stab_test)
    reduced_stab_matrix=[list(str(x).replace("_","I"))[1:] + [-1 if y=="-" else 1 for y in list(str(x))[0]]  for x in rand_cliff.to_stabilizers(canonicalize=True)]

Any suggestions?

potentially related bug report: #13590

Activity

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

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions