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

com.google.javascript.jscomp.graph.LinkedUndirectedGraph Maven / Gradle / Ivy

There is a newer version: 9.0.8
Show newest version
/*
 * Copyright 2008 The Closure Compiler Authors.
 *
 * 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.google.javascript.jscomp.graph;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * An undirected graph using linked list within nodes to store edge
 * information.
 *
 *
 * @param  Value type that the graph node stores.
 * @param  Value type that the graph edge stores.
 */
public final class LinkedUndirectedGraph
    extends UndiGraph implements GraphvizGraph {
  protected final Map> nodes = new LinkedHashMap<>();

  @Override
  public SubGraph newSubGraph() {
    return new SimpleSubGraph<>(this);
  }

  public static  LinkedUndirectedGraph create() {
    return new LinkedUndirectedGraph<>(true, true);
  }

  private final boolean useNodeAnnotations;
  private final boolean useEdgeAnnotations;

  protected LinkedUndirectedGraph(
      boolean useNodeAnnotations, boolean useEdgeAnnotations) {
    this.useNodeAnnotations = useNodeAnnotations;
    this.useEdgeAnnotations = useEdgeAnnotations;
  }

  @Override
  public void connect(N srcValue, E edgeValue, N destValue) {
    LinkedUndirectedGraphNode src = getNodeOrFail(srcValue);
    LinkedUndirectedGraphNode dest = getNodeOrFail(destValue);
    LinkedUndirectedGraphEdge edge =
        useEdgeAnnotations ?
        new AnnotatedLinkedUndirectedGraphEdge<>(src, edgeValue, dest) :
        new LinkedUndirectedGraphEdge<>(src, edgeValue, dest);
    src.getNeighborEdges().add(edge);
    dest.getNeighborEdges().add(edge);
  }

  @Override
  public void disconnect(N srcValue, N destValue) {
    LinkedUndirectedGraphNode src = getNodeOrFail(srcValue);
    LinkedUndirectedGraphNode dest = getNodeOrFail(destValue);
    for (UndiGraphEdge edge :
      getUndirectedGraphEdges(srcValue, destValue)) {
      src.getNeighborEdges().remove(edge);
      dest.getNeighborEdges().remove(edge);
    }
  }

  @Override
  public UndiGraphNode createUndirectedGraphNode(
      N nodeValue) {
    return nodes.computeIfAbsent(
        nodeValue,
        (N k) ->
            useNodeAnnotations
                ? new AnnotatedLinkedUndirectedGraphNode(k)
                : new LinkedUndirectedGraphNode(k));
  }

  @Override
  public List> getNeighborNodes(N value) {
    UndiGraphNode uNode = getUndirectedGraphNode(value);
    return ((LinkedUndirectedGraphNode) uNode).neighborList();
  }

  @SuppressWarnings("unchecked")
  @Override
  public List> getUndirectedGraphEdges(N n1, N n2) {
    UndiGraphNode dNode1 = nodes.get(n1);
    if (dNode1 == null) {
      return null;
    }
    UndiGraphNode dNode2 = nodes.get(n2);
    if (dNode2 == null) {
      return null;
    }
    List> edges = new ArrayList<>();
    for (UndiGraphEdge outEdge : dNode1.getNeighborEdges()) {
      if (outEdge.getNodeA() == dNode2 || outEdge.getNodeB() == dNode2) {
        edges.add(outEdge);
      }
    }
    return edges;
  }

  @Override
  public UndiGraphNode getUndirectedGraphNode(N nodeValue) {
    return nodes.get(nodeValue);
  }

  @Override
  public Collection> getUndirectedGraphNodes() {
    return Collections.unmodifiableCollection(nodes.values());
  }

  @Override
  public GraphNode createNode(N value) {
    return createUndirectedGraphNode(value);
  }

  @Override
  public List> getEdges(N n1, N n2) {
    return Collections.unmodifiableList(getUndirectedGraphEdges(n1, n2));
  }

  @SuppressWarnings("unchecked")
  @Override
  public List> getEdges() {
    List> result = new ArrayList<>();
    for (LinkedUndirectedGraphNode node : nodes.values()) {
      for (UndiGraphEdge edge : node.getNeighborEdges()) {
        if (edge.getNodeA() == node) {
          result.add(edge);
        }
      }
    }
    return result;
  }

  @Override
  public GraphEdge getFirstEdge(N n1, N n2) {
    UndiGraphNode dNode1 = getNodeOrFail(n1);
    UndiGraphNode dNode2 = getNodeOrFail(n2);
    for (UndiGraphEdge outEdge : dNode1.getNeighborEdges()) {
      if (outEdge.getNodeA() == dNode2 || outEdge.getNodeB() == dNode2) {
        return outEdge;
      }
    }
    return null;
  }

  @Override
  public GraphNode getNode(N value) {
    return getUndirectedGraphNode(value);
  }

  @Override
  public boolean isConnected(N n1, N n2) {
    return isConnected(n1, Predicates.alwaysTrue(), n2);
  }

  @Override
  public boolean isConnected(N n1, E e, N n2) {
    return isConnected(n1, Predicates.equalTo(e), n2);
  }

  private boolean isConnected(N n1, Predicate edgePredicate, N n2) {
    UndiGraphNode dNode1 = nodes.get(n1);
    if (dNode1 == null) {
      return false;
    }
    UndiGraphNode dNode2 = nodes.get(n2);
    if (dNode2 == null) {
      return false;
    }
    for (UndiGraphEdge outEdge : dNode1.getNeighborEdges()) {
      if ((outEdge.getNodeA() == dNode1 && outEdge.getNodeB() == dNode2) ||
          (outEdge.getNodeA() == dNode2 && outEdge.getNodeB() == dNode1)) {
        if (edgePredicate.apply(outEdge.getValue())) {
          return true;
        }
      }
    }
    return false;
  }

  @Override
  public List getGraphvizEdges() {
    List edgeList = new ArrayList<>();
    for (LinkedUndirectedGraphNode node : nodes.values()) {
      for (UndiGraphEdge edge : node.getNeighborEdges()) {
        if (edge.getNodeA() == node) {
          edgeList.add((GraphvizEdge) edge);
        }
      }
    }
    return edgeList;
  }

  @Override
  public String getName() {
    return "LinkedUndirectedGraph";
  }

  @Override
  public List getGraphvizNodes() {
    List nodeList = new ArrayList<>(nodes.size());
    for (LinkedUndirectedGraphNode node : nodes.values()) {
      nodeList.add(node);
    }
    return nodeList;
  }

  @Override
  public boolean isDirected() {
    return false;
  }

  @Override
  public Collection> getNodes() {
    return Collections.unmodifiableCollection(nodes.values());
  }

  @Override
  public int getNodeCount() {
    return nodes.size();
  }

  @Override
  public int getNodeDegree(N value) {
    UndiGraphNode uNode = getUndirectedGraphNode(value);
    if (uNode == null) {
      throw new IllegalArgumentException(value + " not found in graph");
    }
    return uNode.getNeighborEdges().size();
  }

  /**
   * An undirected graph node that stores outgoing edges and incoming edges as
   * an list within the node itself.
   */
  static class LinkedUndirectedGraphNode implements UndiGraphNode,
      GraphvizNode {

    private final List> neighborEdges = new ArrayList<>();
    private final N value;

    LinkedUndirectedGraphNode(N nodeValue) {
      this.value = nodeValue;
    }

    @Override
    public List> getNeighborEdges() {
      return neighborEdges;
    }

    @Override
    public Iterator> getNeighborEdgesIterator() {
      return neighborEdges.iterator();
    }

    @Override
    public  A getAnnotation() {
      throw new UnsupportedOperationException(
          "Graph initialized with node annotations turned off");
    }

    @Override
    public void setAnnotation(Annotation data) {
      throw new UnsupportedOperationException(
          "Graph initialized with node annotations turned off");
    }

    @Override
    public N getValue() {
      return value;
    }

    @Override
    public String getColor() {
      return "white";
    }

    @Override
    public String getId() {
      return "LDN" + hashCode();
    }

    @Override
    public String getLabel() {
      return String.valueOf(value);
    }

    private List> neighborList() {
      List> result = new ArrayList<>(neighborEdges.size());
      for (UndiGraphEdge edge : neighborEdges) {
        if (edge.getNodeA() == this) {
          result.add(edge.getNodeB());
        } else {
          result.add(edge.getNodeA());
        }
      }
      return result;
    }
  }

  /**
   * An undirected graph node with annotations.
   */
  static class AnnotatedLinkedUndirectedGraphNode
      extends LinkedUndirectedGraphNode {

    protected Annotation annotation;

    AnnotatedLinkedUndirectedGraphNode(N nodeValue) {
      super(nodeValue);
    }

    @SuppressWarnings("unchecked")
    @Override
    public  A getAnnotation() {
      return (A) annotation;
    }

    @Override
    public void setAnnotation(Annotation data) {
      annotation = data;
    }
  }

  /**
   * An undirected graph edge that stores two nodes at each edge.
   */
  static class LinkedUndirectedGraphEdge implements UndiGraphEdge,
      GraphvizEdge {

    private final UndiGraphNode nodeA;
    private final UndiGraphNode nodeB;
    protected final E value;

    LinkedUndirectedGraphEdge(UndiGraphNode nodeA, E edgeValue,
        UndiGraphNode nodeB) {
      this.value = edgeValue;
      this.nodeA = nodeA;
      this.nodeB = nodeB;
    }

    @Override
    public E getValue() {
      return value;
    }

    @Override
    public GraphNode getNodeA() {
      return nodeA;
    }

    @Override
    public GraphNode getNodeB() {
      return nodeB;
    }

    @Override
    public  A getAnnotation() {
      throw new UnsupportedOperationException(
          "Graph initialized with edge annotations turned off");
    }

    @Override
    public void setAnnotation(Annotation data) {
      throw new UnsupportedOperationException(
          "Graph initialized with edge annotations turned off");
    }

    @Override
    public String getColor() {
      return "black";
    }

    @Override
    public String getLabel() {
      return String.valueOf(value);
    }

    @SuppressWarnings("unchecked")
    @Override
    public String getNode1Id() {
      return ((LinkedUndirectedGraphNode) nodeA).getId();
    }

    @SuppressWarnings("unchecked")
    @Override
    public String getNode2Id() {
      return ((LinkedUndirectedGraphNode) nodeB).getId();
    }

    @Override
    public String toString() {
      return nodeA + " -- " + nodeB;
    }
  }

  /**
   * An annotated undirected graph edge..
   */
  static class AnnotatedLinkedUndirectedGraphEdge
      extends LinkedUndirectedGraphEdge {

    protected Annotation annotation;

    AnnotatedLinkedUndirectedGraphEdge(
        UndiGraphNode nodeA, E edgeValue,
        UndiGraphNode nodeB) {
      super(nodeA, edgeValue, nodeB);
    }

    @SuppressWarnings("unchecked")
    @Override
    public  A getAnnotation() {
      return (A) annotation;
    }

    @Override
    public void setAnnotation(Annotation data) {
      annotation = data;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy