The qsim device

The qsim circuit simulator package provides two additional circuit simulators that can be used with PennyLane-Cirq:

  • qsim, a Schrödinger full state-vector simulator

  • qsimh, a hybrid Schrödinger-Feynman simulator. This simulator cuts the qubit lattice into two parts; each part is individually simulated using qsim, with Feynman-style path summation used to return the final result. Compared to full state-vector simulation, qsimh reduces memory requirements, at the expense of an increased runtime.

For further details see the qsim website.

For a large number of qubits, these simulators are considerably faster than the Cirq simulator:

../_images/qsim_bench.png

In order to use these devices, the qsimcirq package must first be installed:

pip install qsimcirq

You can instantiate the qsim device in PennyLane as follows:

import pennylane as qml

dev = qml.device('cirq.qsim', wires=2)

This device can then be used just like other devices for the evaluation of QNodes within PennyLane. A simple quantum function that returns the expectation value of a measurement and depends on three classical input parameters would look like:

@qml.qnode(dev)
def circuit(x, y, z):
    qml.RZ(z, wires=[0])
    qml.RY(y, wires=[0])
    qml.RX(x, wires=[0])
    qml.CNOT(wires=[0, 1])
    return qml.expval(qml.PauliZ(wires=1))

You can then execute the circuit like any other function to get the quantum mechanical expectation value:

circuit(0.2, 0.1, 0.3)

The qsimh device can be loaded similarly, with the addition of the keyword argument qsimh_options as described below.

Device options

qsim and qsimh use the same method of defining qubits as Cirq, e.g., LineQubit or GridQubit. As with the Cirq device, the qsim and qsimh devices therefore accept an additional argument qubits that can be used to define your own qubits and pass them to the device as a list.

import cirq

qubits = [
  cirq.GridQubit(0, 0),
  cirq.GridQubit(0, 1),
  cirq.GridQubit(1, 0),
  cirq.GridQubit(1, 1),
]

dev = qml.device("cirq.qsim", wires=4, qubits=qubits)

The wire of each qubit corresponds to its index in the qubit list. In the above example, the wire 2 corresponds to cirq.GridQubit(1, 0).

If no qubits are given, the plugin will create an array of LineQubit instances.

qsimh options

qsimh requires specific options to be set for the simulator. These can be passed by the positional argument qsimh_options. See the qsimh usage documentation for further details.

import cirq

qubits = [
  cirq.GridQubit(0, 0),
  cirq.GridQubit(0, 1),
  cirq.GridQubit(1, 0),
  cirq.GridQubit(1, 1),
]

qsimh_options = {
    'k': [0],
    'w': 0,
    'p': 0,
    'r': 2
}

dev = qml.device("cirq.qsimh", wires=4, qsimh_options=qsimh_options, qubits=qubits)

Supported operations

The cirq.qsim and cirq.qsimh devices support most PennyLane operations and observables, with the exceptions of most adjoint operations and QubitUnitary gates on 3 or more qubits.

For state preparation qsim relies on decomposing BasisState into a set of PauliX gates and QubitStateVector via Möttönen state preparation.