advanced 00¶
import numpy as np
import collections
try:
import numqi
except ImportError:
%pip install numqi
import numqi
Optimal Pauli UD¶
In previous notebook, we shows how to certificate the unique determinedness of a Pauli measurement. In this notebook, we will show how to find the optimal Pauli UD.
TODO explain hyperparameter
seed = 233 #seed=233 can find the optimal UD for 3-qubit (size=31), you can try other seed
num_qubit = 3
num_repeat = {2:10, 3:10, 4:80, 5:80}[num_qubit]
num_init_sample = {2:0, 3:10, 4:80, 5:400}[num_qubit]
matrix_subspace = numqi.gate.get_pauli_group(num_qubit, use_sparse=True)
# index=0 is for the identity matrix
kwargs = {'num_repeat':num_repeat, 'num_init_sample':num_init_sample, 'indexF':[0], 'tag_print':True, 'seed':seed}
ud_pauli_index_list = numqi.unique_determine.find_optimal_UD('udp', num_round=2, mat_list=matrix_subspace, **kwargs)
# ud_pauli_index_list = numqi.unique_determine.load_pauli_ud_example(num_qubit) #load the UD stored in numqi package
print('founded UD optimal')
for ind0,pauli_index in enumerate(ud_pauli_index_list):
pauli_str = ' '.join([numqi.gate.pauli_index_to_str(x, num_qubit) for x in pauli_index])
print(f'[round-{ind0}][size={len(pauli_index)}]', pauli_str)
[0.3s/53/1] loss=2.00000 [0.4s/52/1] loss=2.00000
[0.5s/51/1] loss=2.00000 [0.7s/50/1] loss=2.00000
[0.8s/49/2] loss=2.00000 [0.9s/48/2] loss=2.00000
[1.1s/47/2] loss=2.00000 [1.2s/46/3] loss=2.00000
[1.5s/45/5] loss=2.00001
[1.7s/44/8] loss=2.00000 [1.8s/43/9] loss=2.00000
[2.1s/42/13] loss=2.00000 [2.2s/41/13] loss=2.00000
[2.4s/40/13] loss=2.00001 [2.5s/39/13] loss=2.00000
[2.7s/38/15] loss=2.00001
[3.0s/37/21] loss=2.00000 [3.1s/36/21] loss=2.00000
[3.3s/35/27] loss=2.00001 [3.4s/34/27] loss=2.00000
[3.5s/33/29] loss=2.00000 [3.6s/32/29] loss=2.00000 [3.7s/31/29] loss=2.00000
[4.3s/31/31] loss=2.00000 [31] [0, 3, 4, 11, 13, 14, 15, 16, 17, 18, 24, 25, 26, 29, 31, 32, 33, 38, 40, 41, 42, 44, 49, 50, 52, 56, 57, 58, 61, 62, 63]
[0.3s/53/1] loss=2.00000 [0.5s/52/1] loss=2.00000
[0.6s/51/1] loss=2.00000 [0.7s/50/2] loss=2.00000
[0.9s/49/2] loss=2.00000 [1.0s/48/2] loss=2.00000
[1.2s/47/3] loss=2.00000 [1.3s/46/3] loss=2.00000
[1.4s/45/3] loss=2.00000 [1.6s/44/3] loss=2.00000
[1.7s/43/5] loss=2.00000 [1.9s/42/5] loss=2.00000
[2.0s/41/8] loss=2.00000
[2.3s/40/20] loss=2.00000 [2.4s/39/20] loss=2.00000
[2.6s/38/22] loss=2.00000 [2.7s/37/22] loss=2.00000
[2.8s/36/24] loss=2.00000 [2.9s/35/27] loss=2.00000
[3.0s/34/27] loss=2.00000 [3.1s/33/29] loss=2.00000 [3.2s/32/30] loss=2.00000
[3.7s/32/32] loss=2.00000 [32] [0, 1, 4, 6, 7, 8, 10, 11, 12, 14, 15, 17, 22, 23, 24, 26, 27, 28, 30, 31, 32, 41, 45, 49, 54, 55, 56, 58, 59, 60, 62, 63] founded UD optimal [round-0][size=31] III IIZ IXI IYZ IZX IZY IZZ XII XIX XIY XYI XYX XYY XZX XZZ YII YIX YXY YYI YYX YYY YZI ZIX ZIY ZXI ZYI ZYX ZYY ZZX ZZY ZZZ [round-1][size=32] III IIX IXI IXY IXZ IYI IYY IYZ IZI IZY IZZ XIX XXY XXZ XYI XYY XYZ XZI XZY XZZ YII YYX YZX ZIX ZXY ZXZ ZYI ZYY ZYZ ZZI ZZY ZZZ
Numerically, we find that, for Pauli measurements, UDP implies UDA. As you can see above, we search for the optimal UDP Pauli measurements. Below, let's verify that the optimal UDP Pauli measurements are also UDA.
mat_list = [numqi.unique_determine.get_matrix_list_indexing(matrix_subspace, x) for x in ud_pauli_index_list]
is_uda_list = numqi.unique_determine.check_UD('uda', mat_list, num_repeat=num_repeat*5)
for ind0, (pauli_index, (tag, loss)) in enumerate(zip(ud_pauli_index_list, is_uda_list)):
print(f'[round-{ind0}][size={len(pauli_index)}] UDA={tag}, loss={loss:.5f}')
[round-0][size=31] UDA=True, loss=0.98117 [round-1][size=32] UDA=True, loss=1.00008
Clifford equivalence¶
Let $A$ be a UDA or UDP measurement scheme, then applying a unitary transform $A'=UAU^\dagger$ remains a UDA or UDP measurement scheme.
Clifford operators are unitary operators that map Pauli operators to Pauli operators. Therefore, we can apply a Clifford operator to a UD Pauli measurement to obtain another UD Pauli measurement.
num_qubit = 2
size = 11
ud_pauli_index = numqi.unique_determine.load_pauli_ud_example(num_qubit, tag_group_by_size=True)[size][0]
equivalent_list = numqi.gate.get_pauli_subset_equivalent(ud_pauli_index, num_qubit)
ud_pauli_str = ' '.join(numqi.gate.pauli_index_to_str(np.array(ud_pauli_index), num_qubit))
equivalent_str_list = [' '.join(numqi.gate.pauli_index_to_str(np.array(x), num_qubit)) for x in equivalent_list]
print(f'UD: {ud_pauli_str}')
for ind0, x in enumerate(equivalent_str_list):
print(f'equivalent-{ind0}: {x}')
UD: II IX IY IZ XI YX YY YZ ZX ZY ZZ equivalent-0: II IZ XI XX XY YI YX YY ZI ZX ZY equivalent-1: II IX XI XY XZ YI YY YZ ZI ZY ZZ equivalent-2: II IY XI XX XZ YI YX YZ ZI ZX ZZ equivalent-3: II IX IY IZ XX XY XZ YX YY YZ ZI equivalent-4: II IX IY IZ XI YX YY YZ ZX ZY ZZ equivalent-5: II IX IY IZ XX XY XZ YI ZX ZY ZZ
For 3-qubits optimal UD Pauli measurements with 31 operators, we can find 30240
Clifford equivalent schemes in about 4 minutes.
## skip in generating documentation website
# num_qubit = 3
# size = 31
# ud_pauli_index = numqi.unique_determine.load_pauli_ud_example(num_qubit, tag_group_by_size=True)[size][0]
# equivalent_list = numqi.gate.get_pauli_subset_equivalent(ud_pauli_index, num_qubit, use_tqdm=True)
# print('len(equivalent_list):', len(equivalent_list))
We can also list all UD Pauli subsets and check their Clifford equivalence relation.
This calculation should only be done for 2-qubits. 3-qubits is already too large.
all_equivalent_set = numqi.gate.get_pauli_all_subset_equivalent(num_qubit=2)
z0 = {'withI':dict(), 'noI':dict()}
tmp0 = dict()
for key,value in all_equivalent_set.items():
z0['withI'][key] = [x for x in value if (0 in sorted(x)[0])]
for key,value in all_equivalent_set.items():
z0['noI'][key] = [x for x in value if (0 not in sorted(x)[0])]
for key,value in z0.items():
print(key)
for subset_order,z0 in value.items():
tmp0 = collections.Counter([len(x) for x in z0])
tmp0 = sorted(tmp0.items(),key=lambda x:x[0])
tmp0 = '+'.join([f'{v}x{k}' for k,v in tmp0])
print(f'#[len={subset_order}]={len(z0)}, {tmp0}')
print()
#[len=1]=2, 1x1+1x15
#[len=2]=3, 1x15+1x45+1x60
#[len=3]=7, 1x15+1x20+1x45+2x60+2x180
#[len=4]=14, 1x15+1x20+1x30+1x45+3x60+1x90+4x180+2x360
#[len=5]=24, 1x6+1x30+2x45+3x60+1x72+3x90+1x120+4x180+8x360
#[len=6]=36, 1x6+1x10+1x15+1x45+4x60+1x72+4x90+2x120+5x180+15x360+1x720
#[len=7]=45, 1x10+2x15+4x60+4x90+3x120+12x180+15x360+4x720
#[len=8]=48, 2x15+2x60+4x90+4x120+18x180+12x360+6x720
#[len=9]=45, 1x10+2x15+4x60+4x90+3x120+12x180+15x360+4x720
#[len=10]=36, 1x6+1x10+1x15+1x45+4x60+1x72+4x90+2x120+5x180+15x360+1x720
#[len=11]=24, 1x6+1x30+2x45+3x60+1x72+3x90+1x120+4x180+8x360
#[len=12]=14, 1x15+1x20+1x30+1x45+3x60+1x90+4x180+2x360
#[len=13]=7, 1x15+1x20+1x45+2x60+2x180
#[len=14]=3, 1x15+1x45+1x60
#[len=15]=2, 1x1+1x15 withI #[len=1]=1, 1x1 #[len=2]=1, 1x15 #[len=3]=2, 1x45+1x60 #[len=4]=5, 1x15+1x20+1x60+2x180 #[len=5]=9, 1x30+1x45+2x60+1x90+2x180+2x360 #[len=6]=15, 1x6+1x45+1x60+1x72+2x90+1x120+2x180+6x360 #[len=7]=21, 1x10+1x15+3x60+2x90+1x120+3x180+9x360+1x720 #[len=8]=24, 1x15+1x60+2x90+2x120+9x180+6x360+3x720 #[len=9]=24, 1x15+1x60+2x90+2x120+9x180+6x360+3x720 #[len=10]=21, 1x10+1x15+3x60+2x90+1x120+3x180+9x360+1x720 #[len=11]=15, 1x6+1x45+1x60+1x72+2x90+1x120+2x180+6x360 #[len=12]=9, 1x30+1x45+2x60+1x90+2x180+2x360 #[len=13]=5, 1x15+1x20+1x60+2x180 #[len=14]=2, 1x45+1x60 #[len=15]=1, 1x15 noI #[len=1]=1, 1x15 #[len=2]=2, 1x45+1x60 #[len=3]=5, 1x15+1x20+1x60+2x180 #[len=4]=9, 1x30+1x45+2x60+1x90+2x180+2x360 #[len=5]=15, 1x6+1x45+1x60+1x72+2x90+1x120+2x180+6x360 #[len=6]=21, 1x10+1x15+3x60+2x90+1x120+3x180+9x360+1x720 #[len=7]=24, 1x15+1x60+2x90+2x120+9x180+6x360+3x720 #[len=8]=24, 1x15+1x60+2x90+2x120+9x180+6x360+3x720 #[len=9]=21, 1x10+1x15+3x60+2x90+1x120+3x180+9x360+1x720 #[len=10]=15, 1x6+1x45+1x60+1x72+2x90+1x120+2x180+6x360 #[len=11]=9, 1x30+1x45+2x60+1x90+2x180+2x360 #[len=12]=5, 1x15+1x20+1x60+2x180 #[len=13]=2, 1x45+1x60 #[len=14]=1, 1x15 #[len=15]=1, 1x1
UD in other Hermitian matrix subspace¶
Our numerical algorithm can also find the optimal in any Hermitian matrix subspace. Usually, UDP is not equivalent to UDA in other Hermitian matrix subspace.
For example, UD Gell-Mann measurements.
num_qudit = 2
dim_qudit = 3
num_repeat = {(2,3):80, (1,3):10}[(num_qudit,dim_qudit)]
num_init_sample = {(2,3):10, (1,3):0}[(num_qudit,dim_qudit)]
gellmann_basis = numqi.gellmann.all_gellmann_matrix(num_qudit, tensor_n=dim_qudit, with_I=True)
# last item is identity, so put it in indexF (fixed index)
z0 = numqi.unique_determine.find_optimal_UD('udp', num_round=1, mat_list=gellmann_basis,
indexF=[len(gellmann_basis)-1], num_repeat=num_repeat, num_init_sample=num_init_sample, tag_print=True)
# all_index = numqi.unique_determine.save_index_to_file('gellmann-UD.json', key=f'{num_qudit},{dim_qudit},udp', index=z0)
matB_list = [gellmann_basis[x] for x in z0]
numqi.unique_determine.check_UD('udp', matB_list, num_repeat, early_stop_threshold=1e-4, converge_tol=1e-7, dtype='float64', num_worker=19)
[1.8s/53/1] loss=2.00000
[2.8s/52/2] loss=2.00000
[3.8s/51/2] loss=2.00000
[4.7s/50/2] loss=2.00000
[5.7s/49/2] loss=2.00000
[6.8s/48/5] loss=2.00000
[7.8s/47/5] loss=2.00000
[8.8s/46/6] loss=2.00000
[9.9s/45/7] loss=2.00000
[11.0s/44/9] loss=2.00000
[12.1s/43/13] loss=2.00000
[13.8s/42/15] loss=1.81233
[15.5s/41/17] loss=1.81233
[17.1s/40/21] loss=1.81233
[18.5s/39/21] loss=1.81233
[20.3s/38/26] loss=1.81233
[31.0s/38/38] loss=1.81233 [38] [1, 2, 3, 4, 5, 6, 10, 11, 13, 16, 17, 18, 19, 24, 25, 29, 30, 31, 32, 33, 34, 35, 38, 40, 41, 42, 45, 46, 47, 48, 51, 52, 53, 54, 55, 59, 60, 63]
[(True, 1.8123273626119356)]
For example, UD in qutrit projector
## 2 qutrit, projector
matrix_subspace = numqi.unique_determine.get_qutrit_projector_basis(num_qutrit=2)
z0 = numqi.unique_determine.find_optimal_UD('udp', num_round=1, mat_list=matrix_subspace, indexF=[0],
early_stop_threshold=0.001, num_repeat=80, num_init_sample=150, converge_tol=1e-6, tag_print=True)
[7.8s/75/1] loss=0.39500
[10.9s/74/1] loss=0.18550
[14.1s/73/1] loss=0.12605
[17.5s/72/1] loss=0.12602
[20.9s/71/1] loss=0.12601
[24.1s/70/1] loss=0.12005
[27.5s/69/1] loss=0.07381
[30.9s/68/1] loss=0.05852
[34.9s/67/2] loss=0.05843
[38.3s/66/2] loss=0.05732
[42.0s/65/2] loss=0.05732
[45.7s/64/2] loss=0.04580
[49.2s/63/2] loss=0.01227
[52.9s/62/2] loss=0.01210
[56.6s/61/2] loss=0.01190
[60.2s/60/2] loss=0.01185
[64.0s/59/2] loss=0.00937
[68.2s/58/2] loss=0.00937
[72.2s/57/2] loss=0.00937
[78.1s/56/5] loss=0.00910
[82.2s/55/5] loss=0.00691
[86.6s/54/5] loss=0.00690
[92.1s/53/8] loss=0.00674
[96.2s/52/8] loss=0.00608
[100.6s/51/8] loss=0.00572
[105.0s/50/8] loss=0.00560
[109.1s/49/8] loss=0.00559
[117.1s/48/11] loss=0.00559
[121.8s/47/12] loss=0.00559
[128.1s/46/16] loss=0.00421
[137.6s/45/23] loss=0.00718
[151.1s/44/43] loss=0.00123