def test_measurement_density_matrix(backend): from qibo.tests.test_measurement_gate import assert_result state = np.zeros(4) state[2] = 1 rho = np.outer(state, state.conj()) mgate = gates.M(0, 1) mgate.density_matrix = True result = mgate(K.cast(rho), nshots=100) target_binary_samples = np.zeros((100, 2)) target_binary_samples[:, 0] = 1 assert_result(result, decimal_samples=2 * np.ones((100,)), binary_samples=target_binary_samples, decimal_frequencies={2: 100}, binary_frequencies={"10": 100})
def test_maxcut(nqubits, numpy): size = 2**nqubits ham = np.zeros(shape=(size, size), dtype=np.complex128) for i in range(nqubits): for j in range(nqubits): h = np.eye(1) for k in range(nqubits): if (k == i) ^ (k == j): h = np.kron(h, matrices.Z) else: h = np.kron(h, matrices.I) M = np.eye(2**nqubits) - h ham += M target_ham = K.cast(-ham / 2) final_ham = MaxCut(nqubits, numpy=numpy) np.testing.assert_allclose(final_ham.matrix, target_ham)
def test_measurementresult_frequencies(backend): import collections result = measurements.MeasurementResult((0, 1, 2)) result.decimal = K.cast([0, 6, 5, 3, 5, 5, 6, 1, 1, 2, 4], dtype='DTYPEINT') dfreqs = {0: 1, 1: 2, 2: 1, 3: 1, 4: 1, 5: 3, 6: 2} bfreqs = { "000": 1, "001": 2, "010": 1, "011": 1, "100": 1, "101": 3, "110": 2 } assert result.frequencies(binary=True) == bfreqs assert result.frequencies(binary=False) == dfreqs
def test_unitary_channel(backend): a1 = np.array([[0, 1], [1, 0]]) a2 = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) probs = [0.4, 0.3] matrices = [((0, ), a1), ((2, 3), a2)] initial_state = random_density_matrix(4) gate = gates.UnitaryChannel(probs, matrices) gate.density_matrix = True final_state = gate(K.cast(np.copy(initial_state))) eye = np.eye(2) ma1 = np.kron(np.kron(a1, eye), np.kron(eye, eye)) ma2 = np.kron(np.kron(eye, eye), a2) target_state = (0.3 * initial_state + 0.4 * ma1.dot(initial_state.dot(ma1)) + 0.3 * ma2.dot(initial_state.dot(ma2))) K.assert_allclose(final_state, target_state)
def test_reset_channel(backend): initial_rho = random_density_matrix(3) gate = gates.ResetChannel(0, p0=0.2, p1=0.2) gate.density_matrix = True final_rho = gate(K.cast(np.copy(initial_rho))) dtype = initial_rho.dtype collapsed_rho = np.copy(initial_rho).reshape(6 * (2, )) collapsed_rho[0, :, :, 1, :, :] = np.zeros(4 * (2, ), dtype=dtype) collapsed_rho[1, :, :, 0, :, :] = np.zeros(4 * (2, ), dtype=dtype) collapsed_rho[1, :, :, 1, :, :] = np.zeros(4 * (2, ), dtype=dtype) collapsed_rho = collapsed_rho.reshape((8, 8)) collapsed_rho /= np.trace(collapsed_rho) mx = np.kron(np.array([[0, 1], [1, 0]]), np.eye(4)) flipped_rho = mx.dot(collapsed_rho.dot(mx)) target_rho = 0.6 * initial_rho + 0.2 * (collapsed_rho + flipped_rho) K.assert_allclose(final_rho, target_rho)
def test_entropy_numerical(backend): """Check that entropy calculation does not fail for tiny eigenvalues.""" original_backend = qibo.get_backend() qibo.set_backend(backend) 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() np.testing.assert_allclose(result, target) qibo.set_backend(original_backend)
def test_maxcut(nqubits, dense, calcterms): size = 2**nqubits ham = np.zeros(shape=(size, size), dtype=np.complex128) for i in range(nqubits): for j in range(nqubits): h = np.eye(1) for k in range(nqubits): if (k == i) ^ (k == j): h = np.kron(h, matrices.Z) else: h = np.kron(h, matrices.I) M = np.eye(2**nqubits) - h ham += M target_ham = K.cast(-ham / 2) final_ham = hamiltonians.MaxCut(nqubits, dense) if (not dense) and calcterms: _ = final_ham.terms K.assert_allclose(final_ham.matrix, target_ham)
def cache(self): if self._cache is None: cache = K.create_gate_cache(self) qubits = sorted(self.nqubits - q - 1 for q in self.target_qubits) cache.qubits_tensor = K.cast(qubits + [q + self.nqubits for q in qubits], dtype="int32") cache.target_qubits_dm = self.qubits + tuple(q + self.nqubits for q in self.qubits) if not K.is_custom: cache.calculation_cache = K.create_einsum_cache( cache.target_qubits_dm, 2 * self.nqubits) self._cache = cache return self._cache
def test_entropy_random_state(backend): """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(K.cast(rho)) target = - (s * np.log2(s)).sum() K.assert_allclose(result, target) ref_eigvals = np.linalg.eigvalsh(rho) masked_eigvals = ref_eigvals[np.where(ref_eigvals > EIGVAL_CUTOFF)] ref_spectrum = - np.log(masked_eigvals) K.assert_allclose(callback.spectrum[0], ref_spectrum)
def test_measurement_result_parameters_random(backend, accelerators): test_device = K.cpu_devices[0] if accelerators else K.default_device initial_state = random_state(4) set_device_seed(123, accelerators) c = models.Circuit(4, accelerators) output = c.add(gates.M(1, collapse=True)) c.add(gates.RY(0, theta=np.pi * output / 5)) c.add(gates.RX(2, theta=np.pi * output / 4)) result = c(initial_state=np.copy(initial_state)) assert len(output.frequencies()) == 1 set_device_seed(123, accelerators) with K.device(test_device): collapse = gates.M(1, collapse=True) target_state = collapse(K.cast(np.copy(initial_state))) if int(collapse.result.outcome()): target_state = gates.RY(0, theta=np.pi / 5)(target_state) target_state = gates.RX(2, theta=np.pi / 4)(target_state) K.assert_allclose(result, target_state)
def test_measurement_collapse_density_matrix(backend, nqubits, targets): initial_rho = random_density_matrix(nqubits) gate = gates.M(*targets, collapse=True) gate.density_matrix = True final_rho = gate(K.cast(np.copy(initial_rho)), nshots=1) results = gate.result.binary[0] target_rho = np.reshape(initial_rho, 2 * nqubits * (2, )) for q, r in zip(targets, results): r = int(r) slicer = 2 * nqubits * [slice(None)] slicer[q], slicer[q + nqubits] = 1 - r, 1 - r target_rho[tuple(slicer)] = 0 slicer[q], slicer[q + nqubits] = r, 1 - r target_rho[tuple(slicer)] = 0 slicer[q], slicer[q + nqubits] = 1 - r, r target_rho[tuple(slicer)] = 0 target_rho = np.reshape(target_rho, initial_rho.shape) target_rho = target_rho / np.trace(target_rho) K.assert_allclose(final_rho, target_rho)
def test_measurement_result_parameters_multiple_qubits(backend): initial_state = random_state(4) K.set_seed(123) c = models.Circuit(4) output = c.add(gates.M(0, 1, 2, collapse=True)) c.add(gates.RY(1, theta=np.pi * output[0] / 5)) c.add(gates.RX(3, theta=np.pi * output[2] / 3)) result = c(initial_state=np.copy(initial_state)) K.set_seed(123) collapse = gates.M(0, 1, 2, collapse=True) target_state = collapse(K.cast(np.copy(initial_state))) # not including in coverage because outcomes are probabilistic and may # not occur for the CI run if int(collapse.result.outcome(0)): # pragma: no cover target_state = gates.RY(1, theta=np.pi / 5)(target_state) if int(collapse.result.outcome(2)): # pragma: no cover target_state = gates.RX(3, theta=np.pi / 3)(target_state) K.assert_allclose(result, target_state)
def test_measurementresult_apply_bitflips_random_samples_asymmetric(backend): qubits = tuple(range(4)) samples = np.random.randint(0, 2, (20, 4)) result = measurements.MeasurementResult(qubits) result.binary = K.cast(np.copy(samples)) p1_map = {0: 0.2, 1: 0.0, 2: 0.0, 3: 0.1} K.set_seed(123) noisy_result = result.apply_bitflips(p0=0.2, p1=p1_map) p0 = 0.2 * np.ones(4) p1 = np.array([0.2, 0.0, 0.0, 0.1]) K.set_seed(123) sprobs = K.to_numpy(K.random_uniform(samples.shape)) target_samples = np.copy(samples).ravel() ids = (np.where(target_samples == 0)[0], np.where(target_samples == 1)[0]) target_samples[ids[0]] = samples.ravel()[ids[0]] + (sprobs < p0).ravel()[ids[0]] target_samples[ids[1]] = samples.ravel()[ids[1]] - (sprobs < p1).ravel()[ids[1]] target_samples = target_samples.reshape(samples.shape) K.assert_allclose(noisy_result.samples(), target_samples)
def test_symbolic_hamiltonian_state_ev(backend, nqubits, normalize, calcterms, calcdense): local_ham = hamiltonians.SymbolicHamiltonian(symbolic_tfim(nqubits, h=1.0)) + 2 if calcterms: _ = local_ham.terms if calcdense: _ = local_ham.dense dense_ham = hamiltonians.TFIM(nqubits, h=1.0) + 2 state = K.cast(random_complex((2**nqubits, ))) local_ev = local_ham.expectation(state, normalize) target_ev = dense_ham.expectation(state, normalize) K.assert_allclose(local_ev, target_ev) state = random_complex((2**nqubits, )) local_ev = local_ham.expectation(state, normalize) target_ev = dense_ham.expectation(state, normalize) K.assert_allclose(local_ev, target_ev)
def apply_gates(gatelist, nqubits=None, initial_state=None): from qibo import K if initial_state is None: state = K.qnp.zeros(2 ** nqubits) state[0] = 1 elif isinstance(initial_state, np.ndarray): state = np.copy(initial_state) if nqubits is None: nqubits = int(np.log2(len(state))) else: # pragma: no cover assert nqubits == int(np.log2(len(state))) else: # pragma: no cover raise_error(TypeError, "Invalid initial state type {}." "".format(type(initial_state))) state = K.cast(state) for gate in gatelist: state = gate(state) return state
def test_trotter_hamiltonian_matmul(nqubits, normalize): """Test Trotter Hamiltonian expectation value.""" local_ham = hamiltonians.TFIM(nqubits, h=1.0, dense=False) dense_ham = hamiltonians.TFIM(nqubits, h=1.0) state = K.cast(random_complex((2 ** nqubits,))) trotter_ev = local_ham.expectation(state, normalize) target_ev = dense_ham.expectation(state, normalize) K.assert_allclose(trotter_ev, target_ev) state = random_complex((2 ** nqubits,)) trotter_ev = local_ham.expectation(state, normalize) target_ev = dense_ham.expectation(state, normalize) K.assert_allclose(trotter_ev, target_ev) from qibo.core.states import VectorState state = VectorState.from_tensor(state) trotter_matmul = local_ham @ state target_matmul = dense_ham @ state K.assert_allclose(trotter_matmul, target_matmul)
def test_thermal_relaxation_channel(backend, t1, t2, time, excpop): """Check ``gates.ThermalRelaxationChannel`` on a 3-qubit random density matrix.""" initial_rho = random_density_matrix(3) gate = gates.ThermalRelaxationChannel(0, t1, t2, time=time, excited_population=excpop) gate.density_matrix = True final_rho = gate(K.cast(np.copy(initial_rho))) # pylint: disable=E1102 exp, p0, p1 = gate.calculate_probabilities(t1, t2, time, excpop) if t2 > t1: matrix = np.diag([1 - p1, p0, p1, 1 - p0]) matrix[0, -1], matrix[-1, 0] = exp, exp matrix = matrix.reshape(4 * (2, )) # Apply matrix using Eq. (3.28) from arXiv:1111.6950 target_rho = np.copy(initial_rho).reshape(6 * (2, )) target_rho = np.einsum("abcd,aJKcjk->bJKdjk", matrix, target_rho) target_rho = target_rho.reshape(initial_rho.shape) else: pz = exp pi = 1 - pz - p0 - p1 dtype = initial_rho.dtype collapsed_rho = np.copy(initial_rho).reshape(6 * (2, )) collapsed_rho[0, :, :, 1, :, :] = np.zeros(4 * (2, ), dtype=dtype) collapsed_rho[1, :, :, 0, :, :] = np.zeros(4 * (2, ), dtype=dtype) collapsed_rho[1, :, :, 1, :, :] = np.zeros(4 * (2, ), dtype=dtype) collapsed_rho = collapsed_rho.reshape((8, 8)) collapsed_rho /= np.trace(collapsed_rho) mx = np.kron(np.array([[0, 1], [1, 0]]), np.eye(4)) mz = np.kron(np.array([[1, 0], [0, -1]]), np.eye(4)) z_rho = mz.dot(initial_rho.dot(mz)) flipped_rho = mx.dot(collapsed_rho.dot(mx)) target_rho = (pi * initial_rho + pz * z_rho + p0 * collapsed_rho + p1 * flipped_rho) K.assert_allclose(final_rho, target_rho) # Try to apply to state vector if t1 < t2 if t1 < t2: with pytest.raises(ValueError): gate._state_vector_call(initial_rho) # pylint: disable=no-member
def test_post_measurement_bitflips_on_circuit_result(backend): """Check bitflip errors on ``CircuitResult`` objects.""" thetas = np.random.random(4) c = models.Circuit(4) c.add((gates.RX(i, theta=t) for i, t in enumerate(thetas))) c.add(gates.M(0, 1, register_name="a")) c.add(gates.M(3, register_name="b")) result = c(nshots=30) samples = result.samples() K.set_seed(123) noisy_result = result.copy().apply_bitflips({0: 0.2, 1: 0.4, 3: 0.3}) noisy_samples = noisy_result.samples(binary=True) register_samples = noisy_result.samples(binary=True, registers=True) K.set_seed(123) sprobs = K.to_numpy(K.random_uniform(samples.shape)) flipper = K.cast(sprobs < np.array([0.2, 0.4, 0.3]), dtype=samples.dtype) target_samples = (samples + flipper) % 2 K.assert_allclose(noisy_samples, target_samples) # Check register samples K.assert_allclose(register_samples["a"], target_samples[:, :2]) K.assert_allclose(register_samples["b"], target_samples[:, 2:])
def test_measurementregistersresult_frequencies(backend): probs = np.random.random(16) probs = K.cast(probs / np.sum(probs), dtype='DTYPE') result = measurements.MeasurementResult((0, 1, 2, 3), probs, nshots=1000000) frequencies = result.frequencies() qubits = {"a": (0, 1), "b": (2, 3)} result = measurements.MeasurementRegistersResult(qubits, result) register_frequencies = result.frequencies(registers=True) assert register_frequencies.keys() == qubits.keys() rkeys = ["00", "01", "10", "11"] target_frequencies_a = { k: sum(frequencies[f"{k}{l}"] for l in rkeys) for k in rkeys } target_frequencies_b = { k: sum(frequencies[f"{l}{k}"] for l in rkeys) for k in rkeys } assert register_frequencies["a"] == target_frequencies_a assert register_frequencies["b"] == target_frequencies_b
def test_apply_pauli_gate(nqubits, target, gate, compile): """Check ``apply_x``, ``apply_y`` and ``apply_z`` kernels.""" matrices = { "x": np.array([[0, 1], [1, 0]], dtype=np.complex128), "y": np.array([[0, -1j], [1j, 0]], dtype=np.complex128), "z": np.array([[1, 0], [0, -1]], dtype=np.complex128) } state = random_complex((2**nqubits, )) target_state = K.cast(state, dtype=state.dtype) qubits = qubits_tensor(nqubits, [target]) target_state = K.op.apply_gate(state, matrices[gate], qubits, nqubits, target, get_threads()) def apply_operator(state): qubits = qubits_tensor(nqubits, [target]) return getattr(K.op, "apply_{}".format(gate))(state, qubits, nqubits, target, get_threads()) if compile: apply_operator = K.compile(apply_operator) state = apply_operator(state) np.testing.assert_allclose(target_state.numpy(), state.numpy())
def test_apply_gate_cx(nqubits, compile): """Check ``K.op.apply_gate`` for multiply-controlled X gates.""" state = random_complex((2**nqubits, )) target_state = np.array(state) gate = np.eye(2**nqubits, dtype=target_state.dtype) gate[-2, -2], gate[-2, -1] = 0, 1 gate[-1, -2], gate[-1, -1] = 1, 0 target_state = np.dot(gate, target_state) xgate = K.cast([[0, 1], [1, 0]], dtype=state.dtype) controls = list(range(nqubits - 1)) def apply_operator(state): qubits = qubits_tensor(nqubits, [nqubits - 1], controls) return K.op.apply_gate(state, xgate, qubits, nqubits, nqubits - 1, get_threads()) if compile: apply_operator = K.compile(apply_operator) state = apply_operator(state) np.testing.assert_allclose(target_state, state)
def test_swap_pieces(nqubits): state = random_complex((2**nqubits, )) target_state = K.cast(np.copy(state.numpy()), dtype=state.dtype) shape = (2, int(state.shape[0]) // 2) for _ in range(10): global_qubit = np.random.randint(0, nqubits) local_qubit = np.random.randint(0, nqubits) while local_qubit == global_qubit: local_qubit = np.random.randint(0, nqubits) transpose_order = ([global_qubit] + list(range(global_qubit)) + list(range(global_qubit + 1, nqubits))) qubits_t = qubits_tensor(nqubits, [global_qubit, local_qubit]) target_state = K.op.apply_swap(target_state, qubits_t, nqubits, global_qubit, local_qubit, get_threads()) target_state = K.reshape(target_state, nqubits * (2, )) target_state = K.transpose(target_state, transpose_order) target_state = K.reshape(target_state, shape) state = K.reshape(state, nqubits * (2, )) state = K.transpose(state, transpose_order) state = K.reshape(state, shape) piece0, piece1 = state[0], state[1] if K.gpu_devices: # pragma: no cover # case not tested by GitHub workflows because it requires GPU check_unimplemented_error(K.op.swap_pieces, piece0, piece1, local_qubit - 1, nqubits - 1, get_threads()) else: K.op.swap_pieces(piece0, piece1, local_qubit - int(global_qubit < local_qubit), nqubits - 1, get_threads()) np.testing.assert_allclose(target_state[0], piece0.numpy()) np.testing.assert_allclose(target_state[1], piece1.numpy())
def test_swap_pieces_zero_global(nqubits): state = random_complex((2**nqubits, )) target_state = K.cast(np.copy(state.numpy())) shape = (2, int(state.shape[0]) // 2) state = K.reshape(state, shape) for _ in range(10): local = np.random.randint(1, nqubits) qubits_t = qubits_tensor(nqubits, [0, local]) target_state = K.op.apply_swap(target_state, qubits_t, nqubits, 0, local, get_threads()) target_state = K.reshape(target_state, shape) piece0, piece1 = state[0], state[1] if K.gpu_devices: # pragma: no cover # case not tested by GitHub workflows because it requires GPU check_unimplemented_error(K.op.swap_pieces, piece0, piece1, local - 1, nqubits - 1, get_threads()) else: K.op.swap_pieces(piece0, piece1, local - 1, nqubits - 1, get_threads()) np.testing.assert_allclose(target_state[0], piece0.numpy()) np.testing.assert_allclose(target_state[1], piece1.numpy())
def _state_vector_call(self, state): shape = tuple(state.shape) _state = K.qnp.reshape(K.qnp.cast(self.coefficients), shape) return K.cast(_state, dtype="DTYPECPX")
def custom_op_matrix(self): if self._custom_op_matrix is None: self._custom_op_matrix = K.cast(K.qnp.exp(1j * self.parameters)) return self._custom_op_matrix
def _construct_unitary(self): matrix = K.qnp.diag( [1 - self.preset1, self.exp_t2, self.exp_t2, 1 - self.preset0]) matrix[0, -1] = self.preset1 matrix[-1, 0] = self.preset0 return K.cast(matrix)
def construct_unitary(self): unitary = self.parameters rank = int(math.log2(int(unitary.shape[0]))) matrix = K.copy(K.cast(unitary)) return matrix
def construct_unitary(self): return K.cast([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]])
def construct_unitary(self): t = K.cast(self.parameters) phase = K.exp(1j * t) return K.diag([1, phase])
def construct_unitary(self): t = K.cast(self.parameters) phase = K.exp(1j * t / 2.0)[K.newaxis] diag = K.concatenate([K.conj(phase), phase], axis=0) return K.diag(diag)