Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions examples/ibm.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from projectq import MainEngine


def run_entangle(eng, num_qubits=3):
def run_entangle(eng, num_qubits=5):
"""
Runs an entangling operation on the provided compiler engine.

Expand All @@ -16,7 +16,7 @@ def run_entangle(eng, num_qubits=3):
"""
# allocate the quantum register to entangle
qureg = eng.allocate_qureg(num_qubits)

# entangle the qureg
Entangle | qureg

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

# return the list of measurements
# access the probabilities via the back-end:
results = eng.backend.get_probabilities(qureg)
for state in results:
print("Measured {} with p = {}.".format(state, results[state]))

# return one (random) measurement outcome.
return [int(q) for q in qureg]


if __name__ == "__main__":
# create main compiler engine for the IBM back-end
eng = MainEngine(IBMBackend(use_hardware=True, num_runs=1024, verbose=True))
eng = MainEngine(IBMBackend(use_hardware=True, num_runs=1024, verbose=False))
# run the circuit and print the result
print(run_entangle(eng))
2 changes: 1 addition & 1 deletion projectq/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@
# limitations under the License.

"""Define version number here and read it from setup.py automatically"""
__version__ = "0.1.2"
__version__ = "0.1.3"
129 changes: 95 additions & 34 deletions projectq/backends/_ibm/_ibm.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,15 @@ def __init__(self, use_hardware=False, num_runs=1024, verbose=False,
if use_hardware:
self._device = 'real'
else:
self._device = 'sim_trivial'
self._device = 'sim_trivial_2'
self._num_runs = num_runs
self._verbose = verbose
self._user = user
self._password = password
self._mapping = dict()
self._inverse_mapping = dict()
self._mapped_qubits = 0
self._probabilities = dict()

def is_available(self, cmd):
"""
Expand Down Expand Up @@ -101,6 +105,7 @@ def _reset(self):
for _ in range(self._num_qubits):
self._cmds.append([""] * self._num_cols)
self._positions = [0] * self._num_qubits
self._mapped_qubits = 0

def _store(self, cmd):
"""
Expand All @@ -113,14 +118,32 @@ def _store(self, cmd):
"""
gate = cmd.gate
if gate == Allocate or gate == Deallocate:
pass
elif gate == Measure:
return

if self._mapped_qubits == 0:
self._mapping = dict()
self._inverse_mapping = dict()
self._probabilities = dict()

for qr in cmd.qubits:
for qb in qr:
if not qb.id in self._mapping:
self._mapping[qb.id] = self._mapped_qubits
self._inverse_mapping[self._mapped_qubits] = qb.id
self._mapped_qubits += 1
for qb in cmd.control_qubits:
if not qb.id in self._mapping:
self._mapping[qb.id] = self._mapped_qubits
self._inverse_mapping[self._mapped_qubits] = qb.id
self._mapped_qubits += 1

if gate == Measure:
for qr in cmd.qubits:
for qb in qr:
qb_id = qb.id
meas = _IBMGateCommand("measure", qb_id)
self._cmds[qb_id][self._positions[qb_id]] = meas
self._positions[qb_id] += 1
qb_pos = self._mapping[qb.id]
meas = _IBMGateCommand("measure", qb_pos)
self._cmds[qb_pos][self._positions[qb_pos]] = meas
self._positions[qb_pos] += 1

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

qb_id = cmd.qubits[0][0].id
ibm_cmd = _IBMGateCommand(gate_str, qb_id)
self._cmds[qb_id][self._positions[qb_id]] = ibm_cmd
self._positions[qb_id] += 1
qb_pos = self._mapping[cmd.qubits[0][0].id]
ibm_cmd = _IBMGateCommand(gate_str, qb_pos)
self._cmds[qb_pos][self._positions[qb_pos]] = ibm_cmd
self._positions[qb_pos] += 1
else:
ctrl_id = cmd.control_qubits[0].id
qb_id = cmd.qubits[0][0].id
pos = max(self._positions[qb_id], self._positions[ctrl_id])
self._positions[qb_id] = pos
self._positions[ctrl_id] = pos
ibm_cmd = _IBMGateCommand("cx", qb_id, ctrl_id)
self._cmds[qb_id][self._positions[qb_id]] = ibm_cmd
self._positions[qb_id] += 1
self._positions[ctrl_id] += 1
ctrl_pos = self._mapping[cmd.control_qubits[0].id]
qb_pos = self._mapping[cmd.qubits[0][0].id]
pos = max(self._positions[qb_pos], self._positions[ctrl_pos])
self._positions[qb_pos] = pos
self._positions[ctrl_pos] = pos
ibm_cmd = _IBMGateCommand("cx", qb_pos, ctrl_pos)
self._cmds[qb_pos][self._positions[qb_pos]] = ibm_cmd
self._positions[qb_pos] += 1
self._positions[ctrl_pos] += 1

def get_probabilities(self, qureg):
"""
Return the list of basis states with corresponding probabilities.

The measured bits are ordered according to the supplied quantum register,
i.e., the left-most bit in the state-string corresponds to the first qubit
in the supplied quantum register.

Warning:
Only call this function after the circuit has been executed!

Args:
qureg (list<Qubit>): Quantum register determining the order of the
qubits.

Returns:
probability_dict (dict): Dictionary mapping n-bit strings to
probabilities.

Raises:
Exception: If no data is available (i.e., if the circuit has not been
executed).
"""
if len(self._probabilities) == 0:
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._mapping[qureg[i].id]]
probability_dict["".join(mapped_state)] = self._probabilities[state]

return probability_dict

def _run(self):
"""
Expand All @@ -166,6 +225,7 @@ def _run(self):
gate['position'] = j
try:
gate['name'] = cmd.gate
gate['qasm'] = cmd.gate
if not cmd.ctrl is None:
gate['to'] = cmd.ctrl
cnot_qubit_id = i
Expand Down Expand Up @@ -209,8 +269,10 @@ def _run(self):
for j in range(len(lines[i]['gates'])):
try:
name = lines[i]['gates'][j]['name']
qasm = lines[i]['gates'][j]['qasm']
gates += '{"position":' + str(j)
gates += ',"name":"' + name + '"'
gates += ',"qasm":"' + qasm + '"'
if name == "cx":
gates += ',"to":' + str(lines[i]['gates'][j]['to'])
gates += '},'
Expand All @@ -236,27 +298,26 @@ def _run(self):
p_sum = 0.
measured = ""
for state, probability in zip(data['labels'], data['values']):
if self._verbose and probability > 0:
print(str(state) + " with p = " + str(probability))
state = list(reversed(state))
state[2], state[self._cnot_qubit_id] = state[self._cnot_qubit_id], state[2]
state = "".join(state)
p_sum += probability
star = ""
if p_sum >= P and measured == "":
measured = state

star = "*"
self._probabilities[state] = probability
if self._verbose and probability > 0:
print(str(state) + " with p = " + str(probability) + star)

class QB():
def __init__(self, ID):
self.id = ID

# register measurement result
for i in range(len(data['qubits'])):
ID = int(data['qubits'][i])
if ID == 2:
# we may have swapped these two qubits
# (cnot qubit is always #2 on the device)
# --> undo this transformation
ID = self._cnot_qubit_id
elif ID == self._cnot_qubit_id: # same here.
ID = 2
self.main_engine.set_measurement_result(QB(ID), int(measured[i]))
for ID in self._mapping:
location = self._mapping[ID]
self.main_engine.set_measurement_result(QB(ID), int(measured[location]))
self._reset()
except TypeError:
raise Exception("Failed to run the circuit. Aborting.")
Expand Down
4 changes: 2 additions & 2 deletions projectq/backends/_ibm/_ibm_http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class DeviceOfflineError(Exception):
pass


def send(json_qasm, name, device='sim_trivial', user=None, password=None,
def send(json_qasm, name, device='sim_trivial_2', user=None, password=None,
shots=1, verbose=False):
"""
Sends json QASM through the IBM API and runs the quantum circuit represented
Expand All @@ -36,7 +36,7 @@ def send(json_qasm, name, device='sim_trivial', user=None, password=None,
Args:
json_qasm: JSON QASM representation of the circuit to run.
name (str): Name of the experiment.
device (str): 'sim_trivial' or 'real' to run on simulator or on the real
device (str): 'sim_trivial_2' or 'real' to run on simulator or on the real
chip, respectively.
user (str): IBM quantum experience user.
password (str): IBM quantum experience user password.
Expand Down
12 changes: 7 additions & 5 deletions projectq/backends/_ibm/_ibm_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def no_requests(monkeypatch):
monkeypatch.delattr("requests.sessions.Session.request")


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


Expand All @@ -54,11 +54,9 @@ def test_ibm_backend_is_available_control_not(num_ctrl_qubits, is_available):
eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
qubit1 = eng.allocate_qubit()
qureg = eng.allocate_qureg(num_ctrl_qubits)
print(len(qureg))
ibm_backend = _ibm.IBMBackend()
cmd = Command(eng, NOT , (qubit1,))
cmd.add_control_qubits(qureg)
print(cmd)
assert ibm_backend.is_available(cmd) == is_available


Expand All @@ -71,22 +69,26 @@ def test_ibm_backend_functional_test(monkeypatch):
toffoli2cnotandtgate,
entangle,
qft2crandhadamard)
correct_info = '{"playground":[{"line":0,"name":"q","gates":[{"position":0,"name":"h"},{"position":3,"name":"h"},{"position":4,"name":"measure"}]},{"line":1,"name":"q","gates":[{"position":0,"name":"h"},{"position":2,"name":"h"},{"position":3,"name":"measure"}]},{"line":2,"name":"q","gates":[{"position":1,"name":"cx","to":1},{"position":2,"name":"cx","to":0},{"position":3,"name":"h"},{"position":4,"name":"measure"}]},{"line":3,"name":"q","gates":[]},{"line":4,"name":"q","gates":[]}],"numberColumns":40,"numberLines":5,"numberGates":200,"hasMeasures":true,"topology":"250e969c6b9e68aa2a045ffbceb3ac33"}'
correct_info = '{"playground":[{"line":0,"name":"q","gates":[{"position":0,"name":"h","qasm":"h"},{"position":2,"name":"h","qasm":"h"},{"position":3,"name":"measure","qasm":"measure"}]},{"line":1,"name":"q","gates":[{"position":0,"name":"h","qasm":"h"},{"position":3,"name":"h","qasm":"h"},{"position":4,"name":"measure","qasm":"measure"}]},{"line":2,"name":"q","gates":[{"position":1,"name":"cx","qasm":"cx","to":0},{"position":2,"name":"cx","qasm":"cx","to":1},{"position":3,"name":"h","qasm":"h"},{"position":4,"name":"measure","qasm":"measure"}]},{"line":3,"name":"q","gates":[]},{"line":4,"name":"q","gates":[]}],"numberColumns":40,"numberLines":5,"numberGates":200,"hasMeasures":true,"topology":"250e969c6b9e68aa2a045ffbceb3ac33"}'
# patch send
def mock_send(*args, **kwargs):
assert args[0] == correct_info
return {'data': {'qasm': 'qreg q,5;gate h, [[0.7071067811865476,0.7071067811865476],[0.7071067811865476,-0.7071067811865476]];gate measure, [[1,0],[0,0.7071067811865476+0.7071067811865476i]];gate cx, [[1,0,0,0],[0,1,0,0],[0,0,0,1],[0,0,1,0]];\nh q[0];h q[1];cx q[1], q[2];h q[1];cx q[0], q[2];h q[0];measure q[1];h q[2];measure q[0];measure q[2];', 'p': {'values': [0.4580078125, 0.0068359375, 0.013671875, 0.064453125, 0.048828125, 0.0234375, 0.013671875, 0.37109375], 'qubits': [0, 1, 2], 'labels': ['000', '001', '010', '011', '100', '101', '110', '111']}, 'time': 16.12812304496765, 'serialNumberDevice': 'Real5Qv1'}, 'date': '2016-12-27T01:04:04.395Z'}
return {'date': '2017-01-19T14:28:47.622Z', 'data': {'time': 14.429004907608032, 'serialNumberDevice': 'Real5Qv1', 'p': {'labels': ['00000', '00001', '00010', '00011', '00100', '00101', '00110', '00111'], 'values': [0.4521484375, 0.0419921875, 0.0185546875, 0.0146484375, 0.005859375, 0.0263671875, 0.0537109375, 0.38671875], 'qubits': [0, 1, 2]}, 'qasm': 'IBMQASM 2.0;\n\ninclude "qelib1.inc";\nqreg q[5];\ncreg c[5];\n\nh q[0];\nh q[1];\nCX q[0],q[2];\nh q[0];\nCX q[1],q[2];\nmeasure q[0] -> c[0];\nh q[1];\nh q[2];\nmeasure q[1] -> c[1];\nmeasure q[2] -> c[2];\n'}}
monkeypatch.setattr(_ibm, "send", mock_send)

backend = _ibm.IBMBackend()
engine_list = [TagRemover(), LocalOptimizer(10), AutoReplacer(),
TagRemover(), IBMCNOTMapper(), LocalOptimizer(10)]
eng = MainEngine(backend=backend, engine_list=engine_list)
unused_qubit = eng.allocate_qubit()
qureg = eng.allocate_qureg(3)
# entangle the qureg
Entangle | qureg
# measure; should be all-0 or all-1
Measure | qureg
# run the circuit
eng.flush()
prob_dict = eng.backend.get_probabilities([qureg[0],qureg[2],qureg[1]])
assert prob_dict['111'] == pytest.approx(0.38671875)
assert prob_dict['101'] == pytest.approx(0.0263671875)

4 changes: 3 additions & 1 deletion projectq/cengines/_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class MainEngine(BasicEngine):
main_engine (MainEngine): Self.
active_qubits (WeakSet): WeakSet containing all active qubits
dirty_qubits (Set): Containing all dirty qubit ids
backend (BasicEngine): Access the back-end.

"""
def __init__(self, backend=None, engine_list=None):
Expand Down Expand Up @@ -107,7 +108,8 @@ def __init__(self, backend=None, engine_list=None):
" MainEngine(engine_list=[AutoReplacer()])")

engine_list.append(backend)

self.backend = backend

# Test that user did not supply twice the same engine instance
num_different_engines = len(set([id(item) for item in engine_list]))
if len(engine_list) != num_different_engines:
Expand Down