 # Changing wires of an operator

Say I am given an operator (or a tensor of operators) which I might not know, and I want to use them, but on other wires than the ones they are specified on. Can I do this?

A bit of context: I use qml.Hamiltonian objects together with the qml.ExpvalCost. Now I want to “rearrange” the wires to which each of the operators in the Hamiltonian is applies. That is, create a new Hamiltonian object that has the same operators and the same coefficients, but the wires to which each is applied is different.

As an example, say I have the Hamiltonian below :

``````term1 = qml.operation.Tensor(qml.PauliZ(0), qml.PauliX(1), qml.PauliZ(2))
term2 = qml.operation.Tensor(qml.PauliX(0), qml.PauliZ(1), qml.PauliX(2))
H = qml.Hamiltonian([1,1], [term1, term2])
``````

but I don’t want to measure that, but rather [X0 Z1 Z2] + [Z0 X1 X2]. I know I can retrieve the two terms with

``````H.ops
``````

and get the individual operators using

``````H.ops.non_identity_obs
``````

From there however, is there a way to “copy” the operators with the freedom to set the wires?
If I restrict to e.g. Paulis, I could make a list of allowed operators and check each using its name or type, but I would like to keep it more general (and if possible allow for parametrized gates?)

Any tips and pointers are appreciated! Thank you

Hi @scichy,
as far as I am aware, there currently is no UI functionality to do this.
However, it is certainly doable, by manipulating the private `_wires` of each factor in the `Tensor` objects, for each term in the `Hamiltonian`:
Start by defining the wires remapping as a `dict`:

``````wires_map = {0: 1, 1: 0, 2: 2}
``````

Then, iterate over all terms in `H`, and over all observable factors in each term, and apply this remapping via `qml.wires.Wires.map`:

``````new_ops = []
for op in H.ops:
new_obs = []
for ob in op.obs:
ob._wires = ob.wires.map(wires_map)
new_obs.append(ob)
new_ops.append(qml.operation.Tensor(*new_obs))
new_H = qml.Hamiltonian(H.coeffs, new_ops)
``````

This works specifically for `Hamiltonian`, but of course the inner loop could also just be applied to a single `Tensor` object, or the `map` approach without any loop to a single `Observable` like `qml.PauliX(3)`.

To make it a bit more convenient, here is a function that tackles all three cases:

``````def map_wires(H, wires_map):
"""Map the wires of an Observable according to a wires map.

Args:
H (Hamiltonian or Tensor or Observable): Hamiltonian to remap the wires of.
wires_map (dict): Wires map with `(origin, destination)` pairs as key-value pairs.

Returns:
Hamiltonian or Tensor or Observable: A copy of the original Hamiltonian with remapped wires.
"""
if isinstance(H, qml.Hamiltonian):
new_ops = [map_wires(op, wires_map) for op in H.ops]
new_H = qml.Hamiltonian(H.coeffs, new_ops)
elif isinstance(H, qml.operation.Tensor):
new_obs = [map_wires(ob, wires_map) for ob in H.obs]
new_H = qml.operation.Tensor(*new_obs)
elif isinstance(H, qml.operation.Observable):
new_H = copy.copy(H)
new_H._wires = new_H.wires.map(wires_map)

return new_H
``````

Please note that this is untested custom code, so look out for bugs etc.
Also it is not optimized for performance…
It seems to be doing what we want, though ``````wires_map = {i: i+10 for i in range(5)}
Hs = [
qml.PauliX(4),
qml.Hamiltonian(
[1,1],
[
qml.operation.Tensor(qml.PauliZ(0), qml.PauliX(1), qml.PauliZ(2)),
qml.operation.Tensor(qml.PauliX(0), qml.PauliZ(1), qml.PauliX(2)),
],
),
]
``````
``````>>> for H in Hs:
>>>     print(H)
>>>     new_H = map_wires(H, wires_map)
>>>     print(new_H)
PauliX(wires=)
PauliX(wires=)
PauliX(wires=) @ Hadamard(wires=) @ PauliZ(wires=)
PauliX(wires=) @ Hadamard(wires=) @ PauliZ(wires=)
(1) [Z0 X1 Z2]
+ (1) [X0 Z1 X2]
(1) [Z10 X11 Z12]
+ (1) [X10 Z11 X12]
``````

Hope this helps! Let me know if you have any questions.

Side note: `ExpvalCost` is deprecated, you may just use `expval` on a `Hamiltonian` object (see e.g. here)

Hi @dwierichs!

Thanks a lot for that! I had found out about the _wires member, but I was reticent of touching a private member… but if there is no other option I will do, your code surely seems to implement what I was looking for, thank you Having an official way to create a new op with updated wires has been on my mind for a while. Due to other people having the same need, I will see if I can bump it up in priority for development.

3 Likes