Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3c4ecf7

Browse files
committed
IBMBackend: get_probabilities and facilitate accessing the back-end from the MainEngine. TODO: Fix test.
1 parent fb687a4 commit 3c4ecf7

4 files changed

Lines changed: 104 additions & 39 deletions

File tree

examples/ibm.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from projectq import MainEngine
44

55

6-
def run_entangle(eng, num_qubits=3):
6+
def run_entangle(eng, num_qubits=5):
77
"""
88
Runs an entangling operation on the provided compiler engine.
99
@@ -16,7 +16,7 @@ def run_entangle(eng, num_qubits=3):
1616
"""
1717
# allocate the quantum register to entangle
1818
qureg = eng.allocate_qureg(num_qubits)
19-
19+
2020
# entangle the qureg
2121
Entangle | qureg
2222

@@ -26,12 +26,17 @@ def run_entangle(eng, num_qubits=3):
2626
# run the circuit
2727
eng.flush()
2828

29-
# return the list of measurements
29+
# access the probabilities via the back-end:
30+
results = eng.backend.get_probabilities(qureg)
31+
for state in results:
32+
print("Measured {} with p = {}.".format(state, results[state]))
33+
34+
# return one (random) measurement outcome.
3035
return [int(q) for q in qureg]
3136

3237

3338
if __name__ == "__main__":
3439
# create main compiler engine for the IBM back-end
35-
eng = MainEngine(IBMBackend(use_hardware=True, num_runs=1024, verbose=True))
40+
eng = MainEngine(IBMBackend(use_hardware=True, num_runs=1024, verbose=False))
3641
# run the circuit and print the result
3742
print(run_entangle(eng))

projectq/backends/_ibm/_ibm.py

Lines changed: 91 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ def __init__(self, use_hardware=False, num_runs=1024, verbose=False,
7272
self._verbose = verbose
7373
self._user = user
7474
self._password = password
75+
self._mapping = dict()
76+
self._inverse_mapping = dict()
77+
self._mapped_qubits = 0
78+
self._probabilities = dict()
7579

7680
def is_available(self, cmd):
7781
"""
@@ -101,6 +105,7 @@ def _reset(self):
101105
for _ in range(self._num_qubits):
102106
self._cmds.append([""] * self._num_cols)
103107
self._positions = [0] * self._num_qubits
108+
self._mapped_qubits = 0
104109

105110
def _store(self, cmd):
106111
"""
@@ -113,14 +118,32 @@ def _store(self, cmd):
113118
"""
114119
gate = cmd.gate
115120
if gate == Allocate or gate == Deallocate:
116-
pass
117-
elif gate == Measure:
121+
return
122+
123+
if self._mapped_qubits == 0:
124+
self._mapping = dict()
125+
self._inverse_mapping = dict()
126+
self._probabilities = dict()
127+
128+
for qr in cmd.qubits:
129+
for qb in qr:
130+
if not qb.id in self._mapping:
131+
self._mapping[qb.id] = self._mapped_qubits
132+
self._inverse_mapping[self._mapped_qubits] = qb.id
133+
self._mapped_qubits += 1
134+
for qb in cmd.control_qubits:
135+
if not qb.id in self._mapping:
136+
self._mapping[qb.id] = self._mapped_qubits
137+
self._inverse_mapping[self._mapped_qubits] = qb.id
138+
self._mapped_qubits += 1
139+
140+
if gate == Measure:
118141
for qr in cmd.qubits:
119142
for qb in qr:
120-
qb_id = qb.id
121-
meas = _IBMGateCommand("measure", qb_id)
122-
self._cmds[qb_id][self._positions[qb_id]] = meas
123-
self._positions[qb_id] += 1
143+
qb_pos = self._mapping[qb.id]
144+
meas = _IBMGateCommand("measure", qb_pos)
145+
self._cmds[qb_pos][self._positions[qb_pos]] = meas
146+
self._positions[qb_pos] += 1
124147

125148
elif not (gate == NOT and get_control_count(cmd) == 1):
126149
cls = gate.__class__.__name__
@@ -129,20 +152,56 @@ def _store(self, cmd):
129152
else:
130153
gate_str = str(gate).lower()
131154

132-
qb_id = cmd.qubits[0][0].id
133-
ibm_cmd = _IBMGateCommand(gate_str, qb_id)
134-
self._cmds[qb_id][self._positions[qb_id]] = ibm_cmd
135-
self._positions[qb_id] += 1
155+
qb_pos = self._mapping[cmd.qubits[0][0].id]
156+
ibm_cmd = _IBMGateCommand(gate_str, qb_pos)
157+
self._cmds[qb_pos][self._positions[qb_pos]] = ibm_cmd
158+
self._positions[qb_pos] += 1
136159
else:
137-
ctrl_id = cmd.control_qubits[0].id
138-
qb_id = cmd.qubits[0][0].id
139-
pos = max(self._positions[qb_id], self._positions[ctrl_id])
140-
self._positions[qb_id] = pos
141-
self._positions[ctrl_id] = pos
142-
ibm_cmd = _IBMGateCommand("cx", qb_id, ctrl_id)
143-
self._cmds[qb_id][self._positions[qb_id]] = ibm_cmd
144-
self._positions[qb_id] += 1
145-
self._positions[ctrl_id] += 1
160+
ctrl_pos = self._mapping[cmd.control_qubits[0].id]
161+
qb_pos = self._mapping[cmd.qubits[0][0].id]
162+
pos = max(self._positions[qb_pos], self._positions[ctrl_pos])
163+
self._positions[qb_pos] = pos
164+
self._positions[ctrl_pos] = pos
165+
ibm_cmd = _IBMGateCommand("cx", qb_pos, ctrl_pos)
166+
self._cmds[qb_pos][self._positions[qb_pos]] = ibm_cmd
167+
self._positions[qb_pos] += 1
168+
self._positions[ctrl_pos] += 1
169+
170+
def get_probabilities(self, qureg):
171+
"""
172+
Return the list of basis states with corresponding probabilities.
173+
174+
The measured bits are ordered according to the supplied quantum register,
175+
i.e., the left-most bit in the state-string corresponds to the first qubit
176+
in the supplied quantum register.
177+
178+
Warning:
179+
Only call this function after the circuit has been executed!
180+
181+
Args:
182+
qureg (list<Qubit>): Quantum register determining the order of the
183+
qubits.
184+
185+
Returns:
186+
probability_dict (dict): Dictionary mapping n-bit strings to
187+
probabilities.
188+
189+
Raises:
190+
Exception: If no data is available (i.e., if the circuit has not been
191+
executed).
192+
"""
193+
if len(self._probabilities) == 0:
194+
raise RuntimeError("Please, run the circuit first!")
195+
196+
probability_dict = dict()
197+
198+
for state in self._probabilities:
199+
mapped_state = ['0'] * len(qureg)
200+
for i in range(len(qureg)):
201+
mapped_state[i] = state[self._mapping[qureg[i].id]]
202+
probability_dict["".join(mapped_state)] = self._probabilities[state]
203+
204+
return probability_dict
146205

147206
def _run(self):
148207
"""
@@ -239,27 +298,26 @@ def _run(self):
239298
p_sum = 0.
240299
measured = ""
241300
for state, probability in zip(data['labels'], data['values']):
242-
if self._verbose and probability > 0:
243-
print(str(state) + " with p = " + str(probability))
301+
state = list(reversed(state))
302+
state[2], state[self._cnot_qubit_id] = state[self._cnot_qubit_id], state[2]
303+
state = "".join(state)
244304
p_sum += probability
305+
star = ""
245306
if p_sum >= P and measured == "":
246307
measured = state
247-
308+
star = "*"
309+
self._probabilities[state] = probability
310+
if self._verbose and probability > 0:
311+
print(str(state) + " with p = " + str(probability) + star)
312+
248313
class QB():
249314
def __init__(self, ID):
250315
self.id = ID
251-
316+
252317
# register measurement result
253-
for i in range(len(data['qubits'])):
254-
ID = int(data['qubits'][i])
255-
if ID == 2:
256-
# we may have swapped these two qubits
257-
# (cnot qubit is always #2 on the device)
258-
# --> undo this transformation
259-
ID = self._cnot_qubit_id
260-
elif ID == self._cnot_qubit_id: # same here.
261-
ID = 2
262-
self.main_engine.set_measurement_result(QB(ID), int(measured[-1-i]))
318+
for ID in self._mapping:
319+
location = self._mapping[ID]
320+
self.main_engine.set_measurement_result(QB(ID), int(measured[location]))
263321
self._reset()
264322
except TypeError:
265323
raise Exception("Failed to run the circuit. Aborting.")

projectq/backends/_ibm/_ibm_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def no_requests(monkeypatch):
3232
monkeypatch.delattr("requests.sessions.Session.request")
3333

3434

35-
_api_url = 'https://qcwi-staging.mybluemix.net/api/'
35+
_api_url = 'https://quantumexperience.ng.bluemix.net/api/'
3636
_api_url_status = 'https://quantumexperience.ng.bluemix.net/api/'
3737

3838

projectq/cengines/_main.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class MainEngine(BasicEngine):
4444
main_engine (MainEngine): Self.
4545
active_qubits (WeakSet): WeakSet containing all active qubits
4646
dirty_qubits (Set): Containing all dirty qubit ids
47+
backend (BasicEngine): Access the back-end.
4748
4849
"""
4950
def __init__(self, backend=None, engine_list=None):
@@ -107,7 +108,8 @@ def __init__(self, backend=None, engine_list=None):
107108
" MainEngine(engine_list=[AutoReplacer()])")
108109

109110
engine_list.append(backend)
110-
111+
self.backend = backend
112+
111113
# Test that user did not supply twice the same engine instance
112114
num_different_engines = len(set([id(item) for item in engine_list]))
113115
if len(engine_list) != num_different_engines:

0 commit comments

Comments
 (0)