def _config_the_best_mode(self, operator, backend): if not isinstance(operator, (WeightedPauliOperator, MatrixOperator, TPBGroupedWeightedPauliOperator)): logger.debug("Unrecognized operator type, skip auto conversion.") return operator ret_op = operator if not is_statevector_backend(backend) and not ( is_aer_provider(backend) and self._quantum_instance.run_config.shots == 1): if isinstance(operator, (WeightedPauliOperator, MatrixOperator)): logger.debug( "When running with Qasm simulator, grouped pauli can " "save number of measurements. " "We convert the operator into grouped ones.") ret_op = op_converter.to_tpb_grouped_weighted_pauli_operator( operator, TPBGroupedWeightedPauliOperator.sorted_grouping) else: if not is_aer_provider(backend): if not isinstance(operator, MatrixOperator): logger.info( "When running with non-Aer statevector simulator, " "represent operator as a matrix could " "achieve the better performance. We convert " "the operator to matrix.") ret_op = op_converter.to_matrix_operator(operator) else: if not isinstance(operator, WeightedPauliOperator): logger.info("When running with Aer simulator, " "represent operator as weighted paulis could " "achieve the better performance. We convert " "the operator to weighted paulis.") ret_op = op_converter.to_weighted_pauli_operator(operator) return ret_op
def run_on_backend(backend: Union[Backend, BaseBackend], qobj: QasmQobj, backend_options: Optional[Dict] = None, noise_config: Optional[Dict] = None, skip_qobj_validation: bool = False) -> BaseJob: """ run on backend """ if skip_qobj_validation: if is_aer_provider(backend) or is_basicaer_provider(backend): if backend_options is not None: for option, value in backend_options.items(): if option == 'backend_options': for key, val in value.items(): setattr(qobj.config, key, val) else: setattr(qobj.config, option, value) if is_aer_provider(backend) and \ noise_config is not None and \ 'noise_model' in noise_config: qobj.config.noise_model = noise_config['noise_model'] job = backend.run(qobj, validate=False) else: logger.info("Can't skip qobj validation for the %s provider.", backend.provider().__class__.__name__) job = backend.run(qobj, **backend_options, **noise_config) return job else: job = backend.run(qobj, **backend_options, **noise_config) return job
def run_on_backend(backend, qobj, backend_options=None, noise_config=None, skip_qobj_validation=False): """ run on backend """ if skip_qobj_validation: if is_aer_provider(backend): if backend_options is not None: for option, value in backend_options.items(): if option == 'backend_options': for key, val in value.items(): setattr(qobj.config, key, val) else: setattr(qobj.config, option, value) if noise_config is not None and 'noise_model' in noise_config: qobj.config.noise_model = noise_config['noise_model'] job = backend.run(qobj, validate=False) elif is_basicaer_provider(backend): job_id = str(uuid.uuid4()) backend._set_options(qobj_config=qobj.config, **backend_options) job = BasicAerJob(backend, job_id, backend._run_job, qobj) job._future = job._executor.submit(job._fn, job._job_id, job._qobj) else: logger.info("Can't skip qobj validation for the %s provider.", backend.provider().__class__.__name__) job = backend.run(qobj, **backend_options, **noise_config) return job else: job = backend.run(qobj, **backend_options, **noise_config) return job
def run_on_backend(backend, qobj, backend_options=None, noise_config=None, skip_qobj_validation=False): """ run on backend """ if skip_qobj_validation: job_id = str(uuid.uuid4()) if is_aer_provider(backend): from qiskit.providers.aer.aerjob import AerJob temp_backend_options = \ backend_options['backend_options'] if backend_options != {} else None temp_noise_config = noise_config['noise_model'] if noise_config != {} else None job = AerJob(backend, job_id, backend._run_job, qobj, temp_backend_options, temp_noise_config, False) job._future = job._executor.submit(job._fn, job._job_id, job._qobj, *job._args) elif is_basicaer_provider(backend): backend._set_options(qobj_config=qobj.config, **backend_options) job = BasicAerJob(backend, job_id, backend._run_job, qobj) job._future = job._executor.submit(job._fn, job._job_id, job._qobj) else: logger.info( "Can't skip qobj validation for the %s provider.", backend.provider().__class__.__name__) job = backend.run(qobj, **backend_options, **noise_config) return job else: job = backend.run(qobj, **backend_options, **noise_config) return job
def run_on_backend(backend, qobj, backend_options=None, noise_config=None, skip_qobj_validation=False): if skip_qobj_validation: job_id = str(uuid.uuid4()) if is_aer_provider(backend): from qiskit.providers.aer.aerjob import AerJob temp_backend_options = backend_options[ 'backend_options'] if backend_options != {} else None temp_noise_config = noise_config[ 'noise_model'] if noise_config != {} else None job = AerJob(backend, job_id, backend._run_job, qobj, temp_backend_options, temp_noise_config, False) job._future = job._executor.submit(job._fn, job._job_id, job._qobj, *job._args) elif is_basicaer_provider(backend): backend._set_options(qobj_config=qobj.config, **backend_options) job = BasicAerJob(backend, job_id, backend._run_job, qobj) job._future = job._executor.submit(job._fn, job._job_id, job._qobj) elif is_ibmq_provider(backend): # TODO: IBMQJob performs validation during the constructor. the following lines does not # skip validation but run as is. from qiskit.providers.ibmq.ibmqjob import IBMQJob job = IBMQJob(backend, None, backend._api, qobj=qobj) job._future = job._executor.submit(job._submit_callback) else: logger.info( "Can't skip qobj validation for the third-party provider.") job = backend.run(qobj, **backend_options, **noise_config) return job else: job = backend.run(qobj, **backend_options, **noise_config) return job
def run_on_backend(backend, qobj, backend_options=None, noise_config=None, skip_qobj_validation=False): if skip_qobj_validation: job_id = str(uuid.uuid4()) if is_simulator_backend(backend): if is_aer_provider(backend): job = backend.run(qobj, **backend_options, **noise_config) else: job = SimulatorsJob(backend, job_id, backend._run_job, qobj) job._future = job._executor.submit(job._fn, job._job_id, job._qobj) elif is_ibmq_provider(backend): job = IBMQJob(backend, None, backend._api, not is_simulator_backend(backend), qobj=qobj) job._future = job._executor.submit(job._fn, job._job_id, job._qobj) else: logger.info( "Can not skip qobj validation for the third-party provider.") job = backend.run(qobj, **backend_options, **noise_config) return job else: job = backend.run(qobj, **backend_options, **noise_config) return job
def _run(self): """ Run the algorithm to compute the minimum eigenvalue. Returns: dict: Dictionary of results Raises: AquaError: wrong setting of operator and backend. """ if self._auto_conversion: self._operator = \ self._config_the_best_mode(self._operator, self._quantum_instance.backend) for i in range(len(self._aux_operators)): if not self._aux_operators[i].is_empty(): self._aux_operators[i] = \ self._config_the_best_mode(self._aux_operators[i], self._quantum_instance.backend) # sanity check if isinstance( self._operator, MatrixOperator) and not self._quantum_instance.is_statevector: raise AquaError("Non-statevector simulator can not work " "with `MatrixOperator`, either turn ON " "auto_conversion or use the proper " "combination between operator and backend.") self._use_simulator_snapshot_mode = ( is_aer_provider(self._quantum_instance.backend) and self._quantum_instance.run_config.shots == 1 and not self._quantum_instance.noise_config and isinstance( self._operator, (WeightedPauliOperator, TPBGroupedWeightedPauliOperator))) self._quantum_instance.circuit_summary = True self._eval_count = 0 self._ret = self.find_minimum(initial_point=self.initial_point, var_form=self.var_form, cost_fn=self._energy_evaluation, optimizer=self.optimizer) if self._ret['num_optimizer_evals'] is not None and \ self._eval_count >= self._ret['num_optimizer_evals']: self._eval_count = self._ret['num_optimizer_evals'] self._eval_time = self._ret['eval_time'] logger.info( 'Optimization complete in %s seconds.\nFound opt_params %s in %s evals', self._eval_time, self._ret['opt_params'], self._eval_count) self._ret['eval_count'] = self._eval_count self._ret['energy'] = self.get_optimal_cost() self._ret['eigvals'] = np.asarray([self.get_optimal_cost()]) self._ret['eigvecs'] = np.asarray([self.get_optimal_vector()]) self._eval_aux_ops() self.cleanup_parameterized_circuits() return self._ret
def quantum_instance(self, quantum_instance: Union[QuantumInstance, BaseBackend]) -> None: """ set quantum_instance """ super(VQE, self.__class__).quantum_instance.__set__(self, quantum_instance) self._circuit_sampler = CircuitSampler( self._quantum_instance, param_qobj=is_aer_provider(self._quantum_instance.backend)) # Expectation was not passed by user, try to create one if not self._user_valid_expectation: self._try_set_expectation_value_from_factory()
def _run(self) -> 'VQSDResult': """ Run the algorithm to compute the minimum eigenvalue. Returns: dict: dictionary of results Raises: AquaError: wrong setting of operator and backend. """ if self.initial_state is None: raise AquaError("Initial state was never provided") self._initial_state = self.initial_state self._use_simulator_snapshot_mode = ( is_aer_provider(self._quantum_instance.backend) and self._quantum_instance.run_config.shots == 1 and not self._quantum_instance.noise_config) self._quantum_instance.circuit_summary = True self._eval_count = 0 vqresult = self.find_minimum(initial_point=self.initial_point, var_form=self.var_form, cost_fn=self._cost_evaluation, optimizer=self.optimizer) # TODO remove all former dictionary logic self._ret = {} self._ret['num_optimizer_evals'] = vqresult.optimizer_evals self._ret['min_val'] = vqresult.optimal_value self._ret['opt_params'] = vqresult.optimal_point self._ret['eval_time'] = vqresult.optimizer_time if self._ret['num_optimizer_evals'] is not None and \ self._eval_count >= self._ret['num_optimizer_evals']: self._eval_count = self._ret['num_optimizer_evals'] self._eval_time = self._ret['eval_time'] logger.info('Optimization complete in %s seconds.\nFound opt_params %s in %s evals', self._eval_time, self._ret['opt_params'], self._eval_count) self._ret['eval_count'] = self._eval_count result = VQSDResult() result.combine(vqresult) result.eigenvalue = self.get_optimal_value() result.eigenstate = self.get_optimal_vector() result.cost_function_evals = self._eval_count self._ret['energy'] = self.get_optimal_cost() self._ret['eigvals'] = result.eigenvalue self._ret['eigvecs'] = result.eigenstate self.cleanup_parameterized_circuits() return result
def _check_quantum_instance_and_modes_consistent(self) -> None: """ Checks whether the statevector and param_qobj settings are compatible with the backend Raises: ValueError: statevector or param_qobj are True when not supported by backend. """ if self._statevector and not is_statevector_backend(self.quantum_instance.backend): raise ValueError('Statevector mode for circuit sampling requires statevector ' 'backend, not {}.'.format(self.quantum_instance.backend)) if self._param_qobj and not is_aer_provider(self.quantum_instance.backend): raise ValueError('Parameterized Qobj mode requires Aer ' 'backend, not {}.'.format(self.quantum_instance.backend))
def run_on_backend(backend, qobj, backend_options=None, noise_config=None, skip_qobj_validation=False): """ run on backend """ if skip_qobj_validation: job_id = str(uuid.uuid4()) if is_aer_provider(backend): # pylint: disable=import-outside-toplevel try: from qiskit.providers.aer.aerjob import AerJob except ImportError as ex: raise MissingOptionalLibraryError( libname='qiskit-aer', name='run_on_backend', pip_install='pip install qiskit-aer') from ex temp_backend_options = \ backend_options['backend_options'] if backend_options != {} else None temp_noise_config = noise_config[ 'noise_model'] if noise_config != {} else None # Add new options if temp_backend_options is not None or temp_noise_config is not None: config = qobj.config.to_dict() if temp_backend_options is not None: for key, val in temp_backend_options.items(): config[key] = val if not hasattr( val, 'to_dict') else val.to_dict() if temp_noise_config is not None: config['noise_model'] = temp_noise_config qobj.config = QasmQobjConfig.from_dict(config) job = AerJob(backend, job_id, backend._run, qobj) job.submit() elif is_basicaer_provider(backend): backend._set_options(qobj_config=qobj.config, **backend_options) job = BasicAerJob(backend, job_id, backend._run_job, qobj) job._future = job._executor.submit(job._fn, job._job_id, job._qobj) else: logger.info("Can't skip qobj validation for the %s provider.", backend.provider().__class__.__name__) job = backend.run(qobj, **backend_options, **noise_config) return job else: job = backend.run(qobj, **backend_options, **noise_config) return job
def compile_circuits(circuits, backend, backend_config=None, compile_config=None, run_config=None, show_circuit_summary=False, circuit_cache=None, **kwargs): """ An execution wrapper with Qiskit-Terra, with job auto recover capability. The autorecovery feature is only applied for non-simulator backend. This wraper will try to get the result no matter how long it costs. Args: circuits (QuantumCircuit or list[QuantumCircuit]): circuits to execute backend (BaseBackend): backend instance backend_config (dict, optional): configuration for backend compile_config (dict, optional): configuration for compilation run_config (RunConfig, optional): configuration for running a circuit show_circuit_summary (bool, optional): showing the summary of submitted circuits. circuit_cache (CircuitCache, optional): A CircuitCache to use when calling compile_and_run_circuits Returns: QasmObj: compiled qobj. Raises: AquaError: Any error except for JobError raised by Qiskit Terra """ backend_config = backend_config or {} compile_config = compile_config or {} run_config = run_config or {} if backend is None or not isinstance(backend, BaseBackend): raise ValueError( 'Backend is missing or not an instance of BaseBackend') if not isinstance(circuits, list): circuits = [circuits] if is_simulator_backend(backend): circuits = _avoid_empty_circuits(circuits) if MAX_CIRCUITS_PER_JOB is not None: max_circuits_per_job = int(MAX_CIRCUITS_PER_JOB) else: if is_local_backend(backend): max_circuits_per_job = sys.maxsize else: max_circuits_per_job = backend.configuration().max_experiments if circuit_cache is not None and circuit_cache.try_reusing_qobjs: # Check if all circuits are the same length. # If not, don't try to use the same qobj.experiment for all of them. if len(set([len(circ.data) for circ in circuits])) > 1: circuit_cache.try_reusing_qobjs = False else: # Try setting up the reusable qobj # Compile and cache first circuit if cache is empty. The load method will try to reuse it if circuit_cache.qobjs is None: qobj, transpiled_circuits = _compile_wrapper([circuits[0]], backend, backend_config, compile_config, run_config) if is_aer_provider(backend): qobj = _maybe_add_aer_expectation_instruction(qobj, kwargs) circuit_cache.cache_circuit(qobj, [circuits[0]], 0) qobjs = [] transpiled_circuits = [] chunks = int(np.ceil(len(circuits) / max_circuits_per_job)) for i in range(chunks): sub_circuits = circuits[i * max_circuits_per_job:(i + 1) * max_circuits_per_job] if circuit_cache is not None and circuit_cache.misses < circuit_cache.allowed_misses: try: if circuit_cache.cache_transpiled_circuits: transpiled_sub_circuits = compiler.transpile( sub_circuits, backend, **backend_config, **compile_config) qobj = circuit_cache.load_qobj_from_cache( transpiled_sub_circuits, i, run_config=run_config) else: qobj = circuit_cache.load_qobj_from_cache( sub_circuits, i, run_config=run_config) if is_aer_provider(backend): qobj = _maybe_add_aer_expectation_instruction(qobj, kwargs) # cache miss, fail gracefully except (TypeError, IndexError, FileNotFoundError, EOFError, AquaError, AttributeError) as e: circuit_cache.try_reusing_qobjs = False # Reusing Qobj didn't work if len(circuit_cache.qobjs) > 0: logger.info( 'Circuit cache miss, recompiling. Cache miss reason: ' + repr(e)) circuit_cache.misses += 1 else: logger.info( 'Circuit cache is empty, compiling from scratch.') circuit_cache.clear_cache() qobj, transpiled_sub_circuits = _compile_wrapper( sub_circuits, backend, backend_config, compile_config, run_config) transpiled_circuits.extend(transpiled_sub_circuits) if is_aer_provider(backend): qobj = _maybe_add_aer_expectation_instruction(qobj, kwargs) try: circuit_cache.cache_circuit(qobj, sub_circuits, i) except (TypeError, IndexError, AquaError, AttributeError, KeyError) as e: try: circuit_cache.cache_transpiled_circuits = True circuit_cache.cache_circuit(qobj, transpiled_sub_circuits, i) except (TypeError, IndexError, AquaError, AttributeError, KeyError) as e: logger.info( 'Circuit could not be cached for reason: ' + repr(e)) logger.info( 'Transpilation may be too aggressive. Try skipping transpiler.' ) else: qobj, transpiled_sub_circuits = _compile_wrapper( sub_circuits, backend, backend_config, compile_config, run_config) transpiled_circuits.extend(transpiled_sub_circuits) if is_aer_provider(backend): qobj = _maybe_add_aer_expectation_instruction(qobj, kwargs) qobjs.append(qobj) if logger.isEnabledFor(logging.DEBUG) and show_circuit_summary: logger.debug("==== Before transpiler ====") logger.debug(summarize_circuits(circuits)) logger.debug("==== After transpiler ====") logger.debug(summarize_circuits(transpiled_circuits)) return qobjs
def update_backend_schema(self, input_parser): """ Updates backend schema """ if JSONSchema.BACKEND not in self._schema['properties']: return # Updates defaults provider/backend default_provider_name = None default_backend_name = None orig_backend_properties = self._original_schema.get( 'properties', {}).get(JSONSchema.BACKEND, {}).get('properties') if orig_backend_properties is not None: default_provider_name = orig_backend_properties.get( JSONSchema.PROVIDER, {}).get('default') default_backend_name = orig_backend_properties.get( JSONSchema.NAME, {}).get('default') providers = get_local_providers() if default_provider_name is None or default_provider_name not in providers: # use first provider available providers_items = providers.items() provider_tuple = next( iter(providers_items)) if len(providers_items) > 0 else ('', []) default_provider_name = provider_tuple[0] if default_backend_name is None or default_backend_name not in providers.get( default_provider_name, []): # use first backend available in provider default_backend_name = providers.get( default_provider_name)[0] if len( providers.get(default_provider_name, [])) > 0 else '' self._schema['properties'][JSONSchema.BACKEND] = { 'type': 'object', 'properties': { JSONSchema.PROVIDER: { 'type': 'string', 'default': default_provider_name }, JSONSchema.NAME: { 'type': 'string', 'default': default_backend_name }, }, 'required': [JSONSchema.PROVIDER, JSONSchema.NAME], 'additionalProperties': False, } provider_name = input_parser.get_section_property( JSONSchema.BACKEND, JSONSchema.PROVIDER, default_provider_name) backend_names = get_backends_from_provider(provider_name) backend_name = input_parser.get_section_property( JSONSchema.BACKEND, JSONSchema.NAME, default_backend_name) if backend_name not in backend_names: # use first backend available in provider backend_name = backend_names[0] if len(backend_names) > 0 else '' backend = get_backend_from_provider(provider_name, backend_name) config = backend.configuration() # Include shots in schema only if not a statevector backend. # For statevector, shots will be set to 1, in QiskitAqua if not is_statevector_backend(backend): self._schema['properties'][ JSONSchema.BACKEND]['properties']['shots'] = { 'type': 'integer', 'minimum': 1, } default_shots = 1024 # ensure default_shots <= max_shots if config.max_shots: default_shots = min(default_shots, config.max_shots) self._schema['properties'][JSONSchema.BACKEND]['properties'][ 'shots']['maximum'] = config.max_shots self._schema['properties'][JSONSchema.BACKEND]['properties'][ 'shots']['default'] = default_shots self._schema['properties'][ JSONSchema.BACKEND]['properties']['skip_transpiler'] = { 'type': 'boolean', 'default': False, } coupling_map_devices = [] noise_model_devices = [] check_coupling_map = is_simulator_backend(backend) check_noise_model = is_aer_provider( backend) and not is_aer_statevector_backend(backend) try: if (check_coupling_map or check_noise_model) and has_ibmq(): backend_names = get_backends_from_provider('qiskit.IBMQ') for backend_name in backend_names: ibmq_backend = get_backend_from_provider( 'qiskit.IBMQ', backend_name) if is_simulator_backend(ibmq_backend): continue if check_noise_model: noise_model_devices.append('qiskit.IBMQ:' + backend_name) if check_coupling_map and ibmq_backend.configuration( ).coupling_map: coupling_map_devices.append('qiskit.IBMQ:' + backend_name) except Exception as e: logger.debug("Failed to load IBMQ backends. Error {}".format( str(e))) # Includes 'coupling map' and 'coupling_map_from_device' in schema only if a simulator backend. # Actual devices have a coupling map based on the physical configuration of the device. # The user can configure the coupling map so its the same as the coupling map # of a given device in order to better simulate running on the device. # Property 'coupling_map_from_device' is a list of provider:name backends that are # real devices e.g qiskit.IBMQ:ibmqx5. # If property 'coupling_map', an array, is provided, it overrides coupling_map_from_device, # the latter defaults to 'None'. So in total no coupling map is a default, i.e. all to all coupling is possible. if is_simulator_backend(backend): self._schema['properties'][ JSONSchema.BACKEND]['properties']['coupling_map'] = { 'type': ['array', 'null'], 'default': None, } if len(coupling_map_devices) > 0: coupling_map_devices.append(None) self._schema['properties'][JSONSchema.BACKEND]['properties'][ 'coupling_map_from_device'] = { 'type': ['string', 'null'], 'default': None, 'oneOf': [{ 'enum': coupling_map_devices }], } # noise model that can be setup for Aer simulator so as to model noise of an actual device. if len(noise_model_devices) > 0: noise_model_devices.append(None) self._schema['properties'][ JSONSchema.BACKEND]['properties']['noise_model'] = { 'type': ['string', 'null'], 'default': None, 'oneOf': [{ 'enum': noise_model_devices }], } # If a noise model is supplied then the basis gates is set as per the noise model # unless basis gates is not None in which case it overrides noise model and a warning msg is logged. # as it is an advanced use case. self._schema['properties'][ JSONSchema.BACKEND]['properties']['basis_gates'] = { 'type': ['array', 'null'], 'default': None, } # TODO: Not sure if we want to continue with initial_layout in declarative form. # It requires knowledge of circuit registers etc. Perhaps its best to leave this detail to programming API. self._schema['properties'][ JSONSchema.BACKEND]['properties']['initial_layout'] = { 'type': ['object', 'null'], 'default': None, } # The same default and minimum as current RunConfig values self._schema['properties'][ JSONSchema.BACKEND]['properties']['max_credits'] = { 'type': 'integer', 'default': 10, 'minimum': 3, 'maximum': 10, } # Timeout and wait are for remote backends where we have to connect over network if not is_local_backend(backend): self._schema['properties'][ JSONSchema.BACKEND]['properties']['timeout'] = { "type": ["number", "null"], 'default': None, } self._schema['properties'][ JSONSchema.BACKEND]['properties']['wait'] = { 'type': 'number', 'default': 5.0, 'minimum': 0.0, }
def compile_and_run_circuits(circuits, backend, backend_config=None, compile_config=None, run_config=None, qjob_config=None, backend_options=None, noise_config=None, show_circuit_summary=False, has_shared_circuits=False, circuit_cache=None, skip_qobj_validation=False, **kwargs): """ An execution wrapper with Qiskit-Terra, with job auto recover capability. The autorecovery feature is only applied for non-simulator backend. This wraper will try to get the result no matter how long it costs. Args: circuits (QuantumCircuit or list[QuantumCircuit]): circuits to execute backend (BaseBackend): backend instance backend_config (dict, optional): configuration for backend compile_config (dict, optional): configuration for compilation run_config (RunConfig, optional): configuration for running a circuit qjob_config (dict, optional): configuration for quantum job object backend_options (dict, optional): configuration for simulator noise_config (dict, optional): configuration for noise model show_circuit_summary (bool, optional): showing the summary of submitted circuits. has_shared_circuits (bool, optional): use the 0-th circuits as initial state for other circuits. circuit_cache (CircuitCache, optional): A CircuitCache to use when calling compile_and_run_circuits skip_qobj_validation (bool, optional): Bypass Qobj validation to decrease submission time Returns: Result: Result object Raises: AquaError: Any error except for JobError raised by Qiskit Terra """ backend_config = backend_config or {} compile_config = compile_config or {} run_config = run_config or {} qjob_config = qjob_config or {} backend_options = backend_options or {} noise_config = noise_config or {} if backend is None or not isinstance(backend, BaseBackend): raise ValueError( 'Backend is missing or not an instance of BaseBackend') if not isinstance(circuits, list): circuits = [circuits] if is_simulator_backend(backend): circuits = _avoid_empty_circuits(circuits) if has_shared_circuits: return _reuse_shared_circuits(circuits, backend, backend_config, compile_config, run_config, qjob_config, backend_options) with_autorecover = False if is_simulator_backend(backend) else True if MAX_CIRCUITS_PER_JOB is not None: max_circuits_per_job = int(MAX_CIRCUITS_PER_JOB) else: if is_local_backend(backend): max_circuits_per_job = sys.maxsize else: max_circuits_per_job = backend.configuration().max_experiments if circuit_cache is not None and circuit_cache.try_reusing_qobjs: # Check if all circuits are the same length. # If not, don't try to use the same qobj.experiment for all of them. if len(set([len(circ.data) for circ in circuits])) > 1: circuit_cache.try_reusing_qobjs = False else: # Try setting up the reusable qobj # Compile and cache first circuit if cache is empty. The load method will try to reuse it if circuit_cache.qobjs is None: qobj, _ = _compile_wrapper([circuits[0]], backend, backend_config, compile_config, run_config) if is_aer_provider(backend): qobj = _maybe_add_aer_expectation_instruction(qobj, kwargs) circuit_cache.cache_circuit(qobj, [circuits[0]], 0) qobjs = [] jobs = [] job_ids = [] transpiled_circuits = [] chunks = int(np.ceil(len(circuits) / max_circuits_per_job)) for i in range(chunks): sub_circuits = circuits[i * max_circuits_per_job:(i + 1) * max_circuits_per_job] if circuit_cache is not None and circuit_cache.misses < circuit_cache.allowed_misses: try: if circuit_cache.cache_transpiled_circuits: transpiled_sub_circuits = compiler.transpile( sub_circuits, backend, **backend_config, **compile_config) qobj = circuit_cache.load_qobj_from_cache( transpiled_sub_circuits, i, run_config=run_config) else: qobj = circuit_cache.load_qobj_from_cache( sub_circuits, i, run_config=run_config) if is_aer_provider(backend): qobj = _maybe_add_aer_expectation_instruction(qobj, kwargs) # cache miss, fail gracefully except (TypeError, IndexError, FileNotFoundError, EOFError, AquaError, AttributeError) as e: circuit_cache.try_reusing_qobjs = False # Reusing Qobj didn't work if len(circuit_cache.qobjs) > 0: logger.info( 'Circuit cache miss, recompiling. Cache miss reason: ' + repr(e)) circuit_cache.misses += 1 else: logger.info( 'Circuit cache is empty, compiling from scratch.') circuit_cache.clear_cache() qobj, transpiled_sub_circuits = _compile_wrapper( sub_circuits, backend, backend_config, compile_config, run_config) transpiled_circuits.extend(transpiled_sub_circuits) if is_aer_provider(backend): qobj = _maybe_add_aer_expectation_instruction(qobj, kwargs) try: circuit_cache.cache_circuit(qobj, sub_circuits, i) except (TypeError, IndexError, AquaError, AttributeError, KeyError) as e: try: circuit_cache.cache_transpiled_circuits = True circuit_cache.cache_circuit(qobj, transpiled_sub_circuits, i) except (TypeError, IndexError, AquaError, AttributeError, KeyError) as e: logger.info( 'Circuit could not be cached for reason: ' + repr(e)) logger.info( 'Transpilation may be too aggressive. Try skipping transpiler.' ) else: qobj, transpiled_sub_circuits = _compile_wrapper( sub_circuits, backend, backend_config, compile_config, run_config) transpiled_circuits.extend(transpiled_sub_circuits) if is_aer_provider(backend): qobj = _maybe_add_aer_expectation_instruction(qobj, kwargs) # assure get job ids while True: job = run_on_backend(backend, qobj, backend_options=backend_options, noise_config=noise_config, skip_qobj_validation=skip_qobj_validation) try: job_id = job.job_id() break except JobError as e: logger.warning( "FAILURE: the {}-th chunk of circuits, can not get job id, " "Resubmit the qobj to get job id. " "Terra job error: {} ".format(i, e)) except Exception as e: logger.warning( "FAILURE: the {}-th chunk of circuits, can not get job id, " "Resubmit the qobj to get job id. " "Error: {} ".format(i, e)) job_ids.append(job_id) jobs.append(job) qobjs.append(qobj) if logger.isEnabledFor(logging.DEBUG) and show_circuit_summary: logger.debug("==== Before transpiler ====") logger.debug(summarize_circuits(circuits)) logger.debug("==== After transpiler ====") logger.debug(summarize_circuits(transpiled_circuits)) results = [] if with_autorecover: logger.info("Backend status: {}".format(backend.status())) logger.info( "There are {} circuits and they are chunked into {} chunks, " "each with {} circutis (max.).".format(len(circuits), chunks, max_circuits_per_job)) logger.info("All job ids:\n{}".format(job_ids)) for idx in range(len(jobs)): while True: job = jobs[idx] job_id = job_ids[idx] logger.info("Running {}-th chunk circuits, job id: {}".format( idx, job_id)) # try to get result if possible try: result = job.result(**qjob_config) if result.success: results.append(result) logger.info("COMPLETED the {}-th chunk of circuits, " "job id: {}".format(idx, job_id)) break else: logger.warning("FAILURE: the {}-th chunk of circuits, " "job id: {}".format(idx, job_id)) except JobError as e: # if terra raise any error, which means something wrong, re-run it logger.warning( "FAILURE: the {}-th chunk of circuits, job id: {} " "Terra job error: {} ".format(idx, job_id, e)) except Exception as e: raise AquaError( "FAILURE: the {}-th chunk of circuits, job id: {} " "Unknown error: {} ".format(idx, job_id, e)) from e # something wrong here, querying the status to check how to handle it. # keep qeurying it until getting the status. while True: try: job_status = job.status() break except JobError as e: logger.warning("FAILURE: job id: {}, " "status: 'FAIL_TO_GET_STATUS' " "Terra job error: {}".format(job_id, e)) time.sleep(5) except Exception as e: raise AquaError("FAILURE: job id: {}, " "status: 'FAIL_TO_GET_STATUS' " "Unknown error: ({})".format( job_id, e)) from e logger.info("Job status: {}".format(job_status)) # handle the failure job based on job status if job_status == JobStatus.DONE: logger.info( "Job ({}) is completed anyway, retrieve result " "from backend.".format(job_id)) job = backend.retrieve_job(job_id) elif job_status == JobStatus.RUNNING or job_status == JobStatus.QUEUED: logger.info("Job ({}) is {}, but encounter an exception, " "recover it from backend.".format( job_id, job_status)) job = backend.retrieve_job(job_id) else: logger.info( "Fail to run Job ({}), resubmit it.".format(job_id)) qobj = qobjs[idx] # assure job get its id while True: job = run_on_backend( backend, qobj, backend_options=backend_options, noise_config=noise_config, skip_qobj_validation=skip_qobj_validation) try: job_id = job.job_id() break except JobError as e: logger.warning( "FAILURE: the {}-th chunk of circuits, " "can not get job id. Resubmit the qobj to get job id. " "Terra job error: {} ".format(idx, e)) except Exception as e: logger.warning( "FAILURE: the {}-th chunk of circuits, " "can not get job id, Resubmit the qobj to get job id. " "Unknown error: {} ".format(idx, e)) jobs[idx] = job job_ids[idx] = job_id else: results = [] for job in jobs: results.append(job.result(**qjob_config)) result = _combine_result_objects(results) if len(results) != 0 else None return result
def _run(self) -> 'VQEResult': """Run the algorithm to compute the minimum eigenvalue. Returns: The result of the VQE algorithm as ``VQEResult``. Raises: AquaError: Wrong setting of operator and backend. """ if self.operator is None: raise AquaError("The operator was never provided.") self._operator = self.operator self._aux_operators = self.aux_operators if self._auto_conversion: self._operator = \ self._config_the_best_mode(self._operator, self._quantum_instance.backend) for i in range(len(self._aux_operators)): if self._aux_operators[i] is None: continue if not self._aux_operators[i].is_empty(): self._aux_operators[i] = \ self._config_the_best_mode(self._aux_operators[i], self._quantum_instance.backend) # sanity check if isinstance( self._operator, MatrixOperator) and not self._quantum_instance.is_statevector: raise AquaError("Non-statevector simulator can not work " "with `MatrixOperator`, either turn ON " "auto_conversion or use the proper " "combination between operator and backend.") self._use_simulator_snapshot_mode = ( is_aer_provider(self._quantum_instance.backend) and self._quantum_instance.run_config.shots == 1 and not self._quantum_instance.noise_config and isinstance( self._operator, (WeightedPauliOperator, TPBGroupedWeightedPauliOperator))) self._quantum_instance.circuit_summary = True self._eval_count = 0 vqresult = self.find_minimum(initial_point=self.initial_point, var_form=self.var_form, cost_fn=self._energy_evaluation, optimizer=self.optimizer) # TODO remove all former dictionary logic self._ret = {} self._ret['num_optimizer_evals'] = vqresult.optimizer_evals self._ret['min_val'] = vqresult.optimal_value self._ret['opt_params'] = vqresult.optimal_point self._ret['eval_time'] = vqresult.optimizer_time if self._ret['num_optimizer_evals'] is not None and \ self._eval_count >= self._ret['num_optimizer_evals']: self._eval_count = self._ret['num_optimizer_evals'] self._eval_time = self._ret['eval_time'] logger.info( 'Optimization complete in %s seconds.\nFound opt_params %s in %s evals', self._eval_time, self._ret['opt_params'], self._eval_count) self._ret['eval_count'] = self._eval_count self._ret['energy'] = self.get_optimal_cost() self._ret['eigvals'] = np.asarray([self._ret['energy']]) self._ret['eigvecs'] = np.asarray([self.get_optimal_vector()]) self._eval_aux_ops() result = VQEResult() result.combine(vqresult) result.eigenvalue = vqresult.optimal_value + 0j result.eigenstate = self.get_optimal_vector() if 'aux_ops' in self._ret: result.aux_operator_eigenvalues = self._ret['aux_ops'][0] result.cost_function_evals = self._eval_count self.cleanup_parameterized_circuits() return result
def compile_circuits(circuits, backend, backend_config=None, compile_config=None, run_config=None, show_circuit_summary=False, circuit_cache=None, **kwargs): """ An execution wrapper with Qiskit-Terra, with job auto recover capability. The autorecovery feature is only applied for non-simulator backend. This wrapper will try to get the result no matter how long it costs. Args: circuits (QuantumCircuit or list[QuantumCircuit]): circuits to execute backend (BaseBackend): backend instance backend_config (dict, optional): configuration for backend compile_config (dict, optional): configuration for compilation run_config (RunConfig, optional): configuration for running a circuit show_circuit_summary (bool, optional): showing the summary of submitted circuits. circuit_cache (CircuitCache, optional): A CircuitCache to use when calling compile_and_run_circuits kwargs (optional): special aer instructions to evaluation the expectation of a hamiltonian Returns: QasmObj: compiled qobj. Raises: ValueError: backend type is wrong or not given ValueError: no circuit in the circuits """ backend_config = backend_config or {} compile_config = compile_config or {} run_config = run_config or {} if backend is None or not isinstance(backend, BaseBackend): raise ValueError('Backend is missing or not an instance of BaseBackend') if not isinstance(circuits, list): circuits = [circuits] if not circuits: raise ValueError("The input circuit is empty.") if is_simulator_backend(backend): circuits = _avoid_empty_circuits(circuits) if circuit_cache is not None and circuit_cache.try_reusing_qobjs: # Check if all circuits are the same length. # If not, don't try to use the same qobj.experiment for all of them. if len({len(circ.data) for circ in circuits}) > 1: circuit_cache.try_reusing_qobjs = False else: # Try setting up the reusable qobj # Compile and cache first circuit if cache is empty. # The load method will try to reuse it if circuit_cache.qobjs is None: qobj, _ = _compile_wrapper([circuits[0]], backend, backend_config, compile_config, run_config) if is_aer_provider(backend): qobj = _maybe_add_aer_expectation_instruction(qobj, kwargs) circuit_cache.cache_circuit(qobj, [circuits[0]], 0) transpiled_circuits = None if circuit_cache is not None and circuit_cache.misses < circuit_cache.allowed_misses: try: if circuit_cache.cache_transpiled_circuits: transpiled_circuits = compiler.transpile(circuits, backend, **backend_config, **compile_config) qobj = circuit_cache.load_qobj_from_cache(transpiled_circuits, 0, run_config=run_config) else: qobj = circuit_cache.load_qobj_from_cache(circuits, 0, run_config=run_config) if is_aer_provider(backend): qobj = _maybe_add_aer_expectation_instruction(qobj, kwargs) # cache miss, fail gracefully except (TypeError, IndexError, FileNotFoundError, EOFError, AquaError, AttributeError) as e: circuit_cache.try_reusing_qobjs = False # Reusing Qobj didn't work if circuit_cache.qobjs: logger.info('Circuit cache miss, recompiling. Cache miss reason: %s', repr(e)) circuit_cache.misses += 1 else: logger.info('Circuit cache is empty, compiling from scratch.') circuit_cache.clear_cache() qobj, transpiled_circuits = _compile_wrapper(circuits, backend, backend_config, compile_config, run_config) if is_aer_provider(backend): qobj = _maybe_add_aer_expectation_instruction(qobj, kwargs) try: circuit_cache.cache_circuit(qobj, circuits, 0) except (TypeError, IndexError, AquaError, AttributeError, KeyError): try: circuit_cache.cache_transpiled_circuits = True circuit_cache.cache_circuit(qobj, transpiled_circuits, 0) except (TypeError, IndexError, AquaError, AttributeError, KeyError) as e: logger.info('Circuit could not be cached for reason: %s', repr(e)) logger.info('Transpilation may be too aggressive. Try skipping transpiler.') else: qobj, transpiled_circuits = _compile_wrapper(circuits, backend, backend_config, compile_config, run_config) if is_aer_provider(backend): qobj = _maybe_add_aer_expectation_instruction(qobj, kwargs) if logger.isEnabledFor(logging.DEBUG) and show_circuit_summary: logger.debug("==== Before transpiler ====") logger.debug(summarize_circuits(circuits)) if transpiled_circuits is not None: logger.debug("==== After transpiler ====") logger.debug(summarize_circuits(transpiled_circuits)) return qobj
def __init__(self, backend, shots=1024, seed=None, max_credits=10, basis_gates=None, coupling_map=None, initial_layout=None, pass_manager=None, seed_mapper=None, backend_options=None, noise_model=None, timeout=None, wait=5, circuit_cache=None, skip_qobj_validation=False): """Constructor. Args: backend (BaseBackend): instance of selected backend shots (int, optional): number of repetitions of each circuit, for sampling seed (int, optional): random seed for simulators max_credits (int, optional): maximum credits to use basis_gates (list[str], optional): list of basis gate names supported by the target. Default: ['u1','u2','u3','cx','id'] coupling_map (list[list]): coupling map (perhaps custom) to target in mapping initial_layout (dict, optional): initial layout of qubits in mapping pass_manager (PassManager, optional): pass manager to handle how to compile the circuits seed_mapper (int, optional): the random seed for circuit mapper backend_options (dict, optional): all running options for backend, please refer to the provider. noise_model (qiskit.provider.aer.noise.noise_model.NoiseModel, optional): noise model for simulator timeout (float, optional): seconds to wait for job. If None, wait indefinitely. wait (float, optional): seconds between queries to result circuit_cache (CircuitCache, optional): A CircuitCache to use when calling compile_and_run_circuits skip_qobj_validation (bool, optional): Bypass Qobj validation to decrease submission time """ self._backend = backend # setup run config run_config = RunConfig(shots=shots, max_credits=max_credits) if seed: run_config.seed = seed if getattr(run_config, 'shots', None) is not None: if self.is_statevector and run_config.shots != 1: logger.info( "statevector backend only works with shot=1, change " "shots from {} to 1.".format(run_config.shots)) run_config.shots = 1 self._run_config = run_config # setup backend config basis_gates = basis_gates or backend.configuration().basis_gates coupling_map = coupling_map or getattr(backend.configuration(), 'coupling_map', None) self._backend_config = { 'basis_gates': basis_gates, 'coupling_map': coupling_map } # setup noise config noise_config = None if noise_model is not None: if is_aer_provider(self._backend): if not self.is_statevector: noise_config = noise_model else: logger.info( "The noise model can be only used with Aer qasm simulator. " "Change it to None.") else: logger.info( "The noise model can be only used with Qiskit Aer. " "Please install it.") self._noise_config = {} if noise_config is None else { 'noise_model': noise_config } # setup compile config if initial_layout is not None and not isinstance( initial_layout, Layout): initial_layout = Layout(initial_layout) self._compile_config = { 'pass_manager': pass_manager, 'initial_layout': initial_layout, 'seed_mapper': seed_mapper } # setup job config self._qjob_config = {'timeout': timeout} if self.is_local \ else {'timeout': timeout, 'wait': wait} # setup backend options for run self._backend_options = {} if is_ibmq_provider(self._backend): logger.info( "backend_options can not used with the backends in IBMQ provider." ) else: self._backend_options = {} if backend_options is None \ else {'backend_options': backend_options} self._shared_circuits = False self._circuit_summary = False self._circuit_cache = circuit_cache self._skip_qobj_validation = skip_qobj_validation logger.info(self)
def __init__(self, backend, run_config=None, initial_layout=None, pass_manager=None, seed_mapper=None, backend_options=None, noise_model=None, timeout=None, wait=5, circuit_cache=None, skip_qobj_validation=False): """Constructor. Args: backend (BaseBackend): instance of selected backend run_config (RunConfig): the run config see https://github.com/Qiskit/qiskit-terra/blob/master/qiskit/qobj/run_config.py initial_layout (dict): initial layout of qubits in mapping pass_manager (PassManager): pass manager to handle how to compile the circuits seed_mapper (int): the random seed for circuit mapper backend_options (dict): all config setting for backend noise_model (qiskit.provider.aer.noise.noise_model.NoiseModel): noise model for simulator timeout (float or None): seconds to wait for job. If None, wait indefinitely. wait (float): seconds between queries to result circuit_cache (CircuitCache): A CircuitCache to use when calling compile_and_run_circuits skip_qobj_validation (bool): Bypass Qobj validation to decrease submission time """ self._backend = backend # setup run config if run_config is None: run_config = RunConfig(shots=1024, max_credits=10, memory=False) if getattr(run_config, 'shots', None) is not None: if self.is_statevector and run_config.shots == 1: logger.info("statevector backend only works with shot=1, change " "shots from {} to 1.".format(run_config.shots)) run_config.shots = 1 if getattr(run_config, 'memory', None) is not None: if not self.is_simulator and run_config.memory is True: logger.info("The memory flag only supports simulator rather than real device. " "Change it to from {} to False.".format(run_config.memory)) run_config.memory = False self._run_config = run_config # setup backend config coupling_map = getattr(backend.configuration(), 'coupling_map', None) # TODO: basis gates will be [str] rather than comma-separated str basis_gates = backend.configuration().basis_gates if isinstance(basis_gates, list): basis_gates = ','.join(basis_gates) self._backend_config = { 'basis_gates': basis_gates, 'coupling_map': coupling_map } # setup noise config noise_config = None if noise_model is not None: if is_aer_provider(self._backend): if not self.is_statevector: noise_config = noise_model else: logger.info("The noise model can be only used with Aer qasm simulator. " "Change it to None.") else: logger.info("The noise model can be only used with Qiskit Aer. " "Please install it.") self._noise_config = {} if noise_config is None else {'noise_model': noise_config} # setup compile config self._compile_config = { 'pass_manager': pass_manager, 'initial_layout': initial_layout, 'seed_mapper': seed_mapper, 'qobj_id': None } # setup job config self._qjob_config = {'timeout': timeout} if self.is_local \ else {'timeout': timeout, 'wait': wait} # setup backend options for run self._backend_options = {} if isinstance(self._backend.provider(), IBMQProvider): logger.info("backend_options can not used with the backends in IBMQ provider.") else: self._backend_options = {} if backend_options is None \ else {'backend_options': backend_options} self._shared_circuits = False self._circuit_summary = False self._circuit_cache = circuit_cache self._skip_qobj_validation = skip_qobj_validation logger.info(self)