qml.evolve

evolve(*args, **kwargs)[source]
evolve(op, **kwargs)
evolve(op, coeff=1, num_steps=None)

This method is dispatched and its functionality depends on the type of the input op.

Input: Operator


Returns a new operator that computes the evolution of op.

\[e^{-i x \bm{O}}\]
Parameters
  • op (Operator) – operator to evolve

  • coeff (float) – coefficient multiplying the exponentiated operator

Returns

evolution operator

Return type

Evolution

See also

Evolution

Examples

We can use qml.evolve to compute the evolution of any PennyLane operator:

>>> op = qml.evolve(qml.X(0), coeff=2)
>>> op
Exp(-2j PauliX)

Input: ParametrizedHamiltonian


Parameters

op (ParametrizedHamiltonian) – Hamiltonian to evolve

Returns

time evolution \(U(t_0, t_1)\) of the Hamiltonian

Return type

ParametrizedEvolution

The function takes a ParametrizedHamiltonian and solves the time-dependent Schrodinger equation

\[\frac{\partial}{\partial t} |\psi\rangle = -i H(t) |\psi\rangle\]

It returns a ParametrizedEvolution, \(U(t_0, t_1)\), which is the solution to the time-dependent Schrodinger equation for the ParametrizedHamiltonian, such that

\[|\psi(t_1)\rangle = U(t_0, t_1) |\psi(t_0)\rangle\]

The ParametrizedEvolution class uses a numerical ordinary differential equation solver (here).

Examples

When evolving a ParametrizedHamiltonian, a ParametrizedEvolution instance is returned:

coeffs = [lambda p, t: p * t for _ in range(4)]
ops = [qml.X(i) for i in range(4)]

# ParametrizedHamiltonian
H = qml.dot(coeffs, ops)

# ParametrizedEvolution
ev = qml.evolve(H)
>>> ev
ParametrizedEvolution(wires=[0, 1, 2, 3])

The ParametrizedEvolution is an Operator, but does not have a defined matrix unless it is evaluated at set parameters. This is done by calling the ParametrizedEvolution, which has the call signature (p, t):

>>>  qml.matrix(ev([1., 2., 3., 4.], t=[0, 4]))
Array([[ 0.04930558+0.j        ,  0.        -0.03259093j,
     0.        +0.1052632j ,  0.06957878+0.j        ,
     0.        -0.01482305j, -0.00979751+0.j        ,
     0.03164552+0.j        ,  0.        -0.0209179j ,
     0.        +0.33526757j,  0.22161038+0.j        ,
     ...
     ...
     ...
     0.        -0.03259093j,  0.04930566+0.j        ]],      dtype=complex64)

Additional options regarding how the matrix is calculated can be passed to the ParametrizedEvolution along with the parameters, as keyword arguments. These options are:

  • atol (float, optional): Absolute error tolerance

  • rtol (float, optional): Relative error tolerance

  • mxstep (int, optional): maximum number of steps to take for each time point

  • hmax (float, optional): maximum step size

If not specified, they will default to predetermined values.

The ParametrizedEvolution can be implemented in a QNode:

import jax

dev = qml.device("default.qubit.jax", wires=4)
@jax.jit
@qml.qnode(dev, interface="jax")
def circuit(params):
    qml.evolve(H)(params, t=[0, 10])
    return qml.expval(qml.Z(0))
>>> params = [1., 2., 3., 4.]
>>> circuit(params)
Array(0.8627419, dtype=float32)
>>> jax.grad(circuit)(params)
[Array(50.690746, dtype=float32),
Array(-6.296886e-05, dtype=float32),
Array(-6.3341584e-05, dtype=float32),
Array(-7.052516e-05, dtype=float32)]

Note

In the example above, the decorator @jax.jit is used to compile this execution just-in-time. This means the first execution will typically take a little longer with the benefit that all following executions will be significantly faster, see the jax docs on jitting. JIT-compiling is optional, and one can remove the decorator when only single executions are of interest.

Please check the ParametrizedEvolution class for more usage details.

Contents

Using PennyLane

Development

API

Internals