def test_build_from_openfermion(self): print('\n') trial_state = qforte.QuantumComputer(4) trial_prep = [None] * 5 trial_prep[0] = qforte.gate('H', 0, 0) trial_prep[1] = qforte.gate('H', 1, 1) trial_prep[2] = qforte.gate('H', 2, 2) trial_prep[3] = qforte.gate('H', 3, 3) trial_prep[4] = qforte.gate('cX', 0, 1) trial_circ = qforte.QuantumCircuit() #prepare the circuit for gate in trial_prep: trial_circ.add_gate(gate) # use circuit to prepare trial state trial_state.apply_circuit(trial_circ) test_operator = QubitOperator('X2 Y1', 0.0 - 0.25j) test_operator += QubitOperator('Y2 Y1', 0.25) test_operator += QubitOperator('X2 X1', 0.25) test_operator += QubitOperator('Y2 X1', 0.0 + 0.25j) print(test_operator) qforte_operator = qforte.build_from_openfermion(test_operator) qforte.smart_print(qforte_operator) exp = trial_state.direct_op_exp_val(qforte_operator) print(exp) self.assertAlmostEqual(exp, 0.2499999999999999 + 0.0j)
def Fredkin(i, j, k): """ builds a circuit to simulate a three-qubit Fredkin gate (Controled-SWAP, CSWAP gate). :param i: control qubit 1 :param j: swap qubit 1 :param k: swap qubit 2 """ C12 = qforte.gate('cX', j, i) C32 = qforte.gate('cX', j, k) CV23 = qforte.gate('cV', k, j) CV13 = qforte.gate('cV', k, i) F_circ = qforte.Circuit() F_circ.add(C32) F_circ.add(CV23) F_circ.add(CV13) F_circ.add(C12) F_circ.add(CV23.adjoint()) F_circ.add(C32) F_circ.add(C12) return F_circ
def test_cX_gate(self): # test the cX/CNOT gate nqubits = 2 basis0 = make_basis('00') # basis0:|00> basis1 = make_basis('01') # basis1:|10> basis2 = make_basis('10') # basis2:|01> basis3 = make_basis('11') # basis3:|11> computer = Computer(nqubits) CNOT = gate('CNOT', 0, 1) # test CNOT|00> = |00> computer.set_state([(basis0, 1.0)]) computer.apply_gate(CNOT) coeff0 = computer.coeff(basis0) coeff1 = computer.coeff(basis1) coeff2 = computer.coeff(basis2) coeff3 = computer.coeff(basis3) assert coeff0 == approx(1.0, abs=1.0e-16) assert coeff1 == approx(0, abs=1.0e-16) assert coeff2 == approx(0, abs=1.0e-16) assert coeff3 == approx(0, abs=1.0e-16) # test CNOT|10> = |11> computer.set_state([(basis1, 1.0)]) computer.apply_gate(CNOT) coeff0 = computer.coeff(basis0) coeff1 = computer.coeff(basis1) coeff2 = computer.coeff(basis2) coeff3 = computer.coeff(basis3) assert coeff0 == approx(0, abs=1.0e-16) assert coeff1 == approx(0, abs=1.0e-16) assert coeff2 == approx(0, abs=1.0e-16) assert coeff3 == approx(1, abs=1.0e-16) # test CNOT|01> = |01> computer.set_state([(basis2, 1.0)]) computer.apply_gate(CNOT) coeff0 = computer.coeff(basis0) coeff1 = computer.coeff(basis1) coeff2 = computer.coeff(basis2) coeff3 = computer.coeff(basis3) assert coeff0 == approx(0, abs=1.0e-16) assert coeff1 == approx(0, abs=1.0e-16) assert coeff2 == approx(1, abs=1.0e-16) assert coeff3 == approx(0, abs=1.0e-16) # test CNOT|11> = |10> computer.set_state([(basis3, 1.0)]) computer.apply_gate(CNOT) coeff0 = computer.coeff(basis0) coeff1 = computer.coeff(basis1) coeff2 = computer.coeff(basis2) coeff3 = computer.coeff(basis3) assert coeff0 == approx(0, abs=1.0e-16) assert coeff1 == approx(1, abs=1.0e-16) assert coeff2 == approx(0, abs=1.0e-16) assert coeff3 == approx(0, abs=1.0e-16) with pytest.raises(ValueError): gate('CNOT', 0, 1.0)
def test_trotterization_with_controlled_U(self): circ_vec = [build_circuit('Y_0 X_1'), build_circuit('X_0 Y_1')] coef_vec = [-1.0719145972781818j, 1.0719145972781818j] # the operator to be exponentiated minus_iH = QubitOperator() for i in range(len(circ_vec)): minus_iH.add(coef_vec[i], circ_vec[i]) ancilla_idx = 2 # exponentiate the operator Utrot, phase = trotterization.trotterize_w_cRz(minus_iH, ancilla_idx) # Case 1: positive control # initalize a quantum computer qc = Computer(3) # build HF state qc.apply_gate(gate('X', 0, 0)) # put ancilla in |1> state qc.apply_gate(gate('X', 2, 2)) # apply the troterized minus_iH qc.apply_circuit(Utrot) smart_print(qc) coeffs = qc.get_coeff_vec() assert coeffs[5] == approx(-0.5421829373021542, abs=1.0e-15) assert coeffs[6] == approx(-0.8402604730072732, abs=1.0e-15) # Case 2: negitive control # initalize a quantum computer qc = Computer(3) # build HF state qc.apply_gate(gate('X', 0, 0)) # apply the troterized minus_iH qc.apply_circuit(Utrot) smart_print(qc) coeffs = qc.get_coeff_vec() assert coeffs[1] == approx(1, abs=1.0e-15)
def test_H2_experiment_perfect(self): print('\n') #the RHF H2 energy at equilibrium bond length E_hf = -1.1166843870661929 #the H2 qubit hamiltonian circ_vec = [ Circuit(), build_circuit('Z_0'), build_circuit('Z_1'), build_circuit('Z_2'), build_circuit('Z_3'), build_circuit('Z_0 Z_1'), build_circuit('Y_0 X_1 X_2 Y_3'), build_circuit('Y_0 Y_1 X_2 X_3'), build_circuit('X_0 X_1 Y_2 Y_3'), build_circuit('X_0 Y_1 Y_2 X_3'), build_circuit('Z_0 Z_2'), build_circuit('Z_0 Z_3'), build_circuit('Z_1 Z_2'), build_circuit('Z_1 Z_3'), build_circuit('Z_2 Z_3') ] coef_vec = [ -0.098863969784274, 0.1711977489805748, 0.1711977489805748, -0.222785930242875, -0.222785930242875, 0.1686221915724993, 0.0453222020577776, -0.045322202057777, -0.045322202057777, 0.0453222020577776, 0.1205448220329002, 0.1658670240906778, 0.1658670240906778, 0.1205448220329002, 0.1743484418396386 ] H2_qubit_hamiltonian = QubitOperator() for i in range(len(circ_vec)): H2_qubit_hamiltonian.add(coef_vec[i], circ_vec[i]) # circuit for making HF state circ = Circuit() circ.add(gate('X', 0, 0)) circ.add(gate('X', 1, 1)) TestExperiment = Experiment(4, circ, H2_qubit_hamiltonian, 1000000) params2 = [] avg_energy = TestExperiment.perfect_experimental_avg(params2) print('Perfectly Measured H2 Experimental Avg. Energy') print(avg_energy) print('H2 RHF Energy') print(E_hf) experimental_error = abs(avg_energy - E_hf) assert experimental_error == approx(0, abs=1.0e-14)
def generic_test_circ_vec_builder(qb_list, id): circ_vec_tc = [Circuit() for i in range(len(qb_list))] circ_vec_ct = [Circuit() for i in range(len(qb_list))] for i, pair in enumerate(ct_lst): t = pair[0] c = pair[1] if (id == 'cR'): circ_vec_ct[i].add(gate(id, t, c, 3.17 * t * c)) circ_vec_tc[i].add(gate(id, c, t, 1.41 * t * c)) else: circ_vec_ct[i].add(gate(id, t, c)) circ_vec_tc[i].add(gate(id, c, t)) return circ_vec_tc, circ_vec_ct
def build_from_openfermion(OF_qubitops, time_evo_factor = 1.0): """ builds a QuantumOperator instance in qforte from a openfermion QubitOperator instance :param OF_qubitops: (QubitOperator) the QubitOperator instance from openfermion. """ qforte_ops = qforte.QuantumOperator() #for term, coeff in sorted(OF_qubitops.terms.items()): for term, coeff in OF_qubitops.terms.items(): circ_term = qforte.QuantumCircuit() #Exclude zero terms if np.isclose(coeff, 0.0): continue for factor in term: index, action = factor # Read the string name for actions(gates) action_string = OF_qubitops.action_strings[OF_qubitops.actions.index(action)] #Make qforte gates and add to circuit gate_this = qforte.gate(action_string, index, index) circ_term.add_gate(gate_this) #Add this term to operator qforte_ops.add_term(coeff*time_evo_factor, circ_term) return qforte_ops
def build_circuit(Inputstr): circ = qforte.QuantumCircuit() sepstr = Inputstr.split() #Separate string to a list by space for i in range(len(sepstr)): inputgate = sepstr[i].split('_') if len(inputgate) == 2: circ.add_gate(qforte.gate(inputgate[0], int(inputgate[1]), int(inputgate[1]))) else: if 'R' in inputgate[0]: circ.add_gate(qforte.gate(inputgate[0], int(inputgate[1]), int(inputgate[1]), float(inputgate[2]))) else: circ.add_gate(qforte.gate(inputgate[0], int(inputgate[1]), int(inputgate[2]))) return circ
def build_classical_CI_mats(self): """Builds a classical configuration interaction out of single determinants. """ num_tot_basis = len(self._pre_sa_ref_lst) h_CI = np.zeros((num_tot_basis,num_tot_basis), dtype=complex) omega_lst = [] Homega_lst = [] for i, ref in enumerate(self._pre_sa_ref_lst): # NOTE: do NOT use Uprep here (is determinant specific). Un = qforte.Circuit() for j in range(self._nqb): if ref[j] == 1: Un.add(qforte.gate('X', j, j)) QC = qforte.Computer(self._nqb) QC.apply_circuit(Un) omega_lst.append(np.asarray(QC.get_coeff_vec(), dtype=complex)) Homega = np.zeros((2**self._nqb), dtype=complex) QC.apply_operator(self._qb_ham) Homega_lst.append(np.asarray(QC.get_coeff_vec(), dtype=complex)) for j in range(len(omega_lst)): h_CI[i][j] = np.vdot(omega_lst[i], Homega_lst[j]) h_CI[j][i] = np.conj(h_CI[i][j]) return h_CI
def test_op_exp_val_1(self): # test direct expectation value measurement trial_state = Computer(4) trial_prep = [None] * 5 trial_prep[0] = gate('H', 0, 0) trial_prep[1] = gate('H', 1, 1) trial_prep[2] = gate('H', 2, 2) trial_prep[3] = gate('H', 3, 3) trial_prep[4] = gate('cX', 0, 1) trial_circ = Circuit() #prepare the circuit for gate_ in trial_prep: trial_circ.add(gate_) # use circuit to prepare trial state trial_state.apply_circuit(trial_circ) # gates needed for [a1^ a2] operator X1 = gate('X', 1, 1) X2 = gate('X', 2, 2) Y1 = gate('Y', 1, 1) Y2 = gate('Y', 2, 2) # initialize circuits to make operator circ1 = Circuit() circ1.add(X2) circ1.add(Y1) circ2 = Circuit() circ2.add(Y2) circ2.add(Y1) circ3 = Circuit() circ3.add(X2) circ3.add(X1) circ4 = Circuit() circ4.add(Y2) circ4.add(X1) #build the quantum operator for [a1^ a2] a1_dag_a2 = QubitOperator() a1_dag_a2.add(0.0 - 0.25j, circ1) a1_dag_a2.add(0.25, circ2) a1_dag_a2.add(0.25, circ3) a1_dag_a2.add(0.0 + 0.25j, circ4) #get direct expectatoin value exp = trial_state.direct_op_exp_val(a1_dag_a2) assert exp == approx(0.25, abs=2.0e-16)
def test_cY_gate(self): # test the cY gate nqubits = 2 basis0 = make_basis('00') # basis0:|00> basis1 = make_basis('01') # basis1:|10> basis2 = make_basis('10') # basis2:|01> basis3 = make_basis('11') # basis3:|11> computer = Computer(nqubits) cY = gate('cY', 0, 1) # test cY|00> = |00> computer.set_state([(basis0, 1.0)]) computer.apply_gate(cY) coeff0 = computer.coeff(basis0) coeff1 = computer.coeff(basis1) coeff2 = computer.coeff(basis2) coeff3 = computer.coeff(basis3) assert coeff0 == approx(1, abs=1.0e-16) assert coeff1 == approx(0, abs=1.0e-16) assert coeff2 == approx(0, abs=1.0e-16) assert coeff3 == approx(0, abs=1.0e-16) # test cY|01> = |01> computer.set_state([(basis2, 1.0)]) computer.apply_gate(cY) coeff0 = computer.coeff(basis0) coeff1 = computer.coeff(basis1) coeff2 = computer.coeff(basis2) coeff3 = computer.coeff(basis3) assert coeff0 == approx(0, abs=1.0e-16) assert coeff1 == approx(0, abs=1.0e-16) assert coeff2 == approx(1, abs=1.0e-16) assert coeff3 == approx(0, abs=1.0e-16) # test cY|10> = i|11> computer.set_state([(basis1, 1.0)]) computer.apply_gate(cY) coeff0 = computer.coeff(basis0) coeff1 = computer.coeff(basis1) coeff2 = computer.coeff(basis2) coeff3 = computer.coeff(basis3) assert coeff0 == approx(0, abs=1.0e-16) assert coeff1 == approx(0, abs=1.0e-16) assert coeff2 == approx(0, abs=1.0e-16) assert coeff3.imag == approx(1, abs=1.0e-16) # test cY|11> = -i|10> computer.set_state([(basis3, 1.0)]) computer.apply_gate(cY) coeff0 = computer.coeff(basis0) coeff1 = computer.coeff(basis1) coeff2 = computer.coeff(basis2) coeff3 = computer.coeff(basis3) assert coeff0 == approx(0, abs=1.0e-16) assert coeff1.imag == approx(-1.0, abs=1.0e-16) assert coeff2 == approx(0, abs=1.0e-16) assert coeff3 == approx(0, abs=1.0e-16)
def test_circuit(self): print('\n') num_qubits = 10 qc1 = Computer(num_qubits) qc2 = Computer(num_qubits) prep_circ = Circuit() circ = Circuit() for i in range(num_qubits): prep_circ.add(gate('H', i, i)) for i in range(num_qubits): prep_circ.add(gate('cR', i, i + 1, 1.116 / (i + 1.0))) for i in range(num_qubits - 1): circ.add(gate('cX', i, i + 1)) circ.add(gate('cX', i + 1, i)) circ.add(gate('cY', i, i + 1)) circ.add(gate('cY', i + 1, i)) circ.add(gate('cZ', i, i + 1)) circ.add(gate('cZ', i + 1, i)) circ.add(gate('cR', i, i + 1, 3.14159 / (i + 1.0))) circ.add(gate('cR', i + 1, i, 2.17284 / (i + 1.0))) qc1.apply_circuit_safe(prep_circ) qc2.apply_circuit_safe(prep_circ) qc1.apply_circuit_safe(circ) qc2.apply_circuit(circ) C1 = qc1.get_coeff_vec() C2 = qc2.get_coeff_vec() diff_vec = [(C1[i] - C2[i]) * np.conj(C1[i] - C2[i]) for i in range(len(C1))] diff_norm = np.sum(diff_vec) print('\nNorm of diff vec |C - Csafe|') print('-----------------------------') print(' ', diff_norm) assert diff_norm == approx(0, abs=1.0e-16)
def build_Uprep(ref, state_prep_type): Uprep = qforte.Circuit() if state_prep_type == 'occupation_list': for j in range(len(ref)): if ref[j] == 1: Uprep.add(qforte.gate('X', j, j)) else: raise ValueError( "Only 'occupation_list' supported as state preparation type") return Uprep
def test_computer(self): print('\n') # test that 1 - 1 = 0 # print('\n'.join(qc.str())) X = gate('X', 0, 0) print(X) Y = gate('Y', 0, 0) print(Y) Z = gate('Z', 0, 0) print(Z) H = gate('H', 0, 0) print(H) R = gate('R', 0, 0, 0.1) print(R) S = gate('S', 0, 0) print(S) T = gate('T', 0, 0) print(T) cX = gate('cX', 0, 1) print(cX) cY = gate('cY', 0, 1) print(cY) cZ = gate('cZ', 0, 1) print(cZ) # qcircuit = Circuit() # qcircuit.add(qg) # qcircuit.add(Gate(GateType.Hgate,1,1)); # print('\n'.join(qcircuit.str())) # self.assertEqual(subtract(1, 1), 0) computer = Computer(16) # print(repr(computer)) # circuit = Circuit() # circuit.add(X) for i in range(3000): computer.apply_gate(X) computer.apply_gate(Y) computer.apply_gate(Z) computer.apply_gate(H)
def get_qft_circuit(self, direct): """Generates a circuit for Quantum Fourier Transformation with no swaping of bit positions. Arguments --------- self._abegin : int The index of the begin qubit. self._aend : int The index of the end qubit. direct : string The direction of the Fourier Transform can be 'forward' or 'reverse.' Returns ------- qft_circ : QuantumCircuit A circuit representing the Quantum Fourier Transform. """ qft_circ = qforte.QuantumCircuit() lens = self._aend - self._abegin + 1 for j in range(lens): qft_circ.add_gate(qforte.gate('H', j+self._abegin, j+self._abegin)) for k in range(2, lens+1-j): phase = 2.0*np.pi/(2**k) qft_circ.add_gate(qforte.gate('cR', j+self._abegin, j+k-1+self._abegin, phase)) if direct == 'forward': return qft_circ elif direct == 'reverse': return qft_circ.adjoint() else: raise ValueError('QFT directions can only be "forward" or "reverse"') return qft_circ
def qft_circuit(na, nb, direct): """ generates a circuit for Quantum Fourier Transformation :param na: (int) the begin qubit :param nb: (int) the end qubit :param direct: (string) the direction of the Fourier Transform can be 'forward' or 'reverse' """ # Build qft circuit qft_circ = qforte.Circuit() lens = nb - na + 1 for j in range(lens): qft_circ.add(qforte.gate('H', j + na, j + na)) for k in range(2, lens + 1 - j): phase = 2.0 * numpy.pi / (2**k) qft_circ.add(qforte.gate('cR', j + na, j + k - 1 + na, phase)) # Build reversing circuit if lens % 2 == 0: for i in range(int(lens / 2)): qft_circ.add(qforte.gate('SWAP', i + na, lens - 1 - i + na)) else: for i in range(int((lens - 1) / 2)): qft_circ.add(qforte.gate('SWAP', i + na, lens - 1 - i + na)) if direct == 'forward': return qft_circ elif direct == 'reverse': return qft_circ.adjoint() else: raise ValueError('QFT directions can only be "forward" or "reverse"') return qft_circ
def build_expansion_pool(self): print('\n==> Building expansion pool <==') self._sig = qf.QuantumOpPool() if (self._expansion_type == 'complete_qubit'): if (self._nqb > 6): raise ValueError( 'Using complete qubits expansion will result in a very large number of terms!' ) self._sig.fill_pool("complete_qubit", self._ref) elif (self._expansion_type == 'cqoy'): self._sig.fill_pool("cqoy", self._ref) elif (self._expansion_type in {'SD', 'GSD', 'SDT', 'SDTQ', 'SDTQP', 'SDTQPH'}): P = qf.SQOpPool() P.set_orb_spaces(self._ref) P.fill_pool(self._expansion_type) sig_temp = P.get_quantum_operator("commuting_grp_lex", False) # Filter the generated operators, so that only those with an odd number of Y gates are allowed. # See section "Real Hamiltonians and states" in the SI of Motta for theoretical justification. # Briefly, this method solves Ax=b, but all b elements with an odd number of Y gates are imaginary and # thus vanish. This method will not be correct for non-real Hamiltonians or states. for alph, rho in sig_temp.terms(): nygates = 0 temp_rho = qf.QuantumCircuit() for gate in rho.gates(): temp_rho.add_gate( qf.gate(gate.gate_id(), gate.target(), gate.control())) if (gate.gate_id() == "Y"): nygates += 1 if (nygates % 2 == 1): rho_op = qf.QuantumOperator() rho_op.add_term(1.0, temp_rho) self._sig.add_term(1.0, rho_op) elif (self._expansion_type == 'test'): self._sig.fill_pool("test", self._ref) else: raise ValueError('Invalid expansion type specified.') self._NI = len(self._sig.terms())
def test_X_gate(self): # test the Pauli X gate nqubits = 1 basis0 = make_basis('0') basis1 = make_basis('1') computer = Computer(nqubits) X = gate('X', 0) # test X|0> = |1> computer.apply_gate(X) coeff0 = computer.coeff(basis0) coeff1 = computer.coeff(basis1) assert coeff0 == approx(0, abs=1.0e-16) assert coeff1 == approx(1, abs=1.0e-16) # test X|1> = |0> computer.set_state([(basis1, 1.0)]) computer.apply_gate(X) coeff0 = computer.coeff(basis0) coeff1 = computer.coeff(basis1) assert coeff0 == approx(1, abs=1.0e-16) assert coeff1 == approx(0, abs=1.0e-16)
def test_Y_gate(self): # test the Pauli Y gate nqubits = 1 basis0 = make_basis('0') basis1 = make_basis('1') computer = Computer(nqubits) Y = gate('Y', 0, 0) # test Y|0> = i|1> computer.apply_gate(Y) coeff0 = computer.coeff(basis0) coeff1 = computer.coeff(basis1) assert coeff0 == approx(0, abs=1.0e-16) assert coeff1.imag == approx(1.0, abs=1.0 - 16) # test Y|1> = -i|0> computer.set_state([(basis1, 1.0)]) computer.apply_gate(Y) coeff0 = computer.coeff(basis0) coeff1 = computer.coeff(basis1) assert coeff0.imag == approx(-1, abs=1.0e-16) assert coeff1 == approx(0, abs=1.0e-16)
def test_Z_gate(self): # test the Pauli Y gate nqubits = 1 basis0 = make_basis('0') basis1 = make_basis('1') computer = Computer(nqubits) Z = gate('Z', 0, 0) # test Z|0> = |0> computer.apply_gate(Z) coeff0 = computer.coeff(basis0) coeff1 = computer.coeff(basis1) assert coeff0 == approx(1, abs=1.0e-16) assert coeff1 == approx(0, abs=1.0e-16) # test Z|1> = -|1> computer.set_state([(basis1, 1.0)]) computer.apply_gate(Z) coeff0 = computer.coeff(basis0) coeff1 = computer.coeff(basis1) assert coeff0 == approx(0, abs=1.0e-16) assert coeff1 == approx(-1.0, abs=1.0e-16)
def build_orb_energies(self): self._orb_e = [] print('\nBuilding single particle energies list:') print('---------------------------------------') qc = qforte.QuantumComputer(self._nqb) qc.apply_circuit(build_Uprep(self._ref, 'reference')) E0 = qc.direct_op_exp_val(self._qb_ham) for i in range(self._nqb): qc = qforte.QuantumComputer(self._nqb) qc.apply_circuit(build_Uprep(self._ref, 'reference')) qc.apply_gate(qforte.gate('X', i, i)) Ei = qc.direct_op_exp_val(self._qb_ham) if (i < sum(self._ref)): ei = E0 - Ei else: ei = Ei - E0 print(f' {i:3} {ei:+16.12f}') self._orb_e.append(ei)
def get_dynamics_circ(self): """Generates controlled unitaries. Ancilla qubit n controls a Trotter approximation to exp(-iHt*2^n). Returns ------- U : Circuit A circuit approximating controlled application of e^-iHt. """ U = qforte.Circuit() ancilla_idx = self._abegin temp_op = qforte.QubitOperator() scalar_terms = [] for scalar, operator in self._qb_ham.terms(): phase = -1.0j * scalar * self._t if operator.size() == 0: scalar_terms.append(scalar * self._t) else: # Strangely, the code seems to work even if this line is outside the else clause. # TODO: Figure out how. temp_op.add(phase, operator) for n in range(self._n_ancilla): tn = 2 ** n expn_op, _ = trotterize_w_cRz(temp_op, ancilla_idx, trotter_number=self._trotter_number) # Rotation for the scalar Hamiltonian term U.add(qforte.gate('R', ancilla_idx, ancilla_idx, -1.0 * np.sum(scalar_terms) * float(tn))) for i in range(tn): U.add_circuit(expn_op) ancilla_idx += 1 return U
def organizer_to_circuit(op_organizer): """Builds a Circuit from a operator orgainizer. Parameters ---------- op_organizer : list An object to organize what the coefficient and Pauli operators in terms of the QubitOperator will be. The orginzer is of the form [[coeff_a, [ ("X", i), ("Z", j), ("Y", k), ... ] ], [...] ...] where X, Y, Z are strings that indicate Pauli opterators; i, j, k index qubits and coeff_a indicates the coefficient for the ath term in the QubitOperator. """ operator = qforte.QubitOperator() for coeff, word in op_organizer: circ = qforte.Circuit() for letter in word: circ.add(qforte.gate(letter[0], letter[1], letter[1])) operator.add(coeff, circ) return operator
def build_orb_energies(self): """Calculates single qubit energies. Used in quasi-Newton updates. """ self._orb_e = [] print('\nBuilding single particle energies list:') print('---------------------------------------', flush=True) qc = qf.Computer(self._nqb) qc.apply_circuit(build_Uprep(self._ref, 'occupation_list')) E0 = qc.direct_op_exp_val(self._qb_ham) for i in range(self._nqb): qc = qf.Computer(self._nqb) qc.apply_circuit(build_Uprep(self._ref, 'occupation_list')) qc.apply_gate(qf.gate('X', i, i)) Ei = qc.direct_op_exp_val(self._qb_ham) if(i<sum(self._ref)): ei = E0 - Ei else: ei = Ei - E0 print(f' {i:3} {ei:+16.12f}', flush=True) self._orb_e.append(ei)
def get_z_circuit(self): """Generates a circuit of Z gates for each quibit in the ancilla register. Arguments --------- self._abegin : int The index of the begin qubit. self._aend : int The index of the end qubit. Returns ------- z_circ : QuantumCircuit A circuit representing the the Z gates to be measured. """ Z_circ = qforte.QuantumCircuit() for j in range(self._abegin, self._aend + 1): Z_circ.add_gate(qforte.gate('Z', j, j)) return Z_circ
def get_Uhad(self): """Generates a circuit which to puts all of the ancilla regester in superpostion. Arguments --------- self._abegin : int The index of the begin qubit. self._aend : int The index of the end qubit. Returns ------- qft_circ : QuantumCircuit A circuit of consecutive Hadamard gates. """ Uhad = qforte.QuantumCircuit() for j in range(self._abegin, self._aend + 1): Uhad.add_gate(qforte.gate('H', j, j)) return Uhad
def Toffoli(i, j, k): """ builds a circuit to simulate a three-qubit Toffoli gate (Control-Control-NOT, CCNOT gate). :param i: control qubit 1 :param j: control qubit 2 :param k: target qubit """ T1 = qforte.gate('T', i, i) T2 = qforte.gate('T', j, j) T3 = qforte.gate('T', k, k) C12 = qforte.gate('cX', j, i) C13 = qforte.gate('cX', k, i) C23 = qforte.gate('cX', k, j) H3 = qforte.gate('H', k, k) T_circ = qforte.Circuit() T_circ.add(H3) T_circ.add(C23) T_circ.add(T3.adjoint()) T_circ.add(C13) T_circ.add(T3) T_circ.add(C23) T_circ.add(T3.adjoint()) T_circ.add(C13) T_circ.add(T2) T_circ.add(T3) T_circ.add(C12) T_circ.add(H3) T_circ.add(T1) T_circ.add(T2.adjoint()) T_circ.add(C12) return T_circ
def exponentiate_single_term(coefficient, term, Use_cRz=False, ancilla_idx=None, Use_open_cRz=False): """ returns the exponential of an string of Pauli operators multiplied by an imaginary coefficient exp(coefficient * term) Parameters ---------- :param coefficient: float an imaginary coefficient that multiplies the Pauli string :param term: QuantumCircuit a Pauli string to be exponentiated """ # This function assumes that the factor is imaginary. The following tests for it. if np.abs(np.real(coefficient)) > 1.0e-16: print("exp factor: ", coefficient) raise ValueError( 'exponentiate_single_term() called with a real coefficient') # If the Pauli string has no terms this is just a phase factor if term.size() == 0: return (qforte.QuantumCircuit(), np.exp(coefficient)) exponential = qforte.QuantumCircuit() to_z = qforte.QuantumCircuit() to_original = qforte.QuantumCircuit() cX_circ = qforte.QuantumCircuit() prev_target = None max_target = None for gate in term.gates(): id = gate.gate_id() target = gate.target() control = gate.control() if (id == 'X'): to_z.add_gate(qforte.gate('H', target, control)) to_original.add_gate(qforte.gate('H', target, control)) elif (id == 'Y'): to_z.add_gate(qforte.gate('Rzy', target, control)) to_original.add_gate(qforte.gate('Rzy', target, control)) elif (id == 'I'): continue if (prev_target is not None): cX_circ.add_gate(qforte.gate('cX', target, prev_target)) prev_target = target max_target = target # Gate that actually contains the parameterization for the term # TODO(Nick): investigate real/imaginary usage of 'factor' in below expression if (Use_cRz): z_rot = qforte.gate('cRz', max_target, ancilla_idx, -2.0 * np.imag(coefficient)) else: z_rot = qforte.gate('Rz', max_target, max_target, -2.0 * np.imag(coefficient)) # Assemble the actual exponential exponential.add_circuit(to_z) exponential.add_circuit(cX_circ) if (Use_open_cRz): exponential.add_gate(qforte.gate('X', ancilla_idx, ancilla_idx)) exponential.add_gate(z_rot) if (Use_open_cRz): exponential.add_gate(qforte.gate('X', ancilla_idx, ancilla_idx)) adj_cX_circ = cX_circ.adjoint() exponential.add_circuit(adj_cX_circ) adj_to_z = to_z.adjoint() exponential.add_circuit(adj_to_z) return (exponential, 1.0)
def build_qk_mats(self): num_tot_basis = len(self._single_det_refs) * self._nstates_per_ref h_mat = np.zeros((num_tot_basis,num_tot_basis), dtype=complex) s_mat = np.zeros((num_tot_basis,num_tot_basis), dtype=complex) # TODO (opt): make numpy arrays. omega_lst = [] Homega_lst = [] for i, ref in enumerate(self._single_det_refs): for m in range(self._nstates_per_ref): # NOTE: do NOT use Uprep here (is determinant specific). Um = qforte.Circuit() for j in range(self._nqb): if ref[j] == 1: Um.add(qforte.gate('X', j, j)) phase1 = 1.0 if(m>0): fact = (0.0-1.0j) * m * self._mr_dt expn_op1, phase1 = trotterize(self._qb_ham, factor=fact, trotter_number=self._trotter_number) Um.add(expn_op1) QC = qforte.Computer(self._nqb) QC.apply_circuit(Um) QC.apply_constant(phase1) omega_lst.append(np.asarray(QC.get_coeff_vec(), dtype=complex)) QC.apply_operator(self._qb_ham) Homega_lst.append(np.asarray(QC.get_coeff_vec(), dtype=complex)) if(self._diagonalize_each_step): print('\n\n') print(f"{'k(S)':>7}{'E(Npar)':>19}{'N(params)':>14}{'N(CNOT)':>18}{'N(measure)':>20}") print('-------------------------------------------------------------------------------') for p in range(num_tot_basis): for q in range(p, num_tot_basis): h_mat[p][q] = np.vdot(omega_lst[p], Homega_lst[q]) h_mat[q][p] = np.conj(h_mat[p][q]) s_mat[p][q] = np.vdot(omega_lst[p], omega_lst[q]) s_mat[q][p] = np.conj(s_mat[p][q]) if (self._diagonalize_each_step): # TODO (cleanup): have this print to a separate file evals, evecs = canonical_geig_solve(s_mat[0:p+1, 0:p+1], h_mat[0:p+1, 0:p+1], print_mats=False, sort_ret_vals=True) scond = np.linalg.cond(s_mat[0:p+1, 0:p+1]) cs_str = '{:.2e}'.format(scond) k = p+1 self._n_classical_params = k if(k==1): self._n_cnot = self._srqk._n_cnot else: self._n_cnot = 2 * Um.get_num_cnots() self._n_pauli_trm_measures = k * self._Nl + self._srqk._n_pauli_trm_measures self._n_pauli_trm_measures += k * (k-1) * self._Nl self._n_pauli_trm_measures += k * (k-1) print(f' {scond:7.2e} {np.real(evals[self._target_root]):+15.9f} {self._n_classical_params:8} {self._n_cnot:10} {self._n_pauli_trm_measures:12}') return s_mat, h_mat
def get_dynamics_circ(self): """Generates a circuit for controlled dynamics operations used in phase estimation. It approximates the exponentiated hermetina operator H as e^-iHt. Arguments --------- H : QuantumOperator The hermetian operaotr whos dynamics and eigenstates are of interest, ususally the Hamiltonian. trotter_num : int The trotter number (m) to use for the decompostion. Exponentiation is exact in the m --> infinity limit. self._abegin : int The index of the begin qubit. n_ancilla : int The number of anciall qubit used for the phase estimation. Determintes the total number of time steps. t : float The total evolution time. Returns ------- Udyn : QuantumCircuit A circuit approximating controlled application of e^-iHt. """ Udyn = qforte.QuantumCircuit() ancilla_idx = self._abegin total_phase = 1.0 for n in range(self._n_ancilla): tn = 2 ** n temp_op = qforte.QuantumOperator() scaler_terms = [] for h in self._qb_ham.terms(): c, op = h phase = -1.0j * self._t * c #* tn temp_op.add_term(phase, op) gates = op.gates() if op.size() == 0: scaler_terms.append(c * self._t) expn_op, phase1 = trotterize_w_cRz(temp_op, ancilla_idx, trotter_number=self._trotter_number) # Rotation for the scaler Hamiltonian term Udyn.add_gate(qforte.gate('R', ancilla_idx, ancilla_idx, -1.0 * np.sum(scaler_terms) * float(tn))) # NOTE: Approach uses 2^ancilla_idx blocks of the time evolution circuit for i in range(tn): for gate in expn_op.gates(): Udyn.add_gate(gate) ancilla_idx += 1 return Udyn