Пример #1
0
    def __init__(self, circuit: "DistributedCircuit"):
        super(DistributedState, self).__init__(circuit)
        self.device = circuit.memory_device
        self.qubits = circuit.queues.qubits
        self.dtype = DTYPES.get('DTYPECPX')

        # Create pieces
        n = 2**(self.nqubits - self.nglobal)
        with tf.device(self.device):
            self.pieces = [
                tf.Variable(tf.zeros(n, dtype=self.dtype))
                for _ in range(self.ndevices)
            ]

        dtype = DTYPES.get('DTYPEINT')
        self.shapes = {
            "full": tf.cast((2**self.nqubits, ), dtype=dtype),
            "device": tf.cast((len(self.pieces), n), dtype=dtype),
            "tensor": self.nqubits * (2, )
        }

        self.bintodec = {
            "global": 2**np.arange(self.nglobal - 1, -1, -1),
            "local": 2**np.arange(self.nlocal - 1, -1, -1)
        }
Пример #2
0
def test_general_channel(backend, tfmatrices, oncircuit):
    """Test `gates.KrausChannel`."""
    original_backend = qibo.get_backend()
    qibo.set_backend(backend)
    initial_rho = utils.random_density_matrix(2)

    a1 = np.sqrt(0.4) * np.array([[0, 1], [1, 0]])
    a2 = np.sqrt(0.6) * np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1],
                                  [0, 0, 1, 0]])
    if tfmatrices:
        import tensorflow as tf
        from qibo.config import DTYPES
        a1 = tf.cast(a1, dtype=DTYPES.get('DTYPECPX'))
        a2 = tf.cast(a2, dtype=DTYPES.get('DTYPECPX'))

    gate = gates.KrausChannel([((1, ), a1), ((0, 1), a2)])
    assert gate.target_qubits == (0, 1)
    if oncircuit:
        c = models.Circuit(2, density_matrix=True)
        c.add(gate)
        final_rho = c(np.copy(initial_rho)).numpy()
    else:
        if backend == "custom":
            final_rho = gate(np.copy(initial_rho))
        else:
            final_rho = gate(np.copy(initial_rho).reshape(4 * (2, )))
            final_rho = final_rho.numpy().reshape((4, 4))

    m1 = np.kron(np.eye(2), np.array(a1))
    m2 = np.array(a2)
    target_rho = (m1.dot(initial_rho).dot(m1.conj().T) +
                  m2.dot(initial_rho).dot(m2.conj().T))
    np.testing.assert_allclose(final_rho, target_rho)
    qibo.set_backend(original_backend)
Пример #3
0
 def _prepare(self):
     unitary, phi = self.parameter
     matrix = np.zeros(5, dtype=DTYPES.get("NPTYPECPX"))
     matrix[:4] = np.reshape(unitary, (4, ))
     matrix[4] = np.exp(-1j * phi)
     with tf.device(self.device):
         self.matrix = tf.constant(matrix, dtype=DTYPES.get('DTYPECPX'))
Пример #4
0
 def _prepare(self):
     theta, phi = self.parameter
     cos, isin = np.cos(theta), -1j * np.sin(theta)
     phase = np.exp(-1j * phi)
     matrix = np.array([cos, isin, isin, cos, phase],
                       dtype=DTYPES.get('NPTYPECPX'))
     with tf.device(self.device):
         self.matrix = tf.constant(matrix, dtype=DTYPES.get('DTYPECPX'))
Пример #5
0
 def dtype(self):
     if DTYPES.get("DTYPECPX") == tf.complex128:
         return np.complex128
     elif DTYPES.get("DTYPECPX") == tf.complex64:
         return np.complex64
     else: # pragma: no cover
         # case not tested because DTYPECPX is preset to a valid type
         raise_error(TypeError, "Unknown complex type {}."
                                "".format(DTYPES.get("DTYPECPX")))
Пример #6
0
 def _cast_initial_state(self, state: InitStateType) -> tf.Tensor:
     if isinstance(state, tf.Tensor):
         return state
     elif isinstance(state, np.ndarray):
         return tf.cast(state.astype(DTYPES.get('NPTYPECPX')),
                        dtype=DTYPES.get('DTYPECPX'))
     raise_error(
         TypeError, "Initial state type {} is not recognized."
         "".format(type(state)))
Пример #7
0
def test_precision_dictionary(precision):
    """Check if ``set_precision`` changes the ``DTYPES`` dictionary."""
    import qibo
    import tensorflow as tf
    from qibo.config import DTYPES
    original_precision = qibo.get_precision()
    qibo.set_precision(precision)
    if precision == "single":
        assert DTYPES.get("DTYPECPX") == tf.complex64
    else:
        assert DTYPES.get("DTYPECPX") == tf.complex128
    qibo.set_precision(original_precision)
Пример #8
0
def test_two_variables_backpropagation(backend):
    """Check that backpropagation works when using `tf.Variable` parameters."""
    original_backend = qibo.get_backend()
    qibo.set_backend(backend)
    import tensorflow as tf
    from qibo.config import DTYPES
    theta = tf.Variable([0.1234, 0.4321], dtype=DTYPES.get('DTYPE'))

    # TODO: Fix parametrized gates so that `Circuit` can be defined outside
    # of the gradient tape
    with tf.GradientTape() as tape:
        c = Circuit(2)
        c.add(gates.RX(0, theta[0]))
        c.add(gates.RY(1, theta[1]))
        loss = tf.math.real(c()[0])
    grad = tape.gradient(loss, theta)

    t = np.array([0.1234, 0.4321]) / 2.0
    target_loss = np.cos(t[0]) * np.cos(t[1])
    np.testing.assert_allclose(loss.numpy(), target_loss)

    target_grad1 = -np.sin(t[0]) * np.cos(t[1])
    target_grad2 = -np.cos(t[0]) * np.sin(t[1])
    target_grad = np.array([target_grad1, target_grad2]) / 2.0
    np.testing.assert_allclose(grad.numpy(), target_grad)
    qibo.set_backend(original_backend)
Пример #9
0
def test_post_measurement_asymmetric_bitflips():
    """Check applying asymmetric bitflips to measurement samples."""
    import tensorflow as tf
    from qibo.config import DTYPES
    from qibo.tensorflow import measurements
    qubits = tuple(range(4))
    samples = np.random.randint(0, 2, (20, 4))
    result = measurements.GateResult(qubits, binary_samples=samples)
    p1_map = {0: 0.2, 1: 0.0, 2: 0.0, 3: 0.1}
    tf.random.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])
    tf.random.set_seed(123)
    sprobs = tf.random.uniform(samples.shape,
                               dtype=DTYPES.get('DTYPE')).numpy()
    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)
    np.testing.assert_allclose(noisy_result.samples(), target_samples)
Пример #10
0
 def construct_unitary(self) -> np.ndarray:
     cost = np.cos(self._theta / 2)
     sint = np.sin(self._theta / 2)
     eplus = np.exp(1j * (self._phi + self._lam) / 2.0)
     eminus = np.exp(1j * (self._phi - self._lam) / 2.0)
     return np.array([[eplus.conj() * cost, -eminus.conj() * sint],
                      [eminus * sint, eplus * cost]],
                     dtype=DTYPES.get('NPTYPECPX'))
Пример #11
0
 def sample():
     shape = (1 + is_density_matrix) * self.nqubits * (2, )
     probs = self._calculate_probabilities(tf.reshape(state, shape),
                                           is_density_matrix)
     logits = tf.math.log(tf.reshape(probs, probs_dim))
     return tf.random.categorical(logits[tf.newaxis],
                                  nshots,
                                  dtype=DTYPES.get('DTYPEINT'))[0]
Пример #12
0
 def construct_unitary(self) -> np.ndarray:
     theta, phi = self.parameter
     cos, isin = np.cos(theta), -1j * np.sin(theta)
     matrix = np.eye(4, dtype=DTYPES.get('NPTYPECPX'))
     matrix[1, 1], matrix[2, 2] = cos, cos
     matrix[1, 2], matrix[2, 1] = isin, isin
     matrix[3, 3] = np.exp(-1j * phi)
     return matrix
Пример #13
0
 def prepare(self):
     self.is_prepared = True
     self.reprepare()
     qubits = self.qubits + tuple(q + self.nqubits for q in self.qubits)
     self.calculation_cache = self.einsum.create_cache(
         qubits, 2 * self.nqubits)
     self.calculation_cache.cast_shapes(
         lambda x: tf.cast(x, dtype=DTYPES.get('DTYPEINT')))
Пример #14
0
 def construct_unitary(self):
     unitary = self.parameter
     rank = int(np.log2(int(unitary.shape[0])))
     dtype = DTYPES.get('DTYPECPX')
     if isinstance(unitary, tf.Tensor):
         matrix = tf.identity(tf.cast(unitary, dtype=dtype))
     elif isinstance(unitary, np.ndarray):
         matrix = tf.convert_to_tensor(unitary, dtype=dtype)
     return matrix
Пример #15
0
 def construct_unitary(self) -> np.ndarray:
     theta, phi, lam = self.parameters
     cost = np.cos(theta / 2)
     sint = np.sin(theta / 2)
     eplus = np.exp(1j * (phi + lam) / 2.0)
     eminus = np.exp(1j * (phi - lam) / 2.0)
     return np.array([[eplus.conj() * cost, -eminus.conj() * sint],
                      [eminus * sint, eplus * cost]],
                     dtype=DTYPES.get('NPTYPECPX'))
Пример #16
0
 def __init__(self, nqubits):
     super(TensorflowDensityMatrixCircuit, self).__init__(nqubits)
     self.density_matrix = True
     self.shapes = {
         'TENSOR': 2 * self.nqubits * (2, ),
         'VECTOR': (2**nqubits, ),
         'FLAT': 2 * (2**self.nqubits, )
     }
     self.shapes['TF_FLAT'] = tf.cast(self.shapes.get('FLAT'),
                                      dtype=DTYPES.get('DTYPEINT'))
Пример #17
0
 def _apply_bitflips(noiseless_samples: tf.Tensor,
                     probs: Tuple[float]) -> tf.Tensor:
     dtype = DTYPES.get('DTYPE')
     fprobs = tf.cast(probs, dtype=dtype)
     sprobs = tf.random.uniform(noiseless_samples.shape, dtype=dtype)
     flip0 = tf.cast(sprobs < fprobs[0], dtype=noiseless_samples.dtype)
     flip1 = tf.cast(sprobs < fprobs[1], dtype=noiseless_samples.dtype)
     noisy_samples = noiseless_samples + (1 - noiseless_samples) * flip0
     noisy_samples = noisy_samples - noiseless_samples * flip1
     return noisy_samples
Пример #18
0
 def __init__(self, nqubits):
     super(TensorflowCircuit, self).__init__(nqubits)
     self._compiled_execute = None
     self.check_initial_state_shape = True
     self.shapes = {
         'TENSOR': self.nqubits * (2, ),
         'FLAT': (2**self.nqubits, )
     }
     self.shapes['TF_FLAT'] = tf.cast(self.shapes.get('FLAT'),
                                      dtype=DTYPES.get('DTYPEINT'))
Пример #19
0
 def control_unitary(unitary: tf.Tensor) -> tf.Tensor:
     shape = tuple(unitary.shape)
     if shape != (2, 2):
         raise_error(
             ValueError, "Cannot use ``control_unitary`` method for "
             "input matrix of shape {}.".format(shape))
     dtype = DTYPES.get('DTYPECPX')
     zeros = tf.zeros((2, 2), dtype=dtype)
     part1 = tf.concat([tf.eye(2, dtype=dtype), zeros], axis=0)
     part2 = tf.concat([zeros, unitary], axis=0)
     return tf.concat([part1, part2], axis=1)
Пример #20
0
 def __call__(self,
              state: tf.Tensor,
              is_density_matrix: bool = False) -> tf.Tensor:
     shape = tuple(state.shape)
     if self._nqubits is None:
         if is_density_matrix:
             self.nqubits = len(shape) // 2
         else:
             self.nqubits = len(shape)
     _state = np.array(self.coefficients).reshape(shape)
     return tf.convert_to_tensor(_state, dtype=DTYPES.get("DTYPECPX"))
Пример #21
0
def test_variable_theta(backend, accelerators):
    """Check that parametrized gates accept `tf.Variable` parameters."""
    original_backend = qibo.get_backend()
    qibo.set_backend(backend)
    import tensorflow as tf
    from qibo.config import DTYPES
    theta1 = tf.Variable(0.1234, dtype=DTYPES.get('DTYPE'))
    theta2 = tf.Variable(0.4321, dtype=DTYPES.get('DTYPE'))

    cvar = Circuit(2, accelerators)
    cvar.add(gates.RX(0, theta1))
    cvar.add(gates.RY(1, theta2))
    final_state = cvar().numpy()

    c = Circuit(2)
    c.add(gates.RX(0, 0.1234))
    c.add(gates.RY(1, 0.4321))
    target_state = c().numpy()

    np.testing.assert_allclose(final_state, target_state)
    qibo.set_backend(original_backend)
Пример #22
0
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)
Пример #23
0
class EntanglementEntropy(PartialTrace):
    """Von Neumann entanglement entropy callback.

    .. math::
        S = \\mathrm{Tr} \\left ( \\rho \\log _2 \\rho \\right )

    Args:
        partition (list): List with qubit ids that defines the first subsystem
            for the entropy calculation.
            If `partition` is not given then the first subsystem is the first
            half of the qubits.

    Example:
        ::

            from qibo import models, gates, callbacks
            # create entropy callback where qubit 0 is the first subsystem
            entropy = callbacks.EntanglementEntropy([0])
            # initialize circuit with 2 qubits and add gates
            c = models.Circuit(2)
            # add callback gates between normal gates
            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))
            # execute the circuit
            final_state = c()
            print(entropy[:])
            # Should print [0, 0, 1] which is the entanglement entropy
            # after every gate in the calculation.
    """
    _log2 = tf.cast(tf.math.log(2.0), dtype=DTYPES.get('DTYPE'))

    @classmethod
    def _entropy(cls, rho: tf.Tensor) -> tf.Tensor:
      """Calculates entropy by diagonalizing the density matrix."""
      # Diagonalize
      eigvals = tf.math.real(tf.linalg.eigvalsh(rho))
      # Treating zero and negative eigenvalues
      masked_eigvals = tf.gather(eigvals, tf.where(eigvals > EIGVAL_CUTOFF))[:, 0]
      entropy = - tf.reduce_sum(masked_eigvals * tf.math.log(masked_eigvals))
      return entropy / cls._log2

    def __call__(self, state: tf.Tensor, is_density_matrix: bool = False
                 ) -> tf.Tensor:
        # Construct reduced density matrix
        rho = super(EntanglementEntropy, self).__call__(state, is_density_matrix)
        # Calculate entropy of reduced density matrix
        return self._entropy(rho)
Пример #24
0
 def __new__(cls, nqubits, matrix, numpy=False):
     if isinstance(matrix, np.ndarray):
         if not numpy:
             matrix = K.cast(matrix, dtype=DTYPES.get('DTYPECPX'))
     elif isinstance(matrix, K.Tensor):
         if numpy:
             matrix = matrix.numpy()
     else:
         raise raise_error(TypeError, "Invalid type {} of Hamiltonian "
                                      "matrix.".format(type(matrix)))
     if numpy:
         return hamiltonians.NumpyHamiltonian(nqubits, matrix)
     else:
         return hamiltonians.TensorflowHamiltonian(nqubits, matrix)
Пример #25
0
class EntanglementEntropy(callbacks.EntanglementEntropy):
    _log2 = tf.cast(tf.math.log(2.0), dtype=DTYPES.get('DTYPE'))

    def entropy(self, rho: tf.Tensor) -> tf.Tensor:
        # Diagonalize
        eigvals = tf.math.real(tf.linalg.eigvalsh(rho))
        # Treating zero and negative eigenvalues
        masked_eigvals = tf.gather(eigvals,
                                   tf.where(eigvals > EIGVAL_CUTOFF))[:, 0]
        spectrum = -1 * tf.math.log(masked_eigvals)
        if self.compute_spectrum:
            self.spectrum.append(spectrum)
        entropy = tf.reduce_sum(masked_eigvals * spectrum)
        return entropy / self._log2
Пример #26
0
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'))
    result = callbacks.EntanglementEntropy._entropy(rho).numpy()

    mask = eigvals > 0
    target = -(eigvals[mask] * np.log2(eigvals[mask])).sum()

    np.testing.assert_allclose(result, target)
Пример #27
0
    def sample(self, state: tf.Tensor, nshots: int) -> tf.Tensor:
        probs = getattr(self, self._active_call)(state)
        probs = tf.transpose(probs, perm=self.reduced_target_qubits)

        dtype = DTYPES.get('DTYPEINT')
        probs_dim = tf.cast((2**len(self.target_qubits), ), dtype=dtype)
        logits = tf.math.log(tf.reshape(probs, probs_dim))[tf.newaxis]

        samples_dec = tf.random.categorical(logits, nshots, dtype=dtype)[0]
        result = self.measurements.GateResult(self.qubits,
                                              decimal_samples=samples_dec)
        # optional bitflip noise
        if sum(sum(x.values()) for x in self.bitflip_map) > 0:
            result = result.apply_bitflips(*self.bitflip_map)
        return result
Пример #28
0
def test_hamiltonian_initialization():
    """Testing hamiltonian initialization errors."""
    import tensorflow as tf
    from qibo.config import DTYPES
    dtype = DTYPES.get('DTYPECPX')
    with pytest.raises(TypeError):
        H = Hamiltonian(2, "test")
    H1 = Hamiltonian(2, np.eye(4))
    H1 = Hamiltonian(2, np.eye(4), numpy=True)
    H1 = Hamiltonian(2, tf.eye(4, dtype=dtype))
    H1 = Hamiltonian(2, tf.eye(4, dtype=dtype), numpy=True)
    with pytest.raises(ValueError):
        H1 = Hamiltonian(-2, np.eye(4))
    with pytest.raises(RuntimeError):
        H2 = Hamiltonian(np.eye(2), np.eye(4))
    with pytest.raises(ValueError):
        H3 = Hamiltonian(4, np.eye(10))
Пример #29
0
def test_post_measurement_bitflips(probs):
    """Check applying bitflips to measurement samples."""
    import tensorflow as tf
    from qibo.config import DTYPES
    from qibo.tensorflow import measurements
    qubits = tuple(range(4))
    samples = np.random.randint(0, 2, (20, 4))
    result = measurements.GateResult(qubits, binary_samples=samples)
    tf.random.set_seed(123)
    noisy_result = result.apply_bitflips(probs)

    tf.random.set_seed(123)
    if isinstance(probs, dict):
        probs = np.array([probs[q] for q in qubits])
    sprobs = tf.random.uniform(samples.shape,
                               dtype=DTYPES.get('DTYPE')).numpy()
    flipper = sprobs < probs
    target_samples = (samples + flipper) % 2
    np.testing.assert_allclose(noisy_result.samples(), target_samples)
Пример #30
0
    def nqubits(self, n: int):
        """Sets the number of qubit that this gate acts on.

        This is called automatically by the `Circuit.add` method if the gate
        is used on a `Circuit`. If the gate is called on a state then `nqubits`
        is set during the first `__call__`.
        When `nqubits` is set we also calculate the einsum string so that it
        is calculated only once per gate.
        """
        base_gates.Gate.nqubits.fset(self, n)  # pylint: disable=no-member
        if self.is_controlled_by:
            self.control_cache = cache.ControlCache(self)
            nactive = n - len(self.control_qubits)
            targets = self.control_cache.targets
            self.calculation_cache = self.einsum.create_cache(
                targets, nactive, ncontrol=len(self.control_qubits))
        else:
            self.calculation_cache = self.einsum.create_cache(self.qubits, n)
        self.calculation_cache.cast_shapes(
            lambda x: tf.cast(x, dtype=DTYPES.get('DTYPEINT')))