code: def discover_facts(
      X,
      model,
      top_n=10,
      strategy="random_uniform",
      max_candidates=100,
      target_rel=None,
      seed=0,
  ):
      """
      Discover new facts from an existing knowledge graph.
  
      You should use this function when you already have a model trained on a knowledge graph
      and you want to discover potentially true statements in that knowledge graph.
  
      The general procedure of this function is to generate a set of candidate statements
      :math:`C` according to some sampling strategy ``strategy``, then rank them against a set
      of corruptions using the :meth:`ampligraph.latent_features.ScoringBasedEmbeddingModel.evaluate`
      method.
      Candidates that appear in the ``top_n`` ranked statements of this procedure are returned
      as likely true statements.
  
      The majority of the strategies are implemented with the same underlying principle of
      searching for candidate statements:
  
      - from among the less frequent entities (`'entity_frequency'`),
      - less connected entities (`'graph_degree'`, `'cluster_coefficient'`),
      - | less frequent local graph structures (`'cluster_triangles'`, `'cluster_squares'`),
          on the assumption that densely connected entities are less likely to have missing
          true statements.
      - | The remaining strategies (`'random_uniform'`, `'exhaustive'`) generate candidate
          statements by a random sampling of entities and relations or exhaustively, respectively.
  
      .. warning::
          Due to the significant amount of computation required to evaluate all triples using
          the 'exhaustive' strategy, we do not recommend its use at this time.
  
      The function will automatically filter entities that have not been seen by the model,
      and operates on the assumption that the model provided has been fit on the data ``X``
      (determined heuristically), although ``X`` may be a subset of the original data, in
      which case a warning is shown.
  
      The ``target_rel`` argument indicates what relation to generate candidate statements for.
      If this is set to ``None`` then all target relations will be considered for sampling.
  
      Parameters
      ----------
  
      X : ndarray of shape (n, 3)
          The input knowledge graph used to train ``model``, or a subset of it.
      model : EmbeddingModel
          The trained model that will be used to score candidate facts.
      top_n : int
          The cutoff position in ranking to consider a candidate triple as true positive.
      strategy: str
          The candidates generation strategy:
  
          - `'random_uniform'` : generates `N` candidates (:math:`N <= max_candidates`) based on
              a uniform sampling of entities.
          - `'entity_frequency'` : generates candidates by weighted sampling of entities using
              entity frequency.
          - `'graph_degree'` : generates candidates by weighted sampling of entities with
              graph degree.
          - `'cluster_coefficient'` : generates candidates by weighted sampling entities
              with clustering coefficient.
          - `'cluster_triangles'` : generates candidates by weighted sampling entities
              with cluster triangles.
          - `'cluster_squares'` : generates candidates by weighted sampling entities
              with cluster squares.
  
      max_candidates: int or float
          The maximum numbers of candidates generated by ``strategy``.
          Can be an absolute number or a percentage [0,1] of the size of the `X` parameter.
      target_rel : str or list(str)
          Target relations to focus on. The function will discover facts only for that specific relation types.
          If `None`, the function attempts to discover new facts for all relation types in the graph.
      seed : int
          Seed to use for reproducible results.
  
  
      Returns
      -------
      X_pred : ndarray, shape (n, 3)
          A list of new facts predicted to be true.
  
      Example
      -------
      >>> import requests
      >>> from ampligraph.latent_features import ScoringBasedEmbeddingModel
      >>> from ampligraph.datasets import load_from_csv
      >>> from ampligraph.discovery import discover_facts
      >>> # Game of Thrones relations dataset
      >>> url = 'https://ampligraph.s3-eu-west-1.amazonaws.com/datasets/GoT.csv'
      >>> open('GoT.csv', 'wb').write(requests.get(url).content)
      >>> dataset = load_from_csv('.', 'GoT.csv', sep=',')
      >>> model = ScoringBasedEmbeddingModel(eta=5,
      >>>                                    k=300,
      >>>                                    scoring_type='ComplEx')
      >>> model.compile(optimizer='adam', loss='multiclass_nll')
      >>> model.fit(dataset,
      >>>           batch_size=100,
      >>>           epochs=10,
      >>>           validation_freq=50,
      >>>           validation_batch_size=100,
      >>>           validation_data = dataset['valid'])
      >>> discover_facts(dataset,
      >>>                model,
      >>>                top_n=100,
      >>>                strategy='random_uniform',
      >>>                max_candidates=100,
      >>>                target_rel='ALLIED_WITH',
      >>>                seed=0)
      Epoch 1/10
      33/33 [==============================] - 1s 27ms/step - loss: 177.7778
      Epoch 2/10
      33/33 [==============================] - 0s 6ms/step - loss: 177.4795
      Epoch 3/10
      33/33 [==============================] - 0s 6ms/step - loss: 176.9654
      Epoch 4/10
      33/33 [==============================] - 0s 6ms/step - loss: 175.8453
      Epoch 5/10
      33/33 [==============================] - 0s 6ms/step - loss: 173.4385
      Epoch 6/10
      33/33 [==============================] - 0s 6ms/step - loss: 168.8143
      Epoch 7/10
      33/33 [==============================] - 0s 6ms/step - loss: 161.2919
      Epoch 8/10
      33/33 [==============================] - 0s 6ms/step - loss: 151.3496
      Epoch 9/10
      33/33 [==============================] - 0s 6ms/step - loss: 140.4268
      Epoch 10/10
      33/33 [==============================] - 0s 5ms/step - loss: 129.8206
      3175 triples containing invalid keys skipped!
      (array([['House Nymeros Martell of Sunspear', 'ALLIED_WITH',
               'House Mallister of Seagard'],
              ['Ben', 'ALLIED_WITH', 'House Mallister of Seagard'],
              ['Selwyn Tarth', 'ALLIED_WITH', 'House Mallister of Seagard'],
              ['Clarence Charlton', 'ALLIED_WITH', 'House Woods'],
              ['Selwyn Tarth', 'ALLIED_WITH', 'House Woods'],
              ['Dacks', 'ALLIED_WITH', 'Titus Peake'],
              ['Barra', 'ALLIED_WITH', 'Titus Peake'],
              ['House Chelsted', 'ALLIED_WITH', 'Denys Darklyn'],
              ['Crow Spike Keep', 'ALLIED_WITH', 'Denys Darklyn'],
              ['Selwyn Tarth', 'ALLIED_WITH', 'Denys Darklyn'],
              ['House Chelsted', 'ALLIED_WITH', 'House Belmore of Strongsong'],
              ['Barra', 'ALLIED_WITH', 'House Belmore of Strongsong'],
              ['Walder Frey', 'ALLIED_WITH', 'House Belmore of Strongsong']],
             dtype=object),
       array([ 2. , 53. , 73. , 42. , 18. , 59.5, 86. , 76.5, 31. , 60.5, 31.5,
              32. , 24. ]))
      """
      if model.is_backward:
          model = model.model
  
      if not model.is_fitted:
          msg = "Model is not fitted."
          logger.error(msg)
          raise ValueError(msg)
  
      # if not model.is_fitted_on(X):
      #    msg = 'Model might not be fitted on this data.'
      #    logger.warning(msg)
      # raise ValueError(msg)
  
      if strategy not in [
          "random_uniform",
          "entity_frequency",
          "graph_degree",
          "cluster_coefficient",
          "cluster_triangles",
          "cluster_squares",
      ]:
          msg = "%s is not a valid strategy." % strategy
          logger.error(msg)
          raise ValueError(msg)
  
      if strategy == "exhaustive":
          msg = "Strategy is `exhaustive`, ignoring max_candidates."
          logger.info(msg)
  
      if isinstance(max_candidates, float):
          logger.debug(
              "Converting max_candidates float value {} to int value {}".format(
                  max_candidates, int(max_candidates * len(X))
              )
          )
          max_candidates = int(max_candidates * len(X))
  
      if isinstance(target_rel, str):
          target_rel = [target_rel]
  
      if target_rel is None:
          msg = "No target relation specified. Using all relations to generate candidate statements."
          logger.info(msg)
          rel_list = [
              x for x in model.data_indexer.backend.get_all_relations()
          ]
      else:
          missing_rels = []
          for rel in target_rel:
              if (
                  rel
                  not in model.data_indexer.backend.get_all_relations()
              ):
                  missing_rels.append(rel)
  
          if len(missing_rels) > 0:
              msg = "Target relation(s) not found in model: {}".format(
                  missing_rels
              )
              logger.error(msg)
              raise ValueError(msg)
  
          rel_list = [target_rel]
  
      # Set random seed
      np.random.seed(seed)
  
      # Remove unseen entities
      # X_filtered = filter_unseen_entities(X, model)
  
      discoveries = []
      discovery_ranks = []
  
      # Iterate through relations
      for relation in rel_list:
          logger.info(
              "Generating candidates for relation: %s" % relation
          )
  
          candidates = generate_candidates(
              X, strategy, relation, max_candidates, seed=seed
          )
  
          logger.debug(
              "Generated %d candidate statements." % len(candidates)
          )
  
          # Get ranks of candidate statements
          # ranks = evaluate_performance(candidates, model=model, filter_triples=X, use_default_protocol=True,
          #                             verbose=False)
  
          ranks = model.evaluate(
              candidates,
              use_filter={"test": X},
              corrupt_side="s,o",
              verbose=False,
          )
  
          # Select candidate statements within the top_n predicted ranks standard protocol evaluates against
          # corruptions on both sides, we just average the ranks here
          avg_ranks = np.mean(ranks, axis=1)
  
          preds = np.array(avg_ranks) <= top_n
          discoveries.append(candidates[preds])
          discovery_ranks.append(avg_ranks[preds])
  
      logger.info("Discovered %d facts" % len(discoveries))
  
      return np.hstack(discoveries), np.hstack(discovery_ranks)
  
file_path: AmpliGraph/ampligraph/discovery/discovery.py
imports: import logging
  import networkx
  import numpy
  from scipy import optimize, spatial
  from sklearn.cluster import DBSCAN
  from sklearn.neighbors import NearestNeighbors
label_desc: Use image node_id 1 for calling a global function with example usage: discover_facts(X, model, top_n, strategy, max_candidates, target_rel, seed) and returns: np,  np