added a working test with inner/outer graph

Change-Id: Ia1b4f6ed3ed96880e4d78b72373c93d2d34e99cd
This commit is contained in:
Axel Uhl committed 2019-07-15 00:07:17 +02:00
1 parent 1b15154bbc
commit eb39573ce2
3 files changed
+142 -2

No files matched your search

@@ -1,9 +1,13 @@
package com.sap.sailing.windestimation.aggregator.msthmm;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -11,7 +15,10 @@ import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.windestimation.aggregator.msthmm.graph.DijkstraShortestPathFinderImpl;
import com.sap.sailing.windestimation.aggregator.msthmm.graph.ElementAdjacencyQualityMetric;
import com.sap.sailing.windestimation.aggregator.msthmm.graph.ElementWithQuality;
import com.sap.sailing.windestimation.aggregator.msthmm.graph.GroupOutOfWhichToPickTheBestElement;
import com.sap.sailing.windestimation.aggregator.msthmm.graph.InnerGraphSuccessorSupplier;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.NamedImpl;
@@ -38,6 +45,37 @@ public class DijkstraTest {
}
}
private static class CompositeTreeNode implements GroupOutOfWhichToPickTheBestElement<Node, CompositeTreeNode> {
private final CompositeTreeNode parent;
private final Node[] elements;
private final Set<CompositeTreeNode> children;
public CompositeTreeNode(CompositeTreeNode parent, Node... elements) {
this.parent = parent;
this.elements = elements;
this.children = new HashSet<>();
}
@Override
public CompositeTreeNode getParent() {
return parent;
}
@Override
public Iterable<CompositeTreeNode> getChildren() {
return Collections.unmodifiableCollection(children);
}
@Override
public Iterable<Node> getElements() {
return Arrays.asList(elements);
}
public boolean addChild(CompositeTreeNode child) {
return this.children.add(child);
}
}
@Before
public void setUp() {
dijkstra = new DijkstraShortestPathFinderImpl<DijkstraTest.Node>();
@@ -47,6 +85,77 @@ public class DijkstraTest {
edgeQuality = new HashMap<>();
}
@Test
public void testSimpleCompositeTree() {
// set up overarching tree structure:
// root
// |
// level1
// /\
// level2Left level2Right
// | |
// level3Left level3Right
// Each of these tree nodes contains two inner graph nodes
final CompositeTreeNode root = new CompositeTreeNode(/* parent */ null, new Node("Root1", 0.5), new Node("Root2", 0.5));
final CompositeTreeNode level1 = new CompositeTreeNode(/* parent */ root, new Node("L1_1", 0.5), new Node("L1_2", 0.5));
root.addChild(level1);
final CompositeTreeNode level2Left = new CompositeTreeNode(/* parent */ level1, new Node("L2L1", 0.1), new Node("L2L2", 0.9));
level1.addChild(level2Left);
final CompositeTreeNode level2Right = new CompositeTreeNode(/* parent */ level1, new Node("L2R1", 0.9), new Node("L2R2", 0.1));
level1.addChild(level2Right);
final CompositeTreeNode level3Left = new CompositeTreeNode(/* parent */ level2Left, new Node("L3L1", 0.1), new Node("L3L2", 0.9));
level2Left.addChild(level3Left);
final CompositeTreeNode level3Right = new CompositeTreeNode(/* parent */ level2Right, new Node("L3R1", 0.9), new Node("L3R2", 0.1));
level2Right.addChild(level3Right);
// now set up the qualities of the edges connecting the inner nodes; simple model:
// staying on the same inner node index is good (quality 0.9), changing node index is bad (quality 0.1);
// this way, at the junction represented by level1 the path coming up from level2Left with its
// preferred __L2 nodes should end up in L1_2, whereas the path coming up from level2Right with its
// preferred __R1 nodes should end up in L1_1.
setEdgeQuality(level3Left, 0, level2Left, 0, 0.9);
setEdgeQuality(level3Left, 0, level2Left, 1, 0.1);
setEdgeQuality(level3Left, 1, level2Left, 0, 0.1);
setEdgeQuality(level3Left, 1, level2Left, 1, 0.9);
setEdgeQuality(level3Right, 0, level2Right, 0, 0.9);
setEdgeQuality(level3Right, 0, level2Right, 1, 0.1);
setEdgeQuality(level3Right, 1, level2Right, 0, 0.1);
setEdgeQuality(level3Right, 1, level2Right, 1, 0.9);
setEdgeQuality(level2Left, 0, level1, 0, 0.9);
setEdgeQuality(level2Left, 0, level1, 1, 0.1);
setEdgeQuality(level2Left, 1, level1, 0, 0.1);
setEdgeQuality(level2Left, 1, level1, 1, 0.9);
setEdgeQuality(level2Right, 0, level1, 0, 0.9);
setEdgeQuality(level2Right, 0, level1, 1, 0.1);
setEdgeQuality(level2Right, 1, level1, 0, 0.1);
setEdgeQuality(level2Right, 1, level1, 1, 0.9);
setEdgeQuality(level1, 0, root, 0, 0.9);
setEdgeQuality(level1, 0, root, 1, 0.1);
setEdgeQuality(level1, 1, root, 0, 0.1);
setEdgeQuality(level1, 1, root, 1, 0.9);
// now have the inner nodes connected among each other according to the overarching tree structure...
final InnerGraphSuccessorSupplier<Node, CompositeTreeNode> successorSupplier = new InnerGraphSuccessorSupplier<>(
()->root, nodeName->new Node(nodeName, 1.0));
// the edge qualities for the additional artificial nodes will all default to 1.0
// ...and solve the inner graph's shortest path problem, once for each artificial leaf:
final Iterable<Node> bestPathStartingAtLevel3Left = new DijkstraShortestPathFinderImpl<Node>().getShortestPath(
successorSupplier.getArtificialLeaf(level3Left), successorSupplier.getArtificialRoot(),
successorSupplier, getEdgeQualitySupplier());
final Iterable<Node> bestPathStartingAtLevel3Right = new DijkstraShortestPathFinderImpl<Node>().getShortestPath(
successorSupplier.getArtificialLeaf(level3Right), successorSupplier.getArtificialRoot(),
successorSupplier, getEdgeQualitySupplier());
// We expect the two solutions to provide different best inner nodes for the converging level1 node.
// For the indices, note that 0 denotes the artificial leaf node, so index 1 denotes the inner
// level3 node selected, index 2 the inner level2 node, and index 3 the inner level1 node which is
// what we'd like to compare:
assertNotSame(Util.get(bestPathStartingAtLevel3Left, 3), Util.get(bestPathStartingAtLevel3Right, 3));
}
private void setEdgeQuality(CompositeTreeNode fromLevel, int fromInnerNodeZeroBased, CompositeTreeNode toLevel,
int toInnerNodeZeroBased, double quality) {
edgeQuality.put(new Pair<>(Util.get(fromLevel.getElements(), fromInnerNodeZeroBased),
Util.get(toLevel.getElements(), toInnerNodeZeroBased)), quality);
}
@Test
public void testBasicDijkstra() {
edge(startNode, endNode, 1.0);
@@ -57,7 +166,19 @@ public class DijkstraTest {
private Iterable<Node> getShortestPath() {
return dijkstra.getShortestPath(startNode, endNode,
n -> successors.get(n), (n1, n2) -> edgeQuality.get(new Pair<>(n1, n2)));
n -> successors.get(n), getEdgeQualitySupplier());
}
/**
* Returns an {@link ElementAdjacencyQualityMetric} that etrieves the quality from {@link #edgeQuality} and defaults
* to {@code 1.0} if no other quality definition is found in {@link #edgeQuality} for the node pair provided.
*/
private ElementAdjacencyQualityMetric<Node> getEdgeQualitySupplier() {
return (n1, n2) -> {
final Pair<Node, Node> nodes = new Pair<>(n1, n2);
final Double quality = edgeQuality.get(new Pair<>(n1, n2));
return quality == null ? 1.0 : quality;
};
}
@Test
@@ -77,10 +77,11 @@ implements Function<T, Iterable<T>> {
innerChildElements = Collections.singleton(artificialLeaf);
} else {
final Set<T> allInnerChildNodes = new HashSet<>();
for (final GroupOutOfWhichToPickTheBestElement<T, G> child : node.getChildren()) {
for (final G child : node.getChildren()) {
for (final T innerChildElement : child.getElements()) {
allInnerChildNodes.add(innerChildElement);
}
addAllEdges(child);
}
innerChildElements = allInnerChildNodes;
}
@@ -95,4 +96,21 @@ implements Function<T, Iterable<T>> {
public Iterable<T> apply(T t) {
return successors.get(t);
}
/**
* @return the artificial single root node that is parent of all of the
* {@link GroupOutOfWhichToPickTheBestElement#getElements() elements} of the {@link Tree#getRoot() root} of
* the {@link Tree} passed to this object's constructor.
*/
public T getArtificialRoot() {
return artificialRoot;
}
/**
* @return the artificial leaf node for which all {@link GroupOutOfWhichToPickTheBestElement#getElements() elements}
* of the {@code treeLeafNode} are configured as successors.
*/
public T getArtificialLeaf(G treeLeafNode) {
return artificialLeaves.get(treeLeafNode);
}
}
@@ -7,6 +7,7 @@ package com.sap.sailing.windestimation.aggregator.msthmm.graph;
*
* @param <TN>
*/
@FunctionalInterface
public interface Tree<TN extends TreeNode<? extends TN>> {
TN getRoot();
}