From 780a54b53de34b1bb864006bd406a225fa0a10f3 Mon Sep 17 00:00:00 2001 From: Sergi Masot Llima <40757242+sergimasot@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:19:44 +0100 Subject: [PATCH] Initial commit --- .gitattributes | 2 + stabilizers.py | 1402 +++++++++++++++++++++++++++++++++++++ stabilizers_example.ipynb | 1313 ++++++++++++++++++++++++++++++++++ 3 files changed, 2717 insertions(+) create mode 100644 .gitattributes create mode 100644 stabilizers.py create mode 100644 stabilizers_example.ipynb diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/stabilizers.py b/stabilizers.py new file mode 100644 index 0000000..c396aaf --- /dev/null +++ b/stabilizers.py @@ -0,0 +1,1402 @@ +########################################## IMPORTS ############################################### + +from qiskit import QiskitError, QuantumCircuit +from qiskit.quantum_info import Clifford +from qiskit.quantum_info.operators.symplectic.clifford_circuits import * +from qiskit.circuit import Barrier, Delay, Gate, Instruction +from qiskit.circuit.exceptions import CircuitError +from qiskit.providers.fake_provider import FakeWashingtonV2 + +import numpy as np +from random import random +from scipy.sparse import lil_array #, csr_array, coo_array +from time import time +import numbers + +import quimb as qu +import quimb.tensor as qtn +from quimb import quimbify +from autoray import do +import autoray + +################################## Needed gates from quimb ####################################### + +RX = qu.Rx +RZ = qu.Rz +CNOT = qu.controlled('not') +X = qu.pauli('X') +H = qu.hadamard() +Z = qu.pauli('Z') +S = qu.S_gate() +Sdg = qu.S_gate().conj() + +##################################### Auxiliary functions ######################################## + + ### Glossary of concepts ### +# Boolean pauli form = [0,1,0,1 #qubits with an X ; 1,0,0,1 # qubits with a Z; 0 # phase] +# Boolean clifford basis = entries of a clifford tableau (in boolean pauli form) +# gen_clifford class = extension of Qiskit's clifford class to non-clifford circuits + + +def connectivity_kyiv(): + # Uses fake chip Washington and adds two missing connections to get + # the connectivity of the IBM 127qb-chip experiment + fake = FakeWashingtonV2() + cx_instructions = [] + for instruction in fake.instructions: + if instruction[0].name == 'cx': + if instruction[1] not in cx_instructions and (instruction[1][1],instruction[1][0]) not in cx_instructions: + cx_instructions.append(instruction[1]) + cx_instructions.append([109,114]) + cx_instructions.append([9,8]) + + return cx_instructions + + + + +def multiply_bool_pauli(pauli1,pauli2): + # Returns the multiplication of two Paulis in boolean X|Z form with the resulting phase at the end + # !!! This does not fit the boolean form of the tableau because of the phase at the end !!! + pauli = pauli1 # copy the first operator (only need the shape and the phase) + total_qb = len(pauli)//2 + phase_mat = [[1,1,1,1],[1,1,1j,-1j],[1,-1j,1,1j],[1,1j,-1j,1]] # table of phases for each commutation (easy and fast) + + for i in range(len(pauli1)//2): + pauli[-1] *= phase_mat[2*pauli1[i]+pauli1[i+total_qb]][2*pauli2[i]+pauli2[i+total_qb]] + pauli[i],pauli[i+total_qb] = (pauli1[i] + pauli2[i])%2, (pauli1[i+total_qb] + pauli2[i+total_qb])%2 + pauli[-1] *= (-1)**(pauli2[-1]) # add the phase of the second pauli + + return pauli + + + + +def check_comm(vector,entry,complement,accum=None,qubits=None): + # Checks if an operator (vector) in boolean clifford form commutes with another one (entry), usually extracted from a tableau. + # Also stores or updates phase information (accum) that can be used to extract the phase of anticommuting entries. + # This is needed when finding the decomposition of an operator in a given boolean clifford basis (tableau). + comm = 1 + total_qb = len(vector)//2 + + # In the general case we check the whole thing, but if we know (with method arguments) + # which *qubits* to check we can save some time + if qubits is None: + qubits = range(total_qb) + + checks = [(qubit,(vector[qubit],vector[qubit+total_qb])) for qubit in qubits] + for i,v in checks: + comp = (int(entry[i]),int(entry[i+total_qb])) + if v == (0,0) or comp == (0,0): + continue + if v != comp: + comm *= -1 + + # if comm is 1 then vector and given "entry" operator do not anti-commute + if comm > 0: + return 0, accum + # otherwise, they do anti-commute and so "entry" operator is in the decomposition of vector + else: + if (accum is not None): + accum = multiply_bool_pauli(accum,complement) + else: + accum = entry[:-1] + [(-1)**entry[1]] + + return 1, accum + + + + +def expect_tn(bra,G,ket,where,optimize="auto-hq",backend=None,): + # Adapts local_expectation from Quimb.tensor.circuit.Circuit + # Instead of generating rho=ket_1>, it generates ket_1> int: + try: + param = float(param) + epsilon = (abs(param) + 0.5 * 1e-10) % (np.pi / 2) + if epsilon > 1e-10: + raise ValueError(f"{param} is not to a multiple of pi/2") + multiple = int(np.round(param / (np.pi / 2))) + return multiple % 4 + except TypeError as err: + raise ValueError(f"{param} is not bounded") from err + + + +def phase_convert(phase): + if phase==1: + return '+' + elif phase==-1: + return '-' + elif phase==1j: + return '+i' + elif phase==-1j: + return '-i' + + + +def quimb_inital_state(binary_str): + quimb_c = qu.tensor.Circuit(len(binary_str)) + for i,ch in enumerate(binary_str): + if ch=='1': + quimb_c.apply_gate('X',i) + return quimb_c + + + +# This condenses a method used below (which does not use this function because it's more complex) +def trigonometrize(vector): + # For an n-dim vector v, finds an n-dim vector t of angles such that the original vector fulfills: + # v = ( sin(t1)cos(t2), sin(t1)sin(t2)cos(t3), ... , sin(t1)sin(t2)...sin(tn) ) + # which means that t1 will always be pi/2 and is there only to help with automatization + vector_trig = [] + for i in range(len(vector)-1): + coef = vector[i] + for v in vector_trig: + coef /= np.sin(v) + vector_trig.append(np.arccos(coef)) + + return vector_trig + + + + +def check_complexity(gen_clifford,qubits): + # !!!!!!!!!!!!! work in progress !!!!!!!!!!!!! + if gen_clifford.mode=='dict': + return 0,gen_clifford + elif gen_clifford.mode in ['sparse, sparse_comp']: + return 0,gen_clifford + elif gen_clifford.mode=='tn': + old_bond = gen_clifford.xvec.bond_size(qubits[0],qubits[1]) + new_gen_clifford = gen_clifford.copy() + new_gen_clifford.xvec.gate_(CNOT,(qubits[0],qubits[1]),contract='swap+split') + + new_bond = new_gen_clifford.xvec.bond_size(qubits[0],qubits[1]) + if new_bond > old_bond: + return 0,gen_clifford + else: + return 1,new_gen_clifford + + # return gen_clifford.xvec.contraction_width(optimize='random-greedy') + else: return 0,gen_clifford + + + + ########### Translation functions ########### + +def convert(a,b): + # Returns the sum of a and b as a binary string. + # Inputs are expected as integers or binary strings ('10001011') and converted so that they can be added together. + try: + if isinstance(a, (int, np.integer)): + a = np.array([int(t) for t in bin(a)[2:]]) + else: + a = np.array(a) + except TypeError: + a = np.array(a) + + try: + if isinstance(b, (int, np.integer)): + b = np.array([int(t) for t in bin(b)[2:]]) + else: + b = np.array(b) + except TypeError: + b = np.array(b) + + # make them equal length + padding = [0,]*np.abs(len(a)-len(b)) + if len(a)len(b): + b = np.concatenate((padding,b)) + + res = [] + for i,j in zip(a,b): + res.append((i+j)%2) + res = np.array(res, dtype=str) + + return int(''.join(res),2) + + + + +def trans_pauli(observable,qubits=None,total_qubits=None): + # Translates an observable in pauli basis from a string of pauli symbols to the boolean clifford basis + # (in the current implementation the phase of the observable must be handled separately!) + if qubits is not None: + new_obs = '' + if total_qubits is not None: + total_qubits = qubits[-1] + for qb in range(total_qubits): + if qb in qubits: + new_obs += observable[qubits.index(qb)] + else: + new_obs += 'I' + observable = new_obs + else: + total_qubits = len(observable) + + pauli_array = [0,]*(2*total_qubits) + trans = {'I': (0,0), 'X': (1,0), 'Y':(1,1), 'Z':(0,1)} + for i,pauli in enumerate(observable): + pauli_array[i]=trans[pauli][0] + pauli_array[i+total_qubits]=trans[pauli][1] + + pauli_array += [0] # add phase + + return pauli_array + + + +def trans_pauli_rev(observable): + # Translates an observable in pauli basis from the boolean clifford basis to a string of pauli symbols + # (in the current implementation the phase of the observable must be handled separately!) + num_qubits = len(observable)//2 + rev_observable = '' # str((-1)**observable[-1]) # first character is the phase of the observable, stored at the end + trans = {00: 'I', 10: 'X', 11: 'Y', 1: 'Z'} # table of translation with the x,z vectors + for i in range(num_qubits): + rev_observable += trans[int(str(int(observable[i])) + str(int(observable[i+num_qubits])))] # p_i is based on x_i, z_i + + return rev_observable + + +def obs_to_tn(obs,full=False): + if full: # we can opt to save the whole n-qubit observable but with quimb is not necessary + expec = qu.pauli(obs[0]) + for i,ch in enumerate(obs[1:]): + expec = expec & qu.pauli(ch) + return expec, [] + else: + expec = qu.pauli('I') # just in case all obs are "I" + where = [0,] + for i,ch in enumerate(obs): + if ch!='I': + expec = qu.pauli(ch) # If we find one that isn't we replace it + where = [i,] # and mark where because TN is then more efficient + break + for j,ch in enumerate(obs[i+1:]): # We continue adding the rest if there are more + if ch!='I': + expec = expec & qu.pauli(ch) + where.append(j+1) + return expec, where + + + ########## gate decomposition functions ############# + + +def gate_decomposition(tableau,gate,qubits=None): + # decomposes a gate in boolean pauli form into the boolean clifford basis + if type(qubits) is int: qubits = [qubits] + num_qubits = len(tableau)//2 + destab_v = [0,]*num_qubits + stab_v = [0,]*num_qubits + + if gate == [0,]*len(gate): + return 1,destab_v,stab_v + + # We keep track of the operators in the decomposition to find the extra phase needed + accum = [0,]*len(tableau) + [1,] #the last element is where we will store the phase (like the tableau but complex) + # checks if it commutes with the destabilizers + for i in range(len(tableau)//2): + destab = tableau[i] + stab = tableau[i+num_qubits] + stab_v[i],accum = check_comm(gate,destab,stab,accum,qubits) # if it anticommutes, it means stab_v[i] is needed! + + # checks if it commutes with the stabilizer + for i in range(len(tableau)//2): # we need to do this after doing all stabilizers to get correct phase + destab = tableau[i] + stab = tableau[i+num_qubits] + destab_v[i],accum = check_comm(gate,stab,destab,accum,qubits) # if it anticommutes, it means destab_v[i] is needed! + + phase = accum[-1] + + return phase,destab_v,stab_v + + + + +def tgate_decomp(tableau,qubit,dag=False): + # decomposes the tgate into boolean pauli form + gate_list = ([0,0],[0,1]) + gate_coefs = [np.cos(np.pi/8),-1j*np.sin(np.pi/8)] + if dag: gate_coefs[1]*= -1 + + destab_list = [] + stab_list = [] + tot_qubits = len(tableau)//2 + + for i,gate in enumerate(gate_list): + gate_vector = [0,]*(len(tableau)) + gate_vector[qubit] = gate[0] + gate_vector[qubit+tot_qubits] = gate[1] + + phase, destab, stab = gate_decomposition(tableau,gate_vector,qubit) + + gate_coefs[i] *= phase + destab_list.append(destab) + stab_list.append(stab) + + return gate_coefs, destab_list, stab_list + + + + +def ugate_decomp(tableau,qubit,theta,phi,lambd): + # decomposes a generic ugate into boolean pauli form + gate_list = [[0,0],[1,0],[1,1],[0,1]] + # General coefficients fixing the phase of Id to 1 + gate_coefs = [np.cos(theta/2)*np.sqrt((1+np.cos(phi+lambd))/2), + 1j*np.sin(theta/2)*(np.sin(phi)-np.sin(lambd))/np.sqrt(2*(1+np.cos(phi+lambd))), + -1j*np.sin(theta/2)*(np.cos(phi)+np.cos(lambd))/np.sqrt(2*(1+np.cos(phi+lambd))), + -1j*np.cos(theta/2)*(np.sin(phi+lambd))/np.sqrt(2*(1+np.cos(phi+lambd))),] + # results from tracing out tr(UX),tr(UY) and tr(UZ) + # gate_coefs = [np.cos(theta/2)*(1+np.exp(1j*(phi+lambd)))/2, + # np.sin(theta/2)*(np.exp(1j*(phi))-np.exp(1j*(lambd)))/2, + # -1j*np.sin(theta/2)*(np.exp(1j*(phi))+np.exp(1j*(lambd)))/2, + # np.cos(theta/2)*(1-np.exp(1j*(phi+lambd)))/2,] + + final_coefs = [] + destab_list = [] + stab_list = [] + tot_qubits = len(tableau)//2 + + for i,gate in enumerate(gate_list): + if gate_coefs[i] == 0: + continue + gate_vector = [0,]*(len(tableau)) + gate_vector[qubit] = gate[0] + gate_vector[qubit+tot_qubits] = gate[1] + + phase, destab, stab = gate_decomposition(tableau,gate_vector,qubit) + + final_coefs.append(gate_coefs[i]*phase) + destab_list.append(destab) + stab_list.append(stab) + + return final_coefs, destab_list, stab_list + + + + +def cc_gate(qubits,inds,type='x'): + # decomposes a ccx gate into 1qb and 2qb gates + temp = QuantumCircuit(qubits) + if type == 'x': + temp.h(inds[2]) + elif type == 'y': + temp.rx(np.pi/2,inds[2]) + elif type != 'z': + raise CircuitError('cc_gate type not implemented') + + temp.cnot(inds[1],inds[2]) + temp.tdg(inds[2]) + temp.cnot(inds[0],inds[2]) + temp.t(inds[2]) + temp.cnot(inds[1],inds[2]) + temp.tdg(inds[2]) + temp.cnot(inds[0],inds[2]) + temp.t([inds[1],inds[2]]) + temp.cnot(inds[0],inds[1]) + temp.t(inds[0]) + temp.tdg(inds[1]) + temp.cnot(inds[0],inds[1]) + + if type == 'x': + temp.h(inds[2]) + elif type == 'y': + temp.rx(-np.pi/2,inds[2]) + elif type != 'z': + raise CircuitError('cc_gate type not implemented') + + return temp + + + + + +################################# Generalized Clifford class ###################################### + +class gen_clifford(Clifford): + # To make it easy we only initialize with clifford circuits so we can keep the init + + def __init__(self, data, copy=True, mode='sparse_comp', max_bond=None, debug=False, *args, **kwargs): + super(gen_clifford, self).__init__(data, copy=True, *args, **kwargs) + + if isinstance(data, gen_clifford) and copy: + self._xvec = data.xvec.copy() + self._mode = data._mode + self._results = data._results + self._num_clbits = data.num_qubits + self._max_bond = data.max_bond + self._debug = debug + return + + # initalize bond_matrix if it's not a copy + if mode=='tn': + psi0 = qtn.MPS_computational_state('0' * self.num_qubits) + self._xvec = psi0 + elif mode=='dict': + self._xvec = {np.array([0])[0]: 1} + elif mode in ['sparse','sparse_comp']: + if mode=='sparse_comp': + xvec = lil_array((1,1)) + else: + xvec = lil_array((1,2**self.num_qubits),dtype=complex) + xvec[0,0] = 1 + self._xvec = xvec + else: + raise QiskitError('xvec was not initialized') + + # store mode for the update method + self._mode = mode + self._num_clbits = data.num_qubits + self._results = {} + self._max_bond = max_bond # this is useless if mode != 'tn' but it's easier to have the parameter + self._debug = debug + + @property + def xvec(self): + return self._xvec + + @property + def mode(self): + return self._mode + + @property + def num_clbits(self): + return self._num_clbits + + @property + def results(self): + return self._results + + @property + def max_bond(self): + return self._max_bond + + @property + def tableau_ordered(self): + qbs = self.num_qubits + return [np.concatenate([row[qbs-1::-1],row[2*qbs-1:qbs-1:-1],row[-1:]]) + for row in self.tableau] + + def reduce_bond_dim(self,max_bond=None): + if max_bond is not None: + self._max_bond = max_bond + else: + max_bond = self.max_bond + + if self._mode=='tn': + self._xvec.compress(max_bond=max_bond) + else: + print(f"Mode {self._mode} does not use bond dimension") + + return + + + + def computational_basis(self,tol=1e-10j): + # this is brute force, there might be a better way to do it! + qubits = self.num_qubits + comp_vec = np.zeros(2**qubits,dtype=complex) + format_s = '{'+f":0>{qubits}b"+'}' + stab_ket = self.to_quimb_circuit() + + for i in range(2**qubits): + # bra_qc = quimb_inital_state(format_s.format(i)) + bra = qu.tensor.tensor_builder.MPS_computational_state(format_s.format(i)) + # print(bra.H @ stab_ket.psi) + res = 0j + print(f"checking state {format_s.format(i)}") + for j in range(2**qubits): + coef = self.xvec.contract().data[*[int(ch) for ch in format_s.format(j)]] + if np.abs(coef) tol else 0 + print(f"coefficient:{coef}") + print(f"expected value: {val}") + print(f"added value: {coef * val}") + print(f"current res: {res}") + if i==0: + glob_phase = np.conj(res)/np.sqrt(res*np.conj(res)) + + comp_vec[i] = glob_phase*res + + return comp_vec.reshape([2,]*qubits) + + + def to_quimb_circuit(self): + quimb_c = qu.tensor.Circuit(self.num_qubits) + qiskit_c = self.to_circuit() + for gt in qiskit_c: + quimb_c.apply_gate(gt.operation.name, *[qiskit_c.find_bit(qb).index for qb in gt.qubits]) + + return quimb_c + + + + # we need to change the compose method to work with non-cliffords + def compose(self, + other: QuantumCircuit or Instruction, + qargs: list or None = None, + front: bool = False, + ) -> Clifford: + if qargs is None: + qargs = getattr(other, "qargs", None) + # If other is a QuantumCircuit we can more efficiently compose + # using the _append_circuit method to update each gate recursively + # to the current Clifford, rather than converting to a Clifford first + # and then doing the composition of tables. + if not front: + if isinstance(other, QuantumCircuit): + self._append_gen_circuit(other, qargs=qargs) + if isinstance(other, Instruction): + self._append_gen_operation(other, qargs=qargs) + + return self + + def measure_obs(self, observable, qubits=None): + if type(observable) is str: + observable_v = trans_pauli(observable) + else: + observable_v = observable + observable = trans_pauli_rev(observable) + + self.measure(observable_v,observable,qubits) + + return self._results + + def meas_tableau(self, observable, destab, stab, sign): + # modifies the tableau once we have measured a specific observable + tableau = self.tableau.copy() + + k = destab.index(1) + qubits = len(tableau)//2 + stab_k = tableau[k+qubits] + + for i,b in enumerate(destab): + if b: + tableau[i+qubits] = [(tableau[i+qubits][j] + stab_k[j])%2 for j in range(len(stab_k))] + for i,c in enumerate(stab): + if i==k: + tableau[i] = stab_k + if c: + tableau[i] = [(tableau[i][j] + stab_k[j])%2 for j in range(len(stab_k))] + + tableau[k+qubits] = observable + + if sign<0: + tableau[k+qubits][-1] = 1 + + self.tableau = tableau + return tableau + + def normalize(self, insert=-1): + # Normalizes a tensor network + if self.mode != 'tn': + print("Normalize method was called for non-tn mode") + return + + tn = self.xvec + norm = tn.norm() + tn.tensors[insert].modify(data=tn.tensors[insert].data / norm) + + return tn + + def read_tableau_obs(self,destab,stab): + # Returns the Pauli operator corresponding to an observable (obs) given + # in tableau form, using the current destabilizer basis. + qubits = self.num_qubits + pauli_form = [0,]*(2*qubits) + [1,] + for i,check in enumerate(destab+stab): + if check: + pauli_form = multiply_bool_pauli(pauli_form,self.tableau[i]) + phase = pauli_form[-1] + + return phase, trans_pauli_rev(pauli_form) + + # "read_tableau_obs" can be used like this + # print(f"coefficients from ugate decomp:") + # for coef,destab,stab in zip(gate_coefs,destab_list,stab_list): + # print(f"coeff: {coef}, operator: {self.read_tableau_obs(destab,stab)}") + + def update_xvec(self,coefs,destab_list,stab_list,tolerance=1e-10): + # Main method to update xvec. Different applications depending on the format of the vector + mode = self.mode + + if mode == 'tn': + params_sort = sorted(zip(coefs,destab_list,stab_list), key=lambda ins: sum(ins[1])) # [ordered array of (coef,destab,stab)] + + destab_ref = params_sort[0][1] + for i,entry in enumerate(destab_ref): + if entry: self._xvec.gate_(X,i,contract='swap+split') # apply gates to qubits where the first destabilizer is not 0s + stab_ref = params_sort[0][1] + for i,entry in enumerate(stab_ref): + if entry: self._xvec.gate_(Z,i,contract='swap+split') # apply gates to qubits where the first stabilizer is not 0s + coefs_trig = [np.arccos(params_sort[0][0])] + + for i,(co,d,s) in enumerate(params_sort[1:]): + # For a given d we need to implement a R[(X/Y/Z)_i] for all qubits i involved in d and s + # This is done with a cascade of CNOTS, an RX and extra 1qb transf [https://arxiv.org/pdf/2305.04807.pdf] + if np.abs(co)1e-8: + print('Found coefficient bigger than 1 by more than 1e-8. Unlikely to be numerical: recheck calculation.') + elif (np.abs(co)-1)>0: + co = np.sign(co)*1 + # 2 : at the end of the string of coefficients we should be left with 1 + if i==len(params_sort)-1: # + if np.abs(np.abs(co)-1)>1e-8: print('Something went wrong with the last angle') + # 3 : after extracting all the 1j factors phase can only be 1 or -1 + if np.imag(phase)!=0 : print(f"Something went wrong with the angles! Phase is {phase}") + + angle = extra_sign*coefs_trig[-1] + coefs_trig.append(np.arccos(np.abs(co))) # we remove the phase because it's counted in the previous angle + + for j in ind_dict: + if ind_dict[j]=='Y': + self._xvec.gate_(S,j, contract='swap+split') + elif ind_dict[j]=='Z': + self._xvec.gate_(H,j, contract='swap+split') + + prev_ind = diff_inds[0] + for j in diff_inds[1:rot_ind+1]: + self._xvec.gate_(CNOT, (j,prev_ind), contract='swap+split') + prev_ind = j + prev_ind = diff_inds[-1] + for j in diff_inds[-2:rot_ind-1:-1]: + self._xvec.gate_(CNOT, (j, prev_ind), contract='swap+split') + prev_ind = i + + self._xvec.gate_(RX(2*angle), (rot_qubit), contract='swap+split') + + prev_ind = rot_qubit + for j in diff_inds[rot_ind-1::-1]: + if rot_ind == 0: + continue + self._xvec.gate_(CNOT, (prev_ind,j), contract='swap+split') + prev_ind = i + prev_ind = rot_qubit + for j in diff_inds[rot_ind+1:]: + self._xvec.gate_(CNOT, (prev_ind,j), contract='swap+split') + prev_ind = i + + for j in ind_dict: + if ind_dict[j]=='Y': + self._xvec.gate_(Sdg,j, contract='swap+split') + elif ind_dict[j]=='Z': + self._xvec.gate_(H,j, contract='swap+split') + + destab_ref = d + + self._xvec.compress(max_bond=self.max_bond) + + if self._debug: + print('xvec updated') + print(self._xvec) + + elif mode in ['sparse','sparse_comp']: + + _, cols = self._xvec.nonzero() + + if mode == 'sparse': + new_xvec = lil_array(self._xvec.shape,dtype=complex) + elif mode == 'sparse_comp': + # try to make it as big as possible. This will usually be enough without an exhaustive search + new_xvec = lil_array((self._xvec.shape[0],max([self._xvec.shape[1],]+[convert(cols[-1],d)+1 for d in destab_list])),dtype=complex) + + for co,d,s in zip(coefs,destab_list,stab_list): + if np.abs(co)=new_xvec.shape[1]: + # if the method above comes short, this will fix it + expanded_xvec = lil_array((1,convert(c,d)+1),dtype=complex) + _,cols_bis = new_xvec.nonzero() + for cbis in cols_bis: + expanded_xvec[(0,cbis)] = new_xvec[(0,cbis)] + new_xvec = expanded_xvec + res = new_xvec[0,convert(c,d)] + co*(-1)**(sum(np.array(s)*np.array(c_bin))) * self._xvec[0,c] + if np.abs(res)>tolerance: + new_xvec[0,convert(c,d)] = res + else: + new_xvec[0,convert(c,d)] = 0 + + self._xvec = new_xvec + + elif mode=='dict': + + new_xvec = {} + cols = [key for key in self._xvec] + for co,d,s in zip(coefs,destab_list,stab_list): + if np.abs(co)tolerance: + new_xvec[convert(c,d)] = res + else: + new_xvec[convert(c,d)] = 0 + + self._xvec = new_xvec + + return self._xvec + + def measure(self,observable,tag,qubits=None): + # tag is how we will identify the stored result. + # If coming from qiskit, one can just use the clbit that was assigned to that measurement + tableau = self.tableau + xvec = self._xvec + + num_qubits = len(tableau)//2 + + if type(observable) is str: + observable_v = trans_pauli(observable) + elif len(observable)==len(tableau[0]): + observable_v = observable + else: + print("Did not recognize format of observable to measure") + return {} + + if qubits is not None: + try: len(qubits)>1 + except: qubits = [qubits] + + phase, destab, stab = gate_decomposition(self.tableau,observable_v,qubits=qubits) + + if self.mode == 'tn': + ev = phase + new_xvec = xvec.copy() + ref_xvec = xvec.conj() + + for qb,val in enumerate(stab): + if val: + xvec.gate_(Z,qb) + for qb,val in enumerate(destab): + if val: + xvec.gate_(X,qb) + + ev *= ref_xvec @ xvec + ev = np.round(ev,10) + + out0 = (1+ev)/2 + out1 = (1-ev)/2 + outcome = random()>out0 + + # Projection + phase *= (-1)**outcome # takes into account if the result was 0 or 1 + angle = np.pi/4 + + ind_dict = {} + Ys = 0 + for i,(d,s) in enumerate(zip(destab,stab)): + if d: + if s: + ind_dict[i] = 'Y' + Ys += 1 + else: + ind_dict[i] = 'X' + elif s: + ind_dict[i] = 'Z' + + diff_inds = [ind for ind in ind_dict] + rot_ind = int(len(diff_inds)/2) + rot_qubit = diff_inds[rot_ind] + + # basis change + for i in ind_dict: + if ind_dict[i]=='Y': + new_xvec.gate_(S,i, contract='swap+split') + elif ind_dict[i]=='Z': + new_xvec.gate_(H,i, contract='swap+split') + + # CNOTS input + prev_ind = diff_inds[0] + for i in diff_inds[1:rot_ind+1]: + new_xvec.gate_(CNOT, (i,prev_ind), contract='swap+split') + prev_ind = i + prev_ind = diff_inds[-1] + for i in diff_inds[-2:rot_ind-1:-1]: + new_xvec.gate_(CNOT, (i, prev_ind), contract='swap+split') + prev_ind = i + + # Core rotations + renorm = 1/np.sqrt(1+np.abs(ev)) + rot_matrix = quimbify([[np.cos(angle)*renorm, phase * (-1)**Ys * np.sin(angle)*renorm], + [phase * (-1)**Ys * np.sin(angle)*renorm, np.cos(angle)*renorm]]) # this is non-unitary!! + new_xvec.gate_(rot_matrix, (rot_qubit), contract='swap+split') + + # CNOTS output + prev_ind = rot_qubit + for i in diff_inds[rot_ind-1::-1]: + if rot_ind == 0: + continue + new_xvec.gate_(CNOT, (prev_ind,i), contract='swap+split') + prev_ind = i + prev_ind = rot_qubit + for i in diff_inds[rot_ind+1:]: + new_xvec.gate_(CNOT, (prev_ind,i), contract='swap+split') + prev_ind = i + + # basis unchange + for i in ind_dict: + if ind_dict[i]=='Y': + new_xvec.gate_(Sdg,i, contract='swap+split') + elif ind_dict[i]=='Z': + new_xvec.gate_(H,i, contract='swap+split') + + # remove the entries for which i·k = 1 + if 1 in destab: + k = destab.index(1) + new_xvec.gate_(quimbify([[np.sqrt(2),0],[0,0]]), k, contract='swap+split') # this is non-unitary! # it also can be done with a |0> contraction + self.tableau = self.meas_tableau(observable_v,destab,stab,(-1)**outcome) + + # despite the non-unitary matrices, renormalization (which is taken into account) should restore phyisicality, + # which is ensured here: + new_xvec.compress(max_bond=self.max_bond) + new_xvec = self.normalize() + results = {'reg': int(outcome), 'stats':(out0, out1), 'ev':ev} + self._results[tag] = results + self._xvec = new_xvec + + return results + + elif self.mode in ['sparse','sparse_comp']: + _, cols = xvec.nonzero() + inds = lambda x : (0,x) + + if self.mode == 'sparse': + new_xvec_0 = lil_array((1,2**num_qubits),dtype=complex) + new_xvec_1 = lil_array((1,2**num_qubits),dtype=complex) + elif self.mode == 'sparse_comp': + shape = (xvec.shape[0],max([xvec.shape[1],]+[convert(c,destab) for c in cols])) + new_xvec_0 = lil_array(shape,dtype=complex) + new_xvec_1 = lil_array(shape,dtype=complex) + elif self.mode=='dict': + cols = [key for key in xvec] + inds = lambda x : x + + new_xvec_0 = {} + new_xvec_1 = {} + + if destab == [0,]*num_qubits: + out0 = 0 + out1 = 0 + for c in cols: + c_bin = np.array([t for t in format(c, '0' + str(len(stab)) + 'b')],dtype=int) + val = xvec[inds(c)] + if phase*(-1)**(sum(np.array(stab)*np.array(c_bin)))>0: + new_xvec_0[inds(c)] = val + new_xvec_1[inds(c)] = 0 + out0 += val * np.conjugate(val) + elif (-1)*phase*(-1)**(sum(np.array(stab)*np.array(c_bin)))>0: + new_xvec_1[inds(c)] = val + new_xvec_0[inds(c)] = 0 + out1 += val * np.conjugate(val) + else: + print('a value was not counted') + + tot = out0 + out1 + # safety check + if np.abs(1-tot)>1e-6: + print('Measurement outcomes do not sum 1') + for c in cols: + new_xvec_0[inds(c)] /= tot + new_xvec_1[inds(c)] /= tot + out0 /= tot + out1 /= tot + outcome = random()>out0 + if outcome: + new_xvec = new_xvec_1 + else: + new_xvec = new_xvec_0 + ev = out0-out1 + else: + k = [0,]*num_qubits + k[destab.index(1)] = 1 + ev = 0 + renorm_0 = 0 + renorm_1 = 0 + + for c in cols: + coef = 1/np.sqrt(2) + c_bin = np.array([t for t in format(c, '0' + str(len(stab)) + 'b')],dtype=int) + + if sum(np.array(k)*np.array(c_bin))%2: + coef_0 *= phase * (-1)**(sum(np.array(stab)*np.array(c_bin))) + coef_1 = -coef_0 + target_ind = inds(convert(c,destab)) + else: + coef_0 = coef + coef_1 = coef + target_ind = inds(c) + + if self.mode=='dict' and target_ind not in new_xvec_0: + new_xvec_0[target_ind] = 0 + new_xvec_1[target_ind] = 0 + if new_xvec_0[target_ind] != 0: + renorm_0 -= new_xvec_0[target_ind] * np.conjugate(new_xvec_0[target_ind]) + renorm_1 -= new_xvec_1[target_ind] * np.conjugate(new_xvec_1[target_ind]) + new_xvec_0[target_ind] += coef_0*xvec[inds(c)] + new_xvec_1[target_ind] += coef_1*xvec[inds(c)] + renorm_0 += new_xvec_0[target_ind] * np.conjugate(new_xvec_0[target_ind]) + renorm_1 += new_xvec_0[target_ind] * np.conjugate(new_xvec_0[target_ind]) + + if self.mode=='dict' and inds(convert(c,destab)) not in xvec: + conj = 0 + elif self.mode=='sparse_comp' and convert(c,destab)>xvec.shape[1]: + conj = 0 + else: + conj = np.conjugate(xvec[inds(convert(c,destab))]) + + ev += phase * xvec[inds(c)] * conj * (-1)**(sum(np.array(stab)*np.array(c_bin))) + + # sanity check for realness + if np.abs(np.imag(ev))>1e-12: print('We got a complex expected value!') + + out0 = (1+ev)/2 + out1 = (1-ev)/2 + outcome = random()>out0 + + if outcome: + new_xvec = new_xvec_1 + renorm = renorm_1 + else: + new_xvec = new_xvec_0 + renorm = renorm_0 + + if self.mode in ['sparse','sparse_comp']: + _, cols = new_xvec.nonzero() + elif self.mode=='dict': + cols = [key for key in new_xvec] + for c in cols: + new_xvec[inds(c)] *= 1/np.sqrt(renorm) + + self.tableau = self.meas_tableau(observable_v,destab,stab,(-1)**outcome) + + results = {'reg': int(outcome), 'stats':(out0, out1), 'ev':ev} + self._results[tag] = results + self._xvec = new_xvec + + return results + + + ####### Modifying this in the original qiskit should help us ####### + # Right now it's better to initialize with an empty circuit and then + # use our "compose" method for all gates (including clifford) + def _append_gen_circuit(self, circuit, qargs=None, cargs=None): + # Copy of _append_circuit with the _apply_gen_operation below instead (see Qiskit documentation) + if qargs is None: + qargs = list(range(self.num_qubits)) + if cargs is None: + cargs = list(range(self.num_clbits)) + for instruction in circuit: + # start = time() + if instruction.clbits and instruction.operation.name!='measure': + raise QiskitError( + f"Cannot apply Instruction with classical bits: {instruction.operation.name}" + ) + elif instruction.operation.name == 'measure': + cbit = cargs[circuit.find_bit(instruction.clbits[0]).index] + qbit = qargs[circuit.find_bit(instruction.qubits[0]).index] + observable = [0,]*(2*self.num_qubits+1) + observable[qbit + self.num_qubits] = 1 + self.measure(observable,f"cbit_{cbit}",qbit) + continue + # Get the integer position of the flat register + new_qubits = [qargs[circuit.find_bit(bit).index] for bit in instruction.qubits] + self._append_gen_operation(instruction.operation, new_qubits) + + # Sanity check for compression (slows down computation a) + # if self.mode == 'tn': + # self.reduce_bond_dim() + return + + def _append_gen_operation(self, operation, qargs=None): + # Modified _append_operation (see Qiskit documentation) to work with general non-clifford gates + + # Basis Clifford Gates + basis_1q = {"i": self._append_i, "id": self._append_i,"iden": self._append_i, + "x": self._append_x,"y": self._append_y,"z": self._append_z,"h": self._append_h, + "s": self._append_s,"sdg": self._append_sdg,"sinv": self._append_sdg, + "v": self._append_v,"w": self._append_w,} + basis_2q = {"cx": self._append_cx, "cz": self._append_cz, "swap": self._append_swap} + + # Non-clifford gates + non_clifford = ["t", "tdg", "ccx", "ccz"] + + if isinstance(operation, (Barrier, Delay)): + return + + if qargs is None: + print('Found gate with undetermined application qubit. Applying to first available qubits.') + qargs = list(range(self.num_qubits)) + + gate = operation + + if isinstance(gate, str): + name = gate + else: + # assert isinstance(gate, Instruction) + name = gate.name + if getattr(gate, "condition", None) is not None: + raise QiskitError("Conditional gate is not a valid Clifford operation.") + + # Apply gate if it is a Clifford basis gate + if name in non_clifford: + if name=='t': + gate_coefs, destab_list, stab_list = tgate_decomp(self.tableau,qargs[0]) + self.update_xvec(gate_coefs, destab_list, stab_list) + if name=='tdg': + gate_coefs, destab_list, stab_list = tgate_decomp(self.tableau,qargs[0],dag=True) + self.update_xvec(gate_coefs, destab_list, stab_list) + if name=='ccx': + temp = cc_gate(self.num_qubits,qargs[:3],type='x') + self._append_gen_circuit(temp) + if name=='ccz': + temp = cc_gate(self.num_qubits,qargs[:3],type='z') + self._append_gen_circuit(temp) + return + + if name in basis_1q: + if len(qargs) != 1: + raise QiskitError("Invalid qubits for 1-qubit gate.") + basis_1q[name](qargs[0]) + return + if name in basis_2q: + if len(qargs) != 2: + raise QiskitError("Invalid qubits for 2-qubit gate.") + # if name=='cx': ########################################################## work in progress + # cheaper, new_gen_clifford = check_complexity(gen_clifford,qargs) + # if cheaper: + # return new_gen_clifford + basis_2q[name](qargs[0], qargs[1]) + return + + # If u gate, check if it is a Clifford, and if so, apply it + if isinstance(gate, Gate) and name == "u" and len(qargs) == 1: + try: + theta, phi, lambd = tuple(n_half_pis(par) for par in gate.params) + except ValueError as err: + theta, phi, lambd = tuple(par for par in gate.params) + gate_coefs, destab_list, stab_list = ugate_decomp(self.tableau,qargs[0],theta,phi,lambd) + self.update_xvec(gate_coefs, destab_list, stab_list) + if theta == 0: + self._append_rz(qargs[0], lambd + phi) + elif theta == 1: + self._append_rz(qargs[0], lambd - 2) + self._append_h(qargs[0]) + self._append_rz(qargs[0], phi) + elif theta == 2: + self._append_rz(qargs[0], lambd - 1) + self._append_x(qargs[0]) + self._append_rz(qargs[0], phi + 1) + elif theta == 3: + self._append_rz(qargs[0], lambd) + self._append_h(qargs[0]) + self._append_rz(qargs[0], phi + 2) + return + + # If gate is a Clifford, we can either unroll the gate using the "to_circuit" + # method, or we can compose the Cliffords directly. Experimentally, for large + # cliffords the second method is considerably faster. + + if isinstance(gate,Gate) and name in ['rx','ry','rz'] and len(qargs) == 1: + try: + theta = n_half_pis(gate.params[0]) + if name=='rz': + self._append_rz(qargs[0], theta) + elif name=='rx': + self._append_h(qargs[0]) + self._append_rz(qargs[0], theta) + self._append_h(qargs[0]) + elif name=='ry': + self._append_sdg(qargs[0]) + self._append_h(qargs[0]) + self._append_rz(qargs[0], theta) + self._append_h(qargs[0]) + self._append_s(qargs[0]) + + return gen_clifford + except ValueError as err: + theta = gate.params[0] + if name=='rz': + theta, phi, lambd = 0, 0, theta + elif name=='rx': + theta, phi, lambd = theta, -np.pi/2, np.pi/2 + elif name=='ry': + theta, phi, lambd = theta, 0, 0 + gate_coefs, destab_list, stab_list = ugate_decomp(self.tableau,qargs[0],theta,phi,lambd) + # This correction to match usual RZ definition is unnecessary computationally + # if name=='rz': + # gate_coefs = [t*np.exp(-1j*theta/2) for t in gate_coefs] + self.update_xvec(gate_coefs, destab_list, stab_list) + return + + if isinstance(gate, Clifford): + composed_clifford = self.compose(gate, qargs=qargs, front=False) + self.tableau = composed_clifford.tableau + return + + + # If the gate is not directly appendable, we try to unroll the gate with its definition. + # This succeeds only if the gate has all-Clifford definition (decomposition). + # If fails, we need to restore the clifford that was before attempting to unroll and append. + if gate.definition is not None: + try: + self._append_gen_circuit(gate.definition, qargs) + return + except QiskitError: + pass + + # As a final attempt, if the gate is up to 3 qubits, + # we try to construct a Clifford to be appended from its matrix representation. + if isinstance(gate, Gate) and len(qargs) <= 3: + try: + matrix = gate.to_matrix() + gate_cliff = Clifford.from_matrix(matrix) + self._append_gen_operation(gate_cliff, qargs=qargs) + return + except TypeError as err: + raise QiskitError(f"Cannot apply {gate.name} gate with unbounded parameters") from err + except CircuitError as err: + raise QiskitError(f"Cannot apply {gate.name} gate without to_matrix defined") from err + except QiskitError as err: + raise QiskitError(f"Cannot apply non-Clifford gate: {gate.name}") from err + + raise QiskitError(f"Cannot apply {gate}") + + ######## For all the following _append_gate's we have: ######## + """Apply *arbitrary gate* to a Clifford. + + Args: + clifford (Clifford): a Clifford. + qubit (int): gate qubit index. + + Returns: + Clifford: the updated Clifford. + """ + def _append_i(self, qubit): + # Apply an I gate to a Clifford. + return + + def _append_x(self, qubit): + # Apply an X gate to a Clifford. + self.phase ^= self.z[:, qubit] + return + + def _append_y(self, qubit): + # Apply a Y gate to a Clifford. + x = self.x[:, qubit] + z = self.z[:, qubit] + self.phase ^= x ^ z + return + + def _append_z(self, qubit): + # Apply an Z gate to a Clifford. + self.phase ^= self.x[:, qubit] + return + + def _append_rz(self, qubit, multiple): + # Apply an Rz gate to a Clifford. + if multiple % 4 == 1: + self._append_s(qubit) + if multiple % 4 == 2: + self._append_z(qubit) + if multiple % 4 == 3: + self._append_sdg(qubit) + return + + def _append_h(self, qubit): + # Apply a H gate to a Clifford. + x = self.x[:, qubit] + z = self.z[:, qubit] + self.phase ^= x & z + tmp = x.copy() + x[:] = z + z[:] = tmp + return + + def _append_s(self, qubit): + # Apply an S gate to a Clifford. + x = self.x[:, qubit] + z = self.z[:, qubit] + self.phase ^= x & z + z ^= x + return + + def _append_sdg(self, qubit): + # Apply an Sdg gate to a Clifford. + x = self.x[:, qubit] + z = self.z[:, qubit] + self.phase ^= x & ~z + z ^= x + return + + def _append_v(self, qubit): + # Apply a V gate to a Clifford. + x = self.x[:, qubit] + z = self.z[:, qubit] + tmp = x.copy() + x ^= z + z[:] = tmp + return + + def _append_w(self, qubit): + # Apply a W gate to a Clifford. + x = self.x[:, qubit] + z = self.z[:, qubit] + tmp = z.copy() + z ^= x + x[:] = tmp + return + + def _append_cx(self, control, target): + # Apply a CX gate to a Clifford. + x0 = self.x[:, control] + z0 = self.z[:, control] + x1 = self.x[:, target] + z1 = self.z[:, target] + self.phase ^= (x1 ^ z0 ^ True) & z1 & x0 + x1 ^= x0 + z0 ^= z1 + return + + def _append_cz(self, control, target): + # Apply a CZ gate to a Clifford. + x0 = self.x[:, control] + z0 = self.z[:, control] + x1 = self.x[:, target] + z1 = self.z[:, target] + self.phase ^= x0 & x1 & (z0 ^ z1) + z1 ^= x0 + z0 ^= x1 + return + + def _append_swap(self, qubit0, qubit1): + # Apply a Swap gate to a Clifford. + self.x[:, [qubit0, qubit1]] = self.x[:, [qubit1, qubit0]] + self.z[:, [qubit0, qubit1]] = self.z[:, [qubit1, qubit0]] + return + + + ######### Work in progress ########## + # def reduce_distance(self,override=False): # this method is only a performance boost for TN mode + + # # Checks current tableau to see if there is a simplification that makes pauli matrices X,Y,Z + # # more local in terms of index i weight (how many entries are different) + + # self.tableau + # # should be ran after every update for general simplifications (i.e. guaranteed to improve) and also + # # after knowing which qubit to apply a specific transformation (i.e. better for some but worse for others) + + # return self.tableau \ No newline at end of file diff --git a/stabilizers_example.ipynb b/stabilizers_example.ipynb new file mode 100644 index 0000000..4c8cb32 --- /dev/null +++ b/stabilizers_example.ipynb @@ -0,0 +1,1313 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# How to use" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\Users\\Sergi\\miniconda3\\envs\\stab\\Lib\\site-packages\\cotengra\\hyperoptimizers\\hyper.py:34: UserWarning: Couldn't import `kahypar` - skipping from default hyper optimizer and using basic `labels` method instead.\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "from stabilizers import *\n", + "from time import time\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Qiskit's tableau simulations can be initialized from a Clifford circuit ```qc``` created with ```QuantumCircuit``` just by using the class Clifford as:\n", + "```\n", + "Clifford(qc)\n", + "```\n", + "Similarly, after importing our functions from ```stabilizers.py```, we can use the class gen_clifford:\n", + "```\n", + "stab_TN = gen_clifford(qc)\n", + "```\n", + "And we can later add non-Clifford gates ```qc_nonC``` to the circuit with our version of the method ```compose```:\n", + "```\n", + "stab_TN.compose(qc_nonC)\n", + "```\n", + "Since the initialization of the gen_clifford class goes through Qiskit's internal checks, it's better to do the initalization with a Clifford circuit (such as an empty circuit) and add the rest of the gates (Clifford or non-Clifford) with ```compose```. This offers no computational disadvantage to initializing directly. For example:\n", + "```\n", + "qc = QuantumCircuit(n_qubits)\n", + "qc = function_that_adds_all_gates(qc)\n", + "stab_TN = gen_clifford(QuantumCircuit(n_qubits)).compose(qc)\n", + "```\n", + "Measurements of qubits on a Qiskit circuit can be used without issues. In addition, one can measure an observable (as long as the amount of qubits fits the circuit) directly with the method ```measure_obs```\n", + "```\n", + "ev_check = 'IZZIXIY'\n", + "stab_TN.measure_obs(ev_check) \n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As a practical example we can use the circuit from IBM quantum advantage experiment (https://www.nature.com/articles/s41586-023-06096-3) with a reduced amount of qubits" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "def apply_ibm_circ(qc,max_qubits,cx_instructions,rot_angle=np.pi/2,trotter_steps=2):\n", + " for _ in range(trotter_steps):\n", + " for qb in range(qc.num_qubits):\n", + " qc.rx(rot_angle,qb)\n", + " for conn in cx_instructions:\n", + " if conn[0]>=max_qubits or conn[1]>=max_qubits:\n", + " continue\n", + " qc.rzz(-np.pi/2,conn[0],conn[1])\n", + " # qc.cnot(conn[0],conn[1])\n", + " # qc.rz(-np.pi/2,conn[1])\n", + " # qc.cnot(conn[0],conn[1])\n", + " return qc\n", + "\n", + "def apply_ibm_tn(num_qubits,cx_instructions,rot_angle=np.pi/2,trotter_steps=2):\n", + " qc_tn = qtn.Circuit(num_qubits)\n", + " for _ in range(trotter_steps):\n", + " for qb in range(num_qubits):\n", + " qc_tn.apply_gate('RX', rot_angle, qb)\n", + " for conn in cx_instructions:\n", + " if conn[0]>=num_qubits or conn[1]>=num_qubits:\n", + " # print('skipped one')\n", + " continue\n", + " qc_tn.apply_gate('RZZ', -np.pi/2, conn[0], conn[1])\n", + " # qc_tn.apply_gate('CNOT', conn[0], conn[1])\n", + " # qc_tn.apply_gate('RZ', -np.pi/2, conn[1])\n", + " # qc_tn.apply_gate('CNOT', conn[0], conn[1])\n", + " return qc_tn" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Value close to 0 (EV ~0)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "ZZIIIIIIIIIIIII\n", + "{'reg': 1, 'stats': ((0.5061185129+0j), (0.4938814871+0j)), 'ev': (0.0122370258+0j)}\n", + "(0.01223702582620291-3.686287386450715e-17j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IZZIIIIIIIIIIII\n", + "{'reg': 1, 'stats': ((0.509047054+0j), (0.490952946+0j)), 'ev': (0.018094108+0j)}\n", + "(0.01809410795874398+2.8019849895172255e-17j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIZZIIIIIIIIIII\n", + "{'reg': 1, 'stats': ((0.51201267855+0j), (0.48798732145+0j)), 'ev': (0.0240253571+0j)}\n", + "(0.024025357137815843-5.925673092401634e-17j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIZZIIIIIIIIII\n", + "{'reg': 1, 'stats': ((0.5150155019+0j), (0.4849844981+0j)), 'ev': (0.0300310038-0j)}\n", + "(0.030031003770795678-6.694855568032397e-18j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIZZIIIIIIIII\n", + "{'reg': 0, 'stats': ((0.5150155019+0j), (0.4849844981+0j)), 'ev': (0.0300310038-0j)}\n", + "(0.030031003770795702+6.478734815633493e-18j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIZZIIIIIIII\n", + "{'reg': 1, 'stats': ((0.5150155019+0j), (0.4849844981+0j)), 'ev': (0.0300310038+0j)}\n", + "(0.030031003770795723-3.3581484960366227e-18j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIIZZIIIIIII\n", + "{'reg': 1, 'stats': ((0.5150155019+0j), (0.4849844981+0j)), 'ev': (0.0300310038+0j)}\n", + "(0.030031003770795713+7.209944447028604e-18j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIIIZZIIIIII\n", + "{'reg': 0, 'stats': ((0.5150155019+0j), (0.4849844981+0j)), 'ev': (0.0300310038-0j)}\n", + "(0.030031003770795553+1.2543579590951512e-17j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIIIIZZIIIII\n", + "{'reg': 0, 'stats': ((0.5150155019+0j), (0.4849844981+0j)), 'ev': (0.0300310038+0j)}\n", + "(0.030031003770795595+2.767567941370901e-19j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIIIIIZZIIII\n", + "{'reg': 0, 'stats': ((0.51201267855+0j), (0.48798732145+0j)), 'ev': (0.0240253571+0j)}\n", + "(0.02402535713781586+1.3877787807814457e-17j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIIIIIIZZIII\n", + "{'reg': 1, 'stats': ((0.509047054+0j), (0.490952946+0j)), 'ev': (0.018094108-0j)}\n", + "(0.018094107958743916+3.247313001421081e-17j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIIIIIIIZZII\n", + "{'reg': 0, 'stats': ((0.5061185129+0j), (0.4938814871+0j)), 'ev': (0.0122370258-0j)}\n", + "(0.012237025826202853+6.839689691690107e-18j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIIIIIIIIZZI\n", + "{'reg': 1, 'stats': ((0.503115344+0j), (0.496884656+0j)), 'ev': (0.006230688-0j)}\n", + "(0.00623068797109265+7.392036259339303e-17j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIIIIIIIIIZZ\n", + "{'reg': 1, 'stats': ((0.50307791485+0j), (0.49692208515+0j)), 'ev': (0.0061558297+0j)}\n", + "(0.00615582970243107+9.594952122554922e-21j)\n" + ] + } + ], + "source": [ + "# Big non-stabilizer test\n", + "max_qubits = 15\n", + "ev_checks = { f\"z{i}\" : 'I'*i + 'ZZ' + 'I'*(max_qubits-i-2) for i in range(max_qubits-1)}\n", + "\n", + "mode = 'tn'\n", + "# max_bond = 2**16\n", + "trotter_steps = 5\n", + "rot_angle = 0.95*np.pi/2 # np.pi/2\n", + "compare = True\n", + "\n", + "qc_0 = QuantumCircuit(max_qubits)\n", + "\n", + "cx_instructions = connectivity_kyiv()\n", + "# cx_instructions = [[i,i+1] for i in range(max_qubits-1)]\n", + "\n", + "# to compare\n", + "qc = QuantumCircuit(max_qubits,max_qubits)\n", + "qc = apply_ibm_circ(qc,max_qubits,cx_instructions,rot_angle,trotter_steps)\n", + "\n", + "for ev in ev_checks:\n", + " print('Creating and composing...')\n", + " test_temp = gen_clifford(qc_0,mode=mode).compose(qc)\n", + " print('Measuring...')\n", + " test_temp.measure_obs(ev_checks[ev]) \n", + "\n", + " if compare:\n", + " print('Calculating with TN to compare...')\n", + " qc_tn = apply_ibm_tn(max_qubits,cx_instructions,rot_angle,trotter_steps)\n", + " # psi_copy = qc_tn.psi.copy().contract(optimize='random-greedy')\n", + " expec = qu.pauli(ev_checks[ev][0])\n", + " where = [0,]\n", + " for i,ch in enumerate(ev_checks[ev][1:]):\n", + " if ch!='I':\n", + " expec = expec & qu.pauli(ch)\n", + " where.append(i+1)\n", + " # if ch!='I': qc_tn.apply_gate(ch,i)\n", + " # test_temp.results_real = {ev_checks[ev] : psi_copy.conj() @ qc_tn.psi.contract(optimize='random-greedy')}\n", + " test_temp.results_real = {ev_checks[ev] : qc_tn.local_expectation(expec, where=(*where,))}\n", + "\n", + " for t in test_temp.results:\n", + " print(t)\n", + " print(test_temp.results[t])\n", + " if compare: \n", + " print(test_temp.results_real[t])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Value close to 1 (EV ~1)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "ZZIIIIIIIIIIIII\n", + "{'reg': 0, 'stats': (0.9891681701, 0.010831829899999978), 'ev': 0.9783363402}\n", + "(0.9783363386042374+1.5800913496982975e-16j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IZZIIIIIIIIIIII\n", + "{'reg': 0, 'stats': ((0.98941843565+0j), (0.010581564350000017+0j)), 'ev': (0.9788368713-0j)}\n", + "(0.9788368686974653-4.118759484008084e-16j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIZZIIIIIIIIIII\n", + "{'reg': 0, 'stats': ((0.9894046624+0j), (0.010595337599999977+0j)), 'ev': (0.9788093248-0j)}\n", + "(0.9788093249754825-1.6762361818411427e-17j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIZZIIIIIIIIII\n", + "{'reg': 0, 'stats': ((0.98940483995+0j), (0.010595160049999996+0j)), 'ev': (0.9788096799-0j)}\n", + "(0.9788096748395853-2.11467320021183e-16j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIZZIIIIIIIII\n", + "{'reg': 0, 'stats': ((0.9894048396499999+0j), (0.010595160350000021+0j)), 'ev': (0.9788096793-0j)}\n", + "(0.9788096748395865+9.173639999417502e-17j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIZZIIIIIIII\n", + "{'reg': 0, 'stats': ((0.9894048397499999+0j), (0.010595160250000013+0j)), 'ev': (0.9788096795-0j)}\n", + "(0.9788096748395851-1.54988906301684e-16j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIIZZIIIIIII\n", + "{'reg': 0, 'stats': ((0.9894048397499999+0j), (0.010595160250000013+0j)), 'ev': (0.9788096795-0j)}\n", + "(0.9788096748395869-6.116206536441589e-17j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIIIZZIIIIII\n", + "{'reg': 0, 'stats': ((0.9894048397499999+0j), (0.010595160250000013+0j)), 'ev': (0.9788096795-0j)}\n", + "(0.9788096748395859+7.632044561767987e-17j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIIIIZZIIIII\n", + "{'reg': 0, 'stats': ((0.9894048397999999+0j), (0.010595160200000009+0j)), 'ev': (0.9788096796-0j)}\n", + "(0.9788096748395849+1.7215434333794327e-16j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIIIIIZZIIII\n", + "{'reg': 0, 'stats': ((0.98940466505+0j), (0.01059533494999998+0j)), 'ev': (0.9788093301+0j)}\n", + "(0.9788093249754825+7.00244671115419e-17j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIIIIIIZZIII\n", + "{'reg': 0, 'stats': ((0.98941843615+0j), (0.010581563849999975+0j)), 'ev': (0.9788368723+0j)}\n", + "(0.9788368686974646+4.361811631040063e-18j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIIIIIIIZZII\n", + "{'reg': 0, 'stats': ((0.98916816985+0j), (0.01083183015+0j)), 'ev': (0.9783363397+0j)}\n", + "(0.9783363386042327+1.8252054070369312e-16j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIIIIIIIIZZI\n", + "{'reg': 0, 'stats': ((0.9883340442499999+0j), (0.011665955750000012+0j)), 'ev': (0.9766680885-0j)}\n", + "(0.9766680865362461+1.749971756854461e-16j)\n", + "Creating and composing...\n", + "Measuring...\n", + "Calculating with TN to compare...\n", + "IIIIIIIIIIIIIZZ\n", + "{'reg': 0, 'stats': (0.9877641298, 0.012235870199999999), 'ev': 0.9755282596}\n", + "(0.9755282581475722+2.715174981014611e-17j)\n" + ] + } + ], + "source": [ + "# Big non-stabilizer test\n", + "max_qubits = 15\n", + "ev_checks = { f\"z{i}\" : 'I'*i + 'ZZ' + 'I'*(max_qubits-i-2) for i in range(max_qubits-1)}\n", + "\n", + "mode = 'tn'\n", + "# max_bond = 2**16\n", + "trotter_steps = 5\n", + "rot_angle = 0.1*np.pi/2 # np.pi/2\n", + "compare = True\n", + "\n", + "qc_0 = QuantumCircuit(max_qubits)\n", + "\n", + "cx_instructions = connectivity_kyiv()\n", + "# cx_instructions = [[i,i+1] for i in range(max_qubits-1)]\n", + "\n", + "# to compare\n", + "qc = QuantumCircuit(max_qubits,max_qubits)\n", + "qc = apply_ibm_circ(qc,max_qubits,cx_instructions,rot_angle,trotter_steps)\n", + "\n", + "for ev in ev_checks:\n", + " print('Creating and composing...')\n", + " test_temp = gen_clifford(qc_0,mode=mode).compose(qc)\n", + " print('Measuring...')\n", + " test_temp.measure_obs(ev_checks[ev]) \n", + "\n", + " if compare:\n", + " print('Calculating with TN to compare...')\n", + " qc_tn = apply_ibm_tn(max_qubits,cx_instructions,rot_angle,trotter_steps)\n", + " # psi_copy = qc_tn.psi.copy().contract(optimize='random-greedy')\n", + " expec = qu.pauli(ev_checks[ev][0])\n", + " where = [0,]\n", + " for i,ch in enumerate(ev_checks[ev][1:]):\n", + " if ch!='I':\n", + " expec = expec & qu.pauli(ch)\n", + " where.append(i+1)\n", + " # if ch!='I': qc_tn.apply_gate(ch,i)\n", + " # test_temp.results_real = {ev_checks[ev] : psi_copy.conj() @ qc_tn.psi.contract(optimize='random-greedy')}\n", + " test_temp.results_real = {ev_checks[ev] : qc_tn.local_expectation(expec, where=(*where,))}\n", + "\n", + " for t in test_temp.results:\n", + " print(t)\n", + " print(test_temp.results[t])\n", + " if compare: \n", + " print(test_temp.results_real[t])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Value at 1 (EV=1, Stabilizer state)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Calculating with TN to compare...\n", + "measuring\n", + "TN calculation took 40.406938314437866\n", + "Stab computation starting...\n", + "Using max_bond=4:\n", + "Creating and composing...\n", + "Measuring...\n", + "IIIIIIIIZYZYZYZYZYZIIIIIIIIIIIIII\n", + "{'reg': 0, 'stats': (1.0, 0.0), 'ev': 1.0}\n", + "(0.9999999999999738+0j)\n", + "This bond dim took 0.07924032211303711\n" + ] + } + ], + "source": [ + "# Big non-stabilizer test\n", + "max_qubits = 33\n", + "ev_checks = {\n", + " # 'xyz_l' : 'I'*37 + 'XZIZXZ' + 'I'*(52-43) + 'XIIIXXXIIIXZ' + 'I'*(72-64) + 'ZIIYIIIXZ' + 'I'*(90-81) + 'ZZ' + 'I'*(127-92),\n", + " # 'z': 'IIZIZIZ' + 'I'*(101-7) + 'ZIZIZ' + 'I'*(127-106),\n", + "}\n", + "\n", + "mode = 'tn'\n", + "# max_bonds = [2**i for i in range(1,16)] \n", + "max_bonds = [2**2]\n", + "results = []\n", + "trotter_steps = 5\n", + "rot_angle = np.pi/2 # np.pi/2\n", + "compare = True\n", + "real = True\n", + "\n", + "if real:\n", + " cx_instructions = connectivity_kyiv()\n", + " ev_checks['xyz_s'] = 'IIIIIIIIZYIIZXIIIZIIIIIIIIIIZXYXZ'+'I'*(max_qubits-33)\n", + "else:\n", + " cx_instructions = [[i,i+1] for i in range(max_qubits-1)]\n", + " ev_checks['xyz_s'] = 'IIIIIIIIZYZYZYZYZYZIIIIIIIIIIIIII'+'I'*(max_qubits-33)\n", + " \n", + "qc_0 = QuantumCircuit(max_qubits,33)\n", + "\n", + "start = time()\n", + "results_real = {}\n", + "if compare:\n", + " qc_tn = qtn.Circuit(max_qubits)\n", + " print('Calculating with TN to compare...')\n", + " for _ in range(trotter_steps):\n", + " for qb in range(max_qubits):\n", + " qc_tn.apply_gate('RX', rot_angle, qb)\n", + " for conn in cx_instructions:\n", + " if conn[0]>=max_qubits or conn[1]>=max_qubits:\n", + " # print('skipped one')\n", + " continue\n", + " qc_tn.apply_gate('RZZ', -np.pi/2, conn[0], conn[1])\n", + " \n", + " for ev in ev_checks:\n", + " expec = qu.pauli(ev_checks[ev][0])\n", + " where = [0,]\n", + " for i,ch in enumerate(ev_checks[ev][1:]):\n", + " if ch!='I':\n", + " expec = expec & qu.pauli(ch)\n", + " where.append(i+1)\n", + " print('measuring')\n", + " results_real[ev_checks[ev]] = qc_tn.local_expectation(expec, where=(*where,))\n", + "print(f\"TN calculation took {time()-start}\")\n", + "start = time()\n", + "print('Stab computation starting...')\n", + "for max_bond in max_bonds:\n", + " print(f\"Using max_bond={max_bond}:\")\n", + " qc = QuantumCircuit(max_qubits,33)\n", + " for _ in range(trotter_steps):\n", + " for qb in range(qc.num_qubits):\n", + " qc.rx(rot_angle,qb)\n", + " for conn in cx_instructions:\n", + " if conn[0]>=max_qubits or conn[1]>=max_qubits:\n", + " # print('skipped one')\n", + " continue\n", + " qc.rzz(-np.pi/2,conn[0],conn[1])\n", + "\n", + " for ev in ev_checks:\n", + " print('Creating and composing...')\n", + " test_temp = gen_clifford(qc_0,mode=mode,max_bond=max_bond).compose(qc)\n", + " print('Measuring...')\n", + " results.append(test_temp.measure_obs(ev_checks[ev]))\n", + "\n", + " for t in test_temp.results:\n", + " print(t)\n", + " print(test_temp.results[t])\n", + " if compare: \n", + " print(results_real[t])\n", + " print(f\"This bond dim took {time()-start}\") " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Speed test" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Test speed of computation on a Clifford circuit\n", + "If this goes as fast as Qiskit, then the sTN layer is not interfering" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "For 5:\n", + "1.5707963267948966\n", + "Creating and composing...\n", + "Measuring...\n", + "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII\n", + "{'reg': 0, 'stats': ((0.5+0j), (0.5+0j)), 'ev': (-0+0j)}\n", + "Gate count=1355\n", + "It took 1.1561884880065918 s\n", + "For 10:\n", + "1.5707963267948966\n", + "Creating and composing...\n", + "Measuring...\n", + "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII\n", + "{'reg': 1, 'stats': ((0.5+0j), (0.5+0j)), 'ev': (-0+0j)}\n", + "Gate count=4065\n", + "It took 3.2951831817626953 s\n", + "For 20:\n", + "1.5707963267948966\n", + "Creating and composing...\n", + "Measuring...\n", + "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII\n", + "{'reg': 0, 'stats': ((0.5+0j), (0.5+0j)), 'ev': 0j}\n", + "Gate count=9485\n", + "It took 5.462470769882202 s\n", + "For 100:\n", + "1.5707963267948966\n", + "Creating and composing...\n", + "Measuring...\n", + "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII\n", + "{'reg': 0, 'stats': ((0.5+0j), (0.5+0j)), 'ev': 0j}\n", + "Gate count=36585\n", + "It took 8.79501485824585 s\n" + ] + } + ], + "source": [ + "ev_checks = {\n", + " 'z_min': 'I'*(62) + 'Z' + 'I'*(127-63),\n", + "}\n", + "\n", + "mode = 'tn'\n", + "max_bond = 128\n", + "trotter_steps_list = [5,10,20,100]\n", + "rot_angles = [np.pi/2] # this makes it a clifford circuit\n", + "gate_count = 0\n", + "results_trotter = {}\n", + "\n", + "max_qubits = 127\n", + "qc_0 = QuantumCircuit(max_qubits,33)\n", + "\n", + "cx_instructions = connectivity_kyiv()\n", + "\n", + "for trotter_steps in trotter_steps_list:\n", + " print(f\"For {trotter_steps}:\")\n", + " for rot_angle in rot_angles:\n", + " print(rot_angle)\n", + " start = time()\n", + " qc = QuantumCircuit(max_qubits,32)\n", + " for _ in range(trotter_steps):\n", + " for qb in range(qc.num_qubits):\n", + " gate_count += 1\n", + " qc.rx(rot_angle,qb)\n", + " for conn in cx_instructions:\n", + " if conn[0]>=max_qubits or conn[1]>=max_qubits:\n", + " print('skipped one')\n", + " continue\n", + " qc.rzz(-np.pi/2,conn[0],conn[1])\n", + " gate_count += 1\n", + "\n", + " for ev in ev_checks:\n", + " print('Creating and composing...')\n", + " test_temp = gen_clifford(qc_0,mode=mode,max_bond=max_bond).compose(qc)\n", + " print('Measuring...')\n", + " test_temp.measure_obs(ev_checks[ev]) \n", + "\n", + " for t in test_temp.results:\n", + " print(t)\n", + " print(test_temp.results[t])\n", + " total_time = time() - start\n", + " results_trotter[gate_count] = total_time\n", + " print(f\"Gate count={gate_count}\")\n", + " print(f\"It took {total_time} s\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from matplotlib import pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure(figsize=(6,4))\n", + "res = results_trotter\n", + "plt.plot([k for k in res], [res[k] for k in res], label=f\"$\\chi={max_bond}$\")\n", + "plt.ylabel(\"Time\")\n", + "plt.xlabel(\"Gate quantity\")\n", + "plt.legend()\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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HE5E92316tWorKxEly5d8OWXX+LcuXNISUnBF198gfPnzxu3EkVERKCiogIrVqxAeno6Pv/8c6xdu9bkuZo1a4aioiLs3r0bN27cQElJCZo3b45x48bh2WefxTfffIOMjAwcOXIES5YswY8//lhtpoEDB6J58+aYMGECTpw4gd9//x3/+Mc/TNaJiIhAUFAQ3nrrLaSmpuLHH3/Ehx9+aLJOZGQkfv31Vxw4cADnzp3DCy+8gJycnDqPUbNmzbB7925kZ2fj1q1bNa5z8uRJpKSk4MaNGyZbv6ZOnYr33nsPQgg8/vjjdX59IqpnUh9kRUSW7dq1a2LWrFkiNDRU2NvbCxcXF9G1a1fxwQcfiOLiYuN6H330kfD39xeOjo5i8ODBYvPmzXccoD1t2jTh5eVlMh1BeXm5WLRokWjWrJmwt7cX/v7+4vHHHxcnT56sMVNKSoro1auXUCqVonnz5mLXrl13HKS9b98+ERUVJRwcHETv3r3F119/bXJweF5enhg+fLhwcXERPj4+4vXXXxfPPvusyUHcffv2FS+++KLJaw8fPlxMmDDBePu7774TERERws7OrtrpCISommbg4YcfFi4uLsbpCG4rLCwUTk5OYsaMGXf7NhBRI5EJ8aed/EREVkomkyE2NtbiZui+ePEiwsPDkZiYiE6dOkkdh8jm8RgnIiIzVFFRgby8PLz++ut46KGHWJqIzASPcSIiMkP79++Hv78/EhMT7zgejIikw111RERERLXELU5EREREtcTiRERERFRLLE5EREREtcTiRERERFRLLE5EREREtcTiRERERFRLLE5EREREtcTiRERERFRLLE5EREREtfT/AZJkB97YMUOtAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure(figsize=(6,4))\n", + "res = results_trotter\n", + "plt.plot([k for k in res], [res[k] for k in res], label=f\"$\\chi={max_bond}$\")\n", + "plt.ylabel(\"Time\")\n", + "plt.xlabel(\"Gate quantity\")\n", + "plt.legend()\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The computation shouldn't get harder as we add more qubits" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "For 16:\n", + "Creating and composing...\n", + "Measuring...\n", + "Did not recognize format of observable to measure\n", + "Gate count=16\n", + "It took 0.05086398124694824 s\n", + "For 32:\n", + "Creating and composing...\n", + "Measuring...\n", + "Did not recognize format of observable to measure\n", + "Gate count=32\n", + "It took 0.04092907905578613 s\n", + "For 48:\n", + "Creating and composing...\n", + "Measuring...\n", + "Did not recognize format of observable to measure\n", + "Gate count=48\n", + "It took 0.05883479118347168 s\n", + "For 64:\n", + "Creating and composing...\n", + "Measuring...\n", + "Did not recognize format of observable to measure\n", + "Gate count=64\n", + "It took 0.07576704025268555 s\n", + "For 80:\n", + "Creating and composing...\n", + "Measuring...\n", + "Did not recognize format of observable to measure\n", + "Gate count=80\n", + "It took 0.2982032299041748 s\n", + "For 96:\n", + "Creating and composing...\n", + "Measuring...\n", + "Did not recognize format of observable to measure\n", + "Gate count=96\n", + "It took 0.11372208595275879 s\n", + "For 112:\n", + "Creating and composing...\n", + "Measuring...\n", + "Did not recognize format of observable to measure\n", + "Gate count=112\n", + "It took 0.1396021842956543 s\n", + "For 127:\n", + "Creating and composing...\n", + "Measuring...\n", + "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII\n", + "{'reg': 1, 'stats': ((0.5+0j), (0.5+0j)), 'ev': -0j}\n", + "Gate count=127\n", + "It took 1.3085038661956787 s\n" + ] + } + ], + "source": [ + "mode = 'tn'\n", + "max_bond = 128\n", + "trotter_steps = 5\n", + "rot_angles = [np.pi/2] # this makes it a clifford circuit\n", + "gate_count = 0\n", + "results_qbs = {}\n", + "\n", + "max_qubits_list = [16,32,48,64,80,96,112,127]\n", + "qc_0 = QuantumCircuit(max_qubits,33)\n", + "\n", + "cx_instructions = connectivity_kyiv()\n", + "\n", + "for max_qubits in max_qubits_list:\n", + " ev_checks = {\n", + " 'z_min': 'I'*(max_qubits//2) + 'Z' + 'I'*(max_qubits-(max_qubits//2+1)),\n", + " }\n", + "\n", + " print(f\"For {max_qubits}:\")\n", + " for rot_angle in rot_angles:\n", + " start = time()\n", + " qc = QuantumCircuit(max_qubits,32)\n", + " for _ in range(trotter_steps):\n", + " for qb in range(qc.num_qubits):\n", + " gate_count += 1\n", + " qc.rx(rot_angle,qb)\n", + " for conn in cx_instructions:\n", + " if conn[0]>=max_qubits or conn[1]>=max_qubits:\n", + " # print('skipped one')\n", + " continue\n", + " qc.rzz(-np.pi/2,conn[0],conn[1])\n", + " gate_count += 1\n", + "\n", + " for ev in ev_checks:\n", + " print('Creating and composing...')\n", + " test_temp = gen_clifford(qc_0,mode=mode,max_bond=max_bond).compose(qc)\n", + " print('Measuring...')\n", + " test_temp.measure_obs(ev_checks[ev]) \n", + "\n", + " for t in test_temp.results:\n", + " print(t)\n", + " print(test_temp.results[t])\n", + " total_time = time() - start\n", + " results_qbs[gate_count] = total_time\n", + " print(f\"Gate count={max_qubits}\")\n", + " print(f\"It took {total_time} s\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure(figsize=(6,4))\n", + "max_qubits_list = [16,32,48,64,80,96,112,127]\n", + "res = results_qbs\n", + "plt.plot([max_qubits_list[i] for i,_ in enumerate(res)], [10**5 * res[k]/k for k in res], label=f\"$\\chi={128}$\")\n", + "plt.ylabel(\"Time per gate ($x 10^{-5}$)\")\n", + "plt.xlabel(\"Qubits\")\n", + "plt.legend()\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Calculating with TN to compare...\n", + "measuring\n", + "TN gave (0.9548124788490103-9.915113570674663e-17j)\n" + ] + }, + { + "data": { + "text/html": [ + "
TensorNetworkGenVector(tensors=2202, indices=2922)
Tensor(shape=(2), inds=[_7535a3AAZNX], tags={I0, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNY], tags={I1, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNZ], tags={I2, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNa], tags={I3, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNb], tags={I4, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNc], tags={I5, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNd], tags={I6, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNe], tags={I7, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNf], tags={I8, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNg], tags={I9, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNh], tags={I10, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNi], tags={I11, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNj], tags={I12, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNk], tags={I13, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNl], tags={I14, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNm], tags={I15, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNn], tags={I16, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNo], tags={I17, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNp], tags={I18, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNq], tags={I19, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNr], tags={I20, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNs], tags={I21, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNt], tags={I22, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNu], tags={I23, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNv], tags={I24, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNw], tags={I25, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNx], tags={I26, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNy], tags={I27, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZNz], tags={I28, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOA], tags={I29, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOB], tags={I30, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOC], tags={I31, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOD], tags={I32, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOE], tags={I33, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOF], tags={I34, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOG], tags={I35, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOH], tags={I36, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOI], tags={I37, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOJ], tags={I38, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOK], tags={I39, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOL], tags={I40, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOM], tags={I41, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZON], tags={I42, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOO], tags={I43, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOP], tags={I44, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOQ], tags={I45, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOR], tags={I46, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOS], tags={I47, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOT], tags={I48, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOU], tags={I49, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOV], tags={I50, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOW], tags={I51, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOX], tags={I52, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOY], tags={I53, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOZ], tags={I54, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOa], tags={I55, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOb], tags={I56, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOc], tags={I57, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOd], tags={I58, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOe], tags={I59, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOf], tags={I60, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOg], tags={I61, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOh], tags={I62, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOi], tags={I63, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOj], tags={I64, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOk], tags={I65, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOl], tags={I66, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOm], tags={I67, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOn], tags={I68, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOo], tags={I69, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOp], tags={I70, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOq], tags={I71, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOr], tags={I72, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOs], tags={I73, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOt], tags={I74, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOu], tags={I75, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOv], tags={I76, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOw], tags={I77, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOx], tags={I78, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOy], tags={I79, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZOz], tags={I80, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPA], tags={I81, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPB], tags={I82, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPC], tags={I83, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPD], tags={I84, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPE], tags={I85, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPF], tags={I86, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPG], tags={I87, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPH], tags={I88, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPI], tags={I89, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPJ], tags={I90, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPK], tags={I91, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPL], tags={I92, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPM], tags={I93, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPN], tags={I94, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPO], tags={I95, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPP], tags={I96, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPQ], tags={I97, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPR], tags={I98, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])
Tensor(shape=(2), inds=[_7535a3AAZPS], tags={I99, PSI0}),backend=numpy, dtype=complex128, data=array([1.+0.j, 0.+0.j])

...

" + ], + "text/plain": [ + "TensorNetworkGenVector(tensors=2202, indices=2922)" + ] + }, + "execution_count": 81, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Big non-stabilizer test Uncontracted (TN FAST) !!!!!!!!!!!!!!\n", + "max_qubits = 127\n", + "ev_checks = {\n", + " # 'xyz_l' : 'I'*37 + 'XZIZXZ' + 'I'*(52-43) + 'XIIIXXXIIIXZ' + 'I'*(72-64) + 'ZIIYIIIXZ' + 'I'*(90-81) + 'ZZ' + 'I'*(127-92),\n", + " # 'z': 'IIZIZIZ' + 'I'*(101-7) + 'ZIZIZ' + 'I'*(127-106),\n", + "}\n", + "\n", + "mode = 'tn'\n", + "# max_bonds = [2**i for i in range(1,12)] # current trial\n", + "max_bonds = [2**i for i in range(4,)] # target if performance allows it\n", + "# max_bonds = [None]\n", + "results = []\n", + "trotter_steps = 5\n", + "rot_angle = 0.95*np.pi/2 # np.pi/2\n", + "compare = True\n", + "real = True\n", + "\n", + "if real:\n", + " cx_instructions = connectivity_kyiv()\n", + " ev_checks['xyz_s'] = 'IIIIIIIIZYIIZXIIIZIIIIIIIIIIZXYXZ'+'I'*(max_qubits-33)\n", + "else:\n", + " cx_instructions = [[i,i+1] for i in range(max_qubits-1)]\n", + " ev_checks['xyz_s'] = 'IIIIIIIIZYZYZYZYZYZIIIIIIIIIIIIII'+'I'*(max_qubits-33)\n", + " \n", + "qc_0 = QuantumCircuit(max_qubits,33)\n", + "\n", + "start = time()\n", + "results_real = {}\n", + "if compare:\n", + " qc_tn = qtn.Circuit(max_qubits)\n", + " print('Calculating with TN to compare...')\n", + " for _ in range(trotter_steps):\n", + " for qb in range(max_qubits):\n", + " qc_tn.apply_gate('RX', rot_angle, qb)\n", + " for conn in cx_instructions:\n", + " if conn[0]>=max_qubits or conn[1]>=max_qubits:\n", + " # print('skipped one')\n", + " continue\n", + " qc_tn.apply_gate('RZZ', -np.pi/2, conn[0], conn[1])\n", + " \n", + " for ev in ev_checks:\n", + " expec = qu.pauli(ev_checks[ev][0])\n", + " where = [0,]\n", + " for i,ch in enumerate(ev_checks[ev][1:]):\n", + " if ch!='I':\n", + " expec = expec & qu.pauli(ch)\n", + " where.append(i+1)\n", + " print('measuring')\n", + " results_real[ev_checks[ev]] = qc_tn.local_expectation(expec, where=(*where,))\n", + " print(f\"TN gave {results_real[ev_checks[ev]]}\")\n", + " # print(f\"Ended with bond size {max(qc_tn.psi.bond_sizes())}\")\n", + "qc_tn.psi " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Average t-gate entanglement (paper plot)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is based on the idea that clifford maps clifford states bijectively. However, clifford gates are not one to one with tableaus. We must solve this first to perform the experiment." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\Users\\Sergi\\miniconda3\\envs\\stab\\Lib\\site-packages\\cotengra\\hyperoptimizers\\hyper.py:34: UserWarning: Couldn't import `kahypar` - skipping from default hyper optimizer and using basic `labels` method instead.\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "from stabilizers import *\n", + "from time import time\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# Create random cliffords\n", + "n_qubits = 40\n", + "\n", + "from scipy import sparse\n", + "from qiskit.quantum_info import random_clifford\n", + "from random import random\n", + "\n", + "# random_clifford(n_qubits)\n", + "# random()" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Average bond of 100 tries is: 5.520000000000003\n", + "Average increase of 100 tries is: 5.520000000000003\n", + "Max increase of 100 tries is: 16.0\n", + "Min increase of 100 tries is: 2.0\n" + ] + } + ], + "source": [ + "# Big non-stabilizer test\n", + "n_qubits = 30\n", + "\n", + "mode = 'tn'\n", + "max_bond = None # this should work for not limiting max_bond\n", + "\n", + "tries = 100 # this means how many cliffords for each T-gate\n", + "# cx_instructions = connectivity_kyiv()\n", + "average = 0\n", + "average_inc = 0\n", + "samples = []\n", + "samples_pre = []\n", + "\n", + "for i in range(tries):\n", + " qc = QuantumCircuit(n_qubits)\n", + " qc.t(int(n_qubits*random())) \n", + " new_cliff = random_clifford(n_qubits)\n", + " stn = gen_clifford(new_cliff,mode=mode,max_bond=max_bond)\n", + " temp1 = stn.copy()\n", + " res_bond_a = max(stn.xvec.bond_sizes())\n", + " stn.compose(qc)\n", + " temp2 = stn.copy()\n", + " res_bond = max(stn.xvec.bond_sizes())\n", + "\n", + " # print(f\"Obtained bond {res_bond} in trial {i}\")\n", + " samples_pre.append(res_bond_a)\n", + " samples.append(res_bond)\n", + " average += res_bond/tries\n", + " average_inc += (res_bond/res_bond_a)/tries\n", + "\n", + " if (res_bond/res_bond_a)==(max(samples)/samples_pre[np.argmax(samples)]):\n", + " max1 = temp1\n", + " max2 = temp2\n", + " if (res_bond/res_bond_a)==(min(samples)/samples_pre[np.argmin(samples)]):\n", + " min1 = temp1\n", + " min2 = temp2\n", + "\n", + "print(f\"Average bond of {tries} tries is: {average}\")\n", + "print(f\"Average increase of {tries} tries is: {average_inc}\")\n", + "print(f\"Max increase of {tries} tries is: {max(samples)/samples_pre[np.argmax(samples)]}\")\n", + "print(f\"Min increase of {tries} tries is: {min(samples)/samples_pre[np.argmin(samples)]}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "## To calculate amount of clifford circuits given n\n", + "\n", + "def count_clifford_circs(n):\n", + "\n", + " fact1 = 2**(2*n) # phase combinations\n", + " fact2 = 2**(n**2) # Sp(2n) elements\n", + " for k in range(1,n+1):\n", + " fact2 *= (4**k - 1)\n", + "\n", + " return fact1*fact2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plots with n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Big non-stabilizer test\n", + "min_qubits = 2\n", + "max_qubits = 50\n", + "qubit_list = range(min_qubits,max_qubits)\n", + "\n", + "mode = 'tn'\n", + "max_bond = None # this should work for not limiting max_bond\n", + "\n", + "# try_func = lambda x: x**2 + 100*int(x/10) # how many tries we should do for a given n\n", + "try_func = lambda x: x # how many tries we should do for a given n\n", + "\n", + "samples = [[0],[0],]\n", + "averages = [0,]*(len(qubit_list)+2)\n", + "average_incs = [0,]*(len(qubit_list)+2)\n", + "cliff_circuits = [0,0]\n", + "\n", + "for n_qubits in qubit_list:\n", + " samples.append([])\n", + " samples_pre = []\n", + " print(f\"For {n_qubits} qubits\")\n", + " tries = try_func(n_qubits)\n", + " average = 0\n", + " average_inc = 0\n", + " for i in range(tries):\n", + " qc = QuantumCircuit(n_qubits)\n", + " qc.t(int(n_qubits*random())) \n", + " new_cliff = random_clifford(n_qubits)\n", + " test = gen_clifford(new_cliff,mode=mode,max_bond=max_bond)\n", + " res_bond_a = max(test.xvec.bond_sizes())\n", + " test.compose(qc)\n", + " res_bond = max(test.xvec.bond_sizes())\n", + "\n", + " samples_pre.append(res_bond_a)\n", + " samples[-1].append(res_bond)\n", + " \n", + " average += res_bond/tries\n", + " average_inc += (res_bond/res_bond_a)/tries\n", + " \n", + " averages[n_qubits] = average\n", + " average_incs[n_qubits] = average_inc\n", + " # cliff_circuits.append(count_clifford_circs(n_qubits))\n", + "\n", + " print(f\"Average bond of {tries} tries is: {average}\")\n", + " print(f\"Average increase of {tries} tries is: {average_inc}\")\n", + " # print(f\"Amount of possible Cliffords is: {cliff_circuits[-1]}\")\n", + " print(f\"Max increase of {tries} tries is: {max(samples[-1])/samples_pre[np.argmax(samples[-1])]}\")\n", + " print(f\"Min increase of {tries} tries is: {min(samples[-1])/samples_pre[np.argmin(samples[-1])]}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "from matplotlib import pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[Decimal('24'), Decimal('11520'), Decimal('92897280'), Decimal('12128668876800'), Decimal('25410822678459187200'), Decimal('852437556169034724016128000'), Decimal('4.576209955296803515123703816E+35'), Decimal('3.930874438226752547895796428E+45'), Decimal('5.402532081094233125882679856E+56'), Decimal('1.188028235526100326803818368E+69'), Decimal('4.180001752488569306571225047E+82'), Decimal('2.353131651606858058757448268E+97'), Decimal('2.119512534282874757335140730E+113'), Decimal('3.054539463694057850608873081E+130'), Decimal('7.043288462166715668751101221E+148'), Decimal('2.598514793373000602187899570E+168'), Decimal('1.533892395593915676593455267E+189'), Decimal('1.448720407435185154327536371E+211'), Decimal('2.189244382430811488475569644E+234'), Decimal('5.293268118728968715777985491E+258'), Decimal('2.047733919639343922111618749E+284'), Decimal('1.267485904462095526657936186E+311'), Decimal('1.255257240290759990632775211E+339'), Decimal('1.989034492619258790101944703E+368'), Decimal('5.042801536886905778362092953E+398'), Decimal('2.045603326421287167773466433E+430'), Decimal('1.327672465698205291490608023E+463'), Decimal('1.378733914561595986374276498E+497'), Decimal('2.290814647466752080825296264E+532'), Decimal('6.090029925133918947187099560E+568'), Decimal('2.590412246929894509313114999E+606'), Decimal('1.762943221372582028272031823E+645'), Decimal('1.919675174770835845009258577E+685'), Decimal('3.344545854414777522879412414E+726'), Decimal('9.323233113013231296476005897E+768'), Decimal('4.158300921596230647780069797E+812'), Decimal('2.967462697962643385979045634E+857'), Decimal('3.388243431086548390524968084E+903'), Decimal('6.189904152760833500453680407E+950'), Decimal('1.809311010836262715589430762E+999'), Decimal('8.461795215289692771903347523E+1048'), Decimal('6.331866911695199306416714890E+1099'), Decimal('7.580904537132156084327701156E+1151'), Decimal('1.452212799860626795599630215E+1205'), Decimal('4.451019280349556138451243529E+1259'), Decimal('2.182773503822013576431686953E+1315'), Decimal('1.712686418599653384693914491E+1372'), Decimal('2.150141378073016684803217929E+1430'), Decimal('4.318929976201229535772940287E+1489')]\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from decimal import *\n", + "from matplotlib import pyplot as plt\n", + "import numpy as np\n", + "\n", + "def count_clifford_circs_dec(n):\n", + "\n", + " fact1 = Decimal(2.0)**Decimal(2*n) # phase combinations\n", + " fact2 = Decimal(2.0)**Decimal(n**2) # Sp(2n) elements\n", + " for k in range(1,n+1):\n", + " fact2 *= Decimal(4**k - 1)\n", + "\n", + " return fact1*fact2\n", + "\n", + "def count_clifford_circs(n):\n", + "\n", + " fact1 = 2.0**(2*n) # phase combinations\n", + " fact2 = 2.0**(n**2) # Sp(2n) elements\n", + " for k in range(1,n+1):\n", + " fact2 *= (4**k - 1)\n", + "\n", + " return fact1*fact2\n", + "\n", + "max_qubits = 50\n", + "fig = plt.figure(figsize=(3,2))\n", + "\n", + "ax = plt.gca()\n", + "xs = range(1,max_qubits)\n", + "ys = [count_clifford_circs_dec(n) for n in xs]\n", + "print(ys)\n", + "\n", + "# plt.xticks(np.arange(xlim[0], xlim[1]+200, 200))\n", + "\n", + "plt.yscale('log')\n", + "plt.yticks([Decimal(1),Decimal(1e100),Decimal(1e200),Decimal(1e300)], size=14)\n", + "plt.xticks([10,20], size=14)\n", + "plt.plot(xs, ys, color='b')\n", + "# plt.plot(x, [test() for n in x], color='b')\n", + "plt.xlabel(\"Qubits\", size=14)\n", + "# plt.legend()\n", + "# plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA3oAAAJOCAYAAADhz3V3AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAADGBUlEQVR4nOzdd3gU1RrH8e+m95CEEkhCEjqhgyIo2CliAaxIUcECYkWKHQGvogiWi4oFxYYgigoiKIoiF0VQem8hIQRIJb1v5v6xZElIIZCyKb/P88yT3Zk5M++GJdk355z3mAzDMBAREREREZE6w87WAYiIiIiIiEjlUqInIiIiIiJSxyjRExERERERqWOU6ImIiIiIiNQxSvRERERERETqGCV6IiIiIiIidYwSPRERERERkTpGiZ6IiIiIiEgdo0RPRERERESkjlGiJyIiIiIiUsfU+kTvk08+wWQynXP79ddfbR2qiIiIiIhItXCwdQCVxc7OjkaNGpV63NnZuRqjERERERERsZ06k+gFBQURERFh6zBERERERERsrtYP3RQREREREZGilOiJiIiIiIjUMUr0RERERERE6pg6k+jFxcXRo0cPPDw8cHV1pUWLFowcOZK1a9faOjQREREREZFqZTIMw7B1EBXxySefMHr0aOtzHx8f0tPTycnJse4bPXo0H3zwAQ4OJdeeyc7OJjs72/o8Ly+PvXv3EhQUhJ1dncmFRURERERqrPz8fGJiYujWrVupn9ul/Gp9ord69Wr++usvbr75Ztq2bYuzszNms5mNGzfywgsvWNfPe/jhh5k7d26J15g2bRrTp0+vzrBFRERERKQEmzZt4uKLL7Z1GLVerU/0ypKfn8/NN9/MsmXLsLOzY9++fbRu3brYeWf36EVFRdGxY0c2bdpE06ZNqzNkEREREZF66cSJE/Ts2ZPIyEiaN29u63BqvTrdJ2pnZ8fs2bNZtmwZ+fn5/PDDDzzxxBPFznN2di6yoLq3tzcATZs2JTAwsNriFRERERGp7zR1qnLU+e9iq1ataNiwIQDh4eE2jkZERERERKTq1flET0REREREpL6p84ne4cOHiY+PByA0NNTG0YiIiIiIiFS9Wp3onauOjGEYTJ48GbCM9b3hhhuqIywRERERERGbqtWJXmRkJD179uT9998nPDzcmvjl5+fz999/c9111/Hdd98B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TcPR0ZElS5YUm3x68uRJvvjiCxo0aGCT+ERERETOR7rZzKAdO9iSlkYjR0d+7dKF0FLWTROpKZToSaX79ttvMQyD22+/vViSB+Dv728dHy0iIiJSk2WazQzeuZO/UlJo4ODA6s6daefubuuwRM5Jc/Sk0hUs+niuCbGFbdu2jSlTptCjRw8aNWqEs7MzLVq0YPz48Rw/frzY+REREZhMJq688krS09N54oknCAoKwtXVle7du/PDDz9Yz/3666+55JJLcHd3p0mTJjz66KNkZmYWu2ZISAgmkwnDMHjrrbcICwvDxcWFgIAAHn30UZKSks7r+5CXl8e8efPo3bs3Xl5euLq60rVrV958803rhNvC4uLieOqppwgLC8PDwwNvb2/atGnDXXfdxaZNm87r3iIiIlJx2fn53Lx7N2uSkvCwt2dVp0509fS0dVgi5aJETypdUFAQAEuXLiU2NrZcbV555RXeeOMNwLIA5aBBgzAMg3nz5nHRRReVmOwB5OTkcM0117Bw4UJ69epFr1692L59O0OHDuXXX3/ljTfeYPjw4Xh6ejJgwADMZjNz587lvvvuKzWWRx55hMmTJxMYGMjgwYOtba644gpSUlLK9XoyMzPp378/48eP58CBA/Tq1Yt+/fpx4sQJJkyYwC233FJkAnFqaiqXXHIJr776KmlpafTr14/+/fvj4+PD4sWLWblyZbnuKyIiIpUjJz+f23fv5qfERNzs7PixUyd6eXvbOiyR8jOkmKioKAMwoqKiznluZmamsWfPHiMzM7MaIqsdDh8+bLi6uhqA4enpadx9993Ghx9+aGzZssXIy8srsc1vv/1mnDx5ssg+s9lsTJ8+3QCM0aNHFzl25MgRAzAA4+qrrzbS0tKsxxYsWGAARqtWrQwfHx/jn3/+sR6Ljo42GjdubADG4cOHi1wzODjYAAwvLy/j33//te5PTU01rr76agMwHnvssSJtXnjhBQMwFixYUGT/+PHjDcC44447jKSkJOv+lJQUY9CgQQZgzJs3z7r/448/NgDjpptuMsxmc5FrxcbGGjt37izx+1YZ9B4WEREpKtdsNm7dtcvg998N57VrjV8TE20dUr1wPp/B5dzUo1eFDMMg3WyuVZtRCcsqtmjRgh9++IGgoCBSU1P59NNPuf/+++nevTsNGzZk/PjxnDhxokibq666iiZNmhTZZ2dnx9SpUwkICGD58uUl3svOzo558+bhXmis/F133UXDhg05dOgQDz30EBdddJH1WLNmzRgxYgQA69atK/GaDz/8MD169LA+9/DwYO7cuZhMJj766COysrLKfP2xsbF8+OGHBAUFsWDBArwL/fXP09OTjz76CCcnJ+bNm2fdXzDc9eqrr8bOruh/y0aNGtGxY8cy7ykiIiKVw2wY3L1vH9/ExeFkMvFdx45cU8Ji1yI1XZ0sxvLKK6/w9NNPW59XRvJyITLy8/H43/9scu8Llda3L+729hW+zjXXXMOhQ4f48ccfWb16NZs2bWLHjh0kJSUxb948li5dyrp162jbtq21TUJCAsuXL2fXrl0kJSVZF5rMzc0lISGBxMREfH19i9wnJCSENm3aFNlnZ2dHcHAw8fHx9O/fv1hsLVq0ACiWbBYYNmxYsX1hYWF06dKFbdu2sXXrVnr37l3qa1+7di25ubkMHDgQ1xIqcvn7+9O6dWt27txJZmYmrq6u1sTytddeo0mTJlx//fV4ag6AiIhItco3DO7fv58vY2NxMJlY0qED1/n52ToskQtS5xK9/fv3M336dFuHIYCTkxNDhw5l6NChACQlJbF48WKeeeYZYmNjefjhh/nll18AWLRoEQ888ECRhSzPlpqaWizRCwgIKPFcDw+PUo8XHMvOzi6xbXBwcIn7Q0JC2LZtW6nzBQtEREQA8OGHH/Lhhx+WeW5iYiIBAQFcc801TJgwgTfffJM777wTBwcHunfvTr9+/RgzZow1ORUREZGqYRgGDx08yIKTJ7EDvmzfnsENG9o6LJELVqcSvfz8fMaMGUNWVha9e/dmw4YNNo3Hzc6OtL59bRrD+XKzq7rRvA0aNGDcuHE0a9aMwYMH8/vvv5ORkUFcXBz33HMPAG+++SbXX389AQEB1t6wSy+9lA0bNpTYM3v2MMfzPV4VCoqsdO3alS5dupR5rnOhhVZff/11xo4dy7Jly/j111/5888/2bRpE7NmzWLRokXccsstVRq3iIhIfWUYBhMOHeK948cxAZ+1b89tjRvbOiyRCqlTid7cuXP566+/GDFiBK1atbJ5omcymSplGGRdc/XVVwNgNptJSkpi5cqV5OTkMGnSJB577LFi54eHh1drfJGRkXTq1KnE/WCZ51eWwMBAwFI9dO7cued177Zt2zJlyhSmTJlCVlYWb7/9NpMnT+bBBx9UoiciIlIFDMPgqfBw3oqOBmB+27aMOKtugEhtVGeKsRw5coRnn30WPz8/a5l+sY1zzYk8dOgQYBna2bBhQ06dOgWcSZAKW7duHTExMZUfZBmWLFlSbN++ffvYtm0bHh4edO3atcz2V111Ffb29qxYsYLc3NwLjsPFxYVJkybRtGlT4uLiyr1UhYiIiJTftIgIZkVFATCvdWvGNG1q44hEKkedSfTuv/9+0tPTef31189roW6pfM8//zyTJ0/m8OHDxY5FR0czduxYAG666SacnJysxVS++OIL0tPTi5w7bty46gm6kLlz57J161br84yMDB555BEMw2D06NElFlgpLCAggDFjxhAREcGdd95ZYqJ66NAhli5dan3+/fff8/fffxc7b/PmzcTExODh4UGDBg0u/EWJiIhIMS9HRjLj9IidN1u1Ylwpc/9FaqM6MXTzww8/ZM2aNVx77bXcddddtg6n3ktLS+Ott95i9uzZtGnThrCwMFxcXDh27BgbN24kNzeXVq1a8eabbwKWhK9Dhw78+++/tGrVissuu4ysrCx+//13unbtyqWXXspff/1VbfGPHDmSSy65hKuvvhpvb2/WrVvHyZMn6dChAy+++GK5rvHWW28RERHB0qVL+emnn+jatSvNmzcnPT2dPXv2cOjQIQYPHmwdjrl27VreeustAgIC6NatG15eXhw/fpz//e9/5OfnM336dJycnKryZYuIiNQrr0dF8eyRIwC82qIFj5UwskikNqv1iV50dDSTJ0/G1dWV999//4KukZ2dXaQCY2pqamWFVy8999xzXHTRRfz8889s376d//3vfyQnJ+Pl5UXPnj0ZPHgw48ePt6595+TkxP/+9z+effZZVq1axYoVKwgICOCRRx5h6tSpDBo0qFrj/+9//0toaCjz58/nyJEj+Pr68tBDD/Hiiy8WWROvLK6urqxatYqFCxfy6aefsm3bNjZt2kSjRo0IDg5m1KhRRZZxuOeee3BwcGDdunVs2rSJ5ORk/P39GTRoEI899hjXXHNNVb1cOUuOOYeBXwxkR8wOW4ciIiJVJKvxQNJD7gPA9dhiZm36hlk2jqkmWDViFRcHXGzrMKSSmAxbLTJXSW644QZ+/PFHXn31VaZMmWLdP23aNOsyC+d6iYXPLSwqKqrEeWOFZWVlceTIEUJDQ3Fx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iIgcj4KeiIictMYjZ8bGxrZ6v7i4uGaP4ShTp04lODj4mPeHDh3KgAEDAHjvvfcces6oqCgAysvLqaysdOixRURETpWCnoiIuERtba3Dj3nRRRedcN3mzZsdes5zzz2XuLg4cnNzOe+883jppZfYuXMnhmE49DwiIiInQ0FPREROWuNWvJNpmSssLLQvt8XE6cnJySdcd+jQIYeeMyoqin/84x/Ex8ezbds27r//fnr16kV0dDSXX34577zzDvX19Q49p4iIyIko6ImIyElLT0+3L2/ZsqXV+33//feA9dm5rl27OrwuVxk6dCiZmZm8/fbbjB07ljPOOIPS0lJWrlzJLbfcQt++fcnOznZ1mSIi0o4o6ImIyEkbMmQIPj7WHyHLly9v1T4VFRWsW7cOgPPPP5/AwEDAGvpsampqmt23tLS0Vec4XpiyrevQoUOrjnWyQkNDueWWW3jrrbfYvXs3Bw8eZPbs2QQFBdlb+kRERJxFQU9ERE5aYmIio0ePBqyDm+zateuE+zz//POUl5cD1mkQbBp34Txw4ECz+3777betqmvjxo0nXHfOOee06liAPcyeyvN2ycnJTJs2jcmTJwPYQ66IiIgzKOiJiMgpeeqppwgODqa2tpZrr722yfN3R1u9ejVPP/00AD179uTWW2+1r+vRo4d9pMzmWgctFguzZs1qVU1z585ttlVw48aNfPnllwBcf/31rToWYJ8wvaSkpMVtTjSojO2z2UKjiIiIM+injoiInJL09HQWLVqEr68vP/30E3379uWNN95oEop2797NQw89xOWXX05dXR2RkZG89957+Pv727fx9/e3T7r+zDPPsHTpUurq6gDYtWsXV155JT/++GOrasrNzeXSSy+1tzA2NDTw/vvvc8011wDQr18/rrrqqlZ/xt69ewNQVlZmn4vvaLNnz2bEiBH8/e9/5+DBg/b3a2trWbp0KXPmzAHg0ksvbfV5RURETpfJ0PjPIiJyGlavXs3tt99Obm6u/b3IyEhqa2ubtK517dqVZcuW0a9fv2OOcfDgQc477zxycnIAa/gLDg6mrKyM8PBwVq5cyYUXXghYW+dsywCbNm1iyJAhAKxYsYJrr72W+vp6IiMjqampsbe4paSksGnTJtLS0pqcu/H+zf1IHDp0KBs2bAAgPDycmJgYACZOnMjEiROZMWMGM2fOtG8fHBxMcHAwxcXF9uP16tWLTz75hISEhFb8FxURETl9atETEZHTMmLECDIyMnj55ZcZOXIkycnJ1NTUNAl5t9xyCz/99FOzIQ+gU6dOfPvtt9xxxx32aRDCwsK49dZb2bJlC3/4wx9aVcsVV1zBV199xdVXX01QUBCGYZCWlsbkyZPZunXrMSGvNd5//30mTZpEjx49qK+vZ9++fezbt8/ecnnXXXfx+uuvc+ONN9K7d29CQkIoKysjOjqawYMHM3/+fLZs2aKQJyIiTqUWPRERaRNms5krr7ySlStXEhkZySeffNJi0BMRERHHUtATEZE2U11dzcUXX8zXX39NXFwcn376aZM5+ERERKRtKOiJiEibOnz4MIMGDWLnzp0kJiby+eef061bN1eXJSIi4tUU9ERERERERLyMBmMRERERERHxMgp6IiIiIiIiXkZBT0RERERExMso6ImIiIiIiHgZBT0REREREREvo6AnIiIiIiLiZRT0REREREREvIyCnoiIiIiIiJdR0BMREREREfEyCnoiIiIiIiJeRkFPRERERETEy/x/kWLwbPP3WjMAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "max_qubits = 50\n", + "log = True\n", + "x = range(1,max_qubits)\n", + "try_func = lambda x: x**2 + 100*int(x/10) # how many tries we should do for a given n\n", + "\n", + "fig = plt.figure(figsize=(9,6))\n", + "ax1 = plt.gca()\n", + "if log:\n", + " lns1 = ax1.plot(x, averages[1:], color='r', label='Average')#, label=f\"$\\chi={max_bond}$\")\n", + " lns2 = ax1.plot(x, [np.log2(max(k+[1])) for k in samples[1:]], color='g', label='Maximum')#, label=f\"$\\chi={max_bond}$\")\n", + " plt.ylabel(r\"$log(\\chi')$\", fontsize='18')\n", + "else:\n", + " lns1 = ax1.plot(x, [2**k for k in averages[1:]], label='Average')#, label=f\"$\\chi={max_bond}$\")\n", + " lns2 = ax1.plot(x, [max(k+[1]) for k in samples[1:]], color='g', label='Maximum')#, label=f\"$\\chi={max_bond}$\")\n", + " plt.ylabel(r\"$\\chi'$\", fontsize='18')\n", + "plt.xlabel(\"Qubits\", fontsize='18')\n", + "\n", + "\n", + "ax1 = plt.gca()\n", + "ax1.set_yticks([0,1.0,2.0,3,4,5])\n", + "plt.yticks(fontsize='18')\n", + "plt.xticks(fontsize='18')\n", + "# ax1.set_yticks([0,0.5,1.0,1.5,2.0,2.5,3,3.5,4,4.5,5,5.5,6])\n", + "# ax.spines['left'].set_position(('data', 0))\n", + "ax2 = ax1.twinx()\n", + "lns3 = ax2.plot(x, [try_func(n) for n in x], 'c-', label='Samples')\n", + "plt.yticks(fontsize='18')\n", + "\n", + "# added these three lines\n", + "lns = lns1+lns2+lns3\n", + "labs = [l.get_label() for l in lns]\n", + "ax1.legend(lns, labs, loc=0, fontsize='15')\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from decimal import *\n", + "from matplotlib import pyplot as plt\n", + "import numpy as np\n", + "\n", + "qubits = 40\n", + "fig = plt.figure(figsize=(3,2))\n", + "ax = plt.gca()\n", + "\n", + "# plt.xticks(np.arange(xlim[0], xlim[1]+200, 200))\n", + "counts, bins = np.histogram([np.log2(x) for x in samples[qubits]],4,(0.5,4.5))\n", + "# plt.stairs(counts, bins, color='b')\n", + "plt.hist(bins[:-1], bins, weights=counts)\n", + "plt.xticks([1,2,3,4], size=12)\n", + "plt.yticks([500,1000], size=12)\n", + "\n", + "# plt.bar(samples[40], color='b')\n", + "# plt.plot(x, [test() for n in x], color='b')\n", + "plt.xlabel(\"$\\chi$\", size=14)\n", + "# plt.legend()\n", + "# plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import pickle\n", + "\n", + "dump = 0 # if True it saves, if False it loads\n", + "\n", + "if dump:\n", + " save_dict = {'samples': samples, 'averages': averages, 'cliff_circuits':cliff_circuits}\n", + "\n", + " with open(f\"data/stab_chi_sim.pickle\", 'wb') as handle:\n", + " pickle.dump(save_dict, handle, protocol=pickle.HIGHEST_PROTOCOL)\n", + "else:\n", + " with open(f\"data/stab_chi_sim.pickle\", 'rb') as handle:\n", + " save_dict = pickle.load(handle)\n", + " samples = save_dict['samples']\n", + " averages = save_dict['averages']\n", + " cliff_circuits = save_dict['cliff_circuits']\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "qiskit", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.4" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +}