Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 eu.fbk.materializer; import com.google.common.collect.Sets; import java.io.Serializable; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.Set; import java.util.Stack; /** * Provides functions to analyze path statistics. * * @author Michele Mostarda (mostarda@fbk.eu) */ public class PathAnalysis implements Serializable { private static String[] breadthFirst(String s, Edge[] edges) { Queue<String> q = new ArrayDeque<>(); q.add(s); Set<String> visited = new HashSet<>(); visited.add(s); while (!q.isEmpty()) { String current = q.poll(); for (Edge e : edges) { if (current.equals(e.cLeft) && !visited.contains(e.cRight)) { visited.add(e.cRight); q.add(e.cRight); } else if (current.equals(e.cRight) && !visited.contains(e.cLeft)) { visited.add(e.cLeft); q.add(e.cLeft); } } } return visited.toArray(new String[visited.size()]); } protected static List<List<Edge>> sortPathDepthFirst(String s, List<Edge> edges) { if (edges.isEmpty()) return new ArrayList<>(); final Stack<String> stack = new Stack<>(); stack.push(s); final List<List<Edge>> out = new ArrayList<>(); final Map<String, List<Edge>> concurrents = new HashMap<>(); final Set<Edge> visited = new HashSet<>(); while (!stack.isEmpty() && out.size() != edges.size()) { String peek = stack.peek(); boolean added = false; for (Edge edge : edges) { if (edge.cLeft.equals(peek) && !visited.contains(edge)) { List<Edge> concurrent = concurrents.get(peek); if (concurrent == null) { concurrent = new ArrayList<>(); concurrents.put(peek, concurrent); out.add(concurrent); } concurrent.add(edge); visited.add(edge); stack.push(edge.cRight); added = true; break; } else if (edge.cRight.equals(peek) && !visited.contains(edge)) { List<Edge> concurrent = concurrents.get(peek); if (concurrent == null) { concurrent = new ArrayList<>(); concurrents.put(peek, concurrent); out.add(concurrent); } concurrent.add(edge); visited.add(edge); stack.push(edge.cLeft); added = true; break; } } if (!added) stack.pop(); } return out; } private final List<Edge> edges = new ArrayList<>(); public String[] getNodes() { final List<String> nodes = new ArrayList<>(); for (Edge edge : edges) { nodes.add(edge.cLeft); nodes.add(edge.cRight); } return nodes.toArray(new String[nodes.size()]); } public Edge[] getEdges() { return edges.toArray(new Edge[edges.size()]); } public Edge[] getIn(String node) { final List<Edge> nodes = new ArrayList<>(); for (Edge property : edges) { if (property.cRight.equals(node)) { nodes.add(property); } } return nodes.toArray(new Edge[nodes.size()]); } public Edge[] getOut(String node) { final List<Edge> nodes = new ArrayList<>(); for (Edge property : edges) { if (property.cLeft.equals(node)) { nodes.add(property); } } return nodes.toArray(new Edge[nodes.size()]); } public Edge[] getProperties(String left, String right) { final List<Edge> nodes = new ArrayList<>(); for (Edge property : edges) { if (property.cLeft.equals(left) && property.cRight.equals(right)) { nodes.add(property); } } return nodes.toArray(new Edge[nodes.size()]); } public Edge[] getMaxSpanningTree() { final Edge[] edges = getEdges(); Arrays.sort(edges); final Set<String> coveredNodes = new HashSet<>(); final List<Edge> out = new ArrayList<>(); for (Edge edge : edges) { if (!coveredNodes.contains(edge.cLeft) || !coveredNodes.contains(edge.cRight)) { out.add(edge); coveredNodes.add(edge.cLeft); coveredNodes.add(edge.cRight); } } return out.toArray(new Edge[out.size()]); } public boolean isConnected(Edge[] edges) { final Set<String> visited = new HashSet<>(Arrays.asList(breadthFirst(edges[0].cLeft, edges))); final Set<String> allNodes = new HashSet<>(Arrays.asList(getNodes())); final Set<String> difference = Sets.difference(allNodes, visited); return difference.isEmpty(); } public Level[] buildLevels(Edge[] edges) { if (!isConnected(edges)) throw new IllegalArgumentException("Edges must be connected."); final List<List<Edge>> sortedEdges = sortPathDepthFirst(edges[0].cLeft, new ArrayList<>(Arrays.asList(edges))); final Level[] levels = new Level[sortedEdges.size()]; int i = 0; for (List<Edge> sortedEdge : sortedEdges) { boolean revert = i > 1 && i < edges.length - 1 && Sets.intersection(getRight(sortedEdges.get(i - 1)), getLeft(sortedEdges.get(i))).isEmpty(); levels[i++] = new Level(revert, sortedEdge.toArray(new Edge[sortedEdge.size()])); } return levels; } protected void add(String property, int occurrences, String classLeft, String classRight) { edges.add(new Edge(property, occurrences, classLeft, classRight)); } private Set<String> getLeft(List<Edge> edges) { final Set out = new HashSet(); for (Edge e : edges) { out.add(e.cLeft); } return out; } private Set<String> getRight(List<Edge> edges) { final Set out = new HashSet(); for (Edge e : edges) { out.add(e.cRight); } return out; } }