Correctness of function _flatten(x) in utils.py in pennylane\utils.py?

Could @Josh or @Nathan somehow show the correctness of the function _flatten(x)?

def _flatten(x):

"""Iterate through an arbitrarily nested structure, flattening it in depth-first order.

See also :func:_unflatten.

Args:

x (array, Iterable, other): each element of the Iterable may itself be an iterable object

Yields:

other: elements of x in depth-first order

"""

if isinstance(x, np.ndarray):

yield from _flatten(x.flat) # should we allow object arrays? or just "yield from x.flat"?

elif isinstance(x, Iterable) and not isinstance(x, (str, bytes)):

for item in x:

yield from _flatten(item)

else:

yield x

Thanks!

When I used it in the pytorch interface, and x = tensor([1]) it works. But when x = tensor(1) it does not work. It fails in this line: for item in x: in the function.

Hi @cubicgate, could you post your PennyLane/PyTorch code that leads to this error? Thanks!

Hi @josh, here it is:

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
import numpy as np

import pennylane as qml
from pennylane.ops import *

dev_fock_1 = qml.device('strawberryfields.fock', wires=4, cutoff_dim=7)

num_vars = 24
params_1 = Variable(torch.tensor([0.01]*num_vars), requires_grad=True).view(num_vars,1)

@qml.qnode(dev_fock_1, interface="torch")
def work( x_1, params = params_1):
    qml.Displacement(x_1[0], 0, wires=0)
    qml.Displacement(x_1[1], 0, wires=1)
    qml.Displacement(x_1[2], 0, wires=2)
    qml.Displacement(x_1[3], 0, wires=3)
    qml.Displacement(params[0][0], params[1][0], wires=0)
    a0 = qml.expval(NumberState(np.array([1, 0, 0, 0]),wires=[0, 1, 2, 3]))
    a1 = qml.expval(NumberState(np.array([0, 0, 0, 1]),wires=[0, 1, 2, 3]))  
    return [a0, a1]


def main():
    vars_1 = Variable(torch.tensor([0.1, 0.1, 0.1, 0.1]), requires_grad=False)
    me = work(vars_1)

if __name__ == '__main__':
    main()

Hi @cubicgate, a couple of comments to get it working.

  1. PennyLane currently only supports measuring each wire only once in the circuit, so you’ll only be able to return one of a0 or a1, but not both.

  2. We also do not yet support default tensor/array arguments for the QNode. You can get around this by setting the default value to None, i.e., params=None, or by making params a positional argument.

Making these two changes, the above script now runs for me:

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
import numpy as np

import pennylane as qml
from pennylane.ops import *

dev_fock_1 = qml.device('strawberryfields.fock', wires=4, cutoff_dim=7)

num_vars = 24
params_1 = Variable(torch.tensor([0.01]*num_vars), requires_grad=True).view(num_vars,1)

@qml.qnode(dev_fock_1, interface="torch")
def work(x, params=None):
    Displacement(x[0], 0, wires=0)
    Displacement(x[1], 0, wires=1)
    Displacement(x[2], 0, wires=2)
    Displacement(x[3], 0, wires=3)
    Displacement(params[0][0], params[1][0], wires=0)
    a0 = qml.expval(NumberState(np.array([1, 0, 0, 0]), wires=[0, 1, 2, 3]))
    return a0

vars_1 = Variable(torch.tensor([0.1, 0.1, 0.1, 0.1]), requires_grad=False)
me = work(vars_1, params=params_1)

Running the above script gives

tensor(0.0116, dtype=torch.float64)

Thanks @josh for your code. I tried it and got this error:
Traceback (most recent call last):
File “test_pennylane_1.py”, line 26, in
me = work(vars_1, params=params_1)
File “C:\Users\wei\AppData\Local\Programs\Python\Python36\lib\site-packages\pennylane\interfaces\torch.py”, line 390, in custom_apply
return _TorchQNode.apply(keyword_values, *args)
File “C:\Users\wei\AppData\Local\Programs\Python\Python36\lib\site-packages\pennylane\interfaces\torch.py”, line 307, in forward
res = qnode(*ctx.args, **ctx.kwargs)
File “C:\Users\wei\AppData\Local\Programs\Python\Python36\lib\site-packages\pennylane\qnode.py”, line 514, in call
return self.evaluate(args, **kwargs) # args as one tuple
File “C:\Users\wei\AppData\Local\Programs\Python\Python36\lib\site-packages\autograd\tracer.py”, line 48, in f_wrapped
return f_raw(*args, **kwargs)
File “C:\Users\wei\AppData\Local\Programs\Python\Python36\lib\site-packages\pennylane\qnode.py”, line 591, in evaluate
ret = self.device.execute(self.queue, self.ev)
File “C:\Users\wei\AppData\Local\Programs\Python\Python36\lib\site-packages\pennylane_device.py”, line 208, in execute
self.apply(operation.name, operation.wires, operation.parameters)
File “C:\Users\wei\AppData\Local\Programs\Python\Python36\lib\site-packages\pennylane\operation.py”, line 389, in parameters
return _unflatten(temp_val, self.params)[0]
File “C:\Users\wei\AppData\Local\Programs\Python\Python36\lib\site-packages\pennylane\utils.py”, line 89, in _unflatten
val, flat = _unflatten(flat, x)
File “C:\Users\wei\AppData\Local\Programs\Python\Python36\lib\site-packages\pennylane\utils.py”, line 93, in _unflatten
raise TypeError(‘Unsupported type in the model: {}’.format(type(model)))
TypeError: Unsupported type in the model: <class ‘pennylane.variable.Variable’>

Hi @josh, Could I do this?
a0 = qml.expval(NumberState(np.array([1, 0]), wires=[0, 1]))
a1= qml.expval(NumberState(np.array([1, 0]), wires=[2, 3]))

Hi @josh, Could I do this?
a0 = qml.expval(NumberState(np.array([1, 0]), wires=[0, 1]))
a1= qml.expval(NumberState(np.array([1, 0]), wires=[2, 3]))

Yes, that would be fine!

Unfortunately I can’t reproduce the error message you have - could you run qml.about() and paste the output here?

Hi @josh, here it is:

Name: PennyLane
Version: 0.4.0
Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc.
Home-page: http://xanadu.ai
Author: None
Author-email: None
License: Apache License 2.0
Location: c:\users\wei\appdata\local\programs\python\python36\lib\site-packages
Requires: autograd, scipy, toml, numpy, appdirs, semantic-version
Required-by:
Python Version: 3.6.1
Platform Info: WindowsAMD64
Installed plugins: [‘default.gaussian’, ‘default.qubit’, ‘strawberryfields.fock’, ‘strawberryfields.gaussian’]
Numpy Version: 1.16.3
Scipy Version: 1.3.1