Пример #1
0
def test_swap_pieces(nqubits):
    state = utils.random_tensorflow_complex((2 ** nqubits,), dtype=tf.float64)
    target_state = tf.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 = op.apply_swap(target_state, qubits_t, nqubits, global_qubit, local_qubit, get_threads())
        target_state = tf.reshape(target_state, nqubits * (2,))
        target_state = tf.transpose(target_state, transpose_order)
        target_state = tf.reshape(target_state, shape)

        state = tf.reshape(state, nqubits * (2,))
        state = tf.transpose(state, transpose_order)
        state = tf.reshape(state, shape)
        piece0, piece1 = state[0], state[1]
        if tf.config.list_physical_devices("GPU"): # pragma: no cover
            # case not tested by GitHub workflows because it requires GPU
            check_unimplemented_error(op.swap_pieces,
                                      piece0, piece1, local_qubit - 1, nqubits - 1, get_threads())
        else:
            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())
Пример #2
0
 def density_matrix_call(self, state: tf.Tensor) -> tf.Tensor:
     state = self.gate_op(state, self.matrix, self.qubits_tensor_dm,
                          2 * self.nqubits, *self.target_qubits,
                          get_threads())
     adjmatrix = tf.math.conj(self.matrix)
     state = self.gate_op(state, adjmatrix, self.qubits_tensor,
                          2 * self.nqubits, *self.target_qubits_dm,
                          get_threads())
     return state
Пример #3
0
def newtonian(loss,
              initial_parameters,
              args=(),
              method='Powell',
              options=None,
              processes=None):
    """Newtonian optimization approaches based on ``scipy.optimize.minimize``.

    For more details check the `scipy documentation <https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html>`_.

    .. note::
        When using the method ``parallel_L-BFGS-B`` the ``processes`` option controls the
        number of processes used by the parallel L-BFGS-B algorithm through the ``multiprocessing`` library.
        By default ``processes=None``, in this case the total number of logical cores are used.
        Make sure to select the appropriate number of processes for your computer specification,
        taking in consideration memory and physical cores. In order to obtain optimal results
        you can control the number of threads used by each process with the ``qibo.set_threads`` method.
        For example, for small-medium size circuits you may benefit from single thread per process, thus set
        ``qibo.set_threads(1)`` before running the optimization.

    Args:
        loss (callable): Loss as a function of variational parameters to be
            optimized.
        initial_parameters (np.ndarray): Initial guess for the variational
            parameters.
        args (tuple): optional arguments for the loss function.
        method (str): Name of method supported by ``scipy.optimize.minimize`` and ``'parallel_L-BFGS-B'`` for
            a parallel version of L-BFGS-B algorithm.
        options (dict): Dictionary with options accepted by
            ``scipy.optimize.minimize``.
        processes (int): number of processes when using the parallel BFGS method.
    """
    if method == 'parallel_L-BFGS-B':
        import psutil
        from qibo.config import raise_error, get_device, get_threads, log
        if "GPU" in get_device():  # pragma: no cover
            raise_error(RuntimeError,
                        "Parallel L-BFGS-B cannot be used with GPU.")
        if ((processes is not None
             and processes * get_threads() > psutil.cpu_count()) or
            (processes is None and get_threads() != 1)):  # pragma: no cover
            log.warning(
                'Please consider using a lower number of threads per process,'
                ' or reduce the number of processes for better performance')
        o = ParallelBFGS(loss, args=args, options=options, processes=processes)
        m = o.run(initial_parameters)
    else:
        from scipy.optimize import minimize
        m = minimize(loss,
                     initial_parameters,
                     args=args,
                     method=method,
                     options=options)
    return m.fun, m.x
Пример #4
0
def _check_parallel_configuration(processes):
    """Check if configuration is suitable for efficient parallel execution."""
    import psutil
    from qibo import get_device
    from qibo.config import raise_error, get_threads, log
    device = get_device()
    if device is not None and "GPU" in device:  # pragma: no cover
        raise_error(RuntimeError,
                    "Parallel evaluations cannot be used with GPU.")
    if ((processes is not None
         and processes * get_threads() > psutil.cpu_count())
            or (processes is None and get_threads() != 1)):  # pragma: no cover
        log.warning(
            'Please consider using a lower number of threads per process,'
            ' or reduce the number of processes for better performance')
Пример #5
0
def apply_gate(state,
               gate,
               qubits,
               nqubits,
               target,
               omp_num_threads=get_threads()):
    """Applies arbitrary one-qubit gate to a state vector.

    Modifies ``state`` in-place.
    Gates can be controlled to multiple qubits.

    Args:
        state (tf.Tensor): State vector of shape ``(2 ** nqubits,)``.
        gate (tf.Tensor): Gate matrix of shape ``(2, 2)``.
        qubits (tf.Tensor): Tensor that contains control and target qubits in
            sorted order. See :meth:`qibo.tensorflow.cgates.TensorflowGate.qubits_tensor`
            for more details.
        nqubits (int): Total number of qubits in the state vector.
        target (int): Qubit ID that the gate will act on.
            Must be smaller than ``nqubits``.

    Return:
        state (tf.Tensor): State vector of shape ``(2 ** nqubits,)`` after
            ``gate`` is applied.
    """
    return custom_module.apply_gate(state, gate, qubits, nqubits, target,
                                    omp_num_threads)
Пример #6
0
 def sample_frequencies(self, probs, nshots):
     from qibo.config import SHOT_CUSTOM_OP_THREASHOLD
     if self.op is None or nshots < SHOT_CUSTOM_OP_THREASHOLD:
         logits = self.log(probs)[self.newaxis]
         samples = self.random.categorical(logits,
                                           nshots,
                                           dtype=self.dtypes('DTYPEINT'))[0]
         res, counts = self.unique(samples, return_counts=True)
         frequencies = self.zeros(int(probs.shape[0]),
                                  dtype=self.dtypes('DTYPEINT'))
         frequencies = self.backend.tensor_scatter_nd_add(
             frequencies, res[:, self.newaxis], counts)
     else:
         from qibo.config import get_threads
         # Generate random seed using tf
         dtype = self.dtypes('DTYPEINT')
         seed = self.backend.random.uniform(shape=tuple(),
                                            maxval=int(1e8),
                                            dtype=dtype)
         nqubits = int(self.np.log2(tuple(probs.shape)[0]))
         shape = self.cast(2**nqubits, dtype='DTYPEINT')
         frequencies = self.zeros(shape, dtype='DTYPEINT')
         frequencies = self.op.measure_frequencies(frequencies, probs,
                                                   nshots, nqubits, seed,
                                                   get_threads())
     return frequencies
Пример #7
0
def collapse_state(state,
                   qubits,
                   result,
                   nqubits,
                   normalize=True,
                   omp_num_threads=get_threads()):
    return custom_module.collapse_state(state, qubits, result, nqubits,
                                        normalize, omp_num_threads)
Пример #8
0
 def transpose_state(self, pieces, state, nqubits, order):
     if self.op is None:  # pragma: no cover
         pieces = self.reshape(self.backend.stack(pieces), nqubits * (2, ))
         return self.reshape(self.transpose(pieces, order), state.shape)
     else:
         from qibo.config import get_threads
         return self.op.transpose_state(pieces, state, nqubits, order,
                                        get_threads())
Пример #9
0
def test_custom_op_toy_callback(gate, compile):
    """Check calculating ``callbacks`` using intermediate state values."""
    import functools
    state = utils.random_tensorflow_complex((2 ** 2,), dtype=tf.float64)
    mask = utils.random_tensorflow_complex((2 ** 2,), dtype=tf.float64)

    matrices = {"h": np.array([[1, 1], [1, -1]]) / np.sqrt(2),
                "x": np.array([[0, 1], [1, 0]]),
                "z": np.array([[1, 0], [0, -1]])}
    for k, v in matrices.items():
        matrices[k] = np.kron(v, np.eye(2))
    matrices["swap"] = np.array([[1, 0, 0, 0], [0, 0, 1, 0],
                                 [0, 1, 0, 0], [0, 0, 0, 1]])

    target_state = state.numpy()
    target_c1 = mask.numpy().dot(target_state)
    target_state = matrices[gate].dot(target_state)
    target_c2 = mask.numpy().dot(target_state)
    assert target_c1 != target_c2
    target_callback = [target_c1, target_c2]

    htf = tf.cast(np.array([[1, 1], [1, -1]]) / np.sqrt(2), dtype=state.dtype)
    qubits_t1 = qubits_tensor(2, [0])
    qubits_t2 = qubits_tensor(2, [0, 1])
    apply_gate = {"h": functools.partial(op.apply_gate, gate=htf, qubits=qubits_t1,
                                         nqubits=2, target=0, omp_num_threads=get_threads()),
                  "x": functools.partial(op.apply_x, qubits=qubits_t1,
                                         nqubits=2, target=0, omp_num_threads=get_threads()),
                  "z": functools.partial(op.apply_z, qubits=qubits_t1,
                                         nqubits=2, target=0, omp_num_threads=get_threads()),
                  "swap": functools.partial(op.apply_swap, qubits=qubits_t2,
                                            nqubits=2, target1=0, target2=1,
                                            omp_num_threads=get_threads())}

    def apply_operator(state):
        c1 = tf.reduce_sum(mask * state)
        state0 = apply_gate[gate](state)
        c2 = tf.reduce_sum(mask * state0)
        return state0, tf.stack([c1, c2])
    if compile: # pragma: no cover
        # case not tested because it fails
        apply_operator = tf.function(apply_operator)
    state, callback = apply_operator(state)

    np.testing.assert_allclose(target_state, state.numpy())
    np.testing.assert_allclose(target_callback, callback.numpy())
Пример #10
0
 def _swap(self, state, global_qubit: int, local_qubit: int):
     m = self.queues.qubits.reduced_global[global_qubit]
     m = self.nglobal - m - 1
     t = 1 << m
     for g in range(self.ndevices // 2):
         i = ((g >> m) << (m + 1)) + (g & (t - 1))
         local_eff = self.queues.qubits.reduced_local[local_qubit]
         with K.device(self.memory_device):
             K.op.swap_pieces(state.pieces[i], state.pieces[i + t],
                              local_eff, self.nlocal, get_threads())
Пример #11
0
def test_transpose_state(nqubits, ndevices):
    for _ in range(10):
        # Generate global qubits randomly
        all_qubits = np.arange(nqubits)
        np.random.shuffle(all_qubits)
        qubit_order = list(all_qubits)
        state = utils.random_tensorflow_complex((2 ** nqubits,), dtype=tf.float64)

        state_tensor = state.numpy().reshape(nqubits * (2,))
        target_state = np.transpose(state_tensor, qubit_order).ravel()

        new_state = tf.zeros_like(state)
        shape = (ndevices, int(state.shape[0]) // ndevices)
        state = tf.reshape(state, shape)
        pieces = [state[i] for i in range(ndevices)]
        if tf.config.list_physical_devices("GPU"): # pragma: no cover
            # case not tested by GitHub workflows because it requires GPU
            check_unimplemented_error(op.transpose_state,
                                      pieces, new_state, nqubits, qubit_order, get_threads())
        else:
            new_state = op.transpose_state(pieces, new_state, nqubits, qubit_order, get_threads())
            np.testing.assert_allclose(target_state, new_state.numpy())
Пример #12
0
def test_swap_pieces_zero_global(nqubits):
    state = utils.random_tensorflow_complex((2 ** nqubits,), dtype=tf.float64)
    target_state = tf.cast(np.copy(state.numpy()), dtype=state.dtype)
    shape = (2, int(state.shape[0]) // 2)
    state = tf.reshape(state, shape)

    for _ in range(10):
        local = np.random.randint(1, nqubits)

        qubits_t = qubits_tensor(nqubits, [0, local])
        target_state = op.apply_swap(target_state, qubits_t, nqubits, 0, local, get_threads())
        target_state = tf.reshape(target_state, shape)

        piece0, piece1 = state[0], state[1]
        if tf.config.list_physical_devices("GPU"): # pragma: no cover
            # case not tested by GitHub workflows because it requires GPU
            check_unimplemented_error(op.swap_pieces,
                                      piece0, piece1, local - 1, nqubits - 1, get_threads())
        else:
            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())
Пример #13
0
def test_vqe(method, options, compile, filename):
    """Performs a VQE circuit minimization test."""
    import qibo
    original_backend = qibo.get_backend()
    if method == "sgd" or compile:
        qibo.set_backend("matmuleinsum")
    else:
        qibo.set_backend("custom")

    original_threads = get_threads()
    if method == 'parallel_L-BFGS-B':
        if 'GPU' in qibo.get_device():  # pragma: no cover
            pytest.skip("unsupported configuration")
        qibo.set_threads(1)

    nqubits = 6
    layers = 4

    circuit = Circuit(nqubits)
    for l in range(layers):
        for q in range(nqubits):
            circuit.add(gates.RY(q, theta=1.0))
        for q in range(0, nqubits - 1, 2):
            circuit.add(gates.CZ(q, q + 1))
        for q in range(nqubits):
            circuit.add(gates.RY(q, theta=1.0))
        for q in range(1, nqubits - 2, 2):
            circuit.add(gates.CZ(q, q + 1))
        circuit.add(gates.CZ(0, nqubits - 1))
    for q in range(nqubits):
        circuit.add(gates.RY(q, theta=1.0))

    hamiltonian = XXZ(nqubits=nqubits)
    np.random.seed(0)
    initial_parameters = np.random.uniform(0, 2 * np.pi,
                                           2 * nqubits * layers + nqubits)
    v = VQE(circuit, hamiltonian)
    best, params = v.minimize(initial_parameters,
                              method=method,
                              options=options,
                              compile=compile)
    if method == "cma":
        # remove `outcmaes` folder
        import shutil
        shutil.rmtree("outcmaes")
    if filename is not None:
        utils.assert_regression_fixture(params, filename)
    qibo.set_backend(original_backend)
    qibo.set_threads(original_threads)
Пример #14
0
 def initial_state(self, nqubits, is_matrix=False):
     if self.op is None:  # pragma: no cover
         dim = 1 + is_matrix
         shape = dim * (2**nqubits, )
         idx = self.backend.constant([dim * [0]],
                                     dtype=self.dtypes('DTYPEINT'))
         state = self.backend.zeros(shape, dtype=self.dtypes('DTYPECPX'))
         update = self.backend.constant([1], dtype=self.dtypes('DTYPECPX'))
         state = self.backend.tensor_scatter_nd_update(state, idx, update)
         return state
     else:
         from qibo.config import get_threads
         return self.op.initial_state(nqubits,
                                      self.dtypes('DTYPECPX'),
                                      is_matrix=is_matrix,
                                      omp_num_threads=get_threads())
Пример #15
0
    def assign_vector(self, full_state: tf.Tensor):
        """Splits a full state vector and assigns it to the ``tf.Variable`` pieces.

        Args:
            full_state (tf.Tensor): Full state vector as a tensor of shape
                ``(2 ** nqubits)``.
        """
        with tf.device(self.device):
            full_state = tf.reshape(full_state, self.shapes["device"])
            pieces = [full_state[i] for i in range(self.ndevices)]
            new_state = tf.zeros(self.shapes["device"], dtype=self.dtype)
            new_state = op.transpose_state(pieces, new_state, self.nqubits,
                                           self.qubits.transpose_order,
                                           get_threads())
            for i in range(self.ndevices):
                self.pieces[i].assign(new_state[i])
Пример #16
0
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 = utils.random_tensorflow_complex((2 ** nqubits,), dtype=tf.float64)
    target_state = tf.cast(state.numpy(), dtype=state.dtype)
    qubits = qubits_tensor(nqubits, [target])
    target_state = op.apply_gate(state, matrices[gate], qubits, nqubits, target, get_threads())

    def apply_operator(state):
      qubits = qubits_tensor(nqubits, [target])
      return getattr(op, "apply_{}".format(gate))(state, qubits, nqubits, target, get_threads())
    if compile:
        apply_operator = tf.function(apply_operator)
    state = apply_operator(state)

    np.testing.assert_allclose(target_state.numpy(), state.numpy())
Пример #17
0
    def vector(self) -> tf.Tensor:
        """Returns the full state vector as a ``tf.Tensor`` of shape ``(2 ** nqubits,)``.

        This is done by merging the state pieces to a single tensor.
        Using this method will double memory usage.
        """
        if self.qubits.list == list(range(self.nglobal)):
            with tf.device(self.device):
                state = tf.concat([x[tf.newaxis] for x in self.pieces], axis=0)
                state = tf.reshape(state, self.shapes["full"])
        elif self.qubits.list == list(range(self.nlocal, self.nqubits)):
            with tf.device(self.device):
                state = tf.concat([x[:, tf.newaxis] for x in self.pieces],
                                  axis=1)
                state = tf.reshape(state, self.shapes["full"])
        else:  # fall back to the transpose op
            with tf.device(self.device):
                state = tf.zeros(self.shapes["full"], dtype=self.dtype)
                state = op.transpose_state(self.pieces, state, self.nqubits,
                                           self.qubits.reverse_transpose_order,
                                           get_threads())
        return state
Пример #18
0
 def density_matrix_call(self, state: tf.Tensor) -> tf.Tensor:
     return self.gate_op(state, self.matrix, self.qubits_tensor,
                         2 * self.nqubits, *self.target_qubits_dm,
                         get_threads())
Пример #19
0
 def apply_operator(state):
   qubits = qubits_tensor(nqubits, [nqubits - 1], controls)
   return op.apply_gate(state, xgate, qubits, nqubits, nqubits - 1, get_threads())
Пример #20
0
 def state_vector_call(self, state: tf.Tensor) -> tf.Tensor:
     return self.gate_op(state, self.qubits_tensor, self.result_tensor,
                         self.nqubits, self.normalize, get_threads())
Пример #21
0
 def density_matrix_call(self, state: tf.Tensor) -> tf.Tensor:
     state = self.gate_op(state, self.qubits_tensor_dm, self.result_tensor,
                          2 * self.nqubits, False, get_threads())
     state = self.gate_op(state, self.qubits_tensor, self.result_tensor,
                          2 * self.nqubits, False, get_threads())
     return state / tf.linalg.trace(state)
Пример #22
0
 def apply_operator(state, gate):
   qubits = qubits_tensor(nqubits, [target])
   return op.apply_gate(state, gate, qubits, nqubits, target, get_threads())
Пример #23
0
 def state_vector_call(self, state: tf.Tensor) -> tf.Tensor:
     return self.gate_op(state, self.matrix, self.qubits_tensor,
                         self.nqubits, *self.target_qubits, get_threads())
Пример #24
0
 def apply_operator(state):
   qubits = qubits_tensor(nqubits, [target])
   return getattr(op, "apply_{}".format(gate))(state, qubits, nqubits, target, get_threads())
Пример #25
0
 def apply_operator(state):
   qubits = qubits_tensor(nqubits, [target], controls)
   return op.apply_z_pow(state, phase, qubits, nqubits, target, get_threads())
Пример #26
0
 def apply_operator(state):
   qubits = qubits_tensor(nqubits, targets, controls)
   return op.apply_swap(state, qubits, nqubits, *targets, get_threads())
Пример #27
0
 def apply_operator(state):
   qubits = qubits_tensor(2, [0, 1])
   return op.apply_swap(state, qubits, 2, 0, 1, get_threads())