Source code for schrodinger.application.matsci.qb_sdk.api

# Copyright (c) 2021, Qu & Co
# All rights reserved.

# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:

# 1. Redistributions of source code must retain the above copyright notice, this
#    list of conditions and the following disclaimer.

# 2. Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.

# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
This module contains all the public methods of the qubec-sdk API covering all most important use cases such as
authenticating to the QUBEC platform, launching quantum jobs and retrieving previously completed job information.
"""

# built-in
from binascii import Error as EncodingError
from dataclasses import asdict
from typing import Union

# local
from . import PROJECT_VERSION as VERSION
from .client import QubecClient, get_client
from .job import QubecJob
from .parameters import (
    AVAILABLE_ALGORITHMS,
    AVAILABLE_BACKEND_TYPES,
    AVAILABLE_PROPERTIES,
    DEFAULT_BACKEND_TYPE,
    DEFAULT_N_SHOTS,
    DEFAULT_PROVIDER,
    DEFAULT_QPU_CHIP,
    DEFAULT_QUANTUM_PARAMETERS,
    DEFAULT_SCF_PARAMETERS,
    DEFAULT_SIMULATION_TYPE,
    QubecAlgorithm,
    QubecChemistryProblem,
    QubecSdkError,
)
from .tools import encode_geometry_xyz


[docs]def enable_account(username: str, password: str = None, token: str = None) -> dict: """ Login into a QUBEC account providing valid user credentials. This function must be called before starting any QUBEC session otherwise the execution of quantum jobs will not be allowed Args: username (str): The username as registered on the QUBEC platform password (str): The password associated with the username. If no password is provided, then a valid token must be supplied instead token (str): An optional previously retrieved JWT token to use for login Returns: A dictionary with token information. Beware that this might contain a password in clear text, do not store it on disk Raises: QubecSdkError if credentials are invalid or the backed call did not succeed """ client: QubecClient = get_client() if password is not None: client.login(username, password) elif token is not None: client.current_user(token) else: raise QubecSdkError("Provide either password or a valid QUBEC token") return asdict(client.token)
[docs]def execute( problem: dict = None, algorithm_type: Union[str, QubecAlgorithm] = None, backend_type: str = DEFAULT_BACKEND_TYPE, provider: str = DEFAULT_PROVIDER, simulation_type: str = DEFAULT_SIMULATION_TYPE, n_shots: int = DEFAULT_N_SHOTS, qpu_chip: str = DEFAULT_QPU_CHIP, scf_parameters: dict = DEFAULT_SCF_PARAMETERS, quantum_parameters: dict = DEFAULT_QUANTUM_PARAMETERS, ) -> QubecJob: """ Execute a new quantum job on the QUBEC platform. If the QUBEC token in the current session has expired, this function will automatically refresh it Args: problem (dict): A dictionary containing the problem definition which must contain at least 'geometry' and 'basis_set' keys. A full example of this dictionary is: ``` problem = { "geometry": [ ("H", (0.0, 0.0, 0.0)), ("H", (0.5, 0.5, 0.5)) ], "basis_set": "sto-3g", "charge": 1 } ``` algorithm_type (Union[str, QubecAlgorithm]): The type of quantum algorithm to execute. Currently only 'vqa' and 'qpe_re' are allowed values backend_type (str): The backend type where the algorithm needs to be executed. Currently one can choose among 'simulator', 'noisy_simulator' and 'qpu' provider (str): The quantum computing provider to use simulation_type (str): If the algorithm selected is 'vqa', this string contains the type of quantum simulation to execute chosen between 'wavefunction' or 'tomography' n_shots (int): The number of circuit repetitions, used only if 'tomography' is selected as simulation type qpu_chip (str): If 'qpu' is selected as backend_type, this parameter specifies the actual quantum chip to use scf_parameters (dict): the parameters of the self-consistent preprocessing calculation. See qb_sdk.parameters documentation for information on the valid parameters quantum_parameters (dict): the parameters of the quantum job. See qb_sdk.parameters documentation for information on the valid parameters Returns: A QubecJob instance with a unique job identifier created by the QUBEC platform and all the relevant information to retrieve job progress later Raises: QubecSdk if some parameters are wrong or the job has failed to be submitted correctly """ client: QubecClient = get_client() client.refresh_session() try: problem = problem if problem is not None else {} problem_model = QubecChemistryProblem(**problem) problem_model.geometry = encode_geometry_xyz(problem_model.geometry) properties = list(problem_model.properties.keys()) are_valid_props = all( prop in AVAILABLE_PROPERTIES for prop in properties) if len(properties) > 0 and not are_valid_props: raise QubecSdkError( f"Choose among the following physical properties: {AVAILABLE_PROPERTIES}" ) except EncodingError: raise QubecSdkError(f"Wrong problem definition provided: {problem}") except QubecSdkError as e: raise e if isinstance(algorithm_type, QubecAlgorithm): algorithm_type = algorithm_type.name if algorithm_type is None or algorithm_type not in AVAILABLE_ALGORITHMS: raise QubecSdkError( f"Choose among the following quantum algorithms: {AVAILABLE_ALGORITHMS}" ) if backend_type not in AVAILABLE_BACKEND_TYPES: raise QubecSdkError( f"Choose among the following backend types: {AVAILABLE_BACKEND_TYPES}" ) data = { "algorithm_type": algorithm_type, "backend_type": backend_type, "backend": { "provider": provider, "simulation_type": simulation_type, "n_shots": n_shots, "chip": qpu_chip, }, "problem_definition": asdict(problem_model), "scf_parameters": scf_parameters, "quantum_parameters": quantum_parameters, } content = client.submit_job(data) job = QubecJob( content["data"]["job_id"], experiment=data["algorithm_type"], backend_type=data["backend_type"], backend=data["backend"], problem=data["problem_definition"], **scf_parameters, **quantum_parameters, ) return job
[docs]def new_default_session() -> QubecClient: """ Logout from the current QUBEC session and begin a new one """ client: QubecClient = get_client() client.logout() return client
[docs]def version() -> str: """ Get the current package version """ return VERSION
# TODO
[docs]def get_job(job_id: str) -> QubecJob: """ Deserialize and existing QUBEC job into a new QubecJob instance Args: job_id (str): The unique identifier of the job Returns: A populated instance of QubecJob """ pass