def __init__( self, utry: UnitaryLike, radixes: Sequence[int] = [], ) -> None: self.utry = UnitaryMatrix(utry, radixes) self.size = self.utry.get_size() self.radixes = self.utry.get_radixes()
def test_corner_case_2(self) -> None: circuit = Circuit(6) circuit.append_gate(ConstantUnitaryGate(UnitaryMatrix.random(1)), [0]) circuit.append_gate(ConstantUnitaryGate(UnitaryMatrix.random(1)), [1]) circuit.append_gate(ConstantUnitaryGate(UnitaryMatrix.random(1)), [5]) circuit.append_gate( ConstantUnitaryGate(UnitaryMatrix.random(2), ), [ 3, 0, ], ) circuit.append_gate( ConstantUnitaryGate(UnitaryMatrix.random(2), ), [ 5, 0, ], ) circuit.append_gate(ConstantUnitaryGate(UnitaryMatrix.random(1)), [3]) circuit.append_gate( ConstantUnitaryGate(UnitaryMatrix.random(4), ), [ 4, 0, 1, 2, ], ) circuit.append_gate(ConstantUnitaryGate(UnitaryMatrix.random(1)), [5]) circuit.append_gate( ConstantUnitaryGate(UnitaryMatrix.random(3), ), [ 5, 0, 1, ], ) circuit.append_gate(ConstantUnitaryGate(UnitaryMatrix.random(1)), [1]) utry = circuit.get_unitary() ScanPartitioner(3).run(circuit, {}) assert all( isinstance(op.gate, CircuitGate) or len(op.location) > 3 for op in circuit) assert all(not isinstance(op.gate, TaggedGate) or not op.gate.tag != '__fold_placeholder__' for op in circuit) assert circuit.get_unitary() == utry for cycle_index in range(circuit.get_num_cycles()): assert not circuit._is_cycle_idle(cycle_index)
class ConstantUnitaryGate(ConstantGate): """A constant unitary operator.""" def __init__( self, utry: UnitaryLike, radixes: Sequence[int] = [], ) -> None: self.utry = UnitaryMatrix(utry, radixes) self.size = self.utry.get_size() self.radixes = self.utry.get_radixes()
def test_valid_3(self) -> None: u1 = UnitaryMatrix.random(3) u2 = UnitaryMatrix.random(2) ub = UnitaryBuilder(3) ub.apply_left(u1, [0, 1, 2]) assert ub.get_unitary() == u1 ub.apply_left(u2, [1, 2]) prod = u1 @ np.kron(np.identity(2), u2.get_numpy()) assert ub.get_unitary() == prod
def test_valid_2(self) -> None: u1 = UnitaryMatrix.random(3) u2 = UnitaryMatrix.random(2) ub = UnitaryBuilder(3) ub.apply_right(u1, [0, 1, 2]) assert ub.get_unitary() == u1 ub.apply_right(u2, [0, 1]) prod = np.kron(u2.get_numpy(), np.identity(2)) @ u1.get_numpy() assert ub.get_unitary() == prod
def get_unitary(self, params: Sequence[float] = []) -> UnitaryMatrix: """Returns the unitary for this gate, see Unitary for more info.""" self.check_parameters(params) H = dot_product(params, self.sigmav) eiH = sp.linalg.expm(H) return UnitaryMatrix(eiH, check_arguments=False)
def test_full_pauli_gate() -> None: circuit = Circuit(3) circuit.append_gate(PauliGate(3), [0, 1, 2]) cost = HilbertSchmidtResiduals(circuit, UnitaryMatrix(unitary_group.rvs(8))) circuit.minimize(cost) assert cost.get_cost(circuit.get_params()) < 1e-6
def get_unitary_and_grad( self, params: Sequence[float] = [], ) -> tuple[UnitaryMatrix, np.ndarray]: """Returns the unitary and gradient for this gate.""" self.check_parameters(params) a, l = self.split_params(params) l = softmax(l, 10) P = np.sum([a * s.get_numpy() for a, s in zip(l, self.perms)], 0) G = self.gate.get_unitary(a).get_numpy() # type: ignore G = np.kron(G, self.I) PG = P @ G GPT = G @ P.T PGPT = P @ GPT dG = self.gate.get_grad(a) # type: ignore dG = np.kron(dG, self.I) dG = P @ dG @ P.T perm_array = np.array([perm.get_numpy() for perm in self.perms]) dP = perm_array @ GPT + PG @ perm_array.transpose((0, 2, 1)) - 2 * PGPT dP = np.array([10 * x * y for x, y in zip(l, dP)]) U = UnitaryMatrix.closest_to(PGPT, self.get_radixes()) return U, np.concatenate([dG, dP])
class ZGate(ConstantGate, QubitGate): """The Pauli Z gate.""" size = 1 qasm_name = 'z' utry = UnitaryMatrix([ [1, 0], [0, -1], ], )
class YGate(ConstantGate, QubitGate): """The Pauli Y gate.""" size = 1 qasm_name = 'y' utry = UnitaryMatrix([ [0, -1j], [1j, 0], ], )
class TGate(ConstantGate, QubitGate): """The T gate.""" size = 1 qasm_name = 't' utry = UnitaryMatrix([ [1, 0], [0, np.exp(1j * np.pi / 4)], ], )
class TdgGate(ConstantGate, QubitGate): """The T Dagger gate.""" size = 1 qasm_name = 'tdg' utry = UnitaryMatrix([ [1, 0], [0, np.exp(-1j * np.pi / 4)], ], )
class SGate(ConstantGate, QubitGate): """The S gate.""" size = 1 qasm_name = 's' utry = UnitaryMatrix([ [1, 0], [0, 1j], ], )
class HGate(ConstantGate, QubitGate): """The Hadamard gate.""" size = 1 qasm_name = 'h' utry = UnitaryMatrix([ [np.sqrt(2) / 2, np.sqrt(2) / 2], [np.sqrt(2) / 2, -np.sqrt(2) / 2], ], )
class XGate(ConstantGate, QubitGate): """The Pauli X gate.""" size = 1 qasm_name = 'x' utry = UnitaryMatrix([ [0, 1], [1, 0], ], )
class SqrtXGate(ConstantGate, QubitGate): """The Sqrt(X) gate.""" size = 1 qasm_name = 'sx' utry = UnitaryMatrix([ [np.sqrt(2) / 2, -1j * np.sqrt(2) / 2], [-1j * np.sqrt(2) / 2, np.sqrt(2) / 2], ], )
def get_unitary(self, params: Sequence[float] = []) -> UnitaryMatrix: """Returns the unitary for this gate, see Unitary for more info.""" self.check_parameters(params) if hasattr(self, 'utry'): return self.utry # TODO: Find reference U = self.gate.get_unitary(params) right = np.kron(self.OneProj, U) return UnitaryMatrix(self.left + right, self.get_radixes())
def get_unitary(self, params: Sequence[float] = []) -> UnitaryMatrix: """Returns the unitary for this gate, see Unitary for more info.""" self.check_parameters(params) exp = np.exp(1j * params[0]) return UnitaryMatrix([ [1, 0], [0, exp], ], )
def get_unitary_and_grad( self, params: Sequence[float] = [], ) -> tuple[UnitaryMatrix, np.ndarray]: """Returns the unitary and gradient, see Gate for more info.""" self.check_parameters(params) H = dot_product(params, self.sigmav) U, dU = dexpmv(H, self.sigmav) return UnitaryMatrix(U, check_arguments=False), dU
class SqrtCNOTGate(ConstantGate, QubitGate): size = 2 qasm_name = 'csx' utry = UnitaryMatrix([ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0.5 + 0.5j, 0.5 - 0.5j], [0, 0, 0.5 - 0.5j, 0.5 + 0.5j], ], )
class CHGate(ConstantGate, QubitGate): """The controlled-H gate.""" size = 2 qasm_name = 'ch' utry = UnitaryMatrix([ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, np.sqrt(2) / 2, np.sqrt(2) / 2], [0, 0, np.sqrt(2) / 2, -np.sqrt(2) / 2], ], )
def get_unitary(self, params: Sequence[float] = []) -> UnitaryMatrix: """Returns the unitary for this gate, see Unitary for more info.""" self.check_parameters(params) a, l = self.split_params(params) l = softmax(l, 10) P = np.sum([a * s.get_numpy() for a, s in zip(l, self.perms)], 0) G = self.gate.get_unitary(a) # type: ignore # TODO: Change get_unitary params to be union with np.ndarray PGPT = P @ np.kron(G.get_numpy(), self.I) @ P.T return UnitaryMatrix.closest_to(PGPT, self.get_radixes())
def test_minimize_ceres() -> None: circ = Circuit(1) circ.append_gate(RXGate(), location=[0], params=[0.0]) xgate = XGate() xutry = xgate.get_unitary() cost = HilbertSchmidtResidualsGenerator().gen_cost( circ, UnitaryMatrix(-1j * xutry.get_numpy()), ) minimizer = CeresMinimizer() x = minimizer.minimize(cost, np.array([np.pi / 2])) assert cost.get_cost(x) < 1e-6, x
def get_unitary(self, params: Sequence[float] = []) -> UnitaryMatrix: """Returns the unitary for this gate, see Unitary for more info.""" self.check_parameters(params) cos = np.cos(params[0] / 2) sin = -1j * np.sin(params[0] / 2) return UnitaryMatrix([ [cos, sin], [sin, cos], ], )
class SwapGate(ConstantGate, QubitGate): """The swap gate.""" size = 2 qasm_name = 'swap' utry = UnitaryMatrix([ [1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1], ], )
class SdgGate(ConstantGate, QubitGate): """The S Dagger gate.""" size = 1 qasm_name = 'sdg' utry = UnitaryMatrix( [ [1, 0], [0, -1j], ], )
class CNOTGate(ConstantGate, QubitGate): """The controlled-not or controlled-X gate.""" size = 2 qasm_name = 'cx' utry = UnitaryMatrix([ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], ], )
class XXGate(ConstantGate, QubitGate): """The Ising XX coupling gate.""" size = 2 qasm_name = 'rxx(pi/2)' utry = UnitaryMatrix([ [np.sqrt(2) / 2, 0, 0, -1j * np.sqrt(2) / 2], [0, np.sqrt(2) / 2, -1j * np.sqrt(2) / 2, 0], [0, -1j * np.sqrt(2) / 2, np.sqrt(2) / 2, 0], [-1j * np.sqrt(2) / 2, 0, 0, np.sqrt(2) / 2], ], )
def get_unitary(self, params: Sequence[float] = []) -> UnitaryMatrix: """Returns the unitary for this gate, see Unitary for more info.""" self.check_parameters(params) sq2 = np.sqrt(2) / 2 eip = np.exp(1j * params[0]) eil = np.exp(1j * params[1]) return UnitaryMatrix([ [sq2, -eil * sq2], [eip * sq2, eip * eil * sq2], ], )
class CYGate(ConstantGate, QubitGate): """The controlled-Y gate.""" size = 2 qasm_name = 'cy' utry = UnitaryMatrix( [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, -1j], [0, 0, 1j, 0], ], )