/** * Copyright 2011-2017 Asakusa Framework Team. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.asakusafw.utils.graph; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Predicate; import org.junit.Test; /** * Test for {@link Graphs}. */ public class GraphsTest { /** * copies an empty graph. */ @Test public void copy_empty() { Graph<Integer> graph = Graphs.newInstance(); Graph<Integer> copy = Graphs.copy(graph); assertThat(copy.isEmpty(), is(true)); } /** * copies a regular graph. */ @Test public void copy_normal() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3, 4); addPath(graph, 2, 1); addPath(graph, 3, 2); Graph<Integer> copy = Graphs.copy(graph); assertThat(copy.getNodeSet(), is(set(1, 2, 3, 4))); assertThat(copy.getConnected(1), is(set(2))); assertThat(copy.getConnected(2), is(set(1, 3))); assertThat(copy.getConnected(3), is(set(2, 4))); assertThat(copy.getConnected(4), is(set())); } /** * creates a subgraph. */ @Test public void subgraph() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3, 4, 5, 1); addPath(graph, 1, 3, 5, 2, 4, 1); Graph<Integer> sub = Graphs.subgraph(graph, object -> object != 5); Graph<Integer> expect = Graphs.newInstance(); addPath(expect, 1, 2, 3, 4, 1); addPath(expect, 1, 3); addPath(expect, 2, 4); assertThat(sub, is(expect)); } /** * creates an empty subgraph. */ @Test public void subgraph_empty() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3, 4, 5, 1); addPath(graph, 1, 3, 5, 2, 4, 1); Graph<Integer> sub = Graphs.subgraph(graph, object -> false); assertThat(sub.isEmpty(), is(true)); } /** * creates an equivalent subgraph. */ @Test public void subgraph_all() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3, 4, 5, 1); addPath(graph, 1, 3, 5, 2, 4, 1); Graph<Integer> sub = Graphs.subgraph(graph, object -> true); assertThat(sub, is(graph)); } /** * Test method for {@link Graphs#collectAllConnected(Graph, java.util.Collection)}. */ @Test public void testCollectAllConnected_Cyclic() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3, 4, 2); addPath(graph, 3, 5); assertThat(Graphs.collectAllConnected(graph, set(1)), is(set(2, 3, 4, 5))); assertThat(Graphs.collectAllConnected(graph, set(2)), is(set(2, 3, 4, 5))); assertThat(Graphs.collectAllConnected(graph, set(3)), is(set(2, 3, 4, 5))); assertThat(Graphs.collectAllConnected(graph, set(4)), is(set(2, 3, 4, 5))); assertThat(Graphs.collectAllConnected(graph, set(5)), is(set())); } /** * Test method for {@link Graphs#collectAllConnected(Graph, java.util.Collection)}. */ @Test public void testCollectAllConnected_Multi() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3); addPath(graph, 2, 4); addPath(graph, 5, 2); assertThat(Graphs.collectAllConnected(graph, set(1, 2)), is(set(2, 3, 4))); assertThat(Graphs.collectAllConnected(graph, set(1, 5)), is(set(2, 3, 4))); assertThat(Graphs.collectAllConnected(graph, set(3, 4)), is(set())); } /** * Test method for {@link Graphs#collectAllConnected(Graph, java.util.Collection)}. */ @Test public void testCollectAllConnected_Single() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3); addPath(graph, 2, 4); addPath(graph, 5, 2); assertThat(Graphs.collectAllConnected(graph, set(1)), is(set(2, 3, 4))); assertThat(Graphs.collectAllConnected(graph, set(2)), is(set(3, 4))); assertThat(Graphs.collectAllConnected(graph, set(3)), is(set())); assertThat(Graphs.collectAllConnected(graph, set(4)), is(set())); assertThat(Graphs.collectAllConnected(graph, set(5)), is(set(2, 4, 3))); } /** * Test method for {@link Graphs#findNearest(Graph, java.util.Collection, Predicate)}. */ @Test public void findNearest_simple() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, -2, -3); Set<Integer> results = Graphs.findNearest(graph, set(1), object -> object < 0); assertThat(results, is(set(-2))); } /** * Test method for {@link Graphs#findNearest(Graph, java.util.Collection, Predicate)}. */ @Test public void findNearest_hop() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, -3); Set<Integer> results = Graphs.findNearest(graph, set(1), object -> object < 0); assertThat(results, is(set(-3))); } /** * Test method for {@link Graphs#findNearest(Graph, java.util.Collection, Predicate)}. */ @Test public void findNearest_ignoreItself() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, -1, 2, -3); Set<Integer> results = Graphs.findNearest(graph, set(-1), object -> object < 0); assertThat(results, is(set(-3))); } /** * Test method for {@link Graphs#findNearest(Graph, java.util.Collection, Predicate)}. */ @Test public void findNearest_dominants() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, -2, 3, -4, -6); addPath(graph, 1, 5, 3); Set<Integer> results = Graphs.findNearest(graph, set(1), object -> object < 0); assertThat(results, is(set(-2, -4))); } /** * Test method for {@link Graphs#findNearest(Graph, java.util.Collection, Predicate)}. */ @Test public void findNearest_multipath() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, -2, -3); addPath(graph, 1, -2, -4); addPath(graph, 5, 6, -4); addPath(graph, 5, -7, -8); Set<Integer> results = Graphs.findNearest(graph, set(1, 5), object -> object < 0); assertThat(results, is(set(-2, -4, -7))); } /** * Test method for {@link Graphs#findNearest(Graph, java.util.Collection, Predicate)}. */ @Test public void findNearest_overlap() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, -2, 3, -4, 1); Set<Integer> results = Graphs.findNearest(graph, set(1, -2), object -> object < 0); assertThat(results, is(set(-2, -4))); } /** * Test method for {@link Graphs#collectNearest(Graph, java.util.Collection, Predicate)}. */ @Test public void collectNearest_simple() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, -2, -3); Set<Integer> results = Graphs.collectNearest(graph, set(1), object -> object < 0); assertThat(results, is(set(-2))); } /** * Test method for {@link Graphs#collectNearest(Graph, java.util.Collection, Predicate)}. */ @Test public void collectNearest_hop() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, -3); Set<Integer> results = Graphs.collectNearest(graph, set(1), object -> object < 0); assertThat(results, is(set(2, -3))); } /** * Test method for {@link Graphs#collectNearest(Graph, java.util.Collection, Predicate)}. */ @Test public void collectNearest_ignoreItself() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, -1, 2, -3); Set<Integer> results = Graphs.collectNearest(graph, set(-1), object -> object < 0); assertThat(results, is(set(2, -3))); } /** * Test method for {@link Graphs#collectNearest(Graph, java.util.Collection, Predicate)}. */ @Test public void collectNearest_dominants() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, -2, 3, -4, -6); addPath(graph, 1, 5, 3); Set<Integer> results = Graphs.collectNearest(graph, set(1), object -> object < 0); assertThat(results, is(set(-2, 3, 5, -4))); } /** * Test method for {@link Graphs#collectNearest(Graph, java.util.Collection, Predicate)}. */ @Test public void collectNearest_multipath() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, -2, -3); addPath(graph, 1, -2, -4); addPath(graph, 5, 6, -4); addPath(graph, 5, -7, -8); Set<Integer> results = Graphs.collectNearest(graph, set(1, 5), object -> object < 0); assertThat(results, is(set(-2, -4, 6, -7))); } /** * Test method for {@link Graphs#collectNearest(Graph, java.util.Collection, Predicate)}. */ @Test public void collectNearest_overlap() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, -2, 3, -4, 1); Set<Integer> results = Graphs.collectNearest(graph, set(1, -2), object -> object < 0); assertThat(results, is(set(-2, 3, -4))); } /** * Test method for {@link Graphs#findCircuit(Graph)}. */ @Test public void testFindCircuit_Circuit() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3, 1); Set<Set<Integer>> circuits = Graphs.findCircuit(graph); Integer[][] expect = { { 1, 2, 3 } }; assertThat(circuits, is(toPartition(expect))); } /** * Test method for {@link Graphs#findCircuit(Graph)}. */ @Test public void testFindCircuit_Complex() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3, 4, 6); addPath(graph, 2, 5, 7); addPath(graph, 3, 4, 5, 3); Set<Set<Integer>> circuits = Graphs.findCircuit(graph); Integer[][] expect = { { 3, 4, 5 } }; assertThat(circuits, is(toPartition(expect))); } /** * Test method for {@link Graphs#findCircuit(Graph)}. */ @Test public void testFindCircuit_Self() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 2, 3); Set<Set<Integer>> circuits = Graphs.findCircuit(graph); Integer[][] expect = { { 2 } }; assertThat(circuits, is(toPartition(expect))); } /** * Test method for {@link Graphs#findCircuit(Graph)}. */ @Test public void testFindCircuit_Tree() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3); addPath(graph, 2, 4); addPath(graph, 1, 5, 6); addPath(graph, 5, 7); Set<Set<Integer>> circuits = Graphs.findCircuit(graph); Integer[][] expect = {}; assertThat(circuits, is(toPartition(expect))); } /** * Test method for {@link Graphs#findStronglyConnectedComponents(Graph)}. */ @Test public void testFindStronglyConnectedComponents_Circuit() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3, 1); Set<Set<Integer>> scc = Graphs.findStronglyConnectedComponents(graph); Integer[][] expect = { { 1, 2, 3 } }; assertThat(scc, is(toPartition(expect))); } /** * Test method for {@link Graphs#findStronglyConnectedComponents(Graph)}. */ @Test public void testFindStronglyConnectedComponents_Complex() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3, 4, 6); addPath(graph, 2, 5, 7); addPath(graph, 3, 4, 5, 3); Set<Set<Integer>> scc = Graphs.findStronglyConnectedComponents(graph); Integer[][] expect = { { 1 }, { 2 }, { 6 }, { 7 }, { 3, 4, 5 } }; assertThat(scc, is(toPartition(expect))); } /** * Test method for {@link Graphs#findStronglyConnectedComponents(Graph)}. */ @Test public void testFindStronglyConnectedComponents_Tree() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3); addPath(graph, 2, 4); addPath(graph, 1, 5, 6); addPath(graph, 5, 7); Set<Set<Integer>> scc = Graphs.findStronglyConnectedComponents(graph); Integer[][] expect = { { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 } }; assertThat(scc, is(toPartition(expect))); } /** * Test method for {@link Graphs#newInstance()}. */ @Test public void testNewInstance() { Graph<String> graph = Graphs.newInstance(); assertThat(graph.getNodeSet().isEmpty(), is(true)); } /** * Test method for {@link Graphs#sortPostOrder(Graph)}. */ @Test public void testSortPostOrder_Circuit() { Graph<Integer> graph = Graphs.newInstance(); // {1} -> {2, 3, 4} -> {5} addPath(graph, 1, 2, 3, 4, 2, 5); List<Integer> sorted = Graphs.sortPostOrder(graph); assertThat(sorted.size(), is(5)); assertThat(1, isIn(sorted)); assertThat(2, isIn(sorted)); assertThat(3, isIn(sorted)); assertThat(4, isIn(sorted)); assertThat(5, isIn(sorted)); sorted.remove((Integer) 2); sorted.remove((Integer) 3); sorted.remove((Integer) 4); assertThat(sorted, is(Arrays.asList(5, 1))); } /** * Test method for {@link Graphs#sortPostOrder(Graph)}. */ @Test public void testSortPostOrder_List() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3, 4, 5); List<Integer> sorted = Graphs.sortPostOrder(graph); assertThat(sorted, is(Arrays.asList(5, 4, 3, 2, 1))); } /** * Test method for {@link Graphs#sortPostOrder(Graph)}. */ @Test public void testSortPostOrder_Tree() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3); addPath(graph, 1, 2, 4); addPath(graph, 1, 5, 6); addPath(graph, 1, 5, 7); List<Integer> sorted = Graphs.sortPostOrder(graph); assertThat(sorted.size(), is(7)); assertThat(1, isIn(sorted)); assertThat(2, isIn(sorted)); assertThat(3, isIn(sorted)); assertThat(4, isIn(sorted)); assertThat(5, isIn(sorted)); assertThat(6, isIn(sorted)); assertThat(7, isIn(sorted)); assertThat("the last is the root of this tree", sorted.get(6), is(1)); assertPostOrdered(graph, sorted); } /** * Test method for {@link Graphs#transpose(Graph)}. */ @Test public void testTransposeGraph_noEdges() { Graph<Integer> graph = Graphs.newInstance(); prepare(graph, 1); Graph<Integer> expect = Graphs.newInstance(); prepare(expect, 1); assertThat(Graphs.transpose(graph), is(expect)); } /** * Test method for {@link Graphs#transpose(Graph)}. */ @Test public void testTransposeGraph() { Graph<Integer> graph = Graphs.newInstance(); prepare(graph, 1); prepare(graph, 2, 1); prepare(graph, 3, 2, 3, 4); prepare(graph, 4, 5, 6); prepare(graph, 5, 6, 7); Graph<Integer> expect = Graphs.newInstance(); prepare(expect, 1, 2); prepare(expect, 2, 3); prepare(expect, 3, 3); prepare(expect, 4, 3); prepare(expect, 5, 4); prepare(expect, 6, 4, 5); prepare(expect, 7, 5); assertThat(Graphs.transpose(graph), is(expect)); } /** * Test method for {@link Graphs#collectHeads(Graph)}. */ @Test public void testCollectHeads_empty() { Graph<Integer> graph = Graphs.newInstance(); assertThat(Graphs.collectHeads(graph), is(set())); } /** * Test method for {@link Graphs#collectHeads(Graph)}. */ @Test public void testCollectHeads_single() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1); assertThat(Graphs.collectHeads(graph), is(set(1))); } /** * Test method for {@link Graphs#collectHeads(Graph)}. */ @Test public void testCollectHeads_connected() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3); assertThat(Graphs.collectHeads(graph), is(set(1))); } /** * Test method for {@link Graphs#collectHeads(Graph)}. */ @Test public void testCollectHeads_disconnected() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1); addPath(graph, 2); addPath(graph, 3); addPath(graph, 4); assertThat(Graphs.collectHeads(graph), is(set(1, 2, 3, 4))); } /** * Test method for {@link Graphs#collectHeads(Graph)}. */ @Test public void testCollectHeads_multi() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3); addPath(graph, 4, 2, 5); assertThat(Graphs.collectHeads(graph), is(set(1, 4))); } /** * Test method for {@link Graphs#collectHeads(Graph)}. */ @Test public void testCollectHeads_cyclic() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3, 4, 1); assertThat(Graphs.collectHeads(graph), is(set())); } /** * Test method for {@link Graphs#collectTails(Graph)}. */ @Test public void testCollectTails_empty() { Graph<Integer> graph = Graphs.newInstance(); assertThat(Graphs.collectTails(graph), is(set())); } /** * Test method for {@link Graphs#collectTails(Graph)}. */ @Test public void testCollectTails_single() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1); assertThat(Graphs.collectTails(graph), is(set(1))); } /** * Test method for {@link Graphs#collectTails(Graph)}. */ @Test public void testCollectTails_connected() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3); assertThat(Graphs.collectTails(graph), is(set(3))); } /** * Test method for {@link Graphs#collectTails(Graph)}. */ @Test public void testCollectTails_disconnected() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1); addPath(graph, 2); addPath(graph, 3); addPath(graph, 4); assertThat(Graphs.collectTails(graph), is(set(1, 2, 3, 4))); } /** * Test method for {@link Graphs#collectTails(Graph)}. */ @Test public void testCollectTails_multi() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3); addPath(graph, 4, 2, 5); assertThat(Graphs.collectTails(graph), is(set(3, 5))); } /** * Test method for {@link Graphs#collectTails(Graph)}. */ @Test public void testCollectTails_cyclic() { Graph<Integer> graph = Graphs.newInstance(); addPath(graph, 1, 2, 3, 4, 1); assertThat(Graphs.collectTails(graph), is(set())); } @SafeVarargs private static <V> void addPath(Graph<V> graph, V first, V...vertexes) { graph.addNode(first); V current = first; for (V v : vertexes) { graph.addEdge(current, v); current = v; } } private void assertPostOrdered(Graph<?> graph, List<?> list) { for (int i = 0, n = list.size(); i < n; i++) { Object from = list.get(i); for (int j = i + 1; j < n; j++) { Object to = list.get(j); assertThat(from + "=>" + to, graph.isConnected(from, to), is(false)); } } } @SafeVarargs private static <T> void prepare(Graph<T> graph, T from, T...to) { graph.addNode(from); for (T t : to) { graph.addEdge(from, t); } } private Set<Integer> set(Integer...values) { return new HashSet<>(Arrays.asList(values)); } private <T> Set<Set<T>> toPartition(T[][] tss) { Set<Set<T>> results = new HashSet<>(); for (T[] ts : tss) { Set<T> part = new HashSet<>(); for (T t : ts) { part.add(t); } results.add(part); } return results; } }