def test_entropy_bad_state_type(backend): original_backend = qibo.get_backend() qibo.set_backend(backend) entropy = callbacks.EntanglementEntropy([0]) with pytest.raises(TypeError): _ = entropy("test") qibo.set_backend(original_backend)
def test_entropy_product_state(): """Check that the |++> state has zero entropy.""" entropy = callbacks.EntanglementEntropy() state = np.ones(4) / 2.0 result = entropy(state).numpy() np.testing.assert_allclose(result, 0, atol=_atol)
def test_entropy_multiple_executions(accelerators): """Check entropy calculation when the callback is used in multiple executions.""" entropy = callbacks.EntanglementEntropy([0]) target_c = Circuit(2) target_c.add([gates.RY(0, 0.1234), gates.CNOT(0, 1)]) target_state = target_c().numpy() c = Circuit(2, accelerators) c.add(gates.RY(0, 0.1234)) c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) state = c() np.testing.assert_allclose(state.numpy(), target_state) target_c = Circuit(2) target_c.add([gates.RY(0, 0.4321), gates.CNOT(0, 1)]) target_state = target_c().numpy() c = Circuit(2, accelerators) c.add(gates.RY(0, 0.4321)) c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) state = c() np.testing.assert_allclose(state.numpy(), target_state) def target_entropy(t): cos = np.cos(t / 2.0)**2 sin = np.sin(t / 2.0)**2 return -cos * np.log2(cos) - sin * np.log2(sin) target = [0, target_entropy(0.1234), 0, target_entropy(0.4321)] np.testing.assert_allclose(entropy[:].numpy(), target, atol=_atol)
def test_entropy_singlet_state(backend): """Check that the singlet state has maximum entropy.""" from qibo import K entropy = callbacks.EntanglementEntropy([0]) state = np.zeros(4) state[0], state[-1] = 1, 1 state = K.cast(state / np.sqrt(2)) result = entropy(state) K.assert_allclose(result, 1.0)
def test_entropy_switch_partition(): """Check that partition is switched to the largest counterpart.""" entropy = callbacks.EntanglementEntropy([0]) # Prepare ghz state of 5 qubits state = np.zeros(2**5) state[0], state[-1] = 1, 1 state = state / np.sqrt(2) result = entropy(state).numpy() np.testing.assert_allclose(result, 1.0)
def test_entropy_product_state(backend): """Check that the |++> state has zero entropy.""" original_backend = qibo.get_backend() qibo.set_backend(backend) entropy = callbacks.EntanglementEntropy() state = np.ones(4) / 2.0 result = entropy(state) np.testing.assert_allclose(result, 0, atol=_atol) qibo.set_backend(original_backend)
def test_entropy_large_circuit(backend, accelerators): """Check that entropy calculation works for variational like circuit.""" original_backend = qibo.get_backend() qibo.set_backend(backend) thetas = np.pi * np.random.random((3, 8)) target_entropy = callbacks.EntanglementEntropy([0, 2, 4, 5]) c1 = Circuit(8) c1.add((gates.RY(i, thetas[0, i]) for i in range(8))) c1.add((gates.CZ(i, i + 1) for i in range(0, 7, 2))) state1 = c1() e1 = target_entropy(state1) c2 = Circuit(8) c2.add((gates.RY(i, thetas[1, i]) for i in range(8))) c2.add((gates.CZ(i, i + 1) for i in range(1, 7, 2))) c2.add(gates.CZ(0, 7)) state2 = (c1 + c2)() e2 = target_entropy(state2) c3 = Circuit(8) c3.add((gates.RY(i, thetas[2, i]) for i in range(8))) c3.add((gates.CZ(i, i + 1) for i in range(0, 7, 2))) state3 = (c1 + c2 + c3)() e3 = target_entropy(state3) entropy = callbacks.EntanglementEntropy([0, 2, 4, 5]) c = Circuit(8, accelerators) c.add(gates.CallbackGate(entropy)) c.add((gates.RY(i, thetas[0, i]) for i in range(8))) c.add((gates.CZ(i, i + 1) for i in range(0, 7, 2))) c.add(gates.CallbackGate(entropy)) c.add((gates.RY(i, thetas[1, i]) for i in range(8))) c.add((gates.CZ(i, i + 1) for i in range(1, 7, 2))) c.add(gates.CZ(0, 7)) c.add(gates.CallbackGate(entropy)) c.add((gates.RY(i, thetas[2, i]) for i in range(8))) c.add((gates.CZ(i, i + 1) for i in range(0, 7, 2))) c.add(gates.CallbackGate(entropy)) state = c() np.testing.assert_allclose(state3, state) np.testing.assert_allclose(entropy[:], [0, e1, e2, e3]) qibo.set_backend(original_backend)
def test_getitem_bad_indexing(backend): entropy = callbacks.EntanglementEntropy([0]) c = Circuit(2) c.add(gates.RY(0, 0.1234)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) final_state = c() entropy[0] with pytest.raises(IndexError): entropy[1] with pytest.raises(IndexError): entropy["a"]
def test_entropy_in_compiled_circuit(backend): """Check that entropy calculation works when circuit is compiled.""" from qibo import get_backend entropy = callbacks.EntanglementEntropy([0]) c = Circuit(2) c.add(gates.CallbackGate(entropy)) c.add(gates.H(0)) c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) c.compile() final_state = c() K.assert_allclose(entropy[:], [0, 0, 1.0], atol=_atol)
def test_entropy_singlet_state(): """Check that the singlet state has maximum entropy.""" entropy = callbacks.EntanglementEntropy([0]) state = np.zeros(4) state[0], state[-1] = 1, 1 state = state / np.sqrt(2) # Pass the state as `tf.Tensor` to test this functionality as well import tensorflow as tf from qibo.config import DTYPES state = tf.convert_to_tensor(state, dtype=DTYPES.get('DTYPECPX')) result = entropy(state).numpy() np.testing.assert_allclose(result, 1.0)
def test_entropy_in_circuit(accelerators): """Check that entropy calculation works in circuit.""" entropy = callbacks.EntanglementEntropy([0]) c = Circuit(2, accelerators) c.add(gates.CallbackGate(entropy)) c.add(gates.H(0)) c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) state = c() target = [0, 0, 1.0] np.testing.assert_allclose(entropy[:].numpy(), target, atol=_atol)
def test_entropy_switch_partition(backend): """Check that partition is switched to the largest counterpart.""" original_backend = qibo.get_backend() qibo.set_backend(backend) entropy = callbacks.EntanglementEntropy([0]) # Prepare ghz state of 5 qubits state = np.zeros(2**5) state[0], state[-1] = 1, 1 state = state / np.sqrt(2) result = entropy(state) np.testing.assert_allclose(result, 1.0) qibo.set_backend(original_backend)
def test_entropy_numerical(backend): """Check that entropy calculation does not fail for tiny eigenvalues.""" from qibo import K eigvals = np.array([-1e-10, -1e-15, -2e-17, -1e-18, -5e-60, 1e-48, 4e-32, 5e-14, 1e-14, 9.9e-13, 9e-13, 5e-13, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-7, 1, 4, 10]) rho = K.cast(np.diag(eigvals)) callback = callbacks.EntanglementEntropy() result = callback.entropy(rho) mask = eigvals > 0 target = - (eigvals[mask] * np.log2(eigvals[mask])).sum() K.assert_allclose(result, target)
def test_callbacks_fusion(backend): """Check entropy calculation in fused circuit.""" from qibo import callbacks entropy = callbacks.EntanglementEntropy([0]) c = Circuit(5) c.add(gates.H(0)) c.add(gates.X(1)) c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) fused_c = c.fuse() K.assert_allclose(fused_c(), c()) target_entropy = [0.0, 1.0, 0.0, 1.0] K.assert_allclose(entropy[:], target_entropy, atol=1e-7)
def test_entropy_bad_indexing(): """Check exceptions in ``Callback.__getitem__``.""" entropy = callbacks.EntanglementEntropy([0]) c = Circuit(2) c.add(gates.RY(0, 0.1234)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) state = c() entropy[0] with pytest.raises(IndexError): entropy[1] with pytest.raises(IndexError): entropy["a"]
def test_entropy_numerical(): """Check that entropy calculation does not fail for tiny eigenvalues.""" import tensorflow as tf from qibo.config import DTYPES eigvals = np.array([-1e-10, -1e-15, -2e-17, -1e-18, -5e-60, 1e-48, 4e-32, 5e-14, 1e-14, 9.9e-13, 9e-13, 5e-13, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-7, 1, 4, 10]) rho = tf.convert_to_tensor(np.diag(eigvals), dtype=DTYPES.get('DTYPECPX')) callback = callbacks.EntanglementEntropy() result = callback.entropy(rho).numpy() mask = eigvals > 0 target = - (eigvals[mask] * np.log2(eigvals[mask])).sum() np.testing.assert_allclose(result, target)
def test_entropy_in_circuit(accelerators): """Check that entropy calculation works in circuit.""" entropy = callbacks.EntanglementEntropy([0], compute_spectrum=True) c = Circuit(2, accelerators) c.add(gates.CallbackGate(entropy)) c.add(gates.H(0)) c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) state = c() target = [0, 0, 1.0] np.testing.assert_allclose(entropy[:].numpy(), target, atol=_atol) target_spectrum = [0, 0, np.log(2), np.log(2)] entropy_spectrum = np.concatenate(entropy.spectrum).ravel().tolist() np.testing.assert_allclose(entropy_spectrum, target_spectrum, atol=_atol)
def test_entropy_in_circuit(backend, density_matrix): """Check that entropy calculation works in circuit.""" entropy = callbacks.EntanglementEntropy([0], compute_spectrum=True) c = Circuit(2, density_matrix=density_matrix) c.add(gates.CallbackGate(entropy)) c.add(gates.H(0)) c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) state = c() target = [0, 0, 1.0] K.assert_allclose(entropy[:], target, atol=_atol) target_spectrum = [0, 0, np.log(2), np.log(2)] entropy_spectrum = np.concatenate(entropy.spectrum).ravel().tolist() K.assert_allclose(entropy_spectrum, target_spectrum, atol=_atol)
def test_fuse_with_callback(accelerators): """Check entropy calculation in fused circuit.""" from qibo import callbacks entropy = callbacks.EntanglementEntropy([0]) c = Circuit(2, accelerators) c.add(gates.H(0)) c.add(gates.X(1)) c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) fused_c = c.fuse() target_state = c() final_state = fused_c() np.testing.assert_allclose(final_state, target_state) target_entropy = [0.0, 1.0, 0.0, 1.0] np.testing.assert_allclose(entropy[:], target_entropy, atol=1e-7)
def test_entropy_in_distributed_circuit(backend, accelerators, gateconf, target_entropy): """Check that various entropy configurations work in distributed circuit.""" target_c = Circuit(4) target_c.add([gates.H(0), gates.CNOT(0, 1)]) target_state = target_c() entropy = callbacks.EntanglementEntropy([0]) c = Circuit(4, accelerators) for gate in gateconf: if gate == "H": c.add(gates.H(0)) elif gate == "CNOT": c.add(gates.CNOT(0, 1)) elif gate == "entropy": c.add(gates.CallbackGate(entropy)) final_state = c() K.assert_allclose(final_state, target_state) K.assert_allclose(entropy[:], target_entropy, atol=_atol)
def test_entropy_in_distributed_circuit(): """Check that various entropy configurations work in distributed circuit.""" target_c = Circuit(2) target_c.add([gates.H(0), gates.CNOT(0, 1)]) target_state = target_c().numpy() accelerators = {"/GPU:0": 1, "/GPU:1": 1} entropy = callbacks.EntanglementEntropy([0]) c = Circuit(2, accelerators) c.add([gates.H(0), gates.CNOT(0, 1), gates.CallbackGate(entropy)]) final_state = c().numpy() np.testing.assert_allclose(final_state, target_state) np.testing.assert_allclose(entropy[:].numpy(), [1.0], atol=_atol) entropy = callbacks.EntanglementEntropy([0]) c = Circuit(2, accelerators) c.add([gates.H(0), gates.CallbackGate(entropy), gates.CNOT(0, 1)]) final_state = c().numpy() np.testing.assert_allclose(final_state, target_state) np.testing.assert_allclose(entropy[:].numpy(), [0.0], atol=_atol) entropy = callbacks.EntanglementEntropy([0]) c = Circuit(2, accelerators) c.add([gates.CallbackGate(entropy), gates.H(0), gates.CNOT(0, 1)]) final_state = c().numpy() np.testing.assert_allclose(final_state, target_state) np.testing.assert_allclose(entropy[:].numpy(), [0.0], atol=_atol) entropy = callbacks.EntanglementEntropy([0]) c = Circuit(2, accelerators) c.add([gates.CallbackGate(entropy), gates.H(0), gates.CNOT(0, 1), gates.CallbackGate(entropy)]) final_state = c().numpy() np.testing.assert_allclose(final_state, target_state) np.testing.assert_allclose(entropy[:].numpy(), [0, 1.0], atol=_atol) entropy = callbacks.EntanglementEntropy([0]) c = Circuit(2, accelerators) c.add([gates.H(0), gates.CallbackGate(entropy), gates.CNOT(0, 1), gates.CallbackGate(entropy)]) final_state = c().numpy() np.testing.assert_allclose(final_state, target_state) np.testing.assert_allclose(entropy[:].numpy(), [0, 1.0], atol=_atol) entropy = callbacks.EntanglementEntropy([0]) c = Circuit(2, accelerators) c.add([gates.CallbackGate(entropy), gates.H(0), gates.CallbackGate(entropy), gates.CNOT(0, 1)]) final_state = c().numpy() np.testing.assert_allclose(final_state, target_state) np.testing.assert_allclose(entropy[:].numpy(), [0, 0], atol=_atol)
def test_entropy_random_state(): """Check that entropy calculation agrees with numpy.""" # Generate a random positive and hermitian density matrix rho = np.random.random((8, 8)) + 1j * np.random.random((8, 8)) rho = rho + rho.conj().T _, u = np.linalg.eigh(rho) s = 5 * np.random.random(8) s = s / s.sum() rho = u.dot(np.diag(s)).dot(u.conj().T) callback = callbacks.EntanglementEntropy(compute_spectrum=True) result = callback._entropy(rho) target = -(s * np.log2(s)).sum() np.testing.assert_allclose(result.numpy(), target) ref_eigvals = np.linalg.eigvalsh(rho) masked_eigvals = ref_eigvals[np.where(ref_eigvals > EIGVAL_CUTOFF)] ref_spectrum = -np.log(masked_eigvals) np.testing.assert_allclose(callback.spectrum[0].numpy(), ref_spectrum)
def test_entropy_in_compiled_circuit(): """Check that entropy calculation works when circuit is compiled.""" import qibo original_backend = qibo.get_backend() qibo.set_backend("matmuleinsum") entropy = callbacks.EntanglementEntropy([0]) c = Circuit(2) c.add(gates.CallbackGate(entropy)) c.add(gates.H(0)) c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) c.compile() state = c() qibo.set_backend("custom") target = [0, 0, 1.0] np.testing.assert_allclose(entropy[:].numpy(), target, atol=_atol) qibo.set_backend(original_backend)
def test_entropy_in_compiled_circuit(backend): """Check that entropy calculation works when circuit is compiled.""" original_backend = qibo.get_backend() qibo.set_backend(backend) entropy = callbacks.EntanglementEntropy([0]) c = Circuit(2) c.add(gates.CallbackGate(entropy)) c.add(gates.H(0)) c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) if backend == "custom": with pytest.raises(RuntimeError): c.compile() else: c.compile() final_state = c() np.testing.assert_allclose(entropy[:], [0, 0, 1.0], atol=_atol) qibo.set_backend(original_backend)
def test_entropy_density_matrix(backend): from qibo.tests.utils import random_density_matrix rho = random_density_matrix(4) # this rho is not always positive. Make rho positive for this application _, u = np.linalg.eigh(rho) rho = u.dot(np.diag(5 * np.random.random(u.shape[0]))).dot(u.conj().T) # this is a positive rho entropy = callbacks.EntanglementEntropy([1, 3]) entropy.density_matrix = True final_ent = entropy(rho) rho = rho.reshape(8 * (2,)) reduced_rho = np.einsum("abcdafch->bdfh", rho).reshape((4, 4)) eigvals = np.linalg.eigvalsh(reduced_rho).real # assert that all eigenvalues are non-negative assert (eigvals >= 0).prod() mask = eigvals > 0 target_ent = - (eigvals[mask] * np.log2(eigvals[mask])).sum() K.assert_allclose(final_ent, target_ent)
def test_circuit_gate_generator_errors(backend, accelerators): from qibo import callbacks original_backend = qibo.get_backend() qibo.set_backend(backend) smallc = Circuit(2, accelerators=accelerators) smallc.add((gates.H(i) for i in range(2))) with pytest.raises(ValueError): next(smallc.on_qubits(0, 1, 2)) smallc = Circuit(2, accelerators=accelerators) smallc.add(gates.Flatten(np.ones(4) / np.sqrt(2))) with pytest.raises(NotImplementedError): next(smallc.on_qubits(0, 1)) smallc = Circuit(4, accelerators=accelerators) smallc.add(gates.CallbackGate(callbacks.EntanglementEntropy([0, 1]))) with pytest.raises(NotImplementedError): next(smallc.on_qubits(0, 1, 2, 3)) qibo.set_backend(original_backend)
def test_entropy_multiple_executions(backend, accelerators): """Check entropy calculation when the callback is used in multiple executions.""" target_c = Circuit(4) target_c.add([gates.RY(0, 0.1234), gates.CNOT(0, 1)]) target_state = target_c() entropy = callbacks.EntanglementEntropy([0]) c = Circuit(4, accelerators) c.add(gates.RY(0, 0.1234)) c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) state = c() K.assert_allclose(state, target_state) target_c = Circuit(4) target_c.add([gates.RY(0, 0.4321), gates.CNOT(0, 1)]) target_state = target_c() c = Circuit(4, accelerators) c.add(gates.RY(0, 0.4321)) c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) state = c() K.assert_allclose(state, target_state) def target_entropy(t): cos = np.cos(t / 2.0) ** 2 sin = np.sin(t / 2.0) ** 2 return - cos * np.log2(cos) - sin * np.log2(sin) target = [0, target_entropy(0.1234), 0, target_entropy(0.4321)] K.assert_allclose(entropy[:], target, atol=_atol) c = Circuit(8, accelerators) with pytest.raises(RuntimeError): c.add(gates.CallbackGate(entropy)) state = c()
def test_entanglement_entropy(backend): """Check that entanglement entropy calculation works for density matrices.""" original_backend = qibo.get_backend() qibo.set_backend(backend) rho = utils.random_density_matrix(4) # this rho is not always positive. Make rho positive for this application _, u = np.linalg.eigh(rho) rho = u.dot(np.diag(5 * np.random.random(u.shape[0]))).dot(u.conj().T) # this is a positive rho entropy = callbacks.EntanglementEntropy([1, 3]) entropy.density_matrix = True final_ent = entropy(rho) rho = rho.reshape(8 * (2, )) reduced_rho = np.einsum("abcdafch->bdfh", rho).reshape((4, 4)) eigvals = np.linalg.eigvalsh(reduced_rho).real # assert that all eigenvalues are non-negative assert (eigvals >= 0).prod() mask = eigvals > 0 target_ent = -(eigvals[mask] * np.log2(eigvals[mask])).sum() np.testing.assert_allclose(final_ent, target_ent) qibo.set_backend(original_backend)
def test_state_invalid_type(): """Check that ``TypeError`` is raised for bad state type.""" entropy = callbacks.EntanglementEntropy([0]) # Prepare ghz state of 5 qubits with pytest.raises(TypeError): result = entropy([0, 1, 0, 0])
def test_callback_gate_errors(): from qibo import callbacks entropy = callbacks.EntanglementEntropy([0]) gate = gates.CallbackGate(entropy) with pytest.raises(ValueError): gate.construct_unitary()