code: def _compute_edge_weights(
      candidates: list[Candidate],
      term_weights: dict[str, float],
      window_size: int,
      n_toks: int,
  ) -> list[tuple[str, str, dict[str, float]]]:
      """
      Compute weights between candidates that occur within a sliding window(s) of
      each other, then combine with statistical ``term_weights`` and normalize
      by the total number of outgoing edge weights.
      """
      n_coocs: collections.defaultdict = collections.defaultdict(
          lambda: collections.defaultdict(int)
      )
      sum_logdists: collections.defaultdict = collections.defaultdict(
          lambda: collections.defaultdict(float)
      )
      # iterate over windows
      log_ = math.log  # localize this, for performance
      for start_idx in range(n_toks):
          end_idx = start_idx + window_size
          window_cands = (
              cand
              for cand in candidates
              if start_idx <= cand.idx < end_idx
          )
          # get all token combinations within window
          for c1, c2 in itertools.combinations(window_cands, 2):
              n_coocs[c1.text][c2.text] += 1
              try:
                  sum_logdists[c1.text][c2.text] += log_(
                      window_size / abs(c1.idx - c2.idx)
                  )
              except ZeroDivisionError:
                  sum_logdists[c1.text][c2.text] += log_(window_size)
          if end_idx >= n_toks:
              break
      # compute edge weights between co-occurring terms (nodes)
      edge_weights: collections.defaultdict = collections.defaultdict(
          lambda: collections.defaultdict(float)
      )
      for c1, c2_dict in sum_logdists.items():
          for c2, sum_logdist in c2_dict.items():
              edge_weights[c1][c2] = (
                  ((1.0 + sum_logdist) / n_coocs[c1][c2])
                  * term_weights[c1]
                  * term_weights[c2]
              )
      # normalize edge weights by sum of outgoing edge weights per term (node)
      norm_edge_weights: list[tuple[str, str, dict[str, float]]] = []
      for c1, c2s in edge_weights.items():
          sum_edge_weights = sum(c2s.values())
          norm_edge_weights.extend(
              (c1, c2, {"weight": weight / sum_edge_weights})
              for c2, weight in c2s.items()
          )
      return norm_edge_weights
  
file_path: textacy/src/textacy/extract/keyterms/sgrank.py
imports: from __future__ import annotations
  import collections
  import itertools
  import math
  from operator import itemgetter
  from typing import Callable, Collection, Counter, Optional
  import networkx
  from spacy.tokens import Doc, Span
  from ...None import utils
  from ..None import utils
label_desc: Use image node_id 5 for calling a global function with example usage: _compute_edge_weights(candidates, term_weights, window_size, n_toks) and returns: norm_edge_weights