# Proper way to create tensor from scalars

Suppose I have a scalar tensor `t` which `requires_grad` and I would like to merge this into a larger tensor, for example:

``````# Tensor created from scalar `t`; pseudo-code.
M = [[ t**2   , sin(t)      ],
[ cos(t) , sqrt(t + 5) ]]
``````

Then the new tensor `M` is used to perform some computations and finally the gradients (w.r.t `t`) are computed by calling `backward` on the result.

Right now I can think of two ways how to create the larger tensor `M` from the scalar `t`:

Here’s a code example to illustrate what I mean:

``````from functools import partial
from torch import cos, sin, sqrt, stack, tensor
import torch

tensor = partial(tensor, dtype=torch.float64)

# Option 1.
M = stack([
stack([ t**2   , sin(t)      ]),
stack([ cos(t) , sqrt(t + 5) ])
])

# Option 2.
M = (
t**2 * tensor([[1, 0], [0, 0]])
+      sin(t) * tensor([[0, 1], [0, 0]])
+      cos(t) * tensor([[0, 0], [1, 0]])
+ sqrt(t + 5) * tensor([[0, 0], [0, 1]])
)

x = tensor([1, 2])
y = M @ x
result = y @ y

result.backward()
``````

Now my questions is, what is the preferred way to accomplish this task? Maybe there exists even a more dedicated method? I am interested in all aspects, including performance of the resulting graph.

2 Likes

You can just pass the values as a list to `torch.tensor`:

``````N = torch.tensor([[t**2, torch.sin(t)],
[torch.cos(t), torch.sqrt(t+5.)]])
``````

Just calling `tensor` on lists doesn’t seem to work (any more)?

``````import torch
from torch import sin, cos, sqrt

M = [[ t**2   , sin(t)      ],
[ cos(t) , sqrt(t + 5) ]]

z = torch.tensor(M)
# (device(type='cpu'), False)
``````

are nested calls to stack the only option for this?

Here’s a quick nested `stack` implementation in case it’s useful to anyone:

``````import torch

def _nd_peek(x):
"""Return the first element, if any, of nested
iterable ``x`` that is a ``torch.Tensor``.
"""
if isinstance(x, torch.Tensor):
return x
elif isinstance(x, (tuple, list)):
for el in x:
res = _nd_peek(el)
if res:
return res

def _nd_stack(x, device):
"""Recursively stack ``x`` into ``torch.Tensor``,
creating any constant elements encountered on ``device``.
"""
if isinstance(x, (tuple, list)):
elif isinstance(x, torch.Tensor):
# torch element
return x
else:
# torch doesn't like you mixing devices
# so create constant elements correctly

def torch_array(x):
"""Convert ``x`` into ``torch.Tensor`` respecting the device
``````torch_array([[0, t], [t, 0]])