qml.device

device(name, wires=1, *args, **kwargs)[source]

Load a Device and return the instance.

This function is used to load a particular quantum device, which can then be used to construct QNodes.

PennyLane comes with support for the following devices:

  • 'default.qubit': a simple state simulator of qubit-based quantum circuit architectures.

  • 'default.gaussian': a simple simulator of Gaussian states and operations on continuous-variable circuit architectures.

  • 'default.qubit.tf': a state simulator of qubit-based quantum circuit architectures written in TensorFlow, which allows automatic differentiation through the simulation.

  • 'default.qubit.autograd': a state simulator of qubit-based quantum circuit architectures which allows automatic differentiation through the simulation via python’s autograd library.

Additional devices are supported through plugins — see the available plugins for more details.

Parameters
  • name (str) – the name of the device to load

  • wires (int) – the number of wires (subsystems) to initialise the device with

Keyword Arguments
  • config (pennylane.Configuration) – a PennyLane configuration object that contains global and/or device specific configurations.

  • custom_decomps (Dict[Union(str, qml.Operator), Callable]) – Custom decompositions to be applied by the device at runtime.

  • decomp_depth (int) – For when custom decompositions are specified, the maximum expansion depth used by the expansion function.

All devices must be loaded by specifying their short-name as listed above, followed by the wires (subsystems) you wish to initialize. The wires argument can be an integer, in which case the wires of the device are addressed by consecutive integers:

dev = qml.device('default.qubit', wires=5)

def circuit():
   qml.Hadamard(wires=1)
   qml.Hadamard(wires=[0])
   qml.CNOT(wires=[3, 4])
   ...

The wires argument can also be a sequence of unique numbers or strings, specifying custom wire labels that the user employs to address the wires:

dev = qml.device('default.qubit', wires=['ancilla', 'q11', 'q12', -1, 1])

def circuit():
   qml.Hadamard(wires='q11')
   qml.Hadamard(wires=['ancilla'])
   qml.CNOT(wires=['q12', -1] )
   ...

Most devices accept a shots argument which specifies how many circuit executions are used to estimate stochastic return values. In particular, qml.sample() measurements will return as many samples as specified in the shots argument. The shots argument can be changed on a per-call basis using the built-in shots keyword argument.

dev = qml.device('default.qubit', wires=1, shots=10)

@qml.qnode(dev)
def circuit(a):
  qml.RX(a, wires=0)
  return qml.sample(qml.PauliZ(wires=0))
>>> circuit(0.8)  # 10 samples are returned
[ 1  1  1 -1 -1  1  1  1  1  1]
>>> circuit(0.8, shots=3))  # default is overwritten for this call
[1 1 1]
>>> circuit(0.8)  # back to default of 10 samples
[ 1  1  1 -1 -1  1  1  1  1  1]

When constructing a device, we may optionally pass a dictionary of custom decompositions to be applied to certain operations upon device execution. This is useful for enabling support of gates on devices where they would normally be unsupported.

For example, suppose we are running on an ion trap device which does not natively implement the CNOT gate, but we would still like to write our circuits in terms of CNOTs. On a ion trap device, CNOT can be implemented using the IsingXX gate. We first define a decomposition function (such functions have the signature decomposition(*params, wires)):

def ion_trap_cnot(wires):
    return [
        qml.RY(np.pi/2, wires=wires[0]),
        qml.IsingXX(np.pi/2, wires=wires),
        qml.RX(-np.pi/2, wires=wires[0]),
        qml.RY(-np.pi/2, wires=wires[0]),
        qml.RY(-np.pi/2, wires=wires[1])
    ]

Next, we create a device, and a QNode for testing. When constructing the QNode, we can set the expansion strategy to "device" to ensure the decomposition is applied and will be viewable when we draw the circuit.

# As the CNOT gate normally has no decomposition, we can use default.qubit
# here for expository purposes.
dev = qml.device(
    'default.qubit', wires=2, custom_decomps={"CNOT" : ion_trap_cnot}
)

@qml.qnode(dev, expansion_strategy="device")
def run_cnot():
    qml.CNOT(wires=[0, 1])
    return qml.expval(qml.PauliX(wires=1))
>>> print(qml.draw(run_cnot)())
 0: ──RY(1.57)──╭IsingXX(1.57)──RX(-1.57)──RY(-1.57)──┤
 1: ────────────╰IsingXX(1.57)──RY(-1.57)─────────────┤ ⟨X⟩

Some devices may accept additional arguments. For instance, default.gaussian accepts the keyword argument hbar, to set the convention used in the commutation relation \([\x,\p]=i\hbar\) (by default set to 2).

Please refer to the documentation for the individual devices to see any additional arguments that might be required or supported.