import torch


def proliferate(x: torch.Tensor, n: int) -> torch.Tensor:
    """
    Makes "copy" (shares underlying data) of every element of tensor x n times.

    Example:
        >>> x
        tensor([[1, 0],
                [0, 1]])

        >>> proliferate(x, 4)
        tensor([[1, 0],
                [1, 0],
                [1, 0],
                [1, 0],
                [0, 1],
                [0, 1],
                [0, 1],
                [0, 1]])

    :param x: Input tensor containing elements that should be used.
    :type x: torch.Tensor
    :param n: How many times you want to "copy" each element.
    :type n: int
    :return: Tensor containing all elements n times.
    :rtype: torch.Tensor
    """
    assert n > 0

    shapeForExpand = list(x.shape)
    shapeForExpand.insert(1, n)

    shapeForReshape = list(x.shape)
    shapeForReshape[0] *= n

    """
    Step by step on example:
        X
        tensor([[1, 0],
                [0, 1]])

        X.unsqueeze(1)
        tensor([[[1, 0]],

                [[0, 1]]])

        X.unsqueeze(1).expand(shapeForExpand)
        tensor([[[1, 0],
                 [1, 0],
                 [1, 0],
                 [1, 0]],

                [[0, 1],
                 [0, 1],
                 [0, 1],
                 [0, 1]]])

        X.unsqueeze(1).expand(shapeForExpand).reshape(shapeForReshape)
        tensor([[1, 0],
                [1, 0],
                [1, 0],
                [1, 0],
                [0, 1],
                [0, 1],
                [0, 1],
                [0, 1]])
    """

    return x.unsqueeze(1).expand(shapeForExpand).reshape(shapeForReshape)