def compile_swap(gate) -> QCircuit: """ Compile swap gates into CNOT. Parameters ---------- gate: the gate. Returns ------- QCircuit, the result of compilation. """ if gate.name.lower() == "swap": if len(gate.target) != 2: raise TequilaCompilerException("SWAP gates needs two targets") power = 1 if hasattr(gate, "power"): if power is None or power in [1, 1.0]: pass else: raise TequilaCompilerException( "Parametrized SWAPs should be decomposed on top level! Something went wrong" ) c = [] if gate.control is not None: c = gate.control return X(target=gate.target[0], control=[gate.target[1]]) \ + X(target=gate.target[1], control=[gate.target[0]] + list(c), power=power) \ + X(target=gate.target[0], control=[gate.target[1]]) else: return QCircuit.wrap_gate(gate)
def compile_swap(gate) -> QCircuit: """ Compile swap gates into CNOT. Parameters ---------- gate: the gate. Returns ------- QCircuit, the result of compilation. """ if gate.name.lower() == "swap": if len(gate.target) != 2: raise TequilaCompilerException("SWAP gates needs two targets") if hasattr(gate, "power") and gate.parameter != 1: raise TequilaCompilerException( "SWAP gate with power can not be compiled into CNOTS") c = [] if gate.control is not None: c = gate.control return X(target=gate.target[0], control=gate.target[1] + c) \ + X(target=gate.target[1], control=gate.target[0] + c) \ + X(target=gate.target[0], control=gate.target[1] + c) else: return QCircuit.wrap_gate(gate)
def test_basic_gates(): I = sympy.I cos = sympy.cos sin = sympy.sin exp = sympy.exp BS = QubitWaveFunction.from_int angle = sympy.pi gates = [ X(0), Y(0), Z(0), Rx(target=0, angle=angle), Ry(target=0, angle=angle), Rz(target=0, angle=angle), H(0) ] results = [ BS(1), I * BS(1), BS(0), cos(-angle / 2) * BS(0) + I * sin(-angle / 2) * BS(1), cos(-angle / 2) * BS(0) + I * sin(-angle / 2) * I * BS(1), exp(-I * angle / 2) * BS(0), 1 / sympy.sqrt(2) * (BS(0) + BS(1)) ] for i, g in enumerate(gates): wfn = simulate(g, backend="symbolic", variables={angle: sympy.pi}) assert (wfn == strip_sympy_zeros(results[i]))
def compile_exponential_pauli_gate(gate) -> QCircuit: """ Returns the circuit: exp(i*angle*paulistring) primitively compiled into X,Y Basis Changes and CNOTs and Z Rotations :param paulistring: The paulistring in given as tuple of tuples (openfermion format) like e.g ( (0, 'Y'), (1, 'X'), (5, 'Z') ) :param angle: The angle which parametrizes the gate -> should be real :returns: the above mentioned circuit as abstract structure """ if hasattr(gate, "paulistring"): angle = gate.paulistring.coeff * gate.parameter circuit = QCircuit() # the general circuit will look like: # series which changes the basis if necessary # series of CNOTS associated with basis changes # Rz gate parametrized on the angle # series of CNOT (inverted direction compared to before) # series which changes the basis back ubasis = QCircuit() ubasis_t = QCircuit() cnot_cascade = QCircuit() last_qubit = None previous_qubit = None for k, v in gate.paulistring.items(): pauli = v qubit = [k] # wrap in list for targets= ... # see if we need to change the basis axis = 2 if pauli.upper() == "X": axis = 0 elif pauli.upper() == "Y": axis = 1 ubasis += change_basis(target=qubit, axis=axis) ubasis_t += change_basis(target=qubit, axis=axis, daggered=True) if previous_qubit is not None: cnot_cascade += X(target=qubit, control=previous_qubit) previous_qubit = qubit last_qubit = qubit reversed_cnot = cnot_cascade.dagger() # assemble the circuit circuit += ubasis circuit += cnot_cascade circuit += Rz(target=last_qubit, angle=angle, control=gate.control) circuit += reversed_cnot circuit += ubasis_t return circuit else: return QCircuit.wrap_gate(gate)
def test_unitary_gate_u1(gate, angle): """ Test some equivalences for u1 gate """ c_u1 = u1(lambd=angle, target=gate.gates[0].target, control=None if len(gate.gates[0].control) == 0 else gate.gates[0].control) if len(gate.gates[0].control) > 0: c_u1 = X(target=gate.gates[0].control) + c_u1 gate = X(target=gate.gates[0].control) + gate wfn1 = simulate(c_u1, backend="symbolic") wfn2 = simulate(gate, backend="symbolic") assert (numpy.isclose(wfn1.inner(wfn2), 1.0))
def test_unitary_gate_u2(ctrl, phi, lambd): """ Test some equivalences for u2 gate Since u2(\\phi, \\lambda) = Rz(\\phi)Ry(\\pi/2)Rz(\\lambda) """ c_u2 = u2(phi=phi, lambd=lambd, target=0, control=ctrl) c_equiv = Rz(target=0, control=ctrl, angle=lambd) + \ Ry(target=0, control=ctrl, angle=numpy.pi / 2) + \ Rz(target=0, control=ctrl, angle=phi) if ctrl is not None: c_u2 = X(target=ctrl) + c_u2 c_equiv = X(target=ctrl) + c_equiv wfn1 = simulate(c_u2, backend="symbolic") wfn2 = simulate(c_equiv, backend="symbolic") assert (numpy.isclose(wfn1.inner(wfn2), 1.0))
def test_consistency(): angle = numpy.pi / 2 cpairs = [(CNOT(target=0, control=1), X(target=0, control=1)), (Ry(target=0, angle=numpy.pi), Rz(target=0, angle=4 * numpy.pi) + X(target=0)), (Rz(target=0, angle=numpy.pi), Rz(target=0, angle=numpy.pi) + Z(target=0)), (Rz(target=0, angle=angle), Rz(target=0, angle=angle / 2) + Rz(target=0, angle=angle / 2)), (Rx(target=0, angle=angle), Rx(target=0, angle=angle / 2) + Rx(target=0, angle=angle / 2)), (Ry(target=0, angle=angle), Ry(target=0, angle=angle / 2) + Ry(target=0, angle=angle / 2))] for c in cpairs: print("circuit=", c[0], "\n", c[1]) wfn1 = simulate(c[0], backend="symbolic") wfn2 = simulate(c[1], backend="symbolic") assert (numpy.isclose(wfn1.inner(wfn2), 1.0))
def test_unitary_gate_u_u3(gate, theta, phi, lambd): """ Test some equivalences for u3 gate (also U gate, because U = u3) """ c_u3 = u3(theta=theta, phi=phi, lambd=lambd, target=gate.gates[0].target, control=None if len(gate.gates[0].control) == 0 else gate.gates[0].control) if len(gate.gates[0].control) > 0: c_u3 = X(target=gate.gates[0].control) + c_u3 gate = X(target=gate.gates[0].control) + gate wfn1 = simulate(c_u3, backend="symbolic") wfn2 = simulate(gate, backend="symbolic") assert (numpy.isclose(wfn1.inner(wfn2), 1.0))
def create_sub_circ(self, gate, control_bit, target_bit): sub_circ = None if gate == "CNOT": sub_circ = CNOT(control=control_bit, target=target_bit) elif gate == "aCNOT": sub_circ = X(control_bit) sub_circ += CNOT(control=control_bit, target=target_bit) sub_circ += X(control_bit) elif gate == "CROT": a_angle = self.coefficients[self.c_i] sa = sympy.Symbol(a_angle) self.c_i += 1 sub_circ = Ry(control=control_bit, target=target_bit, angle=SympyVariable(sa)) elif gate == "aCROT": a_angle = self.coefficients[self.c_i] sa = sympy.Symbol(a_angle) self.c_i += 1 sub_circ = X(control_bit) sub_circ += Ry(control=control_bit, target=target_bit, angle=SympyVariable(sa)) sub_circ += X(control_bit) elif gate == "X": sub_circ = X(target_bit) elif gate == "ROT": a_angle = self.coefficients[self.c_i] self.c_i += 1 sub_circ = Ry(control=None, target=target_bit, angle=SympyVariable(sympy.Symbol(a_angle))) return sub_circ
def compile_y(gate) -> QCircuit: """ Compile Y gates into X and Rz. Parameters ---------- gate: the gate. Returns ------- QCircuit, the result of compilation. """ if gate.name.lower() == "y": return Rz(target=gate.target, control=None, angle=-numpy.pi / 2) \ + X(target=gate.target, control=gate.control, power=gate.power if gate.is_parametrized() else None) \ + Rz(target=gate.target, control=None, angle=numpy.pi / 2) else: return QCircuit.wrap_gate(gate)
def test_swap(): U = X(0) U += SWAP(0, 2) wfn = simulate(U) wfnx = simulate(X(2)) assert numpy.isclose(numpy.abs(wfn.inner(wfnx))**2, 1.0) U = X(2) U += SWAP(0, 2, power=2.0) wfn = simulate(U) wfnx = simulate(X(0)) assert numpy.isclose(numpy.abs(wfn.inner(wfnx))**2, 1.0) U = X(0) + X(3) U += SWAP(0, 2, control=3) wfn = simulate(U) wfnx = simulate(X(2) + X(3)) assert numpy.isclose(numpy.abs(wfn.inner(wfnx))**2, 1.0) U = X(2) + X(3) U += SWAP(0, 2, control=3, power=2.0) wfn = simulate(U) wfnx = simulate(X(2) + X(3)) assert numpy.isclose(numpy.abs(wfn.inner(wfnx))**2, 1.0)
def hcb_to_me(self, *args, **kwargs): U = QCircuit() for i in range(self.n_orbitals): U += X(target=self.down(i), control=self.up(i)) return U