def test_fubini_study_angle() -> None: for _ in range(REPS): theta = random.uniform(-np.pi, +np.pi) ang = qf.fubini_study_angle(qf.I(0).tensor, qf.Rx(theta, 0).su().tensor) assert np.isclose(2 * ang / abs(theta), 1.0) ang = qf.fubini_study_angle(qf.I(0).tensor, qf.Ry(theta, 0).tensor) assert np.isclose(2 * ang / abs(theta), 1.0) ang = qf.fubini_study_angle(qf.I(0).tensor, qf.Rz(theta, 0).tensor) assert np.isclose(2 * ang / abs(theta), 1.0) ang = qf.fubini_study_angle(qf.Swap(0, 1).tensor, qf.PSwap(theta, 0, 1).tensor) assert np.isclose(2 * ang / abs(theta), 1.0) ang = qf.fubini_study_angle(qf.I(0).tensor, qf.PhaseShift(theta, 0).tensor) assert np.isclose(2 * ang / abs(theta), 1.0) assert qf.fubini_study_close(qf.Rz(theta, 0).tensor, qf.Rz(theta, 0).tensor) for n in range(1, 6): eye = qf.IdentityGate(list(range(n))) assert np.isclose(qf.fubini_study_angle(eye.tensor, eye.tensor), 0.0) with pytest.raises(ValueError): qf.fubini_study_angle(qf.RandomGate([1]).tensor, qf.RandomGate([0, 1]).tensor)
def test_gate_angle() -> None: gate0 = qf.RandomGate([1]) gate1 = qf.RandomGate([1]) qf.gate_angle(gate0, gate1) assert not qf.gates_close(gate0, gate1) assert qf.gates_close(gate0, gate0)
def test_canonical_decomposition() -> None: for tt1 in range(0, 6): for tt2 in range(tt1): for tt3 in range(tt2): t1, t2, t3 = tt1 / 12, tt2 / 12, tt3 / 12 if t3 == 0 and t1 > 0.5: continue coords = np.asarray((t1, t2, t3)) circ0 = qf.Circuit() circ0 += qf.RandomGate([0]) circ0 += qf.RandomGate([1]) circ0 += qf.Can(t1, t2, t3, 0, 1) circ0 += qf.RandomGate([0]) circ0 += qf.RandomGate([1]) gate0 = circ0.asgate() circ1 = qf.canonical_decomposition(gate0) assert qf.gates_close(gate0, circ1.asgate()) canon = circ1[1] new_coords = np.asarray( [canon.param(n) for n in ["tx", "ty", "tz"]]) assert np.allclose(coords, np.asarray(new_coords)) coords2 = qf.canonical_coords(gate0) assert np.allclose(coords, np.asarray(coords2))
def test_decomp_sqrtswap_sandwich() -> None: circ0 = qf.Circuit() circ0 += qf.Can(1 / 4, 1 / 4, 1 / 4, 0, 1) circ0 += qf.RandomGate([0]) circ0 += qf.RandomGate([1]) circ0 += qf.Can(1 / 4, 1 / 4, 1 / 4, 0, 1) gate0 = circ0.asgate() circ1 = qf.canonical_decomposition(gate0) gate1 = circ1.asgate() assert qf.gates_close(gate0, gate1)
def test_bloch_decomposition() -> None: theta = 1.23 gate0 = qf.Rn(theta, 1, 0, 0, 9) gate1 = qf.bloch_decomposition(gate0)[0] assert isinstance(gate1, qf.Gate) assert qf.gates_close(gate0, gate1) gate0 = qf.Rn(theta, 0, 1, 0, 9) gate1 = qf.bloch_decomposition(gate0)[0] assert isinstance(gate1, qf.Gate) assert qf.gates_close(gate0, gate1) gate0 = qf.Rn(theta, 0, 0, 1, 9) gate1 = qf.bloch_decomposition(gate0)[0] assert isinstance(gate1, qf.Gate) assert qf.gates_close(gate0, gate1) gate0 = qf.Rn(pi, np.sqrt(2), 0, np.sqrt(2), 9) gate1 = qf.bloch_decomposition(gate0)[0] assert isinstance(gate1, qf.Gate) assert qf.gates_close(gate0, gate1) for _ in range(REPS): gate3 = qf.RandomGate(qubits=[0]) gate4 = qf.bloch_decomposition(gate3)[0] assert isinstance(gate4, qf.Gate) assert qf.gates_close(gate3, gate4) gate5 = qf.I(0) gate6 = qf.bloch_decomposition(gate5)[0] assert isinstance(gate6, qf.Gate) assert qf.gates_close(gate5, gate6)
def sandwich_decompositions(coords0, coords1, samples=SAMPLES): """Create composite gates, decompose, and return a list of canonical coordinates""" decomps = [] for _ in range(samples): circ = qf.Circuit() circ += qf.Can(*coords0, 0, 1) circ += qf.RandomGate([0]) circ += qf.RandomGate([1]) circ += qf.Can(*coords1, 0, 1) gate = circ.asgate() coords = qf.canonical_coords(gate) decomps.append(coords) return decomps
def test_euler_decomposition() -> None: gate0 = qf.RandomGate([1]) for order in ["XYX", "XZX", "YXY", "YZY", "ZXZ", "ZYZ"]: circ1 = qf.euler_decomposition(gate0, euler=order) gate1 = circ1.asgate() assert qf.gates_close(gate0, gate1)
def test_pauli_decompose_hermitian() -> None: gate = qf.X(0) H = gate.asoperator() pl = qf.pauli_decompose_hermitian(H) assert np.allclose(pl.asoperator(), H) gate = qf.X(0) op = gate.asoperator() H = -scipy.linalg.logm(op) / 1.0j pl = qf.pauli_decompose_hermitian(H) assert np.allclose(pl.asoperator(), H) N = 4 gate2 = qf.RandomGate(range(N)) op = gate2.asoperator() H = -scipy.linalg.logm(op) / 1.0j pl = qf.pauli_decompose_hermitian(H) assert np.allclose(pl.asoperator(), H) op = np.ones(shape=[2, 2, 2]) with pytest.raises(ValueError): qf.pauli_decompose_hermitian(op) op = np.ones(shape=[4, 4]) op[0, 1] = 10000 with pytest.raises(ValueError): qf.pauli_decompose_hermitian(op) op = np.ones(shape=[3, 3]) with pytest.raises(ValueError): qf.pauli_decompose_hermitian(op)
def test_inverse_random() -> None: K = 4 for _ in range(REPS): gate = qf.RandomGate(range(K)) inv = gate.H gate1 = inv @ gate # TODO: almost_identity assert qf.gates_close(qf.IdentityGate([0, 1, 2, 3]), gate1)
def test_entropy() -> None: N = 4 rho0 = qf.mixed_density(N) ent = qf.entropy(rho0, base=2) assert np.isclose(ent, N) # Entropy invariant to unitary evolution chan = qf.RandomGate(range(N)).aschannel() rho1 = chan.evolve(rho0) ent = qf.entropy(rho1, base=2) assert np.isclose(ent, N)
def test_canonical_decomp_sandwich() -> None: for _ in range(REPS): # Random CZ sandwich circ0 = qf.Circuit() circ0 += qf.RandomGate([0]) circ0 += qf.RandomGate([1]) circ0 += qf.CZ(0, 1) circ0 += qf.YPow(0.4, 0) circ0 += qf.YPow(0.25, 1) circ0 += qf.CZ(0, 1) circ0 += qf.RandomGate([0]) circ0 += qf.RandomGate([1]) gate0 = circ0.asgate() circ1 = qf.canonical_decomposition(gate0) gate1 = circ1.asgate() assert qf.gates_close(gate0, gate1) assert qf.almost_unitary(gate0)
def test_mutual_info() -> None: rho0 = qf.mixed_density(4) info0 = qf.mutual_info(rho0, qubits0=[0, 1], qubits1=[2, 3]) # Information invariant to local unitary evolution chan = qf.RandomGate(range(2)).aschannel() rho1 = chan.evolve(rho0) info1 = qf.mutual_info(rho1, qubits0=[0, 1], qubits1=[2, 3]) assert np.isclose(info0, info1) info2 = qf.mutual_info(rho1, qubits0=[0, 1]) assert np.isclose(info0, info2)
def test_kronecker_decomposition() -> None: for _ in range(REPS): left = qf.RandomGate([1]).asoperator() right = qf.RandomGate([1]).asoperator() both = np.kron(left, right) gate0 = qf.Unitary(both, [0, 1]) circ = qf.kronecker_decomposition(gate0) gate1 = circ.asgate() assert qf.gates_close(gate0, gate1) circ2 = qf.Circuit() circ2 += qf.Z(0) circ2 += qf.H(1) gate2 = circ2.asgate() circ3 = qf.kronecker_decomposition(gate2) gate3 = circ3.asgate() assert qf.gates_close(gate2, gate3) circ4 = qf.kronecker_decomposition(gate0, euler="XYX") gate4 = circ4.asgate() assert qf.gates_close(gate0, gate4)
def test_circuit_to_latex_error() -> None: circ = qf.Circuit([qf.RandomGate([0, 1, 2])]) with pytest.raises(NotImplementedError): qf.circuit_to_latex(circ)
def test_circuit_to_cirq_unitary() -> None: gate0 = qf.RandomGate([4, 5]) circ0 = qf.Circuit([gate0]) cqc = circuit_to_cirq(circ0) circ1 = cirq_to_circuit(cqc) assert qf.circuits_close(circ0, circ1)
def test_canonical_decomp_random() -> None: for _ in range(REPS * 2): gate0 = qf.RandomGate([0, 1]) gate1 = qf.canonical_decomposition(gate0).asgate() assert qf.gates_close(gate0, gate1)
def test_cnot_decomposition() -> None: for _ in range(REPS): gate0 = qf.RandomGate([4, 8]) circ = qf.cnot_decomposition(gate0) gate1 = circ.asgate() assert qf.gates_close(gate0, gate1)
def test_zyz_decomposition() -> None: gate0 = qf.RandomGate([1]) circ1 = qf.zyz_decomposition(gate0) gate1 = circ1.asgate() assert qf.gates_close(gate0, gate1)