code: def bidirectional_dijkstra(G, source, target, weight="weight"):
      r"""Dijkstra's algorithm for shortest paths using bidirectional search.
  
      Parameters
      ----------
      G : NetworkX graph
  
      source : node
          Starting node.
  
      target : node
          Ending node.
  
      weight : string or function
          If this is a string, then edge weights will be accessed via the
          edge attribute with this key (that is, the weight of the edge
          joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
          such edge attribute exists, the weight of the edge is assumed to
          be one.
  
          If this is a function, the weight of an edge is the value
          returned by the function. The function must accept exactly three
          positional arguments: the two endpoints of an edge and the
          dictionary of edge attributes for that edge. The function must
          return a number or None to indicate a hidden edge.
  
      Returns
      -------
      length, path : number and list
          length is the distance from source to target.
          path is a list of nodes on a path from source to target.
  
      Raises
      ------
      NodeNotFound
          If either `source` or `target` is not in `G`.
  
      NetworkXNoPath
          If no path exists between source and target.
  
      Examples
      --------
      >>> G = nx.path_graph(5)
      >>> length, path = nx.bidirectional_dijkstra(G, 0, 4)
      >>> print(length)
      4
      >>> print(path)
      [0, 1, 2, 3, 4]
  
      Notes
      -----
      Edge weight attributes must be numerical.
      Distances are calculated as sums of weighted edges traversed.
  
      The weight function can be used to hide edges by returning None.
      So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
      will find the shortest red path.
  
      In practice  bidirectional Dijkstra is much more than twice as fast as
      ordinary Dijkstra.
  
      Ordinary Dijkstra expands nodes in a sphere-like manner from the
      source. The radius of this sphere will eventually be the length
      of the shortest path. Bidirectional Dijkstra will expand nodes
      from both the source and the target, making two spheres of half
      this radius. Volume of the first sphere is `\pi*r*r` while the
      others are `2*\pi*r/2*r/2`, making up half the volume.
  
      This algorithm is not guaranteed to work if edge weights
      are negative or are floating point numbers
      (overflows and roundoff errors can cause problems).
  
      See Also
      --------
      shortest_path
      shortest_path_length
      """
      if source not in G or target not in G:
          msg = f"Either source {source} or target {target} is not in G"
          raise nx.NodeNotFound(msg)
  
      if source == target:
          return (0, [source])
  
      weight = _weight_function(G, weight)
      push = heappush
      pop = heappop
      # Init:  [Forward, Backward]
      dists = [{}, {}]  # dictionary of final distances
      paths = [
          {source: [source]},
          {target: [target]},
      ]  # dictionary of paths
      fringe = [
          [],
          [],
      ]  # heap of (distance, node) for choosing node to expand
      seen = [
          {source: 0},
          {target: 0},
      ]  # dict of distances to seen nodes
      c = count()
      # initialize fringe heap
      push(fringe[0], (0, next(c), source))
      push(fringe[1], (0, next(c), target))
      # neighs for extracting correct neighbor information
      if G.is_directed():
          neighs = [G._succ, G._pred]
      else:
          neighs = [G._adj, G._adj]
      # variables to hold shortest discovered path
      # finaldist = 1e30000
      finalpath = []
      dir = 1
      while fringe[0] and fringe[1]:
          # choose direction
          # dir == 0 is forward direction and dir == 1 is back
          dir = 1 - dir
          # extract closest to expand
          (dist, _, v) = pop(fringe[dir])
          if v in dists[dir]:
              # Shortest path to v has already been found
              continue
          # update distance
          dists[dir][v] = dist  # equal to seen[dir][v]
          if v in dists[1 - dir]:
              # if we have scanned v in both directions we are done
              # we have now discovered the shortest path
              return (finaldist, finalpath)
  
          for w, d in neighs[dir][v].items():
              # weight(v, w, d) for forward and weight(w, v, d) for back direction
              cost = weight(v, w, d) if dir == 0 else weight(w, v, d)
              if cost is None:
                  continue
              vwLength = dists[dir][v] + cost
              if w in dists[dir]:
                  if vwLength < dists[dir][w]:
                      raise ValueError(
                          "Contradictory paths found: negative weights?"
                      )
              elif w not in seen[dir] or vwLength < seen[dir][w]:
                  # relaxing
                  seen[dir][w] = vwLength
                  push(fringe[dir], (vwLength, next(c), w))
                  paths[dir][w] = paths[dir][v] + [w]
                  if w in seen[0] and w in seen[1]:
                      # see if this path is better than the already
                      # discovered shortest path
                      totaldist = seen[0][w] + seen[1][w]
                      if finalpath == [] or finaldist > totaldist:
                          finaldist = totaldist
                          revpath = paths[1][w][:]
                          revpath.reverse()
                          finalpath = paths[0][w] + revpath[1:]
      raise nx.NetworkXNoPath(f"No path between {source} and {target}.")
  
imports: from collections import deque
  from heapq import heappop, heappush
  from itertools import count
  import networkx
  from networkx.algorithms.shortest_paths.generic import _build_paths_from_predecessors
label_desc: Use image node_id 29 for calling a global function with example usage: bidirectional_dijkstra(G, source, target, weight) and returns: int,  list, finaldist,  finalpath