def _decompose_QPE(cmd): """ Decompose the Quantum Phase Estimation gate. """ eng = cmd.engine # Ancillas is the first qubit/qureg. System-qubit is the second qubit/qureg qpe_ancillas = cmd.qubits[0] system_qubits = cmd.qubits[1] # Hadamard on the ancillas Tensor(H) | qpe_ancillas # The Unitary Operator U = cmd.gate.unitary # Control U on the system_qubits if (callable(U)): # If U is a function for i in range(len(qpe_ancillas)): with Control(eng, qpe_ancillas[i]): U(system_qubits, time=2**i) else: for i in range(len(qpe_ancillas)): ipower = int(2**i) with Loop(eng, ipower): with Control(eng, qpe_ancillas[i]): U | system_qubits # Inverse QFT on the ancillas get_inverse(QFT) | qpe_ancillas
def _decompose_parity_measurement(cmd): ancilla = cmd.engine.allocate_qubit() for pos, action in cmd.gate._bases: qureg = Qureg([cmd.qubits[0][pos]]) if action == "X": H | cmd.qubits[0][pos] with Control(cmd.engine, qureg): X | ancilla H | cmd.qubits[0][pos] elif action == "Y": H | cmd.qubits[0][pos] S | cmd.qubits[0][pos] with Control(cmd.engine, qureg): X | ancilla get_inverse(S) | cmd.qubits[0][pos] H | cmd.qubits[0][pos] elif action == "Z": with Control(cmd.engine, qureg): X | ancilla # if there is a minus sign if (cmd.gate._is_inverted): X | ancilla # at last measure the parity: Measure | ancilla
def _decompose_QPE(cmd): # pylint: disable=invalid-name """Decompose the Quantum Phase Estimation gate.""" eng = cmd.engine # Ancillas is the first qubit/qureg. System-qubit is the second qubit/qureg qpe_ancillas = cmd.qubits[0] system_qubits = cmd.qubits[1] # Hadamard on the ancillas Tensor(H) | qpe_ancillas # The Unitary Operator unitary = cmd.gate.unitary # Control U on the system_qubits if callable(unitary): # If U is a function for i, ancilla in enumerate(qpe_ancillas): with Control(eng, ancilla): unitary(system_qubits, time=2**i) else: for i, ancilla in enumerate(qpe_ancillas): ipower = int(2**i) with Loop(eng, ipower): with Control(eng, ancilla): unitary | system_qubits # Inverse QFT on the ancillas get_inverse(QFT) | qpe_ancillas
def observe(agent_memory, qureg, reverse=False): assert len(agent_memory) >= len(qureg), 'Invalid observe. Observed system is larger than what memory ' \ 'of the agent can hold.' if reverse: get_inverse(Add) | (qureg, agent_memory) else: Add | (qureg, agent_memory)
def test_s_gate(): gate = _gates.SGate() assert str(gate) == "S" assert np.array_equal(gate.matrix, np.matrix([[1, 0], [0, 1j]])) assert isinstance(_gates.S, _gates.SGate) assert type(_gates.Sdag) == type(get_inverse(gate)) assert type(_gates.Sdagger) == type(get_inverse(gate))
def run_phase_estimation(eng, U, state, m, n): """ Phase estimation algorithm on unitary U. Args: eng (MainEngine): Main compiler engine to run the phase_estimation algorithm U (np.matrix): the unitary that is to be estimated state (qureg): the input state, which has the form |psi> otimes |0>. State is composed of two parts: 1. The first n qubits are the input state |psi>, which is commonly chosen to be the eigenstate of U 2. The last n qubits are initialized to |0>, which is used to store the binary digits of the estimated phase m (int): number of qubits for input state psi n (int): number of qubits used to store the phase to given precision """ # The beginning index for the phase qubits will have an offset OFFSET = m # Phase 1. performs the controlled U^{2^j} operations for k in range(n): H | state[OFFSET + k] with Control(eng, state[OFFSET + k]): # number of loops required to perfrom the controlled U^{2^j} operation num = int(math.pow(2, k)) # use the buildin loop with Loop(eng, num): U | state[:OFFSET] # Phase 2. performs the inverse QFT operation # Step 2.1 swap the qubits for k in range(int(math.floor(n / 2))): Swap | (state[OFFSET + k], state[OFFSET + n - k - 1]) # Step 2.2 perfrom the original inverse QFT get_inverse(QFT) | state[OFFSET:]
def test_t_gate(): gate = _gates.TGate() assert str(gate) == "T" assert np.array_equal(gate.matrix, np.matrix([[1, 0], [0, cmath.exp(1j * cmath.pi / 4)]])) assert isinstance(_gates.T, _gates.TGate) assert type(_gates.Tdag) == type(get_inverse(gate)) assert type(_gates.Tdagger) == type(get_inverse(gate))
def test_body(): drawer = _drawer.CircuitDrawer() eng = MainEngine(drawer, []) old_tolatex = _drawer.to_latex _drawer.to_latex = lambda x: x qubit1 = eng.allocate_qubit() qubit2 = eng.allocate_qubit() qubit3 = eng.allocate_qubit() H | qubit1 H | qubit2 CNOT | (qubit1, qubit2) X | qubit2 Measure | qubit2 CNOT | (qubit2, qubit1) Z | qubit2 C(Z) | (qubit1, qubit2) C(Swap) | (qubit1, qubit2, qubit3) SqrtX | qubit1 SqrtSwap | (qubit1, qubit2) get_inverse(SqrtX) | qubit1 C(SqrtSwap) | (qubit1, qubit2, qubit3) get_inverse(SqrtSwap) | (qubit1, qubit2) C(Swap) | (qubit3, qubit1, qubit2) C(SqrtSwap) | (qubit3, qubit1, qubit2) del qubit1 eng.flush() circuit_lines = drawer.get_latex() _drawer.to_latex = old_tolatex settings = _to_latex.get_default_settings() settings['gates']['AllocateQubitGate']['draw_id'] = True code = _to_latex._body(circuit_lines, settings) # swap draws 2 nodes + 2 lines each, so is sqrtswap gate, csqrtswap, # inv(sqrt_swap), and cswap. assert code.count("swapstyle") == 36 # CZ is two phases plus 2 from CNOTs + 2 from cswap + 2 from csqrtswap assert code.count("phase") == 8 assert code.count("{{{}}}".format(str(H))) == 2 # 2 hadamard gates assert code.count("{$\Ket{0}") == 3 # 3 qubits allocated # 1 cnot, 1 not gate, 3 SqrtSwap, 1 inv(SqrtSwap) assert code.count("xstyle") == 7 assert code.count("measure") == 1 # 1 measurement assert code.count("{{{}}}".format(str(Z))) == 1 # 1 Z gate assert code.count("{red}") == 3
def high_level_gates(eng, cmd): g = cmd.gate if g == QFT or get_inverse(g) == QFT or g == Swap: return True if isinstance(g, BasicMathGate): return False return eng.next_engine.is_available(cmd)
def perform_simulation(self): for gate in reversed(self._gates): self._simulator.apply_operation(gates.get_inverse(gate)) for bases, qubits, parity in self._simulator.return_stabilizers(): cmd = projqube.projectq.ops.ParityMeasurementGate(bases, parity).generate_command(qubits) self.send([cmd])
def quanutm_phase_estimation(eng): All(H) | phase_reg with Control(eng, phase_reg[0]): run_qnn(eng) with Control(eng, phase_reg[1]): with Loop(eng, 2): run_qnn(eng) with Control(eng, phase_reg[2]): with Loop(eng, 4): run_qnn(eng) Swap | (phase_reg[0], phase_reg[2]) get_inverse(QFT) | phase_reg
def _all_decomps_for(self, cmd): key = cmd.gate.__class__.__name__ inv_key = get_inverse(cmd.gate).__class__.__name__ ds = self.decomposition_rule_set.decompositions forward = ds[key] if key in ds else [] backward = [d.get_inverse_decomposition() for d in ds[inv_key]] if inv_key in ds else [] return [d for d in forward + backward if d.check(cmd)]
def high_level_gates(eng, cmd): # pylint: disable=unused-argument """Remove any MathGates.""" gate = cmd.gate if eng.next_engine.is_available(cmd): return True if gate == QFT or get_inverse(gate) == QFT or gate == Swap: return True if isinstance(gate, BasicMathGate): return False return True
def high_level_gates(eng, cmd): """ Remove any MathGates. """ g = cmd.gate if g == QFT or get_inverse(g) == QFT or g == Swap: return True elif isinstance(g, BasicMathGate): return False return True
def high_level_gates(eng, cmd): g = cmd.gate if g == QFT or get_inverse(g) == QFT or g == Swap: return True if isinstance(g, BasicMathGate): return False # False - http://projectq.readthedocs.io/en/latest/examples.html#shor-s-algorithm-for-factoring if isinstance(g, AddConstant): return True elif isinstance(g, AddConstantModN): return True return False return eng.next_engine.is_available(cmd)
def GetHighLevelGates(eng, cmd): g = cmd.gate if g == QFT or get_inverse(g) == QFT or g == Swap: return True if isinstance(g, BasicMathGate): return False if isinstance(g, AddConstant): return True elif isinstance(g, AddConstantModN): return True return False return eng.next_engine.is_available(cmd)
def test_high_level_gate_set(): mod_list = projectq.setups.ibm16.get_engine_list() saving_engine = DummyEngine(save_commands=True) mod_list = mod_list[:6] + [saving_engine] + mod_list[6:] eng = MainEngine(DummyEngine(), engine_list=mod_list) qureg = eng.allocate_qureg(3) AddConstant(3) | qureg QFT | qureg eng.flush() received_gates = [cmd.gate for cmd in saving_engine.received_commands] assert sum([1 for g in received_gates if g == QFT]) == 1 assert get_inverse(QFT) not in received_gates assert AddConstant(3) not in received_gates
def high_level_gates(eng, cmd): """Filter high-level gates.""" g = cmd.gate if g == QFT or get_inverse(g) == QFT or g == Swap: return True if isinstance(g, BasicMathGate): return False if isinstance(g, AddConstant): return True elif isinstance(g, AddConstantModN): return True return False return eng.next_engine.is_available(cmd)
def _process_command(self, cmd): """ Check whether a command cmd can be handled by further engines and, if not, replace it using the decomposition rules loaded with the setup (e.g., setups.default). Args: cmd (Command): Command to process. Raises: Exception if no replacement is available in the loaded setup. """ if self.is_available(cmd): self.send([cmd]) else: # check for decomposition rules decomp_list = [] potential_decomps = [] inv_list = [] # check for forward rules cls = cmd.gate.__class__.__name__ try: potential_decomps = [ d for d in self.decompositionRuleSet.decompositions[cls] ] except KeyError: pass # check for rules implementing the inverse gate # and run them in reverse inv_cls = get_inverse(cmd.gate).__class__.__name__ try: potential_decomps += [ d.get_inverse_decomposition() for d in self.decompositionRuleSet.decompositions[inv_cls] ] except KeyError: pass # throw out the ones which don't recognize the command for d in potential_decomps: if d.check(cmd): decomp_list.append(d) if len(decomp_list) == 0: raise NoGateDecompositionError("\nNo replacement found for " + str(cmd) + "!") # use decomposition chooser to determine the best decomposition chosen_decomp = self._decomp_chooser(cmd, decomp_list) # the decomposed command must have the same tags # (plus the ones it gets from meta-statements inside the # decomposition rule). # --> use a CommandModifier with a ForwarderEngine to achieve this. old_tags = cmd.tags[:] def cmd_mod_fun(cmd): # Adds the tags cmd.tags = old_tags[:] + cmd.tags cmd.engine = self.main_engine return cmd # the CommandModifier calls cmd_mod_fun for each command # --> commands get the right tags. cmod_eng = CommandModifier(cmd_mod_fun) cmod_eng.next_engine = self # send modified commands back here cmod_eng.main_engine = self.main_engine # forward everything to cmod_eng using the ForwarderEngine # which behaves just like MainEngine # (--> meta functions still work) forwarder_eng = ForwarderEngine(cmod_eng) cmd.engine = forwarder_eng # send gates directly to forwarder # (and not to main engine, which would screw up the ordering). chosen_decomp.decompose(cmd) # run the decomposition
def to_tikz( # pylint: disable=too-many-branches,too-many-locals,too-many-statements self, line, circuit, end=None, draw_gates_in_parallel=True): """ Generate the TikZ code for one line of the circuit up to a certain gate. It modifies the circuit to include only the gates which have not been drawn. It automatically switches to other lines if the gates on those lines have to be drawn earlier. Args: line (int): Line to generate the TikZ code for. circuit (list<list<CircuitItem>>): The circuit to draw. end (int): Gate index to stop at (for recursion). draw_gates_in_parallel (bool): True or False for how to place gates Returns: tikz_code (string): TikZ code representing the current qubit line and, if it was necessary to draw other lines, those lines as well. """ if end is None: end = len(circuit[line]) tikz_code = [] cmds = circuit[line] for i in range(0, end): gate = cmds[i].gate lines = cmds[i].lines ctrl_lines = cmds[i].ctrl_lines all_lines = lines + ctrl_lines all_lines.remove(line) # remove current line for _line in all_lines: gate_idx = 0 while not circuit[_line][gate_idx] == cmds[i]: gate_idx += 1 tikz_code.append(self.to_tikz(_line, circuit, gate_idx)) # we are taking care of gate 0 (the current one) circuit[_line] = circuit[_line][1:] all_lines = lines + ctrl_lines pos = max([ self.pos[ll] for ll in range(min(all_lines), max(all_lines) + 1) ]) for _line in range(min(all_lines), max(all_lines) + 1): self.pos[_line] = pos + self._gate_pre_offset(gate) connections = "" for _line in all_lines: connections += self._line(self.op_count[_line] - 1, self.op_count[_line], line=_line) add_str = "" if gate == X: # draw NOT-gate with controls add_str = self._x_gate(lines, ctrl_lines) # and make the target qubit quantum if one of the controls is if not self.is_quantum[lines[0]]: if sum([self.is_quantum[i] for i in ctrl_lines]) > 0: self.is_quantum[lines[0]] = True elif gate == Z and len(ctrl_lines) > 0: add_str = self._cz_gate(lines + ctrl_lines) elif gate == Swap: add_str = self._swap_gate(lines, ctrl_lines) elif gate == SqrtSwap: add_str = self._sqrtswap_gate(lines, ctrl_lines, daggered=False) elif gate == get_inverse(SqrtSwap): add_str = self._sqrtswap_gate(lines, ctrl_lines, daggered=True) elif gate == Measure: # draw measurement gate for _line in lines: op = self._op(_line) width = self._gate_width(Measure) height = self._gate_height(Measure) shift0 = 0.07 * height shift1 = 0.36 * height shift2 = 0.1 * width add_str += ("\n\\node[measure,edgestyle] ({op}) at ({pos}" ",-{line}) {{}};\n\\draw[edgestyle] ([yshift=" "-{shift1}cm,xshift={shift2}cm]{op}.west) to " "[out=60,in=180] ([yshift={shift0}cm]{op}." "center) to [out=0, in=120] ([yshift=-{shift1}" "cm,xshift=-{shift2}cm]{op}.east);\n" "\\draw[edgestyle] ([yshift=-{shift1}cm]{op}." "center) to ([yshift=-{shift2}cm,xshift=-" "{shift1}cm]{op}.north east);").format( op=op, pos=self.pos[_line], line=_line, shift0=shift0, shift1=shift1, shift2=shift2, ) self.op_count[_line] += 1 self.pos[_line] += self._gate_width( gate) + self._gate_offset(gate) self.is_quantum[_line] = False elif gate == Allocate: # draw 'begin line' add_str = "\n\\node[none] ({}) at ({},-{}) {{$\\Ket{{0}}{}$}};" id_str = "" if self.settings['gates']['AllocateQubitGate']['draw_id']: id_str = "^{{\\textcolor{{red}}{{{}}}}}".format(cmds[i].id) xpos = self.pos[line] try: if self.settings['gates']['AllocateQubitGate'][ 'allocate_at_zero']: self.pos[line] -= self._gate_pre_offset(gate) xpos = self._gate_pre_offset(gate) except KeyError: pass self.pos[line] = max( xpos + self._gate_offset(gate) + self._gate_width(gate), self.pos[line], ) add_str = add_str.format(self._op(line), xpos, line, id_str) self.op_count[line] += 1 self.is_quantum[line] = self.settings['lines']['init_quantum'] elif gate == Deallocate: # draw 'end of line' op = self._op(line) add_str = "\n\\node[none] ({}) at ({},-{}) {{}};" add_str = add_str.format(op, self.pos[line], line) yshift = str(self._gate_height(gate)) + "cm]" add_str += ( "\n\\draw ([yshift={yshift}{op}.center) edge [edgestyle] ([yshift=-{yshift}{op}.center);" ).format(op=op, yshift=yshift) self.op_count[line] += 1 self.pos[line] += self._gate_width(gate) + self._gate_offset( gate) else: # regular gate must draw the lines it does not act upon # if it spans multiple qubits add_str = self._regular_gate(gate, lines, ctrl_lines) for _line in lines: self.is_quantum[_line] = True tikz_code.append(add_str) if not gate == Allocate: tikz_code.append(connections) if not draw_gates_in_parallel: for _line in range(len(self.pos)): if _line != line: self.pos[_line] = self.pos[line] circuit[line] = circuit[line][end:] return "".join(tikz_code)
def _process_command(self, cmd): """ Check whether a command cmd can be handled by further engines and, if not, replace it using the decomposition rules loaded with the setup (e.g., setups.default). Args: cmd (Command): Command to process. Raises: Exception if no replacement is available in the loaded setup. """ if self.is_available(cmd): self.send([cmd]) else: # check for decomposition rules decomp_list = [] potential_decomps = [] # First check for a decomposition rules of the gate class, then # the gate class of the inverse gate. If nothing is found, do the # same for the first parent class, etc. gate_mro = type(cmd.gate).mro()[:-1] # If gate does not have an inverse it's parent classes are # DaggeredGate, BasicGate, object. Hence don't check the last two inverse_mro = type(get_inverse(cmd.gate)).mro()[:-2] rules = self.decompositionRuleSet.decompositions for level in range(max(len(gate_mro), len(inverse_mro))): # Check for forward rules if level < len(gate_mro): class_name = gate_mro[level].__name__ try: potential_decomps = [d for d in rules[class_name]] except KeyError: pass # throw out the ones which don't recognize the command for d in potential_decomps: if d.check(cmd): decomp_list.append(d) if len(decomp_list) != 0: break # Check for rules implementing the inverse gate # and run them in reverse if level < len(inverse_mro): inv_class_name = inverse_mro[level].__name__ try: potential_decomps += [ d.get_inverse_decomposition() for d in rules[inv_class_name] ] except KeyError: pass # throw out the ones which don't recognize the command for d in potential_decomps: if d.check(cmd): decomp_list.append(d) if len(decomp_list) != 0: break if len(decomp_list) == 0: raise NoGateDecompositionError("\nNo replacement found for " + str(cmd) + "!") # use decomposition chooser to determine the best decomposition chosen_decomp = self._decomp_chooser(cmd, decomp_list) # the decomposed command must have the same tags # (plus the ones it gets from meta-statements inside the # decomposition rule). # --> use a CommandModifier with a ForwarderEngine to achieve this. old_tags = cmd.tags[:] def cmd_mod_fun(cmd): # Adds the tags cmd.tags = old_tags[:] + cmd.tags cmd.engine = self.main_engine return cmd # the CommandModifier calls cmd_mod_fun for each command # --> commands get the right tags. cmod_eng = CommandModifier(cmd_mod_fun) cmod_eng.next_engine = self # send modified commands back here cmod_eng.main_engine = self.main_engine # forward everything to cmod_eng using the ForwarderEngine # which behaves just like MainEngine # (--> meta functions still work) forwarder_eng = ForwarderEngine(cmod_eng) cmd.engine = forwarder_eng # send gates directly to forwarder # (and not to main engine, which would screw up the ordering). chosen_decomp.decompose(cmd) # run the decomposition
Z = ZGate() class SGate(BasicGate): """ S gate class """ @property def matrix(self): return np.matrix([[1, 0], [0, 1j]]) def __str__(self): return "S" S = SGate() Sdag = Sdagger = get_inverse(S) class TGate(BasicGate): """ T gate class """ @property def matrix(self): return np.matrix([[1, 0], [0, cmath.exp(1j * cmath.pi / 4)]]) def __str__(self): return "T" T = TGate() Tdag = Tdagger = get_inverse(T)
dataset1[i]=func(i,n) dataset=[x.real for x in dataset1] ''' Quantum ''' #the QFT misses a swap operation for i in range(int(n/2)): Swap | (Qubits[i],Qubits[n-i-1]) QFT | Qubits[0:n] #Control rotation Control_Rotation(eng,Qubits,dataset,n) #inverse QFT get_inverse(QFT) | Qubits[0:n] for i in range(int(n/2)): Swap | (Qubits[i],Qubits[n-i-1]) #Get the quantum output and store in classical numpy. Named Quantum qstate=qutoclass(eng,Qubits, n, 1) #nomalized qsum=math.sqrt(sum(abs(x)**2 for x in qstate)) qstate=qstate/qsum All(Measure) | Qubits ''' Classical ''' #classical method to get the circulent matrix, and solve the problem in classical, named Circulent F=np.zeros((2**n,2**n))*(0+0j) for i in range(2**n):
input() print("It will take your opponents move and compare them.") input() print("But first you'll have to sign in...\n") # prepare qubits qubits = eng.allocate_qureg(5) # referee decides things in the X basis, so we prepare it in the |+> state H | qubits[2] # implement human move if (humanMove == "s"): S | qubits[2] else: get_inverse(S) | qubits[2] # opponent qubit is prepared in state |+> to randomly decide the move to make H | qubits[opponent] # to implement the quantum move, first do an S in all cases S | qubits[2] # then use a controlled-Z to make it into a Sdg if that's what the quantum player chooses H | qubits[2] CNOT | (qubits[opponent], qubits[2]) H | qubits[2] # quantum player wins if the moves where different, which would leave referee in the |+> state # human player wins if the moves were the same # we measure in the X basis to see H | qubits[2]
def zoo_profile(): """Generate and display the zoo of quantum gates.""" # create a main compiler engine with a drawing backend drawing_engine = CircuitDrawer() locations = {0: 1, 1: 2, 2: 0, 3: 3} drawing_engine.set_qubit_locations(locations) main_eng = MainEngine(drawing_engine) qureg = main_eng.allocate_qureg(4) # define a zoo of gates te_gate = TimeEvolution(0.5, 0.1 * QubitOperator('X0 Y2')) def add(x, y): return x, y + 1 zoo = [ (X, 3), (Y, 2), (Z, 0), (Rx(0.5), 2), (Ry(0.5), 1), (Rz(0.5), 1), (Ph(0.5), 0), (S, 3), (T, 2), (H, 1), (Toffoli, (0, 1, 2)), (Barrier, None), (Swap, (0, 3)), (SqrtSwap, (0, 1)), (get_inverse(SqrtSwap), (2, 3)), (SqrtX, 2), (C(get_inverse(SqrtX)), (0, 2)), (C(Ry(0.5)), (2, 3)), (CNOT, (2, 1)), (Entangle, None), (te_gate, None), (QFT, None), (Tensor(H), None), (BasicMathGate(add), (2, 3)), (All(Measure), None), ] # apply them for gate, pos in zoo: if pos is None: gate | qureg elif isinstance(pos, tuple): gate | tuple(qureg[i] for i in pos) else: gate | qureg[pos] main_eng.flush() # generate latex code to draw the circuit s = drawing_engine.get_latex() prefix = 'zoo' with open('{}.tex'.format(prefix), 'w') as f: f.write(s) # compile latex source code and open pdf file os.system('pdflatex {}.tex'.format(prefix)) openfile('{}.pdf'.format(prefix))
H | qubits[3] CNOT | (qubits[3], qubits[2]) X | qubits[3] bobs[2] = 1 T | qubits[2] if (ship == "f"): # f means 3 and 4 H | qubits[3] CNOT | (qubits[3], qubits[4]) X | qubits[3] bobs[3] = 1 T | qubits[3] # apply the bombs # whether or not a bomb is applied corresponds to the two measurment choices for CHSH (in x-y plane) if (bobs[bomb1] == 1): get_inverse(S) | qubits[bomb1] else: S | qubits[bomb1] if (bobs[bomb2] == 1): get_inverse(S) | qubits[bomb2] else: S | qubits[bomb2] # measure all in X basis H | qubits[0] Measure | qubits[0] H | qubits[1] Measure | qubits[1] H | qubits[2] Measure | qubits[2] H | qubits[3]
def high_level_gates(eng, cmd): g = cmd.gate if g == QFT or get_inverse(g) == QFT or g == Swap: return True return eng.next_engine.is_available(cmd)