Skip to content

Commit

Permalink
minor fixes with results, mapper and testing files. Improvement of
Browse files Browse the repository at this point in the history
get_probabilities
  • Loading branch information
Ytterbot committed Jan 16, 2020
1 parent 197e93c commit 03daf79
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 96 deletions.
40 changes: 16 additions & 24 deletions projectq/backends/_ibm/_ibm.py
Expand Up @@ -136,7 +136,6 @@ def _store(self, cmd):
self._allocated_qubits = set()

gate = cmd.gate

if gate == Allocate:
self._allocated_qubits.add(cmd.qubits[0][0].id)
return
Expand Down Expand Up @@ -187,15 +186,8 @@ def _store(self, cmd):
self.qasm += "\nu2(0,pi/2) q[{}];".format(qb_pos)
self._json.append({'qubits': [qb_pos], 'name': 'u2','params': [0, 3.141592653589793]})
else:
assert get_control_count(cmd) == 0
if str(gate) in self._gate_names:
gate_str = self._gate_names[str(gate)]
else:
gate_str = str(gate).lower()

qb_pos = cmd.qubits[0][0].id
self.qasm += "\n{} q[{}];".format(gate_str, qb_pos)
self._json.append({'qubits': [qb_pos], 'name': gate_str})
raise Exception('Command not authorized. You should run the circuit with the appropriate ibm setup.'
'Forbidden command: '+str(cmd))

def _logical_to_physical(self, qb_id):
"""
Expand All @@ -217,6 +209,8 @@ def _logical_to_physical(self, qb_id):
def get_probabilities(self, qureg):
"""
Return the list of basis states with corresponding probabilities.
If input qureg is a subset of the register used for the experiment,
then returns the projected probabilities over the other states.
The measured bits are ordered according to the supplied quantum
register, i.e., the left-most bit in the state-string corresponds to
Expand All @@ -242,13 +236,16 @@ def get_probabilities(self, qureg):
raise RuntimeError("Please, run the circuit first!")

probability_dict = dict()

for state in self._probabilities:
mapped_state = ['0'] * len(qureg)
for i in range(len(qureg)):
mapped_state[i] = state[self._logical_to_physical(qureg[i].id)]
probability = self._probabilities[state]
probability_dict["".join(mapped_state)] = probability
mapped_state = "".join(mapped_state)
if mapped_state not in probability_dict:
probability_dict[mapped_state] = probability
else:
probability_dict[mapped_state] += probability

return probability_dict

Expand All @@ -269,13 +266,13 @@ def _run(self):
if self.qasm == "":
return

max_qubit_id = max(self._allocated_qubits)
max_qubit_id = max(self._allocated_qubits) + 1
qasm = ("\ninclude \"qelib1.inc\";\nqreg q[{nq}];\ncreg c[{nq}];" +
self.qasm).format(nq=max_qubit_id + 1)
self.qasm).format(nq=max_qubit_id)
info = {}
info['qasms'] = [{'qasm': qasm}]
info['json']=self._json
info['nq']=max_qubit_id + 1
info['nq']=max_qubit_id

info['shots'] = self._num_runs
info['maxCredits'] = 10
Expand All @@ -295,7 +292,6 @@ def _run(self):
num_retries=self._num_retries,
interval=self._interval,
verbose=self._verbose)

counts = res['data']['counts']
# Determine random outcome
P = random.random()
Expand All @@ -304,9 +300,10 @@ def _run(self):
length=len(self._measured_ids)
for state in counts:
probability = counts[state] * 1. / self._num_runs
state=state.split('x')[1]
state="{0:b}".format(int(state))
state=state.zfill(length)
state="{0:b}".format(int(state,0))
state=state.zfill(max_qubit_id)
#states in ibmq are right-ordered, so need to reverse state string
state=state[::-1]
p_sum += probability
star = ""
if p_sum >= P and measured == "":
Expand Down Expand Up @@ -345,8 +342,3 @@ def receive(self, command_list):
self._run()
self._reset()

"""
Mapping of gate names from our gate objects to the IBM QASM representation.
"""
_gate_names = {str(Tdag): "tdg",
str(Sdag): "sdg"}
64 changes: 52 additions & 12 deletions projectq/backends/_ibm/_ibm_http_client.py
Expand Up @@ -13,7 +13,9 @@
# limitations under the License.

# helpers to run the jsonified gate sequence on ibm quantum experience server
# api documentation is at https://qcwi-staging.mybluemix.net/explorer/
# api documentation does not exist and has to be deduced from the qiskit code source
# at: https://github.com/Qiskit/qiskit-ibmq-provider

import requests
import getpass
import json
Expand All @@ -25,6 +27,7 @@

_auth_api_url = 'https://auth.quantum-computing.ibm.com/api/users/loginWithToken'
_api_url = 'https://api.quantum-computing.ibm.com/api/'

CLIENT_APPLICATION = 'ibmqprovider/0.4.4'#TODO: call to get the API version automatically


Expand All @@ -35,10 +38,19 @@ def __init__(self):
self.timeout=5.0

def get_list_devices(self,verbose=False):
"""
Get the list of available IBM backends with their properties
Args:
verbose (bool): print the returned dictionnary if True
Returns:
(dict) backends dictionary by name device, containing the qubit size 'nq',
the coupling map 'coupling_map' as well as the device
version 'version'
"""
list_device_url='Network/ibm-q/Groups/open/Projects/main/devices/v/1'
argument={'allow_redirects': True, 'timeout': (self.timeout, None)}
r = super().request('GET', urljoin(_api_url, list_device_url), **argument)

r.raise_for_status()
r_json=r.json()
self.backends=dict()
Expand All @@ -50,6 +62,14 @@ def get_list_devices(self,verbose=False):
return self.backends

def is_online(self,device):
"""
check if the device is in the list of available IBM backends
Args:
device (str): name of the device to check
Returns:
(bool) True if device is available, False otherwise
"""
return device in self.backends

def can_run_experiment(self,info,device):
Expand All @@ -59,17 +79,21 @@ def can_run_experiment(self,info,device):
Args:
info (dict): dictionary sent by the backend containing the code to run
device (str): name of the ibm device to use
:return:
(bool): True if device is big enough, False otherwise
Returns:
(tuple): (bool) True if device is big enough, False otherwise
(int) maximum number of qubit available on the device
(int) number of qubit needed for the circuit
"""
nb_qubit_max=self.backends[device]['nq']
nb_qubit_needed=info['nq']
return nb_qubit_needed<=nb_qubit_max,nb_qubit_max,nb_qubit_needed

def _authenticate(self,token=None):
"""
:param token:
:return:
Args:
token (str): IBM quantum experience user API token.
Returns:
"""
if token is None:
token = getpass.getpass(prompt='IBM Q token > ')
Expand Down Expand Up @@ -98,8 +122,24 @@ def _run(self,info, device):
c_label.append(['c',i])
for i in range(mq):
q_label.append(['q',i])
experiment=[{'header': {'qreg_sizes': [['q', mq]], 'n_qubits': mq, 'memory_slots': nq, 'creg_sizes': [['c', nq]], 'clbit_labels': c_label, 'qubit_labels': q_label, 'name': 'circuit0'}, 'config': {'n_qubits': mq, 'memory_slots': nq}, 'instructions':instructions}]
argument={'data': None, 'json': {'qObject': {'type': 'QASM', 'schema_version': '1.1.0', 'config': {'shots': shots, 'max_credits': maxcredit, 'n_qubits': mq, 'memory_slots': nq, 'memory': False, 'parameter_binds': []}, 'experiments': experiment, 'header': {'backend_version': version, 'backend_name': device}, 'qobj_id': 'e72443f5-7752-4e32-9ac8-156f1f3fee18'}, 'backend': {'name': device}, 'shots': shots}, 'timeout': (self.timeout, None)}
experiment=[{'header': {'qreg_sizes': [['q', mq]], 'n_qubits': mq,
'memory_slots': nq, 'creg_sizes': [['c', nq]],
'clbit_labels': c_label, 'qubit_labels': q_label,
'name': 'circuit0'},
'config': {'n_qubits': mq, 'memory_slots': nq},
'instructions':instructions}]
#Note: qobj_id is not necessary in projectQ, so fixed string for now
argument={'data': None,
'json': {'qObject': {'type': 'QASM', 'schema_version': '1.1.0',
'config': {'shots': shots, 'max_credits': maxcredit,
'n_qubits': mq, 'memory_slots': nq,
'memory': False, 'parameter_binds': []},
'experiments': experiment,
'header': {'backend_version': version,
'backend_name': device},
'qobj_id': 'e72443f5-7752-4e32-9ac8-156f1f3fee18'},
'backend': {'name': device}, 'shots': shots},
'timeout': (self.timeout, None)}
r = super().request('POST', urljoin(_api_url, post_job_url), **argument)
r.raise_for_status()
r_json=r.json()
Expand Down Expand Up @@ -160,7 +200,7 @@ def show_devices(token,verbose=False):
Access the list of available devices and their properties (ex: for setup configuration)
Args:
token (str): IBM quantum experience user password.
token (str): IBM quantum experience user API token.
verbose (bool): If True, additional information is printed
Return:
Expand All @@ -177,7 +217,7 @@ def retrieve(device, token, jobid, num_retries=3000,
Args:
device (str): Device on which the code was run / is running.
token (str): IBM quantum experience user password.
token (str): IBM quantum experience user API token.
jobid (str): Id of the job to retrieve
Return:
Expand All @@ -198,7 +238,7 @@ def send(info, device='ibmq_qasm_simulator',token=None,
Args:
info(dict): Contains representation of the circuit to run.
device (str): name of the ibm device. Simulator chosen by default
token (str): IBM quantum experience user password.
token (str): IBM quantum experience user API token.
shots (int): Number of runs of the same circuit to collect statistics.
verbose (bool): If True, additional information is printed, such as
measurement statistics. Otherwise, the backend simply registers
Expand All @@ -213,7 +253,7 @@ def send(info, device='ibmq_qasm_simulator',token=None,

if verbose:
print("- Authenticating...")
print('TOKEN: '+token)
print('user API token: '+token)
ibmq_session._authenticate(token)

# check if the device is online
Expand Down

0 comments on commit 03daf79

Please sign in to comment.