scanPathsFromMany method

Future<GraphScanResult<T>> scanPathsFromMany(
  1. List<T> fromMany,
  2. NodeMatcher<T> targetMatcher, {
  3. Graph<T>? graph,
  4. NodesProvider<T>? outputsProvider,
  5. int maxExpansion = 3,
})

Performs a scan and returns the found node paths.

The paths should start one of the nodes at fromMany and end at a node that matches targetMatcher.

Implementation

Future<GraphScanResult<T>> scanPathsFromMany(
    List<T> fromMany, NodeMatcher<T> targetMatcher,
    {Graph<T>? graph,
    NodesProvider<T>? outputsProvider,
    int maxExpansion = 3}) async {
  var initTime = DateTime.now();

  GraphWalkingInstruction<bool>? processTarget(GraphNodeStep<T> step) {
    var node = step.node;

    if (targetMatcher.matchesNode(node)) {
      node.markAsTarget();
      if (!findAll) {
        return GraphWalkingInstruction.stop();
      }
    }
    return null;
  }

  if (graph == null) {
    graph = Graph<T>();

    if (outputsProvider == null) {
      return GraphScanResult(graph, fromMany, targetMatcher, [],
          findAll: findAll,
          time: Duration.zero,
          resolvePathsTime: Duration.zero);
    }

    FutureOr<Iterable<T>> nodeOutputsProvider(
        GraphNodeStep<T> step, T nodeValue) {
      var l = outputsProvider(graph!, graph.node(nodeValue));

      if (l is Future<List<Node<T>>>) {
        return l.then((l) => l.toIterableOfValues());
      } else {
        return l.toIterableOfValues();
      }
    }

    await graph.populateAsync(fromMany,
        outputsProvider: nodeOutputsProvider,
        process: processTarget,
        maxExpansion: maxExpansion);
  } else {
    if (graph.isEmpty && outputsProvider == null) {
      return GraphScanResult(graph, fromMany, targetMatcher, [],
          findAll: findAll,
          time: Duration.zero,
          resolvePathsTime: Duration.zero);
    }

    graph.reset();

    final nodeOutputsProvider = outputsProvider != null
        ? (GraphNodeStep<T> step, Node<T> node) =>
            outputsProvider(graph!, node)
        : (GraphNodeStep<T> step, Node<T> node) => node._outputs;

    await GraphWalker<T>(
      maxExpansion: maxExpansion,
      bfs: true,
    ).walkByNodesAsync<bool>(
      graph.valuesToNodes(fromMany, createNodes: true),
      process: processTarget,
      outputsProvider: nodeOutputsProvider,
    );
  }

  var pathsInitTime = DateTime.now();

  var targets = graph.targets;

  var paths = _resolvePaths(targets, maxExpansion);

  if (!findAll) {
    paths = paths.shortestPaths();
  }

  var endTime = DateTime.now();
  var time = endTime.difference(initTime);
  var timePaths = endTime.difference(pathsInitTime);

  return GraphScanResult(graph, fromMany, targetMatcher, paths,
      findAll: findAll, time: time, resolvePathsTime: timePaths);
}