/******************************************************************************* * Breakout Cave Survey Visualizer * * Copyright (C) 2014 James Edwards * * jedwards8 at fastmail dot fm * * This program 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 2 of the License, or (at your option) any later * version. * * This program 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 * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *******************************************************************************/ package org.andork.graph; import java.util.HashSet; import java.util.PriorityQueue; import java.util.Set; import java.util.function.BiFunction; import java.util.function.BiPredicate; import java.util.function.BooleanSupplier; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.ToDoubleFunction; import java.util.stream.Stream; public class Graphs { public static class PriorityNode<N, P extends Comparable<P>> implements Comparable<PriorityNode<N, P>> { public final N node; public final P priority; public PriorityNode(N node, P priority) { super(); this.node = node; this.priority = priority; } @Override public int compareTo(PriorityNode<N, P> o) { return priority.compareTo(o.priority); } } public static <Node extends Comparable<Node>, Id> void traverse(Stream<Node> startNodes, Predicate<Node> nodeVisitor, Function<Node, Id> nodeId, Function<Node, Stream<Node>> connected, BooleanSupplier keepGoing) { PriorityQueue<Node> queue = new PriorityQueue<>(); startNodes.forEach(n -> queue.add(n)); Set<Id> visited = new HashSet<>(); while (!queue.isEmpty() && keepGoing.getAsBoolean()) { Node node = queue.poll(); Id id = nodeId.apply(node); if (!visited.add(id)) { continue; } if (!nodeVisitor.test(node)) { continue; } connected.apply(node).forEach(n -> queue.add(n)); } } public static <Node extends Comparable<Node>, Id> void traverse(Stream<Node> startNodes, Predicate<Node> nodeVisitor, Function<Node, Id> nodeId, Function<Node, Stream<Node>> connected, Consumer<Runnable> bgRunner, long bgPeriod, BooleanSupplier keepGoing) { PriorityQueue<Node> queue = new PriorityQueue<>(); startNodes.forEach(n -> queue.add(n)); Set<Id> visited = new HashSet<>(); while (!queue.isEmpty() && keepGoing.getAsBoolean()) { bgRunner.accept(() -> { long startTime = System.currentTimeMillis(); while (!queue.isEmpty() && keepGoing.getAsBoolean()) { Node node = queue.poll(); Id id = nodeId.apply(node); if (!visited.add(id)) { continue; } if (!nodeVisitor.test(node)) { continue; } connected.apply(node).forEach(n -> queue.add(n)); if (System.currentTimeMillis() - startTime > bgPeriod) { return; } } }); } } public static <Node, Edge> void traverse(Stream<Node> startNodes, ToDoubleFunction<Node> initialPriority, BiFunction<Node, Double, Stream<Edge>> connectedEdges, ToDoubleFunction<Edge> edgeCost, BiFunction<Node, Edge, Node> nextNode, Consumer<Runnable> bgRunner, long bgPeriod, BooleanSupplier keepGoing) { traverse(startNodes.map(n -> new PriorityNode<>(n, initialPriority.applyAsDouble(n))), p -> true, (PriorityNode<Node, Double> p) -> p.node, p -> connectedEdges.apply(p.node, p.priority).map( e -> new PriorityNode<>(nextNode.apply(p.node, e), p.priority + edgeCost.applyAsDouble(e))), bgRunner, bgPeriod, keepGoing); } public static <Node, Edge> void traverse(Stream<Node> startNodes, ToDoubleFunction<Node> initialPriority, BiPredicate<Node, Double> nodeVisitor, Function<Node, Stream<Edge>> connectedEdges, ToDoubleFunction<Edge> edgeCost, BiFunction<Node, Edge, Node> nextNode, Consumer<Runnable> bgRunner, long bgPeriod, BooleanSupplier keepGoing) { traverse(startNodes.map(n -> new PriorityNode<>(n, initialPriority.applyAsDouble(n))), (PriorityNode<Node, Double> p) -> nodeVisitor.test(p.node, p.priority), p -> p.node, p -> connectedEdges.apply(p.node).map( e -> new PriorityNode<>(nextNode.apply(p.node, e), p.priority + edgeCost.applyAsDouble(e))), bgRunner, bgPeriod, keepGoing); } public static <Node> void traverse(Stream<Node> startNodes, ToDoubleFunction<Node> initialPriority, BiPredicate<Node, Double> nodeVisitor, Function<Node, Stream<Node>> connected, ToDoubleFunction<Node> nodeCost) { traverse(startNodes.map(n -> new PriorityNode<Node, Double>(n, initialPriority.applyAsDouble(n))), (PriorityNode<Node, Double> p) -> nodeVisitor.test(p.node, p.priority), p -> p.node, p -> connected.apply(p.node).map( n -> new PriorityNode<Node, Double>(n, p.priority + nodeCost.applyAsDouble(p.node))), () -> true); } public static <Node, Edge> void traverse2(Stream<Node> startNodes, ToDoubleFunction<Node> initialPriority, BiPredicate<Node, Double> nodeVisitor, Function<Node, Stream<Edge>> connectedEdges, ToDoubleFunction<Edge> edgeCost, BiFunction<Node, Edge, Node> nextNode, BooleanSupplier keepGoing) { traverse(startNodes.map(n -> new PriorityNode<>(n, initialPriority.applyAsDouble(n))), (PriorityNode<Node, Double> p) -> nodeVisitor.test(p.node, p.priority), p -> p.node, p -> connectedEdges.apply(p.node).map( e -> new PriorityNode<>(nextNode.apply(p.node, e), p.priority + edgeCost.applyAsDouble(e))), keepGoing); } }