All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ch.ethz.sn.visone3.algorithms.impl.TraversalImpl Maven / Gradle / Ivy

The newest version!
/*
 * This file is part of netroles.
 *
 * netroles is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * netroles is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with netroles.  If not, see .
 */

package ch.ethz.sn.visone3.algorithms.impl;

import ch.ethz.sn.visone3.algorithms.Traversal;
import ch.ethz.sn.visone3.lang.Mapping;
import ch.ethz.sn.visone3.lang.Mappings;
import ch.ethz.sn.visone3.lang.PrimitiveIterable;
import ch.ethz.sn.visone3.lang.PrimitiveList;
import ch.ethz.sn.visone3.networks.Edge;

import java.util.Iterator;
import java.util.Objects;
import java.util.PrimitiveIterator;
import java.util.Stack;
import java.util.function.IntFunction;

/**
 * An implementation of {@link Traversal}.
 */
public class TraversalImpl implements Traversal {

  TraversalImpl() {
  }

  /**
   * Multi source breadth-first-search.
   *
   * @param numVertices
   *          Number of nodes.
   * @param neighbors
   *          Neighbourhood function.
   * @param starts
   *          Start points. A new BFS is started from each of these nodes if the BFS number is still
   *          negative.
   * @param visitor
   *          A traversal visitor. Use {@link Visitor#NULL} instead of {@code null}.
   * @return the BFS number mapping.
   */
  @Override
  public Mapping.OfInt bfs(final int numVertices,
      final IntFunction neighbors, final PrimitiveIterable.OfInt starts,
      final Visitor visitor) {
    Objects.requireNonNull(neighbors);
    Objects.requireNonNull(starts);
    Objects.requireNonNull(visitor);
    final Mapping.OfInt bfsns = Mappings.newIntList(-1, numVertices);
    for (final int i : starts) {
      if (bfsns.getInt(i) < 0) {
        bfs(neighbors, bfsns, i, visitor);
      }
    }
    return bfsns;
  }

  /**
   * Single source breadth-first-search.
   *
   * @param neighbors
   *          Neighbourhood function.
   * @param bfsns
   *          BFS number mapping, will be filled on visiting nodes.
   * @param start
   *          The starting node.
   * @param visitor
   *          A traversal visitor. Use {@link Visitor#NULL} instead of {@code null}.
   */
  private static void bfs(final IntFunction neighbors,
      final Mapping.OfInt bfsns, final int start, final Visitor visitor) {
    visitor.startSearch(start);
    bfsns.setInt(start, 0);
    visitor.visitVertex(start);

    final PrimitiveList.OfInt queue = Mappings.newIntList(); // manually managed fifo
    queue.addInt(start);
    int queueHead = 0;
    while (queueHead != queue.size()) {
      final int source = queue.getInt(queueHead++);
      final int sourceBfsn1 = bfsns.getInt(source) + 1;

      final PrimitiveIterator.OfInt out = neighbors.apply(source).iterator();
      while (out.hasNext()) {
        final int target = out.nextInt();
        if (bfsns.getInt(target) < 0) {
          bfsns.setInt(target, sourceBfsn1);
          queue.addInt(target);
          visitor.visitEdge(source, target, -1);
          visitor.visitVertex(target);
        }
      }

      // keep queue store small
      if (2 * queueHead > queue.size()) {
        queue.removeRange(0, queueHead);
        queueHead = 0;
      }
    }
    visitor.endSearch();
  }

  /**
   * Multi source depth-first-search.
   *
   * @param numVertices
   *          Number of nodes.
   * @param neighbors
   *          Neighbourhood function.
   * @param starts
   *          Start points. A new DFS is started from each of these nodes if the DFS number is still
   *          negative.
   * @param visitor
   *          A traversal visitor. Use {@link Visitor#NULL} instead of {@code null}.
   * @return the DFS number mapping.
   */
  @Override
  public Mapping.OfInt dfs(final int numVertices,
      final IntFunction neighbors, final PrimitiveIterable.OfInt starts,
      final Visitor visitor) {
    Objects.requireNonNull(neighbors);
    Objects.requireNonNull(starts);
    Objects.requireNonNull(visitor);
    final Mapping.OfInt dfsns = Mappings.newIntList(-1, numVertices);
    dfsInternal(neighbors, starts, dfsns, visitor);
    return dfsns;
  }

  /**
   * Multi source depth-first-search.
   *
   * @param neighbors
   *          Neighbourhood function.
   * @param starts
   *          Start points. A new DFS is started from each of these nodes if the DFS number is still
   *          negative.
   * @param dfsns
   *          Mapping as storage for DFS numbers.
   * @param visitor
   *          A traversal visitor. Use {@link Visitor#NULL} instead of {@code null}.
   */
  @Override
  public void dfs(final IntFunction neighbors,
      final PrimitiveIterable.OfInt starts, final Mapping.OfInt dfsns, final Visitor visitor) {
    Objects.requireNonNull(neighbors);
    Objects.requireNonNull(starts);
    Objects.requireNonNull(visitor);
    Objects.requireNonNull(dfsns);

    dfsInternal(neighbors, starts, dfsns, visitor);
  }

  @Override
  public void edgeDfs(final int numEdges, IntFunction> edges,
      final PrimitiveIterable.OfInt starts, final Mapping.OfInt dfsns, final Visitor visitor) {
    Objects.requireNonNull(edges);
    Objects.requireNonNull(starts);
    Objects.requireNonNull(visitor);
    final boolean[] edgeMark = new boolean[numEdges];

    for (final int i : starts) {
      if (dfsns.getInt(i) < 0) {
        edgeDfsInternal(edges, dfsns, i, visitor, edgeMark);
      }
    }
  }

  /**
   * Multi source depth-first-search.
   *
   * @param neighbors
   *          Neighbourhood function.
   * @param starts
   *          Start points. A new DFS is started from each of these nodes if the DFS number is still
   *          negative.
   * @param dfsns
   *          Mapping as storage for DFS numbers.
   * @param visitor
   *          A traversal visitor. Use {@link Visitor#NULL} instead of {@code null}.
   */
  private static void dfsInternal(final IntFunction neighbors,
      final PrimitiveIterable.OfInt starts, final Mapping.OfInt dfsns, final Visitor visitor) {

    for (final int i : starts) {
      if (dfsns.getInt(i) < 0) {
        dfsInternal(neighbors, dfsns, i, visitor);
      }
    }
  }

  /**
   * Single source depth-first-search.
   *
   * @param neighbors
   *          Neighbourhood function.
   * @param dfsns
   *          DFS number mapping, will be filled on visiting nodes.
   * @param start
   *          The starting node.
   * @param visitor
   *          A traversal visitor. Use {@link Visitor#NULL} instead of {@code null}.
   */
  private static Mapping.OfInt dfsInternal(final IntFunction neighbors,
      final Mapping.OfInt dfsns, final int start, final Visitor visitor) {
    visitor.startSearch(start);
    final PrimitiveList.OfInt vertexStack = Mappings.newIntList();
    final Stack neighborTraversalStack = new Stack<>();
    int dfsn = 0;
    vertexStack.addInt(start);
    neighborTraversalStack.push(neighbors.apply(start).iterator());

    while (!vertexStack.isEmpty()) {
      final int source = vertexStack.getInt(vertexStack.size() - 1);
      PrimitiveIterator.OfInt neighborIterator = neighborTraversalStack.peek();

      if (dfsns.getInt(source) < 0) {
        dfsns.setInt(source, dfsn++);
        visitor.visitVertex(source);
      }
      if (!neighborIterator.hasNext()) {
        visitor.backtrackVertex(source);

        vertexStack.removeIndex(vertexStack.size() - 1);
        neighborTraversalStack.pop();
      } else {
        int target = neighborIterator.nextInt();
        if (dfsns.getInt(target) < 0) {
          vertexStack.addInt(target);
          neighborTraversalStack.push(neighbors.apply(target).iterator());
        }
        visitor.visitEdge(source, target, -1);
      }
    }
    visitor.endSearch();
    return dfsns;
  }

  private static Mapping.OfInt edgeDfsInternal(final IntFunction> edges,
      final Mapping.OfInt dfsns, final int start, final Visitor visitor, boolean[] edgeMark) {
    visitor.startSearch(start);
    final PrimitiveList.OfInt vertexStack = Mappings.newIntList();
    final Stack> neighborTraversalStack = new Stack<>();

    int dfsn = 0;
    vertexStack.addInt(start);
    neighborTraversalStack.push(edges.apply(start).iterator());

    while (!vertexStack.isEmpty()) {
      final int source = vertexStack.getInt(vertexStack.size() - 1);
      Iterator edgeIterator = neighborTraversalStack.peek();

      if (dfsns.getInt(source) < 0) {
        dfsns.setInt(source, dfsn++);
        visitor.visitVertex(source);
      }
      if (!edgeIterator.hasNext()) {
        visitor.backtrackVertex(source);

        vertexStack.removeIndex(vertexStack.size() - 1);
        neighborTraversalStack.pop();
      } else {
        Edge edge = edgeIterator.next();
        int idx = edge.getIndex();
        if (!edgeMark[idx]) {
          edgeMark[idx] = true;
          int target = edge.getTarget();
          if (dfsns.getInt(target) < 0) {
            vertexStack.addInt(target);
            neighborTraversalStack.push(edges.apply(target).iterator());
          }
          visitor.visitEdge(source, target, idx);
        }
      }
    }
    visitor.endSearch();
    return dfsns;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy