code: def train_test_split_no_unseen(
      X,
      test_size=100,
      seed=0,
      allow_duplication=False,
      filtered_test_predicates=None,
  ):
      """Split into train and test sets.
  
      This function carves out a test set that contains only entities
      and relations which also occur in the training set.
  
      This is an improved version which is much faster - since this does not sample like in the earlier approach but
      rather shuffles indices and gets the test set of required size by selecting from the shuffled indices only triples
      which do not disconnect entities/relations.
  
      Parameters
      ----------
      X : ndarray, shape (n, 3)
          The dataset to split.
      test_size : int, float
          If `int`, the number of triples in the test set.
          If `float`, the percentage of total triples.
      seed : int
          A random seed used to split the dataset.
      allow_duplication: bool
          Flag to indicate if the test set can contain duplicated triples.
      filtered_test_predicates: None, list
          If `None`, all predicate types will be considered for the test set.
          If `list`, only the predicate types in the list will be considered for
          the test set.
  
      Returns
      -------
      X_train : ndarray, shape (n, 3)
          The training set.
      X_test : ndarray, shape (n, 3)
          The test set.
  
      Example
      -------
      >>> import numpy as np
      >>> from ampligraph.evaluation import train_test_split_no_unseen
      >>> # load your dataset to X
      >>> X = np.array([['a', 'y', 'b'],
      >>>               ['f', 'y', 'e'],
      >>>               ['b', 'y', 'a'],
      >>>               ['a', 'y', 'c'],
      >>>               ['c', 'y', 'a'],
      >>>               ['a', 'y', 'd'],
      >>>               ['c', 'y', 'd'],
      >>>               ['b', 'y', 'c'],
      >>>               ['f', 'y', 'e']])
      >>> # if you want to split into train/test datasets
      >>> X_train, X_test = train_test_split_no_unseen(X, test_size=2)
      >>> X_train
      array([['a', 'y', 'd'],
         ['b', 'y', 'a'],
         ['a', 'y', 'c'],
         ['f', 'y', 'e'],
         ['a', 'y', 'b'],
         ['c', 'y', 'a'],
         ['b', 'y', 'c']], dtype='<U1')
      >>> X_test
      array([['f', 'y', 'e'],
         ['c', 'y', 'd']], dtype='<U1')
      >>> # if you want to split into train/valid/test datasets, call it 2 times
      >>> X_train_valid, X_test = train_test_split_no_unseen(X, test_size=2, backward_compatible=True)
      >>> X_train, X_valid = train_test_split_no_unseen(X_train_valid, test_size=2, backward_compatible=True)
      >>> X_train
      array([['a', 'y', 'b'],
         ['a', 'y', 'd'],
         ['a', 'y', 'c'],
         ['c', 'y', 'a'],
         ['f', 'y', 'e']], dtype='<U1')
      >>> X_valid
      array([['c', 'y', 'd'],
         ['f', 'y', 'e']], dtype='<U1')
      >>> X_test
      array([['b', 'y', 'c'],
         ['b', 'y', 'a']], dtype='<U1')
      """
  
      np.random.seed(seed)
      if filtered_test_predicates:
          candidate_idx = np.isin(X[:, 1], filtered_test_predicates)
          X_test_candidates = X[candidate_idx]
          X_train = X[~candidate_idx]
      else:
          X_train = None
          X_test_candidates = X
  
      if isinstance(test_size, float):
          test_size = int(len(X_test_candidates) * test_size)
  
      entities, entity_cnt = np.unique(
          np.concatenate(
              [X_test_candidates[:, 0], X_test_candidates[:, 2]]
          ),
          return_counts=True,
      )
      rels, rels_cnt = np.unique(
          X_test_candidates[:, 1], return_counts=True
      )
      dict_entities = dict(zip(entities, entity_cnt))
      dict_rels = dict(zip(rels, rels_cnt))
      idx_test = []
      idx_train = []
  
      all_indices_shuffled = np.random.permutation(
          np.arange(X_test_candidates.shape[0])
      )
  
      for i, idx in enumerate(all_indices_shuffled):
          test_triple = X_test_candidates[idx]
          # reduce the entity and rel count
          dict_entities[test_triple[0]] = (
              dict_entities[test_triple[0]] - 1
          )
          dict_rels[test_triple[1]] = dict_rels[test_triple[1]] - 1
          dict_entities[test_triple[2]] = (
              dict_entities[test_triple[2]] - 1
          )
  
          # test if the counts are > 0
          if (
              dict_entities[test_triple[0]] > 0
              and dict_rels[test_triple[1]] > 0
              and dict_entities[test_triple[2]] > 0
          ):
              # Can safetly add the triple to test set
              idx_test.append(idx)
              if len(idx_test) == test_size:
                  # Since we found the requested test set of given size
                  # add all the remaining indices of candidates to training set
                  idx_train.extend(list(all_indices_shuffled[i + 1 :]))
  
                  # break out of the loop
                  break
  
          else:
              # since removing this triple results in unseen entities, add it to
              # training
              dict_entities[test_triple[0]] = (
                  dict_entities[test_triple[0]] + 1
              )
              dict_rels[test_triple[1]] = dict_rels[test_triple[1]] + 1
              dict_entities[test_triple[2]] = (
                  dict_entities[test_triple[2]] + 1
              )
              idx_train.append(idx)
  
      if len(idx_test) != test_size:
          # if we cannot get the test set of required size that means we cannot get unique triples
          # in the test set without creating unseen entities
          if allow_duplication:
              # if duplication is allowed, randomly choose from the existing test
              # set and create duplicates
              duplicate_idx = np.random.choice(
                  idx_test, size=(test_size - len(idx_test))
              ).tolist()
              idx_test.extend(list(duplicate_idx))
          else:
              # throw an exception since we cannot get unique triples in the test set without creating
              # unseen entities
              raise Exception(
                  "Cannot create a test split of the desired size. "
                  "Some entities will not occur in both training and test set. "
                  "Set allow_duplication=True,"
                  "remove filter on test predicates or "
                  "set test_size to a smaller value."
              )
  
      if X_train is None:
          X_train = X_test_candidates[idx_train]
      else:
          X_train_subset = X_test_candidates[idx_train]
          X_train = np.concatenate([X_train, X_train_subset])
      X_test = X_test_candidates[idx_test]
  
      X_train = np.random.permutation(X_train)
      X_test = np.random.permutation(X_test)
  
      return X_train, X_test
  
imports: import logging
  from collections.abc import Iterable
  from itertools import islice, product
  import numpy
  import pandas
  from tqdm import tqdm
  from ..evaluation import hits_at_n_score, mr_score, mrr_score
label_desc: Use image node_id 1 for calling a global function with example usage: train_test_split_no_unseen(X, test_size, seed, allow_duplication, filtered_test_predicates) and returns: X_train,  X_test