# 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

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.