Ejemplo n.º 1
0
def run(qobj, executable):
    """
    Run simulation on C++ simulator inside a subprocess.

    Args:
        qobj (Qobj): qobj dictionary defining the simulation to run
        executable (string): filename (with path) of the simulator executable
    Returns:
        dict: A dict of simulation results
    """

    # Open subprocess and execute external command
    try:
        with subprocess.Popen([executable, '-'],
                              stdin=PIPE,
                              stdout=PIPE,
                              stderr=PIPE) as proc:
            cin = json.dumps(qobj_to_dict(qobj, version='0.0.1'),
                             cls=QASMSimulatorEncoder).encode()
            cout, cerr = proc.communicate(cin)
        if cerr:
            logger.error('ERROR: Simulator encountered a runtime error: %s',
                         cerr.decode())
        sim_output = cout.decode()
        return json.loads(sim_output, cls=QASMSimulatorDecoder)

    except FileNotFoundError:
        msg = "ERROR: Simulator exe not found at: %s" % executable
        logger.error(msg)
        return {"status": msg, "success": False}
Ejemplo n.º 2
0
    def _run_job(self, qobj):
        """Run circuits in q_job"""
        result_list = []
        self._validate(qobj)

        qobj_old_format = qobj_to_dict(qobj, version='0.0.1')

        s = JKUSimulatorWrapper(self._configuration['exe'], silent=self.silent)
        #self._shots = qobj['config']['shots']
        s.shots = qobj_old_format['config']['shots']
        start = time.time()
        for circuit in qobj_old_format['circuits']:
            result_list.append(s.run_on_qobj_circuit(circuit))
        end = time.time()
        job_id = str(uuid.uuid4())
        result = {
            'backend': self._configuration['name'],
            'id': qobj_old_format['id'],
            'job_id': job_id,
            'result': result_list,
            'status': 'COMPLETED',
            'success': True,
            'time_taken': (end - start)
        }
        return result_from_old_style_dict(
            result, [circuit.header.name for circuit in qobj.experiments])
    def get_execution_list(self, qobj, print_func=print):
        """Print the compiled circuits that are ready to run.

        Note:
            This method is intended to be used during interactive sessions, and
            prints directly to stdout instead of using the logger by default. If
            you set print_func with a log function (eg. log.info) it will be used
            instead of the stdout.

        Returns:
            list(str): names of the circuits in `qobj`
        """
        if not qobj:
            print_func("no executions to run")
        execution_list = []

        qobj = qobj_to_dict(qobj, version='0.0.1')

        print_func("id: %s" % qobj['id'])
        print_func("backend: %s" % qobj['config']['backend_name'])
        print_func("qobj config:")
        for key in qobj['config']:
            if key != 'backend':
                print_func(' ' + key + ': ' + str(qobj['config'][key]))
        for circuit in qobj['circuits']:
            execution_list.append(circuit["name"])
            print_func('  circuit name: ' + str(circuit["name"]))
            print_func('  circuit config:')
            for key in circuit['config']:
                print_func('   ' + key + ': ' + str(circuit['config'][key]))
        return execution_list
Ejemplo n.º 4
0
    def __init__(self,
                 api,
                 is_device,
                 qobj=None,
                 job_id=None,
                 backend_name=None,
                 creation_date=None):
        """IBMQJob init function.
        We can instantiate jobs from two sources: A QObj, and an already submitted job returned by
        the API servers.

        Args:
            api (IBMQuantumExperience): IBM Q API
            is_device (bool): whether backend is a real device  # TODO: remove this after Qobj
            qobj (Qobj): The Quantum Object. See notes below
            job_id (String): The job ID of an already submitted job.
            backend_name(String): The name of the backend that run the job.
            creation_date(String): When the job was run.

        Notes:
            It is mandatory to pass either ``qobj`` or ``job_id``. Passing a ``qobj``
            will ignore ``job_id`` and will create an instance representing
            an already-created job retrieved from the API server.
        """
        super().__init__()
        self._job_data = None
        if qobj is not None:
            # TODO: No need for this conversion, just use the new equivalent members above
            old_qobj = qobj_to_dict(qobj, version='0.0.1')
            self._job_data = {
                'circuits': old_qobj['circuits'],
                'hpc': old_qobj['config'].get('hpc'),
                'seed': old_qobj['circuits'][0]['config']['seed'],
                'shots': old_qobj['config']['shots'],
                'max_credits': old_qobj['config']['max_credits']
            }
        self._future_captured_exception = None
        self._api = api
        self._id = job_id
        self._backend_name = qobj.header.backend_name if qobj is not None else backend_name
        self._status = JobStatus.INITIALIZING
        # In case of not providing a qobj, it assumes job_id has been provided
        # and query the API for updating the status.
        if qobj is None:
            self.status()
        self._queue_position = None
        self._cancelled = False
        self._is_device = is_device

        def current_utc_time():
            """Gets the current time in UTC format"""
            datetime.datetime.utcnow().replace(
                tzinfo=datetime.timezone.utc).isoformat()

        self._creation_date = creation_date or current_utc_time()
        self._future = None
        self._api_error_msg = None
Ejemplo n.º 5
0
    def _run_job(self, qobj):
        """Run qobj. This is a blocking call.

        Args:
            qobj (Qobj): job description
        Returns:
            Result: Result object
        """
        result_list = []
        qobj_converted = qobj_to_dict(qobj, version='0.0.1')
        for circuit in qobj_converted['circuits']:
            result_list.append(self.run_circuit(circuit))
        job_id = str(uuid.uuid4())
        return Result(
            {'job_id': job_id, 'result': result_list, 'status': 'COMPLETED'})
Ejemplo n.º 6
0
    def __init__(self, backend, job_id, api, is_device, qobj=None,
                 creation_date=None, api_status=None, **kwargs):
        """IBMQJob init function.

        We can instantiate jobs from two sources: A QObj, and an already submitted job returned by
        the API servers.

        Args:
            backend (str): The backend instance used to run this job.
            job_id (str): The job ID of an already submitted job. Pass `None`
                if you are creating a new one.
            api (IBMQuantumExperience): IBM Q API
            is_device (bool): whether backend is a real device  # TODO: remove this after Qobj
            qobj (Qobj): The Quantum Object. See notes below
            creation_date (str): When the job was run.
            api_status (str): `status` field directly from the API response.
            kwargs (dict): You can pass `backend_name` to this function although
                it has been deprecated.

        Notes:
            It is mandatory to pass either ``qobj`` or ``job_id``. Passing a ``qobj``
            will ignore ``job_id`` and will create an instance representing
            an already-created job retrieved from the API server.
        """
        if 'backend_name' in kwargs:
            warnings.warn('Passing the parameter `backend_name` is deprecated, '
                          'pass the `backend` parameter with the instance of '
                          'the backend running the job.', DeprecationWarning)

        super().__init__(backend, job_id)
        self._job_data = None

        if qobj is not None:
            validate_qobj_against_schema(qobj)

            self._qobj_payload = qobj_to_dict(qobj, version='1.0.0')
            # TODO: No need for this conversion, just use the new equivalent members above
            old_qobj = qobj_to_dict(qobj, version='0.0.1')
            self._job_data = {
                'circuits': old_qobj['circuits'],
                'hpc':  old_qobj['config'].get('hpc'),
                'seed': old_qobj['circuits'][0]['config']['seed'],
                'shots': old_qobj['config']['shots'],
                'max_credits': old_qobj['config']['max_credits']
            }

        self._future_captured_exception = None
        self._api = api
        self._backend = backend
        self._cancelled = False
        self._status = JobStatus.INITIALIZING
        # In case of not providing a `qobj`, it is assumed the job already
        # exists in the API (with `job_id`).
        if qobj is None:
            # Some API calls (`get_status_jobs`, `get_status_job`) provide
            # enough information to recreate the `Job`. If that is the case, try
            # to make use of that information during instantiation, as
            # `self.status()` involves an extra call to the API.
            if api_status == 'VALIDATING':
                self._status = JobStatus.VALIDATING
            elif api_status == 'COMPLETED':
                self._status = JobStatus.DONE
            elif api_status == 'CANCELLED':
                self._status = JobStatus.CANCELLED
                self._cancelled = True
            else:
                self.status()
        self._queue_position = None
        self._is_device = is_device

        def current_utc_time():
            """Gets the current time in UTC format"""
            datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat()

        self._creation_date = creation_date or current_utc_time()
        self._future = None
        self._api_error_msg = None
Ejemplo n.º 7
0
    def _submit(self):
        """Submit job to IBM Q.

        Returns:
            dict: submission info including job id from server

        Raises:
            QISKitError: The backend name in the job doesn't match this backend.
            ResultError: If the API reported an error with the submitted job.
            RegisterSizeError: If the requested register size exceeded device
                capability.
        """
        qobj = qobj_to_dict(self._qobj, version='0.0.1')
        api_jobs = []
        for circuit in qobj['circuits']:
            job = {}
            if not circuit.get('compiled_circuit_qasm', None):
                compiled_circuit = transpile(circuit['circuit'])
                circuit['compiled_circuit_qasm'] = compiled_circuit.qasm(
                    qeflag=True)
            if isinstance(circuit['compiled_circuit_qasm'], bytes):
                job['qasm'] = circuit['compiled_circuit_qasm'].decode()
            else:
                job['qasm'] = circuit['compiled_circuit_qasm']
            if circuit.get('name', None):
                job['name'] = circuit['name']
            # convert numpy types for json serialization
            compiled_circuit = json.loads(
                json.dumps(circuit['compiled_circuit'],
                           default=_numpy_type_converter))
            job['metadata'] = {'compiled_circuit': compiled_circuit}
            api_jobs.append(job)

        seed0 = qobj['circuits'][0]['config']['seed']
        hpc = None
        if qobj['config'].get('hpc', None):
            try:
                # Use CamelCase when passing the hpc parameters to the API.
                hpc = {
                    'multiShotOptimization':
                    qobj['config']['hpc']['multi_shot_optimization'],
                    'ompNumThreads':
                    qobj['config']['hpc']['omp_num_threads']
                }
            except (KeyError, TypeError):
                hpc = None
        backend_name = qobj['config']['backend_name']
        if backend_name != self._backend_name:
            raise QISKitError("inconsistent qobj backend "
                              "name ({0} != {1})".format(
                                  backend_name, self._backend_name))
        try:
            submit_info = self._api.run_job(
                api_jobs,
                backend=backend_name,
                shots=qobj['config']['shots'],
                max_credits=qobj['config']['max_credits'],
                seed=seed0,
                hpc=hpc)
        # pylint: disable=broad-except
        except Exception as err:
            self._status = JobStatus.ERROR
            self._status_msg = str(err)
            self._exception = err
            return None
        if 'error' in submit_info:
            self._status = JobStatus.ERROR
            self._status_msg = str(submit_info['error'])
            self._exception = IBMQJobError(self._status_msg)
            return submit_info
        self._id = submit_info.get('id')
        self.creation_date = submit_info.get('creationDate')
        self._status = JobStatus.QUEUED
        return submit_info
Ejemplo n.º 8
0
    def cache_circuit(self, qobj, circuits, chunk):
        """
        A method for caching compiled qobjs by storing the compiled qobj
        and constructing a mapping array from the uncompiled operations in the circuit
        to the instructions in the qobj. Note that the "qobjs" list in the cache dict is a
        list of the cached chunks, each element of which contains a single qobj with as
        many experiments as is allowed by the execution backend. E.g. if the backend allows
        300 experiments per job and the user wants to run 500 circuits,
        len(circuit_cache['qobjs']) == 2,
        len(circuit_cache['qobjs'][0].experiments) == 300, and
        len(circuit_cache['qobjs'][1].experiments) == 200.

        This feature is only applied if 'circuit_caching' is True in the 'problem' Aqua
        dictionary section.

        Args:
            qobj (Qobj): A compiled qobj to be saved
            circuits (list): The original uncompiled QuantumCircuits
            chunk (int): If a larger list of circuits was broken into chunks by run_algorithm for separate runs,
            which chunk number `circuits` represents
        """

        self.qobjs.insert(chunk, copy.deepcopy(qobj))

        self.mappings.insert(chunk, [{} for i in range(len(circuits))])
        for circ_num, input_circuit in enumerate(circuits):

            qreg_sizes = [
                reg.size for reg in input_circuit.qregs
                if isinstance(reg, QuantumRegister)
            ]
            qreg_indeces = {
                reg.name: sum(qreg_sizes[0:i])
                for i, reg in enumerate(input_circuit.qregs)
            }
            op_graph = {}

            # Unroll circuit in case of composite gates
            raw_gates = []
            for gate in input_circuit.data:
                if isinstance(gate, CompositeGate):
                    raw_gates += gate.instruction_list()
                else:
                    raw_gates += [gate]

            for i, uncompiled_gate in enumerate(raw_gates):
                if not hasattr(uncompiled_gate,
                               'params') or len(uncompiled_gate.params) < 1:
                    continue
                if uncompiled_gate.name == 'snapshot': continue
                regs = [(reg, qubit) for (reg, qubit) in uncompiled_gate.qargs]
                qubits = [
                    qubit + qreg_indeces[reg.name] for reg, qubit in regs
                    if isinstance(reg, QuantumRegister)
                ]
                gate_type = uncompiled_gate.name
                type_and_qubits = gate_type + qubits.__str__()
                op_graph[type_and_qubits] = \
                    op_graph.get(type_and_qubits, []) + [i]
            mapping = {}
            for compiled_gate_index, compiled_gate in enumerate(
                    qobj.experiments[circ_num].instructions):
                if not hasattr(compiled_gate,
                               'params') or len(compiled_gate.params) < 1:
                    continue
                if compiled_gate.name == 'snapshot': continue
                type_and_qubits = compiled_gate.name + compiled_gate.qubits.__str__(
                )
                if len(op_graph[type_and_qubits]) > 0:
                    uncompiled_gate_index = op_graph[type_and_qubits].pop(0)
                    uncompiled_gate = raw_gates[uncompiled_gate_index]
                    regs = [(reg, qubit)
                            for (reg, qubit) in uncompiled_gate.qargs]
                    qubits = [
                        qubit + qreg_indeces[reg.name] for reg, qubit in regs
                        if isinstance(reg, QuantumRegister)
                    ]
                    if (compiled_gate.name == uncompiled_gate.name) and (
                            compiled_gate.qubits.__str__()
                            == qubits.__str__()):
                        mapping[compiled_gate_index] = uncompiled_gate_index
                else:
                    raise Exception(
                        "Circuit shape does not match qobj, found extra {} instruction in qobj"
                        .format(type_and_qubits))
            self.mappings[chunk][circ_num] = mapping
            for type_and_qubits, ops in op_graph.items():
                if len(ops) > 0:
                    raise Exception(
                        "Circuit shape does not match qobj, found extra {} in circuit"
                        .format(type_and_qubits))
        if self.cache_file is not None and len(self.cache_file) > 0:
            cache_handler = open(self.cache_file, 'wb')
            qobj_dicts = [qobj_to_dict(qob) for qob in self.qobjs]
            pickle.dump({
                'qobjs': qobj_dicts,
                'mappings': self.mappings
            },
                        cache_handler,
                        protocol=pickle.HIGHEST_PROTOCOL)
            cache_handler.close()
            logger.debug("Circuit cache saved to file: {}".format(
                self.cache_file))
Ejemplo n.º 9
0
    def __init__(self,
                 backend,
                 job_id,
                 api,
                 is_device,
                 qobj=None,
                 creation_date=None,
                 **kwargs):
        """IBMQJob init function.
        We can instantiate jobs from two sources: A QObj, and an already submitted job returned by
        the API servers.

        Args:
            api (IBMQuantumExperience): IBM Q API
            is_device (bool): whether backend is a real device  # TODO: remove this after Qobj
            qobj (Qobj): The Quantum Object. See notes below
            job_id (String): The job ID of an already submitted job. Pass `None`
            if you are creating a new one.
            creation_date(String): When the job was run.
            backend (str): The backend instance used to run this job.
            kwargs (dict): You can pass `backend_name` to this function although
                it has been deprecated.

        Notes:
            It is mandatory to pass either ``qobj`` or ``job_id``. Passing a ``qobj``
            will ignore ``job_id`` and will create an instance representing
            an already-created job retrieved from the API server.
        """
        if 'backend_name' in kwargs:
            warnings.warn(
                'Passing the parameter `backend_name` is deprecated, '
                'pass the `backend` parameter with the instance of '
                'the backend running the job.', DeprecationWarning)

        super().__init__(backend, job_id)
        self._job_data = None

        if qobj is not None:
            validate_qobj_against_schema(qobj)

            self._qobj_payload = qobj_to_dict(qobj, version='1.0.0')
            # TODO: No need for this conversion, just use the new equivalent members above
            old_qobj = qobj_to_dict(qobj, version='0.0.1')
            self._job_data = {
                'circuits': old_qobj['circuits'],
                'hpc': old_qobj['config'].get('hpc'),
                'seed': old_qobj['circuits'][0]['config']['seed'],
                'shots': old_qobj['config']['shots'],
                'max_credits': old_qobj['config']['max_credits']
            }

        self._future_captured_exception = None
        self._api = api
        self._backend = backend
        self._status = JobStatus.INITIALIZING
        # In case of not providing a qobj, it assumes job_id has been provided
        # and query the API for updating the status.
        if qobj is None:
            self.status()
        self._queue_position = None
        self._cancelled = False
        self._is_device = is_device

        def current_utc_time():
            """Gets the current time in UTC format"""
            datetime.datetime.utcnow().replace(
                tzinfo=datetime.timezone.utc).isoformat()

        self._creation_date = creation_date or current_utc_time()
        self._future = None
        self._api_error_msg = None