# -*- coding: utf-8 -*-
""" Backend device of quantum computing """
import datetime
from qlazy.util import read_config_ini
from qlazy.gpu import is_gpu_available, is_gpu_supported_lib, gpu_preparation
from qlazy.QCirc import QCirc
from qlazy.Observable import Observable
BACKEND_DEVICES = {'qlazy': ['qstate_simulator',
'stabilizer_simulator',
'mps_simulator'],
'qulacs': ['cpu_simulator'],
'ibmq': ['aer_simulator',
'aer_simulator_statevector',
'aer_simulator_matrix_product_state'],
'braket_local': ['braket_sv'],
'braket_aws': ['sv1',
'tn1',
'dm1'],
'braket_ionq': ['ionq'],
'braket_rigetti': ['aspen_11',
'aspen_m_1'],
'braket_oqc': ['lucy']}
BACKEND_DEVICES_GPU = {'qlazy': ['qstate_gpu_simulator'],
'qulacs': ['gpu_simulator']}
if is_gpu_available() is True and is_gpu_supported_lib() is True:
gpu_preparation()
USE_GPU = True
else:
USE_GPU = False
[docs]class Backend:
""" Backend device of quantum computing
Attributes
----------
product : str
product name of the backend
('qlazy' or 'qulacs' or 'ibmq')
device : str
device name of the product
config_braket : dict
config for amazon braket backend
{'backet_name': str, 'poll_timeout_seconds': int}
Notes
-----
If you use amazon braket backend (braket_local, braket_aws,
braket_ionq, braket_rigetti, braket_oqc), you must have
config.ini file in your '~/.qlazy/' directory,
and discribe like following example ...
Example
-------
>>> bk = Backend(product='qlazy', device='stabilizer_simulator')
>>> bk = Backend(product='qulacs', device='gpu_simulator')
>>> bk = Backend(product='ibmq', device='least_busy')
>>> bk = Backend(product='braket_rigetti', device='aspen_11') # read ~/.qlazy/config.ini
...
$ cat ~/.qlazy/config.ini
[backend_braket]
backet_name = amazon-braket-xxxx # set your s3 backet name
...
$ cat ~/.qlazy/config.ini
[backend_braket]
backet_name = amazon-braket-xxxx # set your s3 backet name
poll_timeout_seconds = 86400 # set 1-day (default: 5-days)
"""
def __init__(self, product=None, device=None):
#
# set attributes (product, device)
#
if product is None:
self.product = 'qlazy'
if device is None:
self.device = 'qstate_simulator'
else:
self.device = device
elif product in BACKEND_DEVICES.keys():
self.product = product
self.device = device
else:
raise ValueError("product:{} is unknown.".format(product))
self.config_braket = None
#
# set method (__run)
#
# qlazy
if self.product == 'qlazy':
# qstate simulator
if self.device == 'qstate_simulator':
from qlazy.backend.qlazy_qstate_simulator import run_cpu
self.__run = run_cpu
# qstate simulator (GPU)
elif self.device == 'qstate_gpu_simulator':
from qlazy.backend.qlazy_qstate_simulator import run_gpu
if USE_GPU is False:
raise ValueError("Your environment not support GPU.")
self.__run = run_gpu
# stabilizer simulator
elif self.device == 'stabilizer_simulator':
from qlazy.backend.qlazy_stabilizer_simulator import run
self.__run = run
# mps simulator
elif self.device == 'mps_simulator':
from qlazy.backend.qlazy_mps_simulator import run
self.__run = run
else:
raise ValueError("device:'{}' is unknown for product:'{}'."
.format(self.device, self.product))
# qulacs
elif self.product == 'qulacs':
# cpu_simulator
if self.device == 'cpu_simulator':
from qlazy.backend.qulacs_simulator import run_cpu
self.__run = run_cpu
# gpu_simulator
elif self.device == 'gpu_simulator':
from qlazy.backend.qulacs_simulator import run_gpu
if USE_GPU is False:
raise ValueError("Your environment not support GPU.")
self.__run = run_gpu
else:
raise ValueError("device:'{}' is unknown for product:'{}'."
.format(self.device, self.product))
# ibmq
elif self.product == 'ibmq':
from qlazy.backend.ibmq import run
self.__run = run
# braket
elif self.product in ('braket_local', 'braket_aws',
'braket_ionq', 'braket_rigetti', 'braket_oqc'):
from qlazy.backend.amazon_braket import run
if self.product != 'braket_local' and self.config_braket is None:
config_ini = read_config_ini()
backet_name = config_ini['backend_braket'].get('backet_name')
poll_timeout_seconds = config_ini['backend_braket'].get('poll_timeout_seconds')
if poll_timeout_seconds is not None:
poll_timeout_seconds = int(poll_timeout_seconds)
self.config_braket = {'backet_name': backet_name,
'poll_timeout_seconds': poll_timeout_seconds}
self.__run = run
else:
raise ValueError("device:'{}' is unknown for product:'{}'."
.format(self.device, self.product))
[docs] @classmethod
def products(cls):
""" get products list """
return list(BACKEND_DEVICES)
[docs] @classmethod
def qlazy_devices(cls):
""" get qlazy's devices list """
devices = BACKEND_DEVICES['qlazy']
if is_gpu_supported_lib() is True and is_gpu_available() is True:
devices += BACKEND_DEVICES_GPU['qlazy']
return devices
[docs] @classmethod
def qulacs_devices(cls):
""" get qulacs's devices list """
devices = BACKEND_DEVICES['qulacs']
if is_gpu_available() is True:
devices += BACKEND_DEVICES_GPU['qulacs']
return devices
[docs] @classmethod
def ibmq_devices(cls):
""" get ibmq's devices list """
devices = BACKEND_DEVICES['ibmq']
try:
from qiskit import IBMQ
provider = IBMQ.load_account()
ibmq_backend_system_names = [b.name() for b in
provider.backends(simulator=False, operational=True)]
except Exception:
pass
else:
devices += ['least_busy']
devices += ibmq_backend_system_names
return devices
[docs] @classmethod
def devices(cls, product):
""" get devices list for the product """
if product in ('qlazy', 'qulacs', 'braket_local', 'braket_aws',
'braket_ionq', 'braket_rigetti', 'braket_oqc'):
device_list = BACKEND_DEVICES[product]
elif product == 'qlazy':
device_list = Backend.qlazy_devices()
elif product == 'qulacs':
device_list = Backend.qulacs_devices()
elif product == 'ibmq':
device_list = Backend.ibmq_devices()
else:
raise ValueError("unknown product: {}".format(product))
return device_list
def __str__(self):
backend_dict = {'product': self.product, 'device': self.device}
return str(backend_dict)
[docs] def run(self, qcirc=None, shots=1, cid=None, out_state=False, init=None, **kwargs):
"""
run the quantum circuit.
Parameters
----------
qcirc : instance of QCirc
quantum circuit.
shots : int, default 1
number of measurements.
cid : list, default None
classical register id list to count frequency.
out_state : bool, default False
output classical and quantum information after execting circuit.
(only for qlazy's qstate and stabilizer simulator)
init : instance of QState, Stabilizer, MPState
initial quantum state
Returns
-------
result : incetance of Result
measurement result.
Examples
--------
>>> # simple example
>>> from qlazy import QCirc, Backend
>>> bk = Backend(product='qlazy', device='qstate_simulator')
>>> qc = QCirc().h(0).cx(0,1).measure(qid=[0,1], cid=[0,1])
>>> result = bk.run(qcirc=qc, shots=100)
>>> print(result.frequency)
Counter({'00': 51, '11': 49})
>>> ...
>>> # control quantum gate by measured results
>>> from qlazy import QCirc, Backend
>>> bk = Backend(product='qlazy', device='qstate_simulator')
>>> qc = QCirc.h(0)
>>> qc.cx(0,1).measure(qid=[0],cid=[0])
>>> qc.x(0, ctrl=0).x(1, ctrl=0).measure(qid=[0,1], cid=[0,1])
>>> result = bk.run(qcirc=qc, shots=100)
>>> print(result.frequency)
Counter({'00': 100})
"""
if not isinstance(qcirc, QCirc):
raise TypeError("qcirc must be QCirc or ParamtricQCirc.")
if not isinstance(shots, int):
raise TypeError("shots must be int.")
if cid is not None and not isinstance(cid, list):
raise TypeError("cid must be list of int.")
elif cid is not None:
for x in cid:
if not isinstance(x, int):
raise TypeError("cid must be list of int.")
if not isinstance(out_state, bool):
raise TypeError("out_state must be bool.")
start_time = datetime.datetime.now()
result = self.__run(qcirc=qcirc, shots=shots, cid=cid, backend=self,
out_state=out_state, init=init, **kwargs)
end_time = datetime.datetime.now()
result.start_time = start_time
result.end_time = end_time
result.elapsed_time = (end_time - start_time).total_seconds()
return result
def _get_expectation_value_by_calculation(self, qcirc, observable, state='qstate', init=None):
""" estimate expectation value by calcu """
if state == 'qstate' or state == 'mpstate':
result = self.run(qcirc=qcirc, out_state=True, init=init)
else:
raise ValueError("state must be 'qstate' or 'mpstate'.")
if state == 'qstate':
expval = result.qstate.expect(observable=observable)
elif state == 'mpstate':
expval = result.mpstate.expect(observable=observable)
return expval
def _get_expectation_value_by_measurement(self, qcirc, observable, shots, init=None):
""" estimate expectation value by measurements """
expval = 0.+0.j
for wpp in observable.weighted_pp_list:
qid = []
qc_pp = QCirc()
for q, pstr in zip(wpp['pp'].qid, wpp['pp'].pauli_list):
if pstr == 'X':
qid.append(q)
qc_pp.h(q)
elif pstr == 'Y':
qid.append(q)
qc_pp.rx(q, phase=0.5)
elif pstr == 'Z':
qid.append(q)
cid = qid[:]
qc = qcirc + qc_pp
qc.measure(qid=qid, cid=cid)
fac = wpp['weight'] * wpp['pp'].factor # complex (imaginary is zero, maybe)
result = self.run(qcirc=qc, shots=shots, cid=cid, init=init)
freq = result.frequency
n_even = 0
n_odd = 0
for m, f in freq.items():
if sum(list(map(int, list(m)))) % 2 == 0:
n_even += f
else:
n_odd += f
expval += fac * (n_even - n_odd) / (n_even + n_odd)
return expval
[docs] def expect(self, qcirc=None, observable=None, shots=None, precise=False, init=None):
"""
run the quantum circuit.
Parameters
----------
qcirc : instance of QCirc
quantum circuit.
observable : instance of Observable
obserbable considerd.
shots : int, default - None
number of measurements for estimating the expectation value.
precise : bool, default - False
precise calculation (only qlazy and qulacs) or estimation by measurements.
init : instance of QState, MPState
initial quantum state
Returns
-------
expval : complex
expectation value
Examples
--------
>>> # simple example
>>> from qlazy import QCirc, Backend
>>> from qlazy.Observable import X,Y,Z
>>> bk = Backend(product='qlazy', device='qstate_simulator')
>>> ob = Z(0)*X(1)
>>> qc = QCirc().h(0).cx(0,1)
>>> exp = bk.expect(qcirc=qc, shots=10000, observable=ob)
>>> print(exp.real)
>>> 0.0074
"""
if not isinstance(qcirc, QCirc):
raise TypeError("qcirc must be QCirc or ParamtricQCirc.")
if not isinstance(observable, Observable):
raise TypeError("observable must be Observable.")
if not observable.is_hermitian():
raise ValueError("the observable must be a hermitian.")
if qcirc.qubit_num < observable.qubit_num:
raise ValueError("total qubit number of the observable must be less than qcirc's.")
if precise is True:
if self.product == 'qlazy':
if self.device == 'qstate_simulator':
expval = self._get_expectation_value_by_calculation(qcirc, observable, state='qstate', init=init)
elif self.device == 'qstate_gpu_simulator':
expval = self._get_expectation_value_by_calculation(qcirc, observable, state='qstate', init=init)
elif self.device == 'mps_simulator':
expval = self._get_expectation_value_by_calculation(qcirc, observable, state='mpstate', init=init)
else:
raise ValueError("device must be 'qstate_simulator' or 'mps_simulator'.")
elif self.product == 'qulacs':
if init is not None:
raise ValueError("init option is not supported in qulacs backend.")
expval = self._get_expectation_value_by_calculation(qcirc, observable, state='qstate')
else:
raise ValueError("product must be qlazy or qulacs.")
else:
if isinstance(shots, int):
expval = self._get_expectation_value_by_measurement(qcirc, observable, shots, init=init)
else:
raise ValueError("shots must be set as int.")
return expval