def ghz_state(n, noisy=False, kraus=None): """ This creates an n qubit ghz state :param n: The number of qubits in the state :param string: The string for the initial state of the density matrix e.g '000' produces a state where all the three qubits are in the ground state while '111' produces a state where all the qubits are the excited state :param ar: This is a list of numbers that specifies the various control and target position e.g ghz_state(4, '0000', [1,2,1,3,1,4]) creates two control operations with first qubit being the control and the second qubit being the target and the second operation has first being the control with the third qubit being the target third operation has the first qubit being the control and the fourth qubit being the target :param noisy: If true decoherence is added between gate applications :param kraus: This will be a 3 dimensional array of kraus matrices :return: returns the state of the qubit after the controlled x operations. This should be a ghz state. """ string = '0'*n q = qubit.Qubit(string, n) h_gate = op.superkron(g.h(), np.eye(pow(2, n-1))) q.state = np.dot(h_gate, np.dot(q.state, h_gate)) if noisy is False: for i in range(1, n+1): controlgate = g.c_u(g.x(), n, i, i + 1) q.state = np.dot(controlgate, np.dot(q.state, op.ctranspose(controlgate))) else: for i in range(1, n+1): controlgate = g.c_u(g.x(), n, i, i + 1) q.q_decohere(kraus, n) q.state = np.dot(controlgate, np.dot(q.state, op.ctranspose(controlgate))) return q
def pauli_group(n, full=False, normalize=True): """ :param n: number of qubits :param full: If true returns the full pauli group for n qubits including group elements that differ by center of the group :param normalize: If true returns pauli group elements so that group are normalized :return: Returns a dictionary of unitary representation of the single qubit pauli group """ if normalize: pauli_matrix = { 'I': id() / sqrt(2), 'X': x() / sqrt(2), 'Y': y() / sqrt(2), 'Z': z() / sqrt(2) } else: pauli_matrix = {'I': id(), 'X': x(), 'Y': y(), 'Z': z()} center = {'i': 1j, '-i': -1j, '1': 1, '-1': -1} pauli_labels = [''.join(i) for i in product('IXYZ', repeat=n)] qubit_group = {} pauli_dict = {} if full is False: for pl in pauli_labels: pauli_dict[pl] = op.superkron(pauli_matrix, val=1, string=pl) else: for i in center: for p in pauli_dict: qubit_group[str(i) + str(p)] = dot(center[i], pauli_dict[p]) return pauli_dict
def get_projectors(self, measure_strings): """ :return: """ if isinstance(measure_strings, list): for i in measure_strings: yield op.superkron(self.oper_dict, val=1, string=i)
def apply_kraus(K, rho_s, n, non_ideal_qubits=0, partial_bath=False): """ :param K: List of kraus operators :param rho: density matrix of system :param n: Number of qubits :return: Return evolved density matrix """ out = np.zeros((pow(2, n), pow(2, n)), dtype=complex) if partial_bath: ideal_qubits_oper = {'0': g.id()} id_oper = op.superkron(ideal_qubits_oper, val=1, string='0' * (n - non_ideal_qubits)) for kraus in K: new_kraus = op.superkron(kraus, id_oper) out += np.dot(new_kraus, np.dot(rho_s, op.ctranspose(new_kraus))) return out else: for kraus in K: out += np.dot(kraus, np.dot(rho_s, op.ctranspose(kraus))) return out
def c_u(u, n, i, j): """ This creates a controlled unitary operation on n qubits :param u: Unitary matrix :param n: The number of qubits to be used :param i: the position of control qubit for the controlled operation :param j: the position of target qubit for the controlled operation :return: the controlled operation """ term_1 = {"0": id(), "1": e_ij((2, 2), 1, 1)} term_2 = {"0": id(), "2": u, "1": e_ij((2, 2), 2, 2)} # What happens when the control qubit is in the zero state label_1 = op.generatetensorstring(n, i) cu_1 = op.superkron(term_1, val=1, string=label_1) # What happens when the control bit is in the one state label_2 = op.controlgatestring(n, ('1', i), ('2', j)) cu_2 = op.superkron(term_2, val=1, string=label_2) return cu_1 + cu_2
def measure_basis(self, pauli_string='', undo_basis=False): """ :param pauli_string: Basis in which to make the measurement :param undo_basis: Boolean variable :return: """ measurement_operator = 1 if pauli_string != '' and undo_basis is False: for char in pauli_string: if char == 'X': measurement_operator = op.superkron(measurement_operator, g.r_y(-np.pi / 2)) elif char == 'Y': measurement_operator = op.superkron(measurement_operator, g.r_x(np.pi / 2)) else: measurement_operator = op.superkron(measurement_operator, g.id()) self.operator(measurement_operator) elif pauli_string != '' and undo_basis is True: for char in pauli_string: if char == 'X': measurement_operator = op.superkron(measurement_operator, g.r_y(np.pi / 2)) elif char == 'Y': measurement_operator = op.superkron(measurement_operator, g.r_x(-np.pi / 2)) else: measurement_operator = op.superkron(measurement_operator, g.id()) self.operator(measurement_operator) else: pass
def __init__(self, string, n, no_measurment_qubits=1, left_justified=False): """ :param string: This should be a string of 1's and 0's where 1 is the |1> and 0 is |0> :param n: The number of qubits in the system :param no_measurment_qubits: The number of qubits that will be measured :return: Returns the Description of class variables state: This is the density matrix of the system classical_states: This is a dictionary of computational basis states that should have has its keys labels of computational basis states and values the corresponding probabilities no_measurement_qubits: The number of qubits you intend to measure classical_states_history: Has a key values all possible measurement syndromes and keeps a record of their probabilities single_kraus: These are the kraus operators used for a single qubit. They are used to create kraus operators for the n qubit system partial_bath: This is aa boolean variable. If true some qubits the last m qubits on the left will not decohere no_non_ideal_qubits: These are the number of qubits, k that will decohere. m+k must equal to n the number of qubits in the system hamiltonian: The hamiltonian of the system T: The total evolution time of the system state: The state of the quantum system for n qubits """ self.oper_dict = {'0': g.b1(), '1': g.b4(), '2': g.id()} self.state = op.superkron(self.oper_dict, val=1, string=string) self.n = n self.no_measurement_qubits = no_measurment_qubits self.measurement_string = op.createlabel(self.no_measurement_qubits, 2) for i in range(len(self.measurement_string)): if left_justified: self.measurement_string[i] = self.measurement_string[i].ljust(self.n, '2') else: self.measurement_string[i] = self.measurement_string[i].rjust(self.n, '2') # self.projectors = {i.replace('2', ''): op.superkron(self.oper_dict, val=1, string=i) for i in # self.measurement_string} self.classical_states = {i.replace('2', ''): 0 for i in self.measurement_string} self.classical_states_history = {i.replace('2', ''): [] for i in self.measurement_string} self.hamiltonian = None self.dt = None self.U = None self.xlabel = '' self.ylabel = '' self.T = None self.kraus_operators = [] self.expect_values = {} self.yield_kraus = None self.single_kraus = None self.partial_bath= False self.no_non_ideal_qubits = 0
def stabilizer(stabilizer, n, ancilla_label): """ Stabilizer must contain only X and Z operators :param stabilizer: The stabilizer you want to measure :param ancilla_label: The ancilla_label qubit used to measure the stabilizer :param n: The number of data qubits in the circuit :return: A unitary that represents a quantum circuit that is used to measure a specific stabilizer, using CNOT and Hadamard gates """ # The numbering of qubits starts from 1 rather than 0 stabilizer_dict = {} oper_dict = {'0': id(), '1': h()} unitary = identity(pow(2, n)) for counter, s in enumerate(stabilizer, 1): if s == 'I' or s == 'i': continue else: stabilizer_dict[counter] = s for s in stabilizer_dict: if stabilizer_dict[s] == 'Z' or stabilizer_dict[s] == 'z': unitary = dot(unitary, c_u(x(), n, s, ancilla_label)) elif stabilizer_dict[s] == 'X' or stabilizer_dict[s] == 'x': string = op.generatehamiltoniantring(n, '1', onestring=True, pos=s - 1, pad='0') unitary = dot(unitary, op.superkron(oper_dict, val=1, string=string)) unitary = dot(unitary, c_u(x(), n, s, ancilla_label)) unitary = dot(unitary, op.superkron(oper_dict, val=1, string=string)) return unitary
def step_operator(self, step): """ :param step: The step in the circuit :return: Returns a the operator for the particular step in the circuit """ op_list = [] if isinstance(step, str): for s in self.bucket[step]: op_list.append(self.gate_list[s]) operators = list(map(eval, op_list)) for i in range(len(operators)): if self.check_signature(operators[i]) is not []: arg = self.arg_bucket[step][operators[i].__name__] operators[i] = operators[i](*arg) else: operators[i] = operators[i]() o = op.superkron(*operators) return o
init = '111' oper_dict = {'0': g.z()} E = [np.array([[1, 0], [0, np.cos(np.pi/10)]]), np.array([[0, np.sin(np.pi/10)], [0, 0]])] # k = ne.generic_kraus(1, classical_error=False, opers=E) # generator_kraus = ne.kraus_generator(1, classical_error=False, opers=E) # m = [op.superkron(k[i]) for i in range(len(k))] q2 = Qubit(init, 3, no_measurment_qubits=3) q2.single_kraus = E q2.dt = 0.01 q2.T = 1 q2.partial_bath = True q2.no_non_ideal_qubits = 2 # k = ne.kraus_ad(q2.n, 0.001, 10 ** (-2)) # k = ne.kraus_exact(q2.n, q2.dt, 10**(-6), 10**(-6), markovian=True) # q2.kraus_operators = m # q2.yield_kraus = generator_kraus q2.xlabel = 'time' q2.ylabel = 'Probability' q2.hamiltonian = 0.5*op.superkron(oper_dict, val=1, string='000') q2.evolve(basis='ZZZ') # print('Returned state : ', q2.measure(return_state=True)) # print('Probability distribution :', q2.classical_states) # q2.expectation_values({'X':op.superkron(g.z(), g.z(), g.z(), g.z(), g.z()), 'Y':op.superkron(g.y(), g.y(), g.y(), g.y(), g.y())}) q2.graph('111') q2.graph('011') q2.graph('001') q2.graph('000') # print(q2.expect_values)
out = np.zeros((pow(2, n), pow(2, n)), dtype=complex) if partial_bath: ideal_qubits_oper = {'0': g.id()} id_oper = op.superkron(ideal_qubits_oper, val=1, string='0' * (n - non_ideal_qubits)) for kraus in K: new_kraus = op.superkron(kraus, id_oper) out += np.dot(new_kraus, np.dot(rho_s, op.ctranspose(new_kraus))) return out else: for kraus in K: out += np.dot(kraus, np.dot(rho_s, op.ctranspose(kraus))) return out if __name__ == '__main__': state = op.superkron(g.b4(), g.b4()) state_1 = op.superkron(g.b4(), g.b4()) E = [np.array([[1, 0], [0, np.cos(np.pi / 5)]]), np.array([[0, np.sin(np.pi / 5)], [0, 0]])] kraus = generic_kraus(2, classical_error=False, opers=E) m = [op.superkron(kraus[i]) for i in range(len(kraus))] for i in range(4): print(i) generator_kraus = kraus_generator(2, non_ideal_qubits=1, partialbath=True, classical_error=False, opers=E) state = apply_kraus(generator_kraus, state, 2, non_ideal_qubits=1, partial_bath=True) print('New Method:', state) for i in range(4): state_1 = serial_decohere(m, state_1, 2) print('Old Method: ', state_1)
out = np.dot(out, self.step_operator(i)) out = op.ctranspose(out) return out def apply_unitary(self): """ Applies unitary to the quantum state """ U = self.circuit_unitary() self.qubits.operator(U) if __name__ == '__main__': # This should create a 3 qubit GHZ circuit xxx = op.superkron(g.x(), g.x(), g.x()) c = Circuit('000', measurement_qubits=3) c.add_step('h,id,id', arg_list=[[], [], []]) c.add_step('c_u', arg_list=[[g.x(), 3, 1, 2]]) c.add_step('c_u', arg_list=[[g.x(), 3, 2, 3]]) ghz = c.qubits.state # print('GHZ state : ', ghz) # This should be a Toffoli gate circuit d = Circuit('110', measurement_qubits=3) d.add_step('x,id,id', arg_list=[[], [], []]) d.add_step('id,id,r_y', arg_list=[[], [], [g.pi / 4]]) d.add_step('c_u', arg_list=[[g.x(), 3, 2, 3]]) d.add_step('id,id,r_y', arg_list=[[], [], [g.pi / 4]]) d.add_step('id,id,x', arg_list=[[], [], []])