# Copyright 2018 Heisenberg Quantum Simulations
# -*- coding: utf-8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Provides a projectq engine that translates a projectq circuit to a cirq circuit.
"""
import cirq
version = [int(cirq.__version__[0]), int(cirq.__version__[2])]
if (version[0] == 0 and version[1] <= 3):
from .common_rules_03x import common_gates_ruleset
else:
from .common_rules_040 import common_gates_ruleset
from projectq import ops as pqo
from projectq.cengines import BasicEngine
from projectq.meta import get_control_count
from . import xmon_rules
import cirq
[docs]class CIRQ(BasicEngine):
r"""
A projectq backend designated to translating to cirq.
Args:
qubits (list(:class:`cirq.devices.grid_qubit`)): the qubits
device (:class:`cirq.devices.Device`): a device that provides the qubits.
rules (cirqprojectq._rules_pq_to_cirq.Ruleset_pq_to_cirq): rule set
strategy (:class:`cirq.circuits.InsertStrategy`): Insert strategy in cirq.
"""
def __init__(self, qubits=None, device=None, rules=None,
strategy=cirq.circuits.InsertStrategy.EARLIEST):
BasicEngine.__init__(self)
self.strategy = strategy
#TODO: Make rules an input.
if rules is None:
self._rules = common_gates_ruleset
self._rules.add_rules(xmon_rules.ALL_RULES)
assert not (qubits is None and device is None), "Please specify one of qubits or device!"
self._device = device
self._qubits = qubits or device.qubits
self._reset()
self._new = True
@property
def circuit(self):
r"""
:class:`cirq.Circuit`: the circuit stored in the engine.
"""
return self._circuit
# TODO: use a device?
@property
def device(self):
r"""
:class:`cirq.devices.Device`: A device. Currently not used.
"""
return self._device
@property
def qubits(self):
r"""
list(:class:`cirq.QubitID`): The cirq qubits used in the circuit.
"""
return self._qubits
def _reset(self):
r"""Resets the circuit."""
self._circuit = cirq.circuits.Circuit()
self._operations = []
self._mapping = dict()
self._inverse_mapping = dict()
[docs] def reset(self, keep_map=True):
r"""Resets the engine."""
map_ = self._mapping.copy()
imap_ = self._inverse_mapping.copy()
self._reset()
self._new = True
if keep_map:
self._mapping = map_
self._inverse_mapping = imap_
[docs] def is_available(self, cmd):
"""
Returns true if the command can be translated.
Args:
cmd (Command): Command for which to check availability
"""
if cmd.gate in (pqo.Measure, pqo.Allocate, pqo.Deallocate, pqo.Barrier):
return True
else:
if type(cmd.gate) in self._rules.known_rules:
return True
else:
return False
def _store(self, cmd):
r"""Append operations given in cmd to the :class:`cirq.Circuit`.
Args:
cmd: Projectq command.
"""
if self._new:
self._new = False
self._operations = []
if cmd.gate == pqo.Allocate:
qb_id = cmd.qubits[0][0].id
#TODO placement
# for tag in cmd.tags:
# if isinstance(tag, QubitPlacementTag):
# self._mapping[qb_id] = tag.position
# self._inverse_mapping[tag.position] = qb_id
# break
if qb_id not in self._mapping:
self._mapping[qb_id] = qb_id
# raise Exception("No qubit placement info found in Allocate.\n"
# "Please make sure you are using the CIRQ Mapper")
# TODO check if id in device.qubits
return
elif cmd.gate in (pqo.Allocate, pqo.Deallocate, pqo.Barrier):
return
else:
try:
self._operations.append(self._rules.translate(cmd, self._mapping, self._qubits))
except:
raise TypeError("Gate {} not known".format(cmd.gate.__class__))
def _run(self):
r"""Appends operations to circuit and resets operations."""
self.circuit.append(self._operations,
strategy=cirq.circuits.InsertStrategy.EARLIEST)
self._operations = []
[docs] def receive(self, command_list):
"""
Receives a command list and, for each command, stores it until
completion.
Args:
command_list: List of commands to execute
"""
for cmd in command_list:
if not cmd.gate == pqo.FlushGate():
self._store(cmd)
else:
self._run()
self._new = True