def compile(self, circuit): # need to compile Hadamard gates # take over to tq compiler at some point compiled = [] for gate in circuit.gates: if gate.name.lower() == "h": angle = gate.parameter if hasattr(gate, "parameter") else 1.0 decomposed = tq.QCircuit() decomposed += tq.gates.Ry(angle=-numpy.pi / 4, target=gate.target) decomposed += tq.gates.Rz(angle=angle * numpy.pi, target=gate.target, control=gate.control) decomposed += tq.gates.Ry(angle=numpy.pi / 4, target=gate.target) compiled += decomposed.gates else: compiled.append(gate) return tq.QCircuit(gates=compiled)
def run_ising_circuits(n_qubits, g=1.0, *args, **kwargs): H = simplified_ising(n_qubits=n_qubits, g=g) if n_qubits < 10: exact_gs = numpy.linalg.eigvalsh(H.to_matrix())[0] else: exact_gs = None # orquestra workaround if "generators" in kwargs: kwargs["generators"] = json.loads(kwargs["generators"]) if "fix_angles" in kwargs: kwargs["fix_angles"] = yaml.load(kwargs["fix_angles"], Loader=yaml.SafeLoader) if "connectivity" in kwargs: kwargs["connectivity"] = yaml.load(kwargs["connectivity"], Loader=yaml.SafeLoader) # initial mean-field like state n_qubits = H.n_qubits UMF = sum([tq.gates.Ry(angle=("a", q), target=q) for q in range(n_qubits)],tq.QCircuit()) # encoder to save circuits as string encoder = CircuitGenEncoder() # solve "mean field" EMF = tq.ExpectationValue(H=H, U=UMF) result = tq.minimize(EMF) result_dict = {"schema":"schema"} result_dict["data"] = test_circuits(H=H, UMF=UMF, mf_variables=result.variables, *args, **kwargs) result_dict["kwargs"]=kwargs result_dict["g"]=g result_dict["exact_ground_state"]=exact_gs result_dict["mean_field_energy"]=float(result.energy) with open("isingdata.json", "w") as f: f.write(json.dumps(result_dict, indent=2))
def ans4(num_qubits, layers, arg, enc): U = tq.QCircuit() for l in range(layers): # Layer single-qubit gates for q in range(num_qubits): # No encoding: if enc == False: theta = tq.Variable(name="th_{}{}".format(l, q)) phi = tq.Variable(name="ph_{}{}".format(l, q)) U += tq.gates.Rx(target=q, angle=theta) + tq.gates.Rz(target=q, angle=phi) # Encoding: if enc == True: theta = tq.Variable(name="thenc_{}{}".format(l, q)) phi = tq.Variable(name="phenc_{}{}".format(l, q)) wth = tq.Variable(name="thw_{}{}".format(l, q)) wph = tq.Variable(name="phw_{}{}".format(l, q)) U += tq.gates.Rx(target=q, angle=wth*arg + theta) + tq.gates.Rz(target=q, angle=wph*arg + phi) # Layer XX gates # no encoding in entangling gates # SAME entangling gates U += XX(0,1,"a") + XX(2,3,"b") + XX(1,2,"c") + XX(0,3,"d") + XX(0,2,"e") + XX(1,3,"f") #if enc == False: #U += XX(0,1, "a{}".format(l)) + XX(2,3,"b{}".format(l)) + XX(1,2,"c{}".format(l)) + XX(0,3,"d{}".format(l)) + XX(0,2,"e{}".format(l)) + XX(1,3,"f{}".format(l)) #if enc == True: # U += XX(0,1, "aw{}".format(l)) + XX(2,3,"bw{}".format(l)) + XX(1,2,"cw{}".format(l)) + XX(0,3,"dw{}".format(l)) + XX(0,2,"ew{}".format(l)) + XX(1,3,"fw{}".format(l)) return (U)
def get_qubit_wise(self, binary=False): ''' Return the qubit-wise form of the current binary hamiltonian. And the unitary transformation U, where U = prod_i (1/2) ** (1/2) * (lagrangian_basis[i] + new_basis[i]) Parameters ---------- binary : determines whether the returned qwc hamiltonian is binary or qubit hamiltonian Returns ------- hamiltonian : BinaryHamiltonian or QubitHamiltonian The original hamiltonian in qubit-wise commuting form U : QCircuit The unitary circuit that transforms the original hamiltonian into qwc form ''' if not self.is_commuting(): raise TequilaException( 'Not all terms in the Hamiltonians are commuting.') if self.is_qubit_wise_commuting(): qubit_wise_hamiltonian = self qwc_u = tq.QCircuit() else: qubit_wise_hamiltonian, lagrangian_basis, new_basis = self.single_qubit_form( ) # Constructing the unitary that rotates into qubit-wise parts qwc_u = tq.QCircuit() for i in range(len(lagrangian_basis)): sigma = lagrangian_basis[i].to_pauli_strings() tau = new_basis[i].to_pauli_strings() qwc_u += tq.gates.ExpPauli(angle=-tq.numpy.pi / 2, paulistring=sigma) qwc_u += tq.gates.ExpPauli(angle=-tq.numpy.pi / 2, paulistring=tau) qwc_u += tq.gates.ExpPauli(angle=-tq.numpy.pi / 2, paulistring=sigma) single_qub_u = qubit_wise_hamiltonian.z_form() # Return the basis in terms of Binary Hamiltonian if binary: return qubit_wise_hamiltonian, qwc_u + single_qub_u else: return qubit_wise_hamiltonian.to_qubit_hamiltonian( ), qwc_u + single_qub_u
def prune_circuit(self, circuit, variables, threshold=1.e-4): gates = [] for gate in circuit.gates: if hasattr(gate, "parameter"): angle = self.fix_periodicity(gate.parameter(variables)) if not numpy.isclose(angle, 0.0, atol=threshold): gates.append(gate) else: gates.append(gate) if len(gates) != len(circuit.gates): print("pruned from {} to {}".format(len(circuit.gates), len(gates))) return tq.QCircuit(gates=gates)
def decode(self, string: str, variables: dict = None): string_gates = string.split(self.gate_separator) circuit = tq.QCircuit() for gate in string_gates: gate = gate.strip() if gate == "": continue angle, gate = gate.split(self.angle_separator) try: angle = float(angle) except: angle = angle.strip() if angle == "": angle = 1.0 elif variables is not None and angle in variables: angle = variables[angle] ps = self.decode_paulistring(input=gate) circuit += tq.gates.ExpPauli(paulistring=ps, angle=angle) return circuit
def make_random_constant_depth_circuit(self, depth, past_moment=None): connectivity = self.connectivity circuit = tq.QCircuit() primitives = self.generators if past_moment is None: past_moment = [] else: if hasattr(past_moment, "gates"): past_moment = [g.make_generator().paulistrings[0] for g in past_moment.gates] for moment in range(depth): qubits = list(connectivity.keys()) current_moment = [] while (len(qubits) > 0): try: p = numpy.random.choice(primitives, 1)[0] q0 = int(numpy.random.choice(qubits, 1, replace=False)[0]) available_connections = [x for x in connectivity[q0] if x in qubits] q = [q0] if len(p) > 1: q += list(numpy.random.choice(available_connections, len(p) - 1, replace=False)) ps = tq.PauliString(data={q[i]: p[i] for i in range(len(p))}) current_moment.append(ps) if ps in past_moment: # will result in not adding the gate qubits = [x for x in qubits if x not in q] continue angle = "a_{}_{}".format(p, len(circuit.gates)) if p in self.fix_angles: angle = self.fix_angles[p] circuit += tq.gates.ExpPauli(paulistring=str(ps), angle=angle) qubits = [x for x in qubits if x not in q] except ValueError as E: print("failed", "\n", str(E)) print(qubits) continue past_moment = current_moment return circuit
def z_form(self): ''' Parameters ---------- self : BinaryHamiltonian a qubit-wise commuting hamiltonian Modifies ---------- self : BinaryHamiltoina The original hamiltonian but in qubit-wise commuting form with all z Returns ---------- U : QCircuit the single qubit transformation that rotates each term to z ''' U = tq.QCircuit() non_z = {} for p in self.binary_terms: for qub in range(self.n_qubit): z_data = {qub: 'z'} if p.has_x(qub): p.set_z(qub) non_z[qub] = 'x' elif p.has_y(qub): p.set_z(qub) non_z[qub] = 'y' for qub, term in non_z.items(): xy_data = {qub: term} z_data = {qub: 'z'} U += tq.gates.ExpPauli(angle=-tq.numpy.pi / 2, paulistring=tq.PauliString(z_data)) U += tq.gates.ExpPauli(angle=-tq.numpy.pi / 2, paulistring=tq.PauliString(xy_data)) U += tq.gates.ExpPauli(angle=-tq.numpy.pi / 2, paulistring=tq.PauliString(z_data)) return U
def manual_ansatz(n_qubits, n_layers=1, connectivity=None, static=False): # no pbc U = tq.QCircuit() for l in range(n_layers): for q in range(n_qubits): angle = (l,q,0) if not static else (l,0) angle = tq.assign_variable(angle) U += tq.gates.Ry(angle=angle*numpy.pi, target=q) for q in range(n_qubits//2): angle = (l, 2*q,2*q+1, 1) if not static else 1.0 angle = tq.assign_variable(angle) U += tq.gates.ExpPauli(paulistring="X({})Y({})".format(2*q,2*q+1), angle=angle*numpy.pi) #U += tq.gates.ExpPauli(paulistring="Y({})X({})".format(2*q,2*q+1), angle=angle*numpy.pi) # for q in range(n_qubits): # angle = (l, q,1) if not static else (l,1) # U += tq.gates.Ry(angle=angle, target=q) for q in range(n_qubits//2-1): angle = (l, 2*q+1, 2*q+2, 1) if not static else 1.0 angle = tq.assign_variable(angle) U += tq.gates.ExpPauli(paulistring="X({})Y({})".format(2*q+1,(2*q+2)%n_qubits), angle=angle*numpy.pi) #U += tq.gates.ExpPauli(paulistring="Y({})X({})".format(2*q+1,(2*q+2)%n_qubits), angle=angle*numpy.pi) return U
initial_state = "|1>_a|1>_b" # Notation has to be consistent with your S trotter_steps = 20 # number of trotter steps for the BeamSplitter samples = 1000 # number of samples to simulate simulator = None # Pick the Simulator (None -> let tequila do it) t = 0.25 # beam-splitter parameter setup = PhotonicSetup(pathnames=['a', 'b'], S=S, qpm=qpm) # the beam splitter is parametrized as phi=i*pi*t setup.add_beamsplitter(path_a='a', path_b='b', t=t, steps=trotter_steps) # need explicit circuit for initial state state = setup.initialize_state(state=initial_state) # can only do product states right now, alltough more general ones are possible # with code adaption Ui = tq.QCircuit() assert (len(state.state) == 1) key = [k for k in state.state.keys()][0] for i, q in enumerate(key.array): if q == 1: Ui += tq.gates.X(target=i) # full circuit (initial state plus mapped HOM setup) U = Ui + setup.setup + tq.gates.Measurement(target=[0, 1, 2, 3]) print(U) # those are the qubit counts given back by tequila qcounts = tq.simulate(U, samples=samples) # those are the qubit counts re-interpreted as photonic counts pcounts = PhotonicStateVector(paths=setup.paths, state=qcounts)