Пример #1
0
 def dense(self):
     """Creates the equivalent :class:`qibo.abstractions.hamiltonians.MatrixHamiltonian`."""
     if self._dense is None:
         log.warning("Calculating the dense form of a symbolic Hamiltonian. "
                     "This operation is memory inefficient.")
         self.dense = self.calculate_dense()
     return self._dense
Пример #2
0
    def state_vector_call(self, state):
        if self.evolution is None:
            raise_error(
                ValueError, "Gap callback can only be used in "
                "adiabatic evolution models.")
        hamiltonian = self.evolution.hamiltonian()
        # Call the eigenvectors so that they are cached for the ``exp`` call
        hamiltonian.eigenvectors()
        eigvals = hamiltonian.eigenvalues()
        if isinstance(self.mode, int):
            return K.real(eigvals[self.mode])

        # case: self.mode == "gap"
        excited = 1
        gap = K.real(eigvals[excited] - eigvals[0])
        if not self.check_degenerate:
            return gap

        while K.less(gap, EIGVAL_CUTOFF):
            gap = K.real(eigvals[excited] - eigvals[0])
            excited += 1
        if excited > 1:
            log.warning("The Hamiltonian is degenerate. Using eigenvalue {} "
                        "to calculate gap.".format(excited))
        return gap
Пример #3
0
    def iterative_grover(self, lamda_value=6/5):
        """Iterative approach of Grover for when the number of solutions is not known.

        Args:
            lamda_value (real): parameter that controls the evolution of the iterative method.
                                Must be between 1 and 4/3.

        Returns:
            measured (str): bitstring measured and checked as a valid solution.
            total_iterations (int): number of times the oracle has been called.
        """
        k = 1
        lamda = lamda_value
        total_iterations = 0
        while True:
            it = np.random.randint(k + 1)
            if it != 0:
                total_iterations += it
                circuit = self.circuit(it)
                result = circuit(nshots=1)
                measured = result.frequencies(binary=True).most_common(1)[0][0]
                if self.check(measured, *self.check_args):
                    return measured, total_iterations
            k = min(lamda * k, np.sqrt(self.sup_size))
            if total_iterations > (9/4) * np.sqrt(self.sup_size):
                log.warning("Too many total iterations, output might not be solution.")
                return measured, total_iterations
Пример #4
0
 def set_threads(self, nthreads):
     log.warning(
         "`set_threads` is not supported by the tensorflow "
         "backend. Please use tensorflow's thread setters: "
         "`tf.config.threading.set_inter_op_parallelism_threads` "
         "or `tf.config.threading.set_intra_op_parallelism_threads` "
         "to switch the number of threads.")
     abstract.AbstractBackend.set_threads(self, nthreads)
Пример #5
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
Пример #6
0
def set_precision(dtype="double"):
    """Set precision for states and gates simulation.

    Args:
        dtype (str): possible options are 'single' for single precision
            (complex64) and 'double' for double precision (complex128).
    """
    if not config.ALLOW_SWITCHERS and dtype != K.precision:
        log.warning("Precision should not be changed after allocating gates.")
    for bk in K.constructed_backends.values():
        bk.set_precision(dtype)
Пример #7
0
 def initialize_tensorflow(self):
     """Initializes active Tensorflow backend (if available)."""
     os.environ["TF_CPP_MIN_LOG_LEVEL"] = str(config.LOG_LEVEL)
     import tensorflow as tf
     import qibo.tensorflow.custom_operators as op
     if not op._custom_operators_loaded:  # pragma: no cover
         log.warning("Einsum will be used to apply gates with Tensorflow. "
                     "Removing custom operators from available backends.")
         self.available_backends.pop("custom")
         self.available_backends[
             "tensorflow"] = TensorflowDefaultEinsumBackend
     self.active_backend = "tensorflow"
Пример #8
0
def set_device(name):
    """Set default execution device.

    Args:
        name (str): Device name. Should follow the pattern
            '/{device type}:{device number}' where device type is one of
            CPU or GPU.
    """
    if not config.ALLOW_SWITCHERS and name != K.default_device:
        log.warning("Device should not be changed after allocating gates.")
    K.set_device(name)
    for bk in K.constructed_backends.values():
        if bk.name != "numpy" and bk != K.active_backend:
            bk.set_device(name)
Пример #9
0
 def initialize_numpy(self):  # pragma: no cover
     """Initializes active numpy backend (if Tensorflow is not available)."""
     # case not tested because CI has tf installed
     log.warning("Tensorflow is not installed. Falling back to numpy. "
                 "Numpy does not support Qibo custom operators and GPU. "
                 "Einsum will be used to apply gates on CPU.")
     # remove Tensorflow backends
     self.available_backends.pop("custom")
     self.available_backends.pop("tensorflow")
     self.available_backends.pop("tensorflow_defaulteinsum")
     self.available_backends.pop("tensorflow_matmuleinsum")
     # use numpy for defaulteinsum and matmuleinsum backends
     self.available_backends["defaulteinsum"] = NumpyDefaultEinsumBackend
     self.available_backends["matmuleinsum"] = NumpyMatmulEinsumBackend
     self.active_backend = "numpy"
Пример #10
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')
Пример #11
0
def set_backend(backend="qibojit"):
    """Sets backend used for mathematical operations and applying gates.

    The following backends are available:
    'qibojit': Numba/cupy backend with custom operators for applying gates,
    'qibotf': Tensorflow backend with custom operators for applying gates,
    'tensorflow': Tensorflow backend that applies gates using ``tf.einsum``,
    'numpy': Numpy backend that applies gates using ``np.einsum``.

    Args:
        backend (str): A backend from the above options.
    """
    if not config.ALLOW_SWITCHERS and backend != K.name:
        log.warning("Backend should not be changed after allocating gates.")
    K.active_backend = backend
    K.show_config()
Пример #12
0
def set_backend(backend="qibojit", platform=None):
    """Sets backend used for mathematical operations and applying gates.

    The following backends are available:
    'qibojit': Numba/cupy backend with custom operators for applying gates,
    'tensorflow': Tensorflow backend that applies gates using ``tf.einsum``,
    'numpy': Numpy backend that applies gates using ``np.einsum``.

    Args:
        backend (str): A backend from the above options.
        platform (str): Optional platform specification for backends that
            support this. For example, the 'qibojit' backend supports two
            platforms ('cupy', 'cuquantum') when used with GPU.
    """
    if not config.ALLOW_SWITCHERS and backend != K.name:
        log.warning("Backend should not be changed after allocating gates.")
    K.active_backend = K.construct_backend(backend)
    if platform is not None:
        K.set_platform(platform)
    K.show_config()
Пример #13
0
    def from_symbolic(cls, symbolic_hamiltonian, symbol_map):
        """Creates a ``Hamiltonian`` from a symbolic Hamiltonian.

        We refer to the :ref:`How to define custom Hamiltonians using symbols? <symbolicham-example>`
        example for more details.

        Args:
            symbolic_hamiltonian (sympy.Expr): The full Hamiltonian written
                with symbols.
            symbol_map (dict): Dictionary that maps each symbol that appears in
                the Hamiltonian to a pair of (target, matrix).

        Returns:
            A :class:`qibo.abstractions.hamiltonians.SymbolicHamiltonian` object
            that implements the Hamiltonian represented by the given symbolic
            expression.
        """
        log.warning(
            "`Hamiltonian.from_symbolic` and the use of symbol maps is "
            "deprecated. Please use `SymbolicHamiltonian` and Qibo symbols "
            "to construct Hamiltonians using symbols.")
        return SymbolicHamiltonian(symbolic_hamiltonian, symbol_map)
Пример #14
0
def _check_parallel_configuration(processes):  # pragma: no cover
    """Check if configuration is suitable for efficient parallel execution."""
    import sys, psutil
    from qibo import get_device, get_backend, get_threads
    from qibo.config import raise_error, log
    device = get_device()
    if sys.platform == "win32" or sys.platform == 'darwin':  # pragma: no cover
        raise_error(RuntimeError,
                    "Parallel evaluations supported only on linux.")
    if get_backend() == "tensorflow":  # pragma: no cover
        raise_error(
            RuntimeError,
            f"{get_backend()} backend does not support parallel evaluations.")
    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')
Пример #15
0
    def __init__(self):

        self.available_backends = {}
        self.hardware_backends = {}
        active_backend = "numpy"

        # load profile from default file
        from pathlib import Path
        profile_path = Path(
            os.environ.get('QIBO_PROFILE',
                           Path(__file__).parent / "profiles.yml"))
        try:
            with open(profile_path) as f:
                import yaml
                profile = yaml.safe_load(f)
        except FileNotFoundError:  # pragma: no cover
            raise_error(FileNotFoundError,
                        f"Profile file {profile_path} not found.")

        # check if numpy is installed
        if self.check_availability("numpy"):
            from qibo.backends.numpy import NumpyBackend
            self.available_backends["numpy"] = NumpyBackend
        else:  # pragma: no cover
            raise_error(
                ModuleNotFoundError, "Numpy is not installed. "
                "Please install it using "
                "`pip install numpy`.")

        for backend in profile.get('backends'):
            name = backend.get('name')
            if self.check_availability(name):
                if name == 'tensorflow' or name == 'qibotf':
                    os.environ["TF_CPP_MIN_LOG_LEVEL"] = str(
                        config.TF_LOG_LEVEL)
                    import tensorflow as tf  # pylint: disable=E0401
                    if tf.__version__ < TF_MIN_VERSION:  # pragma: no cover
                        raise_error(
                            RuntimeError,
                            f"TensorFlow version not supported, minimum is {TF_MIN_VERSION}."
                        )
                import importlib
                custom_backend = getattr(
                    importlib.import_module(backend.get('from')),
                    backend.get('class'))
                self.available_backends[name] = custom_backend
                if backend.get('is_hardware', False):  # pragma: no cover
                    self.hardware_backends[name] = custom_backend
                if profile.get('default') == name:
                    active_backend = name

        self.constructed_backends = {}
        self._active_backend = None
        self.qnp = self.construct_backend("numpy")
        # Create the default active backend
        if "QIBO_BACKEND" in os.environ:  # pragma: no cover
            self.active_backend = os.environ.get("QIBO_BACKEND")
        else:
            self.active_backend = active_backend

        # raise performance warning if qibojit and qibotf are not available
        self.show_config()
        if active_backend == "numpy":  # pragma: no cover
            log.warning(
                "numpy backend uses `np.einsum` and supports CPU only. "
                "Consider installing the qibojit or qibotf backends for "
                "increased performance and to enable GPU acceleration.")
        elif active_backend == "tensorflow":  # pragma: no cover
            # case not tested because CI has tf installed
            log.warning("qibotf library was not found. `tf.einsum` will be "
                        "used to apply gates. In order to install Qibo's "
                        "high performance custom operators for TensorFlow "
                        "please use `pip install qibotf`. Alternatively, "
                        "consider installing the qibojit backend.")
Пример #16
0
    def __init__(self):
        # load profile from default file
        from pathlib import Path
        profile_path = Path(os.environ.get(
            'QIBO_PROFILE', Path(__file__).parent / "profiles.yml"))
        try:
            with open(profile_path) as f:
                import yaml
                self.profile = yaml.safe_load(f)
        except FileNotFoundError:  # pragma: no cover
            raise_error(FileNotFoundError, f"Profile file {profile_path} not found.")

        # dictionary to cache if backends are available
        # used by ``self.check_availability``
        self._availability = {}

        # create numpy backend (is always available as numpy is a requirement)
        if self.check_availability("numpy", check_version=False):
            from qibo.backends.numpy import NumpyBackend
            self.qnp = NumpyBackend()
        else:  # pragma: no cover
            raise_error(ModuleNotFoundError, "Numpy is not installed. "
                                             "Please install it using "
                                             "`pip install numpy`.")

        # loading backend names and version
        self._backends_min_version = {backend.get("name"): backend.get("minimum_version") for backend in self.profile.get("backends")}

        # find the default backend name
        default_backend = os.environ.get('QIBO_BACKEND', self.profile.get('default'))

        # check if default backend is described in the profile file
        if default_backend != "numpy":

            if default_backend not in (backend.get("name") for backend in self.profile.get("backends")): # pragma: no cover
                raise_error(ModuleNotFoundError, f"Default backend {default_backend} not set in {profile_path}.")

            # change the default backend if it is not available
            if not self.check_availability(default_backend):  # pragma: no cover
                # set the default backend to the first available declared backend in the profile file
                # if none is available it falls back to numpy
                for backend in self.profile.get('backends'):
                    name = backend.get('name')
                    if self.check_availability(name) and not backend.get('is_hardware'):
                        # excluding hardware backends from default for development
                        # convenience until proper hardware testing is implemented
                        default_backend = name
                        break
                    # make numpy default if no other backend is available
                    default_backend = "numpy"

        self.active_backend = None
        self.constructed_backends = {"numpy": self.qnp}
        self.hardware_backends = {}
        # set default backend as active
        self.active_backend = self.construct_backend(default_backend)

        # raise performance warning if qibojit is not available
        self.show_config()
        if str(self) == "numpy":  # pragma: no cover
            log.warning("numpy backend uses `np.einsum` and supports CPU only. "
                        "Consider installing the qibojit backend for "
                        "increased performance and to enable GPU acceleration.")
        elif str(self) == "tensorflow":  # pragma: no cover
            # case not tested because CI has tf installed
            log.warning("tensorflow backend uses `tf.einsum` "
                        "to apply gates. In order to install Qibo's "
                        "high performance custom operators "
                        "please use `pip install qibojit`.")
Пример #17
0
 def eigvalsh(self, x, k=6):
     if self.issparse(x):
         log.warning("Calculating sparse matrix eigenvectors because "
                     "sparse modules do not provide ``eigvals`` method.")
         return self.eigh(x, k=k)[0]
     return self.backend.linalg.eigvalsh(x)
Пример #18
0
"""TensorFlow custom operator for Tensor initial state."""
from qibo.config import log

_custom_operators_loaded = False
try:
    import tensorflow as tf
    try:
        from qibo.tensorflow.custom_operators.python.ops.qibo_tf_custom_operators import initial_state
        from qibo.tensorflow.custom_operators.python.ops.qibo_tf_custom_operators import transpose_state
        from qibo.tensorflow.custom_operators.python.ops.qibo_tf_custom_operators import swap_pieces
        from qibo.tensorflow.custom_operators.python.ops.qibo_tf_custom_operators import apply_gate
        from qibo.tensorflow.custom_operators.python.ops.qibo_tf_custom_operators import apply_x
        from qibo.tensorflow.custom_operators.python.ops.qibo_tf_custom_operators import apply_y
        from qibo.tensorflow.custom_operators.python.ops.qibo_tf_custom_operators import apply_z
        from qibo.tensorflow.custom_operators.python.ops.qibo_tf_custom_operators import apply_z_pow
        from qibo.tensorflow.custom_operators.python.ops.qibo_tf_custom_operators import apply_two_qubit_gate
        from qibo.tensorflow.custom_operators.python.ops.qibo_tf_custom_operators import apply_fsim
        from qibo.tensorflow.custom_operators.python.ops.qibo_tf_custom_operators import apply_swap
        from qibo.tensorflow.custom_operators.python.ops.qibo_tf_custom_operators import collapse_state
        from qibo.tensorflow.custom_operators.python.ops.qibo_tf_custom_operators import measure_frequencies
        # Import gradients
        from qibo.tensorflow.custom_operators.python.ops.qibo_tf_custom_operators_grads import _initial_state_grad
        _custom_operators_loaded = True
    except tf.errors.NotFoundError:  # pragma: no cover
        log.warning(
            "Custom operators not found, skipping custom operators load.")

except ModuleNotFoundError:  # pragma: no cover
    # case not tested because CI has tf installed
    log.warning("Tensorflow is not installed. Skipping custom operators load.")
Пример #19
0
 def ground_state(self):
     if self._ground_state is None:
         log.warning("Ground state for this Hamiltonian was not given.")
         return self.eigenvectors()[:, 0]
     return self._ground_state()
Пример #20
0
        # CI uses tensorflow as default backend
        K = NumpyBackend()
    else:  # pragma: no cover
        raise_error(
            ValueError, "Environment variable `QIBO_BACKEND` has "
            "unknown value {}. Please select either "
            "`tensorflow` or `numpy`."
            "".format(_BACKEND_NAME))
else:
    try:
        os.environ["TF_CPP_MIN_LOG_LEVEL"] = str(config.LOG_LEVEL)
        import tensorflow as tf
        import qibo.tensorflow.custom_operators as op
        _CUSTOM_OPERATORS_LOADED = op._custom_operators_loaded
        if not _CUSTOM_OPERATORS_LOADED:  # pragma: no cover
            log.warning("Removing custom operators from available backends.")
            AVAILABLE_BACKENDS.remove("custom")
        K = TensorflowBackend()
    except ModuleNotFoundError:  # pragma: no cover
        # case not tested because CI has tf installed
        log.warning("Tensorflow is not installed. Falling back to numpy.")
        K = NumpyBackend()
        AVAILABLE_BACKENDS = [
            b for b in AVAILABLE_BACKENDS if "tensorflow" not in b
        ]
        AVAILABLE_BACKENDS.remove("custom")

K.qnp = numpy_backend
_BACKEND_NAME = K.name

Пример #21
0
 def set_threads(self, nthreads):
     log.warning("Numpy backend supports only single-thread execution. "
                 "Cannot change the number of threads.")
     abstract.AbstractBackend.set_threads(self, nthreads)
Пример #22
0
 def set_device(self, name):
     log.warning("Numpy does not support device placement. "
                 "Aborting device change.")