code: def generate_synthetic_data(
      tensor_size: int,
      n_data: int,
      limit_rank: int,
      prob_distr: Callable = torch.randn,
      random_seed: int = None,
  ):
      """Generates synthetic demonstrations.
  
      Args:
          tensor_size (int): Size of the tensor.
          n_data (int): Number of demonstrations.
          limit_rank (int): Limit rank of each tensor.
          prob_distr (Callable, optional): Distribution of the entries of the
          tensor.
          random_seed (int, optional): Random seed for reproducibility.
      """
      if random_seed is not None:
          torch.random.manual_seed(random_seed)
      for _ in range(n_data):
          # rank = torch.randint(low=1, high=limit_rank + 1, size=(1,)).item()
          rank = limit_rank
          output_tensor = torch.zeros(
              tensor_size, tensor_size, tensor_size
          )
          list_of_triplets = []
          for i in range(rank):
              valid_triplet = False
              while not valid_triplet:
                  u = prob_distr(tensor_size)
                  v = prob_distr(tensor_size)
                  w = prob_distr(tensor_size)
                  generated_tensor = (
                      u.reshape(-1, 1, 1)
                      * v.reshape(1, -1, 1)
                      * w.reshape(1, 1, -1)
                  )
                  if not (generated_tensor == 0).all():
                      valid_triplet = True
                      list_of_triplets.append((u, v, w))
                      output_tensor += generated_tensor
          yield output_tensor, list_of_triplets
  
imports: from typing import Callable
  import torch
label_desc: Use image node_id 1 for calling a global function with example usage: generate_synthetic_data(tensor_size, n_data, limit_rank, prob_distr, random_seed) without return types