Skip to content

Commit

Permalink
moditect#27 Making Node a self-referential interface type, allowing f…
Browse files Browse the repository at this point in the history
…or specific sub-types
  • Loading branch information
gunnarmorling committed Jan 26, 2019
1 parent 9a69924 commit b3e1488
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 166 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@
/**
* @author Gerd Wütherich (gw@code-kontor.io)
*/
public class Dependency {
public class Dependency<T extends Node<T>> {

private final Node to;
private final T to;
private final int aggregatedWeight;

public Dependency(Node to, int aggregatedWeight) {
public Dependency(T to, int aggregatedWeight) {
this.to = to;
this.aggregatedWeight = aggregatedWeight;
}

public Node getTo() {
public T getTo() {
return to;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package org.moditect.deptective.internal.graph;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
Expand All @@ -42,8 +41,8 @@ public class GraphUtils {
* contain just a single node. If you want to detect 'real' cycle (size > 1) please use
* {@link GraphUtils#detectCycles(Collection)}.
*/
public static List<List<Node>> detectStronglyConnectedComponents(Collection<Node> nodes) {
return new Tarjan<>().detectStronglyConnectedComponents(Objects.requireNonNull(nodes));
public static <T extends Node<T>> List<List<T>> detectStronglyConnectedComponents(Collection<T> nodes) {
return new Tarjan<T>().detectStronglyConnectedComponents(Objects.requireNonNull(nodes));
}

/**
Expand All @@ -52,8 +51,8 @@ public static List<List<Node>> detectStronglyConnectedComponents(Collection<Node
* @param nodes
* @return a list of strongly connected components (SCCs) with a size > 1.
*/
public static List<List<Node>> detectCycles(Collection<Node> nodes) {
return new Tarjan<>().detectStronglyConnectedComponents(nodes).stream().filter(cycle -> cycle.size() > 1)
public static <T extends Node<T>> List<List<T>> detectCycles(Collection<T> nodes) {
return new Tarjan<T>().detectStronglyConnectedComponents(nodes).stream().filter(cycle -> cycle.size() > 1)
.collect(Collectors.toList());
}

Expand All @@ -63,9 +62,9 @@ public static List<List<Node>> detectCycles(Collection<Node> nodes) {
* @param nodes the collection of nodes
* @return
*/
public static IDependencyStructureMatrix createDependencyStructureMatrix(
Collection<Node> nodes) {
return new DependencyStructureMatrix(nodes);
public static <T extends Node<T>> IDependencyStructureMatrix<T> createDependencyStructureMatrix(
Collection<T> nodes) {
return new DependencyStructureMatrix<T>(nodes);
}

/**
Expand All @@ -75,23 +74,12 @@ public static IDependencyStructureMatrix createDependencyStructureMatrix(
* @param nodes the collection of nodes
* @return the adjacency matrix for the given list of nodes
*/
public static int[][] computeAdjacencyMatrix(List<Node> nodes) {
public static <T extends Node<T>> int[][] computeAdjacencyMatrix(List<T> nodes) {
Objects.requireNonNull(nodes);
return computeAdjacencyMatrix(nodes.toArray(new Node[nodes.size()]));
}

/**
* An adjacency matrix is a square matrix used to represent a finite graph. The elements of the matrix
* indicate whether pairs of vertices are connected (adjacent) or not in the graph.
*
* @param nodes the array of nodes
* @return the adjacency matrix for the given list of nodes
*/
public static int[][] computeAdjacencyMatrix(Node... nodes) {
int[][] result = new int[nodes.length][nodes.length];
int[][] result = new int[nodes.size()][nodes.size()];
for (int i = 0; i < result.length; i++) {
for (int j = 0; j < result.length; j++) {
Dependency dependency = nodes[i].getOutgoingDependencyTo(nodes[j]);
Dependency<T> dependency = nodes.get(i).getOutgoingDependencyTo(nodes.get(j));
result[i][j] = dependency != null ? dependency.getAggregatedWeight() : 0;
}
}
Expand All @@ -105,40 +93,28 @@ public static int[][] computeAdjacencyMatrix(Node... nodes) {
* @param nodes the array of nodes
* @return the adjacency list for the given list of nodes
*/
public static int[][] computeAdjacencyList(Collection<Node> nodes) {
Objects.requireNonNull(nodes);
return computeAdjacencyList(nodes.toArray(new Node[nodes.size()]));
}

/**
* An adjacency list is a collection of (unordered) lists used to represent a finite graph. Each list
* describes the set of neighbors of a node.
*
* @param nodes the array of nodes
* @return the adjacency list for the given list of nodes
*/
public static int[][] computeAdjacencyList(Node... nodes) {
public static <T extends Node<T>>int[][] computeAdjacencyList(Collection<T> nodes) {

int[][] matrix;

// prepare
int i = 0;
Map<Node, Integer> map = new HashMap<Node, Integer>();
for (Node iArtifact : nodes) {
Map<T, Integer> map = new HashMap<T, Integer>();
for (T iArtifact : nodes) {
map.put(iArtifact, i);
i++;
}
matrix = new int[nodes.length][];
matrix = new int[map.size()][];

for (Node node : nodes) {
Collection<Dependency> dependencies = node.getOutgoingDependenciesTo(Arrays.asList(nodes));
for (T node : nodes) {
Collection<Dependency<T>> dependencies = node.getOutgoingDependenciesTo(nodes);
if (dependencies == null) {
dependencies = Collections.emptyList();
}
int index = map.get(node);
matrix[index] = new int[dependencies.size()];
int count = 0;
for (Dependency dependency : dependencies) {
for (Dependency<?> dependency : dependencies) {
matrix[index][count] = map.get(dependency.getTo());
count++;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
/**
* @author Gerd W&uuml;therich (gw@code-kontor.io)
*/
public interface IDependencyStructureMatrix {
public interface IDependencyStructureMatrix <T extends Node<T>> {

List<Node> getOrderedNodes();
List<T> getOrderedNodes();

List<Dependency> getUpwardDependencies();
List<Dependency<T>> getUpwardDependencies();

List<List<Node>> getCycles();
List<List<T>> getCycles();

boolean isCellInCycle(int i, int j);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@
*/
public interface INodeSorter {

SortResult sort(List<Node> node);
<T extends Node<T>> SortResult<T> sort(List<T> node);

public interface SortResult {
public interface SortResult <T extends Node<T>> {

List<Node> getOrderedNodes();
List<T> getOrderedNodes();

List<Dependency> getUpwardsDependencies();
List<Dependency<T>> getUpwardsDependencies();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,86 +16,23 @@
package org.moditect.deptective.internal.graph;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
* @author Gerd W&uuml;therich (gw@code-kontor.io)
*/
public class Node {
public interface Node<T extends Node<T>> {

private Map<Node, Dependency> outgoingDependencies;
private final String id;

public Node(String id) {
this.id = Objects.requireNonNull(id);
}

public String getId() {
return id;
}

public Dependency getOutgoingDependencyTo(Node node) {
if (!hasOutgoingDependencies()) {
return null;
}

return outgoingDependencies.get(node);
}

public Set<Dependency> getOutgoingDependenciesTo(Collection<Node> nodes) {
return Objects.requireNonNull(nodes).stream()
.map(node -> getOutgoingDependencyTo(node))
.filter(dep -> dep != null)
.collect(Collectors.toSet());
}

public boolean hasOutgoingDependencies() {
return outgoingDependencies != null && !outgoingDependencies.isEmpty();
default Set<Dependency<T>> getOutgoingDependenciesTo(Collection<T> nodes) {
return nodes.stream()
.map(c -> getOutgoingDependencyTo(c))
.filter(Objects::nonNull)
.collect(Collectors.toSet());
}

public void addOutgoingDependency(Node to, int aggregatedWeight) {
outgoingDependencies().put(to, new Dependency(to, aggregatedWeight));
}
Dependency<T> getOutgoingDependencyTo(T node);

@Override
public String toString() {
return "Node [id=" + id + "]";
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (id == null) {
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
return true;
}

private Map<Node, Dependency> outgoingDependencies() {
if (outgoingDependencies == null) {
outgoingDependencies = new HashMap<>();
}
return outgoingDependencies;
}
boolean hasOutgoingDependencies();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* Copyright 2019 The ModiTect 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 org.moditect.deptective.internal.graph;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
* @author Gerd W&uuml;therich (gw@code-kontor.io)
*/
public class SimpleNode implements Node<SimpleNode> {

private Map<SimpleNode, Dependency<SimpleNode>> outgoingDependencies;
private final String id;

public SimpleNode(String id) {
this.id = Objects.requireNonNull(id);
}

public String getId() {
return id;
}

@Override
public Dependency<SimpleNode> getOutgoingDependencyTo(SimpleNode node) {
if (!hasOutgoingDependencies()) {
return null;
}

return outgoingDependencies.get(node);
}

@Override
public boolean hasOutgoingDependencies() {
return outgoingDependencies != null && !outgoingDependencies.isEmpty();
}

public void addOutgoingDependency(SimpleNode to, int aggregatedWeight) {
outgoingDependencies().put(to, new Dependency<>(to, aggregatedWeight));
}

@Override
public String toString() {
return "SimpleNode [id=" + id + "]";
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SimpleNode other = (SimpleNode) obj;
if (id == null) {
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
return true;
}

private Map<SimpleNode, Dependency<SimpleNode>> outgoingDependencies() {
if (outgoingDependencies == null) {
outgoingDependencies = new HashMap<>();
}
return outgoingDependencies;
}
}
Loading

0 comments on commit b3e1488

Please sign in to comment.