def __init__(self, N, verbose=False, drawing=False, bounds=(-0.05, 0.05), shots=0, sym_translation=False, sym_reflection=False, name='Unnamed'): """ Args: N (int): number of qubits verbose (bool): whether or not to output messages about the circuit drawing (bool): whether to draw the circuit instead of computing bounds (tuple): lower and upper bound for random initial parameters shots (int): number of shots for evaluation sym_translation (bool): whether or not the circuit and the Hamiltonian are invariant under translation sym_reflection (bool): whether or not the circuit and Hamiltonian are invariant under reflection. requires sym_translation=True name (str): name of the circuit Returns: Sets: N (arg) verbose (arg) drawing (arg) bounds (arg) shots (arg) sym_translation (arg) sym_reflection (arg) eng (projectq.MainEngine) name (arg) Comments: draw() requires drawing=True sym_reflection=True requires sym_translation=True """ # if we use reflection symmetry, require translation symmetry and N%2=0 if sym_reflection: assert sym_translation, ('Only use sym_reflection together with ' 'sym_translation') assert N % 2 == 0, ('Only use sym_reflection for even N') self.N = N self.verbose = verbose self.drawing = drawing self.bounds = bounds self.shots = shots self.sym_translation = sym_translation self.sym_reflection = sym_reflection self.name = name if drawing: self.eng = pq.MainEngine(backend=pq.backends.CircuitDrawer(), engine_list=[]) else: self.eng = pq.MainEngine(backend=pq.backends.Simulator(), engine_list=[])
def test_trotter_order_does_not_matter_for_high_trotter_number(self): size = 4 hamiltonian = dual_basis_hamiltonian(n_dimensions=1, system_size=size) hamiltonian.compress() eng1 = projectq.MainEngine() eng2 = projectq.MainEngine() reg1 = eng1.allocate_qureg(size) reg2 = eng2.allocate_qureg(size) eng1.flush() eng2.flush() # Choose random state. state = numpy.zeros(2**size, dtype=complex) for i in range(len(state)): state[i] = (random.random() * numpy.exp(1j * 2 * numpy.pi * random.random())) state /= numpy.linalg.norm(state) # Put randomly chosen state in the registers. eng1.backend.set_wavefunction(state, reg1) eng2.backend.set_wavefunction(state, reg2) # Swap and change the input ordering for reg1. These operations should # cancel each other out. projectq.ops.Swap | (reg1[1], reg1[2]) projectq.ops.C(projectq.ops.Z) | (reg1[1], reg1[2]) _low_depth_trotter_simulation.simulate_dual_basis_evolution( reg1, hamiltonian=hamiltonian, trotter_steps=7, input_ordering=[0, 2, 1, 3], first_order=False) _low_depth_trotter_simulation.simulate_dual_basis_evolution( reg2, hamiltonian=hamiltonian, trotter_steps=7, first_order=False) # Undo the inital swaps on reg1. projectq.ops.Swap | (reg1[1], reg1[2]) projectq.ops.C(projectq.ops.Z) | (reg1[1], reg1[2]) projectq.ops.All(projectq.ops.H) | reg1 eng1.flush() projectq.ops.All(projectq.ops.H) | reg2 eng2.flush() self.assertTrue( numpy.allclose(ordered_wavefunction(eng1), ordered_wavefunction(eng2), atol=1e-2)) projectq.ops.All(projectq.ops.Measure) | reg1 projectq.ops.All(projectq.ops.Measure) | reg2
def d_cal(vec1, vec2): """ a function that calculate the euclid distance in a quantum way :param vec1: a list form vector, like [1, 2, 3, 5], totally 2^n elements :param vec2: a list form vector, with the same shape of vec1 :return: distance between vec1 and vec2 """ # first normalize the two vectors: norm1 = np.linalg.norm(np.array(vec1)) norm2 = np.linalg.norm(np.array(vec2)) print(norm1, norm2) theta = np.arcsin(abs(norm1 / np.sqrt(norm1**2 + norm2**2))) u_wavefun = vec1 / norm1 v_wavefun = vec2 / norm2 wavefun = (np.kron(np.array([1, 0]), np.array(u_wavefun)) + np.kron(np.array([0, 1]), np.array(v_wavefun))) / np.sqrt(2) # print(wavefun) # projectq setup eng = projectq.MainEngine() qureg = eng.allocate_qureg(int(np.log2(len(vec1))) + 1) eng.flush() eng.backend.set_wavefunction(wavefun, qureg) H | qureg[-1] Ry(2 * theta - np.pi / 2) | qureg[-1] eng.flush() prop = eng.backend.get_probability('1', [qureg[-1]]) Measure | qureg print(prop) return np.sqrt(2 * prop * (norm1**2 + norm2**2))
def reset(self): """Reset/initialize the device by initializing the backend and engine, and allocating qubits. """ backend = pq.backends.ClassicalSimulator( **self.filter_kwargs_for_backend(self._kwargs)) self._eng = pq.MainEngine(backend, verbose=self._kwargs['verbose']) super().reset()
def __init__(self, x, y, n_qubits, epoch): """ Initialization of the class :param x: (ndarray, shape(num_data, 2)), two elements represents HR and VR :param y: (ndarray, shape(num_data, 1)), label of corresponding data :param n_qubits: the number of qubits that represent one element of a vector in x :param epoch: the maximum iteration of the optimization """ n = len(x) self.train_x = x[0:(n - round(n / 6))] self.train_y = y[0:(n - round(n / 6))] self.test_x = x[(n - round(n / 6)):] self.test_y = y[(n - round(n / 6)):] self.epoch = epoch self.n_qubits1data = n_qubits self.n_qubits = len( self.train_x[0] ) * n_qubits + 2 # two qubits for one ancilla qubit and one output qubit self.alpha = np.pi * np.random.rand( len(self.train_x[0]) + 1) - np.pi / 2 # the last one is the bios self.init_wavefun = np.zeros(len(self.train_x[0])**self.n_qubits) self.init_wavefun[0] = 1 # set the wave_function to |0> self.eng = projectq.MainEngine() self.qureg = self.eng.allocate_qureg(self.n_qubits) self.eng.flush() self.data2theta( self.train_x) # transform the data into binary representation self.data2theta(self.test_x) self.loss = []
def test_restriction(): engine_list = grid_setup.get_engine_list(num_rows=3, num_columns=2, one_qubit_gates=(Rz, H), two_qubit_gates=(CNOT, AddConstant)) backend = DummyEngine(save_commands=True) eng = projectq.MainEngine(backend, engine_list) qubit1 = eng.allocate_qubit() qubit2 = eng.allocate_qubit() qubit3 = eng.allocate_qubit() eng.flush() CNOT | (qubit1, qubit2) H | qubit1 Rz(0.2) | qubit1 Measure | qubit1 Swap | (qubit1, qubit2) Rx(0.1) | (qubit1) AddConstant(1) | qubit1 + qubit2 + qubit3 eng.flush() assert backend.received_commands[4].gate == X assert len(backend.received_commands[4].control_qubits) == 1 assert backend.received_commands[5].gate == H assert backend.received_commands[6].gate == Rz(0.2) assert backend.received_commands[7].gate == Measure for cmd in backend.received_commands[7:]: assert cmd.gate != Swap assert not isinstance(cmd.gate, Rx) assert not isinstance(cmd.gate, AddConstant)
def __init__(self, v_input, v_output): self.v_in = v_input self.v_tgt = v_output self.theta = np.pi * (np.random.rand(3)) self.eng = projectq.MainEngine() self.qureg = self.eng.allocate_qureg(1) self.eng.flush()
def test_chooser_Ry_reducer(): # Without the chooser_Ry_reducer function, i.e. if the restricted gate set # just picked the first option in each decomposition list, the circuit # below would be decomposed into 8 single qubit gates and 1 two qubit # gate. # # Including the Allocate, Measure and Flush commands, this would result in # 13 commands. # # Using the chooser_Rx_reducer you get 10 commands, since you now have 4 # single qubit gates and 1 two qubit gate. for engine_list, count in [ (restrictedgateset.get_engine_list(one_qubit_gates=(Rx, Ry), two_qubit_gates=(Rxx, )), 13), (get_engine_list(), 11) ]: backend = DummyEngine(save_commands=True) eng = projectq.MainEngine(backend, engine_list, verbose=True) qubit1 = eng.allocate_qubit() qubit2 = eng.allocate_qubit() H | qubit1 CNOT | (qubit1, qubit2) Rz(0.2) | qubit1 Measure | qubit1 eng.flush() assert len(backend.received_commands) == count
def test_average_fidelity_on_bit_flip_chanel(): r"""Test the average fidelity of the bit flip map.""" qubits = 1 dim = 2**qubits for i, prob_error in enumerate([1., 0.5, 0.25]): # Test different probabilities # Obtain the actual true answer kraus = [np.sqrt(1 - prob_error) * np.eye(dim), np.sqrt(prob_error) * np.array([[0., 1.], [1., 0.]])] true_answer = (np.abs(np.trace(kraus[0]))**2 + np.abs(np.trace(kraus[1]))**2 + dim) /\ (dim**2 + dim) # Construct the channel and perform average fidelity estimation. eng = projectq.MainEngine() register = eng.allocate_qureg(qubits) eng.flush() # Need to flush it in order to set_wavefunction def bit_flip(engine, register): rando = np.random.random() # Get uniform random number from zero to one.. if rando < prob_error: # If it is less than probability of error. XGate() | register engine.flush() chan_dev = QDeviceChannel(eng, register, bit_flip) fidelity = chan_dev.estimate_average_fidelity_channel(500, 0.001, cheat=bool(i % 2)) assert np.abs(fidelity - true_answer) < 1e-1
def test_state_preparation(n_qubits, zeros): engine_list = restrictedgateset.get_engine_list(one_qubit_gates=(Ry, Rz, Ph)) eng = projectq.MainEngine(engine_list=engine_list) qureg = eng.allocate_qureg(n_qubits) eng.flush() f_state = [ 0.2 + 0.1 * x * cmath.exp(0.1j + 0.2j * x) for x in range(2**n_qubits) ] if zeros: for i in range(2**(n_qubits - 1)): f_state[i] = 0 norm = 0 for amplitude in f_state: norm += abs(amplitude)**2 f_state = [x / math.sqrt(norm) for x in f_state] StatePreparation(f_state) | qureg eng.flush() wavefunction = deepcopy(eng.backend.cheat()[1]) # Test that simulator hasn't reordered wavefunction mapping = eng.backend.cheat()[0] for key in mapping: assert mapping[key] == key All(Measure) | qureg eng.flush() assert np.allclose(wavefunction, f_state, rtol=1e-10, atol=1e-10)
def test_inverse_of_unitary_two_design(): r"""Test inverse of unitary two design with the unitary two design is the identity.""" eng = projectq.MainEngine() register = eng.allocate_qureg(4) eng.flush() # Need to flush it in order to set_wavefunction def identity(engine): pass chan_dev = ProjectQDeviceAdaptor(eng, register) for index in range(0, 2 ** 4): for _ in range(0, 25): # Set the wave-function to match the basis state. zero = [0.] * (2**4) zero[index] = 1 # Turn Probability is one on the that basis state. eng.backend.set_wavefunction(zero, register) eng.flush() epsilon = 1 phases = chan_dev.approximate_unitary_two_design(epsilon) chan_dev.inverse_of_unitary_two_design(phases) wave_function_after = np.array(eng.backend.cheat()[1]) assert np.all(np.abs(wave_function_after - np.array(zero)) < 1e-3) All(Measure) | register
def uccsd_trotter_engine(compiler_backend=projectq.backends.Simulator(), qubit_graph=None, opt_size=None): """Define a ProjectQ compiler engine that is common for use with UCCSD This defines a ProjectQ compiler engine that decomposes time evolution gates using a first order Trotter decomposition on non-commuting gates down to a base gate decomposition. Args: compiler_backend(projectq.backend): Define the backend on the circuit compiler, so that it may either simulate gates numerically or alternatively print a gate sequence, e.g. using projectq.backends.CommandPrinter() qubit_graph(Graph): Graph object specifying connectivity of qubits. The values of the nodes of this unique qubit ids. If None, all-to-all connectivity is assumed. opt_size(int): Number for ProjectQ local optimizer to determine size of blocks optimized over. Returns: projectq.cengine that is the compiler engine set up with these rules and decompostions. """ rule_set = (projectq.cengines.DecompositionRuleSet( modules=[projectq.setups.decompositions])) # Set rules for splitting non-commuting operators trotter_rule_set = (projectq.cengines.DecompositionRule( gate_class=TimeEvolution, gate_decomposer=_first_order_trotter, gate_recognizer=_identify_non_commuting)) rule_set.add_decomposition_rule(trotter_rule_set) # Set rules for 2 qubit gates that act on non-adjacent qubits if qubit_graph is not None: connectivity_rule_set = (projectq.cengines.DecompositionRule( gate_class=projectq.ops.NOT.__class__, gate_decomposer=(lambda x: _direct_graph_swap(x, qubit_graph)), gate_recognizer=( lambda x: _non_adjacent_filter(None, x, qubit_graph, True)))) rule_set.add_decomposition_rule(connectivity_rule_set) # Build the full set of engines that will be applied to qubits replacer = projectq.cengines.AutoReplacer(rule_set) compiler_engine_list = [ replacer, projectq.cengines.InstructionFilter(lambda x, y: (_non_adjacent_filter( x, y, qubit_graph) and _two_gate_filter(x, y))) ] if opt_size is not None: compiler_engine_list.append(projectq.cengines.LocalOptimizer(opt_size)) # Start the compiler engine with these rules compiler_engine = (projectq.MainEngine(backend=compiler_backend, engine_list=compiler_engine_list)) return compiler_engine
def __init__(self): self.theta = np.random.rand(2*3*3).reshape(3, 2, 3) self.data = [(0, 0), (1, 0), (0, 1), (1, 1)] self.label = [0, 1, 1, 0] self.loss = [] self.eng = projectq.MainEngine() self.qureg = self.eng.allocate_qureg(2) self.eng.flush()
def test_PermutePi4Front(): eng = projectq.MainEngine() perm = PermutePi4Front() qubit = eng.allocate_qubit() perm.next_engine = A() perm.receive([X.generate_command(qubit)]) perm.receive([Y.generate_command(qubit)]) perm.receive([T.generate_command(qubit)]) perm.receive([FlushGate().generate_command(qubit)]) return
def reset(self): """Reset/initialize the device by initializing the backend and engine, and allocating qubits. """ backend = pq.backends.IBMBackend(num_runs=self.shots, **self.filter_kwargs_for_backend( self._kwargs)) self._eng = pq.MainEngine(backend, verbose=self._kwargs['verbose'], engine_list=pq.setups.ibm.get_engine_list()) super().reset()
def mv(v): eng = projectq.MainEngine(backend=Simulator(), engine_list=[]) qureg = eng.allocate_qureg(n_sites) eng.flush() eng.backend.set_wavefunction(v, qureg) eng.backend.apply_qubit_operator(hamiltonian, qureg) order, output = deepcopy(eng.backend.cheat()) for i in order: assert i == order[i] eng.backend.set_wavefunction([1] + [0] * (2**n_sites - 1), qureg) return output
def test_simple1(): eng = projectq.MainEngine( engine_list=[BasisRotation()], backend=OpenSurgeryExporter(output="test_simple_case1"), verbose=True) qubit1 = eng.allocate_qubit() qubit2 = eng.allocate_qubit() gates.T | qubit2 ParityMeasurementGate("Z0 X1") | qubit1 + qubit2 eng.flush() del qubit1 del qubit2 #assert(False) #now check output with open("test_simple_case1") as fin: line = fin.readline() line = line.strip() assert (line == "INIT 2") line = fin.readline() line = line.strip() assert (line == "NEED A") line = fin.readline() line = line.strip() assert (line == "MZZ A 1") line = fin.readline() line = line.strip() assert (line == "MX A") line = fin.readline() line = line.strip() assert (line == "S ANCILLA") line = fin.readline() line = line.strip() assert (line == "MXX ANCILLA 1") line = fin.readline() line = line.strip() assert (line == "H 1") line = fin.readline() line = line.strip() assert (line == "MZZ 0 1") os.remove("test_simple_case1")
def evl(psi0, ops, n_qubits): eng = projectq.MainEngine() wavefunction = eng.allocate_qureg(n_qubits) eng.flush() eng.backend.set_wavefunction(psi0, wavefunction) ops | wavefunction[0] eng.flush() psi = eng.backend.cheat()[1] All(Measure) | wavefunction return psi
def __init__(self, node, num, maxQubits=10): """ Initialize the simple engine. If no number is given for maxQubits, the assumption will be 10. """ super().__init__(node=node, num=num, maxQubits=maxQubits) # We start with no active qubits self.activeQubits = 0 self.eng = pQ.MainEngine() self.qubitReg = []
def test_or(): a = Debugger() engine_list = [a] eng = projectq.MainEngine(engine_list=engine_list, backend=CommandPrinter()) q1 = eng.allocate_qubit() q2 = eng.allocate_qubit() ParityMeasurementGate("Z0 X1") | q1 + q2 assert (a.commands[-1].gate._bases[0][0] == 0) assert (a.commands[-1].gate._bases[0][1] == "Z")
def simulate_chp_files(): # Initialize the Clifford simulator engine_list = [MultiqubitMeasurementCliffordEngine()] engine = projectq.MainEngine(engine_list=engine_list) engine_list[0].next_engine = A() # the id of the file from the dictionary file_id = "epr" file_url = list_of_local_files[file_id] # load and return the file as list of strings lines = get_only_chp_instructions(load_local_file(file_url)) # How many qubits does the circuit have? nrq = get_number_of_qubits(lines) print("number of qubits in CHP file", nrq) # Allocate the qubits and initialize them into the Z basis qubits = [] for qi in range(nrq): qubit = engine.allocate_qubit() qubits.append(qubit) # Transform CHP instructions into ProjectQ commands simulator_commands = [] for line in lines: parts_line = line.split(" ") chp_instr_type = parts_line[0] # qb_tuple = (qubits[int(parts_line[1])]) if len(parts_line) == 3: # cnot has two qubits qb_tuple = (qubits[int(parts_line[1])], qubits[int(parts_line[2])]) # Dummy value cmd = None # Translation between strings and gate types if chp_instr_type == "h": projectq.ops.H | qb_tuple elif chp_instr_type == "p": projectq.ops.S | qb_tuple elif chp_instr_type == "m": projectq.ops.Measure | qb_tuple elif chp_instr_type == "c": projectq.ops.CNOT | qb_tuple print(engine_list[0]._simulator._stabilizers) engine.flush() return
def test_parameter_any(): engine_list = restrictedgateset.get_engine_list(one_qubit_gates="any", two_qubit_gates="any") backend = DummyEngine(save_commands=True) eng = projectq.MainEngine(backend, engine_list) qubit1 = eng.allocate_qubit() qubit2 = eng.allocate_qubit() gate = BasicGate() gate | (qubit1, qubit2) gate | qubit1 eng.flush() print(len(backend.received_commands)) assert backend.received_commands[2].gate == gate assert backend.received_commands[3].gate == gate
def test_multirotation(): commands = GetCommand() eng = projectq.MainEngine(engine_list=[commands]) qubit1 = eng.allocate_qubit() qubit2 = eng.allocate_qubit() gates.CNOT | (qubit1, qubit2) gates.TimeEvolution(-1, gates.QubitOperator("X0 Z1")) | Qureg(qubit1 + qubit2) cmd2_info = [[(0,"X"), (1,"Z")], "pi4", 1] permute_cnot(commands.commands[0], commands.commands[1], cmd2_info) print(cmd2_info) assert(len(cmd2_info[0])==2) assert(cmd2_info[0][0][1] == "Y" and cmd2_info[0][1][1] == "Y")
def reset(self): """Reset/initialize the device by initializing the backend and engine, and allocating qubits.""" backend = pq.backends.IBMBackend(num_runs=self.shots, **self.filter_kwargs_for_backend( self._kwargs)) token = self._kwargs.get("token", "") hw = self._kwargs.get("use_hardware", False) device = self._kwargs.get( "device", "ibmq_qasm_simulator" if not hw else "ibmqx2") self._eng = pq.MainEngine( backend, verbose=self._kwargs["verbose"], engine_list=get_engine_list(token=token, device=device), ) super().reset()
def test_single_rotation2(): commands = GetCommand() eng = projectq.MainEngine(engine_list=[commands]) qubit1 = eng.allocate_qubit() qubit2 = eng.allocate_qubit() gates.CNOT | (qubit1, qubit2) gates.Rz(1) | qubit2 cmd2_info = [[(0, "Z")], "pi4", 1] permute_cnot(commands.commands[0], commands.commands[1], cmd2_info) print(cmd2_info) assert (len(cmd2_info[0]) == 2) assert (cmd2_info[0][1][1] == "Z")
def test_MultiqubitMeasurementCliffordEngine(): debugger = A() engine_list = [MultiqubitMeasurementCliffordEngine()] eng = projectq.MainEngine(engine_list=engine_list) engine_list[0].next_engine = debugger qubit1 = eng.allocate_qubit() qubit2 = eng.allocate_qubit() projectq.ops.H | qubit1 projectq.ops.CNOT | (qubit1[0], qubit2[0]) projectq.ops.Measure | qubit1 projectq.ops.Measure | qubit2 eng.flush() print(debugger.commands[2].gate._bases) print(debugger.commands[3].gate._bases) assert(False)
def test_decomposition(): a = Debugger() decomp = DecompositionRuleSet( modules=[projectq.setups.decompositions.parity_measurement]) engine_list = [AutoReplacer(decomp), InstructionFilter(is_supported), a] eng = projectq.MainEngine(engine_list=engine_list, backend=CommandPrinter(accept_input=False)) q1 = eng.allocate_qubit() q2 = eng.allocate_qubit() ParityMeasurementGate("Z0 X1") | q1 + q2 print(a.commands) #TODO #assert(a.commands[-1].gate._bases[0][0] == 0) #assert(a.commands[-1].gate._bases[0][1] == "Z") assert (False)
def test_simulate_dual_basis_hamiltonian_with_spin_and_potentials(self): big_eng = projectq.MainEngine() big_reg = big_eng.allocate_qureg(2 * self.size) hamiltonian = dual_basis_hamiltonian(1, self.size, spinless=False) for i in range(2 * self.size): coefficient = 1. / (i + 1) if i % 3: coefficient = -coefficient hamiltonian += FermionOperator(((i, 1), (i, 0)), coefficient) # Choose random state. initial_state = numpy.zeros(2**(2 * self.size), dtype=complex) for i in range(len(initial_state)): initial_state[i] = (random.random() * numpy.exp(1j * 2 * numpy.pi * random.random())) initial_state /= numpy.linalg.norm(initial_state) # Put randomly chosen state in the registers. big_eng.flush() big_eng.backend.set_wavefunction(initial_state, big_reg) _low_depth_trotter_simulation.simulate_dual_basis_evolution( big_reg, hamiltonian, trotter_steps=7, first_order=False, input_ordering=list(range(7, -1, -1))) big_eng.flush() # get_sparse_operator reverses the indices - we've accounted for this # with the reversed input_ordering. evol_matrix = expm(-1j * get_sparse_operator( hamiltonian, n_qubits=2 * self.size)).todense() initial_state = numpy.matrix(initial_state).T expected = evol_matrix * initial_state self.assertTrue( numpy.allclose(ordered_wavefunction(big_eng), expected.T, atol=1e-2), msg=str(numpy.array(ordered_wavefunction(big_eng) - expected.T))) projectq.ops.All(projectq.ops.Measure) | big_reg
def test_average_fidelity_on_the_identity_channel(): r"""Test that the average fidelity on the identity channel.""" qubits = 4 dim = 2**qubits true_answer = (np.abs(np.trace(np.eye(dim))**2) + dim) / (dim**2 + dim) # Construct the channel eng = projectq.MainEngine() register = eng.allocate_qureg(qubits) eng.flush() # Need to flush it in order to set_wavefunction def identity(engine, register): pass chan_dev = QDeviceChannel(eng, register, identity) fidelity = chan_dev.estimate_average_fidelity_channel(100, 0.1) assert np.abs(fidelity - true_answer) < 1e-4
def generate_instructions(): # engines = lattice_surgery.OpenSurgeryExporterEngineList() engines = lattice_surgery.get_engine_list() eng = projectq.MainEngine( backend=OpenSurgeryExporter(output="perceptron_instructions"), engine_list=engines, verbose=False) # Fig2 of arxiv:1811.02266 perceptron qreg = eng.allocate_qureg(4) ancilla = eng.allocate_qubit() # U_i # currently tensor doesn't work Tensor(H) | qreg Tensor(Z) | qreg[:3] CZ | (qreg[1], qreg[2]) CZ | (qreg[0], qreg[2]) CZ | (qreg[0], qreg[1]) ControlledGate(Z, 2) | (qreg[0], qreg[1], qreg[2]) # U_w Tensor(Z) | [qreg[1], qreg[2]] CZ | (qreg[1], qreg[3]) CZ | (qreg[0], qreg[2]) CZ | (qreg[0], qreg[1]) ControlledGate(Z, 2) | (qreg[1], qreg[2], qreg[3]) ControlledGate(Z, 2) | (qreg[0], qreg[1], qreg[3]) ControlledGate(Z, 3) | (qreg[0], qreg[1], qreg[2], qreg[3]) Tensor(H) | qreg Tensor(X) | qreg # perform measurement ControlledGate(X, 4) | (qreg, ancilla) Measure | ancilla Tensor(Measure) | qreg eng.flush() return