Skip to content
This repository has been archived by the owner on Dec 7, 2021. It is now read-only.

Commit

Permalink
Merge branch 'seed-simulator' of github.com:Cryoris/qiskit-aqua into …
Browse files Browse the repository at this point in the history
…seed-simulator
  • Loading branch information
Cryoris committed Nov 5, 2020
2 parents b70c19c + 61676b7 commit 3ba2a8e
Show file tree
Hide file tree
Showing 15 changed files with 204 additions and 66 deletions.
16 changes: 14 additions & 2 deletions qiskit/aqua/operators/converters/circuit_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from qiskit.providers import Backend
from qiskit.circuit import QuantumCircuit, Parameter, ParameterExpression
from qiskit import QiskitError
from qiskit.aqua import QuantumInstance
from qiskit.aqua import QuantumInstance, AquaError
from qiskit.aqua.utils.backend_utils import is_aer_provider, is_statevector_backend
from qiskit.aqua.operators.operator_base import OperatorBase
from qiskit.aqua.operators.list_ops.list_op import ListOp
Expand Down Expand Up @@ -165,6 +165,8 @@ def convert(self,
Returns:
The converted Operator with CircuitStateFns replaced by DictStateFns or VectorStateFns.
Raises:
AquaError: if extracted circuits are empty.
"""
if self._last_op is None or id(operator) != id(self._last_op):
# Clear caches
Expand All @@ -181,6 +183,11 @@ def convert(self,
if not self._circuit_ops_cache:
self._circuit_ops_cache = {}
self._extract_circuitstatefns(self._reduced_op_cache)
if not self._circuit_ops_cache:
raise AquaError(
'Circuits are empty. '
'Check that the operator is an instance of CircuitStateFn or its ListOp.'
)

if params:
p_0 = list(params.values())[0] # type: ignore
Expand Down Expand Up @@ -243,8 +250,13 @@ def sample_circuits(self,
Returns:
The dictionary mapping ids of the CircuitStateFns to their replacement StateFns.
Raises:
AquaError: if extracted circuits are empty.
"""
if circuit_sfns or not self._transpiled_circ_cache:
if not circuit_sfns and not self._transpiled_circ_cache:
raise AquaError('CircuitStateFn is empty and there is no cache.')

if circuit_sfns:
if self._statevector:
circuits = [op_c.to_circuit(meas=False) for op_c in circuit_sfns]
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ def __init__(self,
Args:
reps: The number of times to repeat the Trotterization circuit.
"""
super().__init__(order=1, reps=1)
super().__init__(order=1, reps=reps)
16 changes: 13 additions & 3 deletions qiskit/aqua/operators/legacy/weighted_pauli_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,19 @@ def to_opflow(self, reverse_endianness=False):
pauli_ops = []
for [w, p] in self.paulis:
pauli = Pauli.from_label(str(p)[::-1]) if reverse_endianness else p
# Adding the imaginary is necessary to handle the imaginary coefficients in UCCSD.
# TODO fix these or add support for them in Terra.
pauli_ops += [PrimitiveOp(pauli, coeff=np.real(w) + np.imag(w))]
# This weighted pauli operator has the coeff stored as a complex type
# irrespective of whether the value has any imaginary part or not.
# For many operators the coeff will be real. Hence below the coeff is made real,
# when creating the PrimitiveOp, since it can be stored then as a float, if its
# value is real, i.e. has no imaginary part. This avoids any potential issues around
# complex - but if there are complex coeffs then maybe that using the opflow
# later will fail if it happens to be used where complex is not supported.
# Now there are imaginary coefficients in UCCSD that would need to be handled
# when this is converted to opflow (evolution of hopping operators) where currently
# Terra does not handle complex.
# TODO fix these or add support for them in Terra
coeff = np.real(w) if np.isreal(w) else w
pauli_ops += [PrimitiveOp(pauli, coeff=coeff)]
return sum(pauli_ops)

@property
Expand Down
2 changes: 1 addition & 1 deletion qiskit/aqua/operators/state_fns/dict_state_fn.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def sample(self,
shots: int = 1024,
massive: bool = False,
reverse_endianness: bool = False) -> dict:
probs = np.array(list(self.primitive.values()))**2
probs = np.square(np.abs(np.array(list(self.primitive.values()))))
unique, counts = np.unique(aqua_globals.random.choice(list(self.primitive.keys()),
size=shots,
p=(probs / sum(probs))),
Expand Down
2 changes: 1 addition & 1 deletion qiskit/aqua/operators/state_fns/operator_state_fn.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class OperatorStateFn(StateFn):

# TODO allow normalization somehow?
def __init__(self,
primitive: Union[OperatorBase] = None,
primitive: OperatorBase = None,
coeff: Union[int, float, complex, ParameterExpression] = 1.0,
is_measurement: bool = False) -> None:
"""
Expand Down
64 changes: 43 additions & 21 deletions qiskit/aqua/quantum_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,18 @@

""" Quantum Instance module """

from typing import Optional, List, Union, Dict, Callable
from typing import Optional, List, Union, Dict, Callable, Tuple
import copy
import logging
import time
import numpy as np

from qiskit.providers import BaseBackend
from qiskit.providers import Backend, BaseBackend
from qiskit.transpiler import CouplingMap, PassManager
from qiskit.transpiler.layout import Layout
from qiskit.assembler.run_config import RunConfig
from qiskit.circuit import QuantumCircuit
from qiskit.result import Result
from qiskit.qobj import Qobj
from qiskit import compiler

Expand Down Expand Up @@ -59,7 +61,7 @@ class QuantumInstance:
"statevector_hpc_gate_opt"] + _BACKEND_OPTIONS_QASM_ONLY

def __init__(self,
backend: BaseBackend,
backend: Union[Backend, BaseBackend],
# run config
shots: int = 1024,
seed_simulator: Optional[int] = None,
Expand Down Expand Up @@ -195,7 +197,7 @@ def __init__(self,
"with the statevector simulation.")
else:
self._meas_error_mitigation_cls = measurement_error_mitigation_cls
self._meas_error_mitigation_fitters: Dict = {}
self._meas_error_mitigation_fitters: Dict[str, Tuple[np.ndarray, float]] = {}
# TODO: support different fitting method in error mitigation?
self._meas_error_mitigation_method = 'least_squares'
self._cals_matrix_refresh_period = cals_matrix_refresh_period
Expand All @@ -220,6 +222,7 @@ def __init__(self,
self._skip_qobj_validation = skip_qobj_validation
self._circuit_summary = False
self._job_callback = job_callback
self._time_taken = 0.
logger.info(self)

def __str__(self) -> str:
Expand Down Expand Up @@ -274,7 +277,7 @@ def assemble(self,

def execute(self,
circuits: Union[QuantumCircuit, List[QuantumCircuit]],
had_transpiled: bool = False) -> Qobj:
had_transpiled: bool = False) -> Result:
"""
A wrapper to interface with quantum backend.
Expand Down Expand Up @@ -305,7 +308,7 @@ def execute(self,
qubit_index_str = '_'.join([str(x) for x in qubit_index]) + \
"_{}".format(self._meas_error_mitigation_shots or self._run_config.shots)
meas_error_mitigation_fitter, timestamp = \
self._meas_error_mitigation_fitters.get(qubit_index_str, (None, 0))
self._meas_error_mitigation_fitters.get(qubit_index_str, (None, 0.))

if meas_error_mitigation_fitter is None:
# check the asked qubit_index are the subset of build matrices
Expand All @@ -318,7 +321,7 @@ def execute(self,
self._run_config.shots == stored_shots:
# the qubit used in current job is the subset and shots are the same
meas_error_mitigation_fitter, timestamp = \
self._meas_error_mitigation_fitters.get(key, (None, 0))
self._meas_error_mitigation_fitters.get(key, (None, 0.))
meas_error_mitigation_fitter = \
meas_error_mitigation_fitter.subset_fitter(
qubit_sublist=qubit_index)
Expand Down Expand Up @@ -350,15 +353,18 @@ def execute(self,
self._backend_options,
self._noise_config,
self._skip_qobj_validation, self._job_callback)
self._time_taken += cals_result.time_taken
result = run_qobj(qobj, self._backend, self._qjob_config,
self._backend_options, self._noise_config,
self._skip_qobj_validation, self._job_callback)
self._time_taken += result.time_taken
else:
# insert the calibration circuit into main qobj if the shots are the same
qobj.experiments[0:0] = cals_qobj.experiments
result = run_qobj(qobj, self._backend, self._qjob_config,
self._backend_options, self._noise_config,
self._skip_qobj_validation, self._job_callback)
self._time_taken += result.time_taken
cals_result = result

logger.info("Building calibration matrix for measurement error mitigation.")
Expand All @@ -373,6 +379,7 @@ def execute(self,
result = run_qobj(qobj, self._backend, self._qjob_config,
self._backend_options, self._noise_config,
self._skip_qobj_validation, self._job_callback)
self._time_taken += result.time_taken

if meas_error_mitigation_fitter is not None:
logger.info("Performing measurement error mitigation.")
Expand All @@ -398,6 +405,7 @@ def execute(self,
result = run_qobj(qobj, self._backend, self._qjob_config,
self._backend_options, self._noise_config,
self._skip_qobj_validation, self._job_callback)
self._time_taken += result.time_taken

if self._circuit_summary:
self._circuit_summary = False
Expand Down Expand Up @@ -439,6 +447,15 @@ def set_config(self, **kwargs):
else:
raise ValueError("unknown setting for the key ({}).".format(k))

@property
def time_taken(self) -> float:
"""Accumulated time taken for execution."""
return self._time_taken

def reset_execution_results(self) -> None:
""" Reset execution results """
self._time_taken = 0.

@property
def qjob_config(self):
"""Getter of qjob_config."""
Expand Down Expand Up @@ -544,14 +561,18 @@ def skip_qobj_validation(self, new_value):
""" sets skip qobj validation flag """
self._skip_qobj_validation = new_value

def maybe_refresh_cals_matrix(self, timestamp=None):
def maybe_refresh_cals_matrix(self,
timestamp: Optional[float] = None) -> bool:
"""
Calculate the time difference from the query of last time.
Args:
timestamp: timestamp
Returns:
bool: whether or not refresh the cals_matrix
Whether or not refresh the cals_matrix
"""
timestamp = timestamp or 0
timestamp = timestamp or 0.
ret = False
curr_timestamp = time.time()
difference = int(curr_timestamp - timestamp) / 60.0
Expand All @@ -560,27 +581,28 @@ def maybe_refresh_cals_matrix(self, timestamp=None):

return ret

def cals_matrix(self, qubit_index=None):
def cals_matrix(self,
qubit_index: Optional[List[int]] = None) -> \
Optional[Union[Tuple[np.ndarray, float], Dict[str, Tuple[np.ndarray, float]]]]:
"""
Get the stored calibration matrices and its timestamp.
Args:
qubit_index (list[int]): the qubit index of corresponding calibration matrix.
If None, return all stored calibration matrices.
qubit_index: the qubit index of corresponding calibration matrix.
If None, return all stored calibration matrices.
Returns:
tuple(np.ndarray, int): the calibration matrix and the creation timestamp if qubit_index
is not None otherwise, return all matrices and their timestamp
in a dictionary.
The calibration matrix and the creation timestamp if qubit_index
is not None otherwise, return all matrices and their timestamp
in a dictionary.
"""
ret = None
shots = self._meas_error_mitigation_shots or self._run_config.shots
if qubit_index:
qubit_index_str = '_'.join([str(x) for x in qubit_index]) + "_{}".format(shots)
fitter, timestamp = self._meas_error_mitigation_fitters.get(qubit_index_str, None)
if fitter is not None:
ret = (fitter.cal_matrix, timestamp)
return fitter.cal_matrix, timestamp
else:
ret = {k: (v.cal_matrix, t) for k, (v, t)
in self._meas_error_mitigation_fitters.items()}
return ret
return {k: (v.cal_matrix, t) for k, (v, t)
in self._meas_error_mitigation_fitters.items()}
return None
Loading

0 comments on commit 3ba2a8e

Please sign in to comment.