def hadamard_axbxc(gate) -> QCircuit: """ Decompose 1 control parametrized hadamard into single qubit rotation and CNOT. Parameters ---------- gate: the gate Returns ------- QCircuit, the result of compilation. """ if not isinstance(gate, PowerGateImpl) or gate.name not in [ 'H', 'h', 'hadamard' ]: return QCircuit.wrap_gate(gate) power = gate.parameter target = gate.target a = power.wrap(a_calc) b = power.wrap(b_calc) theta = power.wrap(theta_calc) phase = power * jnp.pi / 2 result = QCircuit() result += Rz((a - b) / 2, target) result += CNOT(gate.control, target) result += Rz(-(a + b) / 2, target) result += Ry(-theta / 2, target) result += CNOT(gate.control, target) result += Ry(theta / 2, target) result += Rz(a, target) result += Phase(numpy.pi * power / 2, gate.control) return result
def compile_power_base(gate): """ Base case of compile_power_gate: convert a 1-qubit parametrized power gate into rotation gates. Parameters ---------- gate: the gate. Returns ------- A QCircuit; the result of compilation. """ if not isinstance(gate, PowerGateImpl): return QCircuit.wrap_gate(gate) if gate.is_controlled(): return QCircuit.wrap_gate(gate) power = gate.power if gate.name.lower() in ['h', 'hadamard']: ### off by global phase of Exp[ pi power /2] theta = power * numpy.pi result = QCircuit() result += Ry(angle=-numpy.pi / 4, target=gate.target) result += Rz(angle=theta, target=gate.target) result += Ry(angle=numpy.pi / 4, target=gate.target) elif gate.name == 'X': ### off by global phase of Exp[ pi power /2] ''' if we wanted to do it formally we would use the following a=-numpy.pi/2 b=numpy.pi/2 theta = power*numpy.pi result = QCircuit() result+= Rz(angle=b,target=gate.target) result+= Ry(angle=theta,target=gate.target) result+= Rz(angle=a,target=gate.target) ''' result = Rx(angle=power * numpy.pi, target=gate.target) elif gate.name == 'Y': ### off by global phase of Exp[ pi power /2] theta = power * numpy.pi result = QCircuit() result += Ry(angle=theta, target=gate.target) elif gate.name == 'Z': ### off by global phase of Exp[ pi power /2] a = 0 b = power * numpy.pi theta = 0 result = QCircuit() result += Rz(angle=b, target=gate.target) else: raise TequilaException('passed a gate with name ' + gate.name + ', which cannot be handled!') return result
def hadamard_base(gate) -> QCircuit: """ base case for hadamard compilation; returns powers of hadamard as sequence of single qubit rotations. Parameters ---------- gate: the gate. Returns ------- A QCircuit; the result of compilation. """ if not isinstance(gate, PowerGateImpl) or gate.name not in [ 'H', 'h', 'hadamard' ]: return QCircuit.wrap_gate(gate) power = gate.parameter a = power.wrap(a_calc) b = power.wrap(b_calc) theta = power.wrap(theta_calc) result = QCircuit() result += Rz(angle=b, target=gate.target) result += Ry(angle=theta, target=gate.target) result += Rz(angle=a, target=gate.target) return result
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 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 change_basis(target, axis=None, name=None, daggered=False): """ helper function; returns circuit that performs change of basis. Parameters ---------- target: the qubit having its basis changed axis: The axis of rotation to shift into. daggered: bool: adjusts the sign of the gate if axis = 1, I.E, change of basis about Y axis. Returns ------- QCircuit that performs change of basis on target qubit onto desired axis """ if axis is None and name is None: raise TequilaException('axis or name must be given.') if name: name = name.lower() if name in ['h', 'hadamard'] and daggered: return Ry(angle=numpy.pi / 4, target=target) elif name in ['h', 'hadamard']: return Ry(angle=-numpy.pi / 4, target=target) else: name_to_axis = {'rx': 0, 'ry': 1, 'rz': 2} axis = name_to_axis.get(name, name) if isinstance(axis, str): axis = RotationGateImpl.string_to_axis[axis.lower()] if axis == 0 and daggered: return Ry(angle=numpy.pi / 2, target=target) elif axis == 0: return Ry(angle=-numpy.pi / 2, target=target) elif axis == 1 and daggered: return Rx(angle=-numpy.pi / 2, target=target) elif axis == 1: return Rx(angle=numpy.pi / 2, target=target) else: return QCircuit()
def compile_ch(gate: QGateImpl) -> QCircuit: """ Compile CH gates into its equivalent: CH = Ry(0.25pi) CZ Ry(-0.25pi) Parameters ---------- gate: the gate. Returns ------- QCircuit, the result of compilation. """ if gate.name.lower() == "h" and gate.is_controlled(): return Ry(target=gate.target, control=None, angle=-numpy.pi / 4) \ + Z(target=gate.target, control=gate.control, power=gate.power if gate.is_parametrized() else None) \ + Ry(target=gate.target, control=None, angle=numpy.pi / 4) else: return QCircuit.wrap_gate(gate)
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 hadamard_axbxc(gate) -> QCircuit: if not isinstance(gate, PowerGateImpl) or gate.name not in [ 'H', 'h', 'hadamard' ]: return QCircuit.wrap_gate(gate) power = gate.parameter target = gate.target a = power.wrap(a_calc) b = power.wrap(b_calc) theta = power.wrap(theta_calc) phase = power * jnp.pi / 2 result = QCircuit() result += Rz((a - b) / 2, target) result += CNOT(gate.control, target) result += Rz(-(a + b) / 2, target) result += Ry(-theta / 2, target) result += CNOT(gate.control, target) result += Ry(theta / 2, target) result += Rz(a, target) result += Phase(numpy.pi * power / 2, gate.control) return result
def hadamard_base(gate) -> QCircuit: if not isinstance(gate, PowerGateImpl) or gate.name not in [ 'H', 'h', 'hadamard' ]: return QCircuit.wrap_gate(gate) power = gate.parameter a = power.wrap(a_calc) b = power.wrap(b_calc) theta = power.wrap(theta_calc) result = QCircuit() result += Rz(angle=b, target=gate.target) result += Ry(angle=theta, target=gate.target) result += Rz(angle=a, target=gate.target) return result
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 compile_power_base(gate): if not isinstance(gate, PowerGateImpl): return QCircuit.wrap_gate(gate) power = gate.parameter if gate.name in ['H', 'h', 'Hadamard', 'hadamard']: return compile_h_power(gate=gate) if gate.name == 'X': ### off by global phase of Exp[ pi power /2] ''' if we wanted to do it formally we would use the following a=-numpy.pi/2 b=numpy.pi/2 theta = power*numpy.pi result = QCircuit() result+= Rz(angle=b,target=gate.target) result+= Ry(angle=theta,target=gate.target) result+= Rz(angle=a,target=gate.target) ''' result = Rx(angle=power * numpy.pi, target=gate.target) elif gate.name == 'Y': ### off by global phase of Exp[ pi power /2] theta = power * numpy.pi result = QCircuit() result += Ry(angle=theta, target=gate.target) elif gate.name == 'Z': ### off by global phase of Exp[ pi power /2] a = 0 b = power * numpy.pi theta = 0 result = QCircuit() result += Rz(angle=b, target=gate.target) else: raise TequilaException('passed a gate with name ' + gate.name + ', which cannot be handled!') return result
def get_axbxc_decomp(gate): """ Break down single controlled parametrized power gates into CNOT and rotations. Parameters ---------- gate: the gate. Returns ------- QCircuit; the result of compilation. """ if not isinstance(gate, PowerGateImpl) or gate.name not in ['X', 'Y', 'Z']: return QCircuit.wrap_gate(gate) power = gate.parameter target = gate.target result = QCircuit() if gate.name == 'X': a = -numpy.pi / 2 b = numpy.pi / 2 theta = power * numpy.pi ''' result+=Phase(numpy.pi*power/2,gate.control) result+=Rz(-(a-b)/2,target) result+=CNOT(gate.control,target) #result+=Rz(-(a+b)/2,target) result+=Ry(-theta/2,target) result+=CNOT(gate.control,target) result+=Ry(theta/2,target) result+=Rz(a,target=target) ''' ''' result+=Rz((a-b)/2,target) result+=CNOT(gate.control,target) #result+=Rz(-(a+b)/2,target) result+=Ry(-theta/2,target) result+=CNOT(gate.control,target) result+=Ry(theta/2,target) result+=Rz(a,target) result += Phase(numpy.pi * power / 2, gate.control) ''' result += Rx(angle=theta, target=target, control=gate.control) result += Phase(numpy.pi * power / 2, gate.control) elif gate.name == 'Y': ### off by global phase of Exp[ pi power /2] theta = power * numpy.pi ''' result+=Phase(numpy.pi*power/2,gate.control) result+=CNOT(gate.control,target) result+=Ry(-theta/2,target) result+=CNOT(gate.control,target) result+=Ry(theta/2,target) ''' a = 0 b = 0 # result+=Rz((a-b)/2,target) result += CNOT(gate.control, target) # result+=Rz(-(a+b)/2,target) result += Ry(-theta / 2, target) result += CNOT(gate.control, target) result += Ry(theta / 2, target) # result+=Rz(a,target) result += Phase(numpy.pi * power / 2, gate.control) elif gate.name == 'Z': a = 0 b = power * numpy.pi theta = 0 result += Rz(b / 2, target) result += CNOT(gate.control, target) result += Rz(-b / 2, target) result += CNOT(gate.control, target) # result+=Rz(a,target) result += Phase(numpy.pi * power / 2, gate.control) ''' result+=Rz(b/2,target) result+=CNOT(gate.control,target) result+=Rz(-b/2,target) result+=CNOT(gate.control,target) ''' return result
assert (numpy.isclose(wfn1.inner(wfn2), 1.0)) @pytest.mark.parametrize( "gate, theta, phi, lambd", [ (Rx(target=0, control=None, angle=numpy.pi / 5), numpy.pi / 5, -numpy.pi / 2, numpy.pi / 2), # Rx(angle) = u3(angle, -pi/2, pi/2) (Rx(target=0, control=1, angle=numpy.pi / 6), numpy.pi / 6, -numpy.pi / 2, numpy.pi / 2), (Rx(target=0, control=None, angle=numpy.pi / 7), numpy.pi / 7, -numpy.pi / 2, numpy.pi / 2), (Rx(target=0, control=1, angle=numpy.pi / 8), numpy.pi / 8, -numpy.pi / 2, numpy.pi / 2), (Ry(target=0, control=1, angle=numpy.pi / 4), numpy.pi / 4, 0, 0), # Ry(angle) = u3(angle, 0, 0) (Ry(target=0, control=1, angle=numpy.pi / 5), numpy.pi / 5, 0, 0), (Ry(target=0, control=1, angle=numpy.pi / 3), numpy.pi / 3, 0, 0), (Ry(target=0, control=1, angle=numpy.pi / 2), numpy.pi / 2, 0, 0), (Rz(target=0, control=None, angle=numpy.pi), 0, 0, numpy.pi), # Rz(angle) = U(0, 0, angle) (Rz(target=0, control=1, angle=numpy.pi / 6), 0, 0, numpy.pi / 6), (Rz(target=0, control=None, angle=numpy.pi / 7), 0, 0, numpy.pi / 7), (Rz(target=0, control=1, angle=numpy.pi / 8), 0, 0, numpy.pi / 8) ]) 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,
def get_axbxc_decomp(gate): if not isinstance(gate, PowerGateImpl) or gate.name not in ['X', 'Y', 'Z']: return QCircuit.wrap_gate(gate) power = gate.parameter target = gate.target result = QCircuit() if gate.name == 'X': a = -numpy.pi / 2 b = numpy.pi / 2 theta = power * numpy.pi ''' result+=Phase(numpy.pi*power/2,gate.control) result+=Rz(-(a-b)/2,target) result+=CNOT(gate.control,target) #result+=Rz(-(a+b)/2,target) result+=Ry(-theta/2,target) result+=CNOT(gate.control,target) result+=Ry(theta/2,target) result+=Rz(a,target=target) ''' ''' result+=Rz((a-b)/2,target) result+=CNOT(gate.control,target) #result+=Rz(-(a+b)/2,target) result+=Ry(-theta/2,target) result+=CNOT(gate.control,target) result+=Ry(theta/2,target) result+=Rz(a,target) result += Phase(numpy.pi * power / 2, gate.control) ''' result += Rx(angle=theta, target=target, control=gate.control) result += Phase(numpy.pi * power / 2, gate.control) elif gate.name == 'Y': ### off by global phase of Exp[ pi power /2] theta = power * numpy.pi ''' result+=Phase(numpy.pi*power/2,gate.control) result+=CNOT(gate.control,target) result+=Ry(-theta/2,target) result+=CNOT(gate.control,target) result+=Ry(theta/2,target) ''' a = 0 b = 0 # result+=Rz((a-b)/2,target) result += CNOT(gate.control, target) # result+=Rz(-(a+b)/2,target) result += Ry(-theta / 2, target) result += CNOT(gate.control, target) result += Ry(theta / 2, target) # result+=Rz(a,target) result += Phase(numpy.pi * power / 2, gate.control) elif gate.name == 'Z': a = 0 b = power * numpy.pi theta = 0 result += Rz(b / 2, target) result += CNOT(gate.control, target) result += Rz(-b / 2, target) result += CNOT(gate.control, target) # result+=Rz(a,target) result += Phase(numpy.pi * power / 2, gate.control) ''' result+=Rz(b/2,target) result+=CNOT(gate.control,target) result+=Rz(-b/2,target) result+=CNOT(gate.control,target) ''' return result