Committed by
Gerrit Code Review
Disjoint Path Pairs (Suurballe) utils
Change-Id: Ie5895899818ea9d6eacf66cbb589ddf33fa3f89d Disjoint Path Pairs (Suurballe) utils Change-Id: Ie5895899818ea9d6eacf66cbb589ddf33fa3f89d Disjoint Path Pairs (SRLG with GA) utils Change-Id: If072df987621add385ae785f10c8d0a9e45ad559
Showing
8 changed files
with
1193 additions
and
0 deletions
| 1 | +/* | ||
| 2 | + * Copyright 2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +package org.onlab.graph; | ||
| 19 | + | ||
| 20 | +import java.util.List; | ||
| 21 | +import java.util.Objects; | ||
| 22 | +import java.util.Set; | ||
| 23 | + | ||
| 24 | +import static com.google.common.collect.ImmutableSet.of; | ||
| 25 | +import static com.google.common.base.MoreObjects.toStringHelper; | ||
| 26 | + | ||
| 27 | + | ||
| 28 | +public class DisjointPathPair<V extends Vertex, E extends Edge<V>> implements Path<V, E> { | ||
| 29 | + public Path<V, E> path1, path2; | ||
| 30 | + boolean usingPath1 = true; | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * Creates a Disjoint Path Pair from two paths. | ||
| 34 | + * | ||
| 35 | + * @param p1 first path | ||
| 36 | + * @param p2 second path | ||
| 37 | + */ | ||
| 38 | + public DisjointPathPair(Path<V, E> p1, Path<V, E> p2) { | ||
| 39 | + path1 = p1; | ||
| 40 | + path2 = p2; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + @Override | ||
| 44 | + public V src() { | ||
| 45 | + return path1.src(); | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + @Override | ||
| 49 | + public V dst() { | ||
| 50 | + return path1.dst(); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + @Override | ||
| 54 | + public double cost() { | ||
| 55 | + if (!hasBackup()) { | ||
| 56 | + return path1.cost(); | ||
| 57 | + } | ||
| 58 | + return path1.cost() + path2.cost(); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + @Override | ||
| 62 | + public List<E> edges() { | ||
| 63 | + if (usingPath1 || !hasBackup()) { | ||
| 64 | + return path1.edges(); | ||
| 65 | + } else { | ||
| 66 | + return path2.edges(); | ||
| 67 | + } | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + /** | ||
| 71 | + * Checks if this path pair contains a backup/secondary path. | ||
| 72 | + * | ||
| 73 | + * @return boolean representing whether it has backup | ||
| 74 | + */ | ||
| 75 | + public boolean hasBackup() { | ||
| 76 | + return path2 != null && path2.edges() != null; | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + @Override | ||
| 80 | + public String toString() { | ||
| 81 | + return toStringHelper(this) | ||
| 82 | + .add("src", src()) | ||
| 83 | + .add("dst", dst()) | ||
| 84 | + .add("cost", cost()) | ||
| 85 | + .add("edges", edges()) | ||
| 86 | + .toString(); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + @Override | ||
| 90 | + public int hashCode() { | ||
| 91 | + Set<Path<V, E>> paths; | ||
| 92 | + if (!hasBackup()) { | ||
| 93 | + paths = of(path1); | ||
| 94 | + } else { | ||
| 95 | + paths = of(path1, path2); | ||
| 96 | + } | ||
| 97 | + return Objects.hash(paths); | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + @Override | ||
| 101 | + public boolean equals(Object obj) { | ||
| 102 | + if (this == obj) { | ||
| 103 | + return true; | ||
| 104 | + } | ||
| 105 | + if (obj instanceof DisjointPathPair) { | ||
| 106 | + final DisjointPathPair other = (DisjointPathPair) obj; | ||
| 107 | + return Objects.equals(this.src(), other.src()) && | ||
| 108 | + Objects.equals(this.dst(), other.dst()) && | ||
| 109 | + (Objects.equals(this.path1, other.path1) && | ||
| 110 | + Objects.equals(this.path2, other.path2)) || | ||
| 111 | + (Objects.equals(this.path1, other.path2) && | ||
| 112 | + Objects.equals(this.path2, other.path1)); | ||
| 113 | + } | ||
| 114 | + return false; | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | + /** | ||
| 118 | + * Returns number of paths inside this path pair object. | ||
| 119 | + * | ||
| 120 | + * @return number of paths | ||
| 121 | + */ | ||
| 122 | + public int size() { | ||
| 123 | + if (hasBackup()) { | ||
| 124 | + return 2; | ||
| 125 | + } | ||
| 126 | + return 1; | ||
| 127 | + } | ||
| 128 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +package org.onlab.graph; | ||
| 19 | + | ||
| 20 | +import java.util.List; | ||
| 21 | +import java.util.Objects; | ||
| 22 | +import java.util.Set; | ||
| 23 | + | ||
| 24 | +import static com.google.common.collect.ImmutableSet.of; | ||
| 25 | +import static com.google.common.base.MoreObjects.toStringHelper; | ||
| 26 | + | ||
| 27 | + | ||
| 28 | +public class DisjointPathPair<V extends Vertex, E extends Edge<V>> implements Path<V, E> { | ||
| 29 | + public Path<V, E> path1, path2; | ||
| 30 | + boolean usingPath1 = true; | ||
| 31 | + | ||
| 32 | +<<<<<<< HEAD | ||
| 33 | + /** | ||
| 34 | + * Creates a Disjoint Path Pair from two paths. | ||
| 35 | + * | ||
| 36 | + * @param p1 first path | ||
| 37 | + * @param p2 second path | ||
| 38 | + */ | ||
| 39 | +======= | ||
| 40 | +>>>>>>> Disjoint Path Pairs (Suurballe) utils | ||
| 41 | + public DisjointPathPair(Path<V, E> p1, Path<V, E> p2) { | ||
| 42 | + path1 = p1; | ||
| 43 | + path2 = p2; | ||
| 44 | + } | ||
| 45 | +<<<<<<< HEAD | ||
| 46 | + | ||
| 47 | + @Override | ||
| 48 | +======= | ||
| 49 | +>>>>>>> Disjoint Path Pairs (Suurballe) utils | ||
| 50 | + public V src() { | ||
| 51 | + return path1.src(); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | +<<<<<<< HEAD | ||
| 55 | + @Override | ||
| 56 | + public V dst() { | ||
| 57 | + return path1.dst(); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + @Override | ||
| 61 | +======= | ||
| 62 | + public V dst() { | ||
| 63 | + return path1.dst(); | ||
| 64 | + } | ||
| 65 | +>>>>>>> Disjoint Path Pairs (Suurballe) utils | ||
| 66 | + public double cost() { | ||
| 67 | + if (!hasBackup()) { | ||
| 68 | + return path1.cost(); | ||
| 69 | + } | ||
| 70 | + return path1.cost() + path2.cost(); | ||
| 71 | + } | ||
| 72 | +<<<<<<< HEAD | ||
| 73 | + | ||
| 74 | + @Override | ||
| 75 | +======= | ||
| 76 | +>>>>>>> Disjoint Path Pairs (Suurballe) utils | ||
| 77 | + public List<E> edges() { | ||
| 78 | + if (usingPath1 || !hasBackup()) { | ||
| 79 | + return path1.edges(); | ||
| 80 | + } else { | ||
| 81 | + return path2.edges(); | ||
| 82 | + } | ||
| 83 | + } | ||
| 84 | +<<<<<<< HEAD | ||
| 85 | + | ||
| 86 | + /** | ||
| 87 | + * Checks if this path pair contains a backup/secondary path. | ||
| 88 | + * | ||
| 89 | + * @return boolean representing whether it has backup | ||
| 90 | + */ | ||
| 91 | + public boolean hasBackup() { | ||
| 92 | + return path2 != null && path2.edges() != null; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + /** | ||
| 96 | + * Switches this disjoint path pair to using its backup path, instead of | ||
| 97 | + * using its primary. | ||
| 98 | + */ | ||
| 99 | + public void useBackup() { | ||
| 100 | + usingPath1 = !usingPath1; | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + @Override | ||
| 104 | +======= | ||
| 105 | + public boolean hasBackup() { | ||
| 106 | + return path2 != null && path2.edges() != null; | ||
| 107 | + } | ||
| 108 | + public void useBackup() { | ||
| 109 | + usingPath1 = !usingPath1; | ||
| 110 | + } | ||
| 111 | +>>>>>>> Disjoint Path Pairs (Suurballe) utils | ||
| 112 | + public String toString() { | ||
| 113 | + return toStringHelper(this) | ||
| 114 | + .add("src", src()) | ||
| 115 | + .add("dst", dst()) | ||
| 116 | + .add("cost", cost()) | ||
| 117 | + .add("edges", edges()) | ||
| 118 | + .toString(); | ||
| 119 | + } | ||
| 120 | +<<<<<<< HEAD | ||
| 121 | + | ||
| 122 | + @Override | ||
| 123 | +======= | ||
| 124 | +>>>>>>> Disjoint Path Pairs (Suurballe) utils | ||
| 125 | + public int hashCode() { | ||
| 126 | + Set<Path<V, E>> paths; | ||
| 127 | + if (!hasBackup()) { | ||
| 128 | + paths = of(path1); | ||
| 129 | + } else { | ||
| 130 | + paths = of(path1, path2); | ||
| 131 | + } | ||
| 132 | + return Objects.hash(paths); | ||
| 133 | + } | ||
| 134 | +<<<<<<< HEAD | ||
| 135 | + | ||
| 136 | + @Override | ||
| 137 | +======= | ||
| 138 | +>>>>>>> Disjoint Path Pairs (Suurballe) utils | ||
| 139 | + public boolean equals(Object obj) { | ||
| 140 | + if (this == obj) { | ||
| 141 | + return true; | ||
| 142 | + } | ||
| 143 | + if (obj instanceof DisjointPathPair) { | ||
| 144 | + final DisjointPathPair other = (DisjointPathPair) obj; | ||
| 145 | + return Objects.equals(this.src(), other.src()) && | ||
| 146 | + Objects.equals(this.dst(), other.dst()) && | ||
| 147 | + (Objects.equals(this.path1, other.path1) && | ||
| 148 | + Objects.equals(this.path2, other.path2)) || | ||
| 149 | + (Objects.equals(this.path1, other.path2) && | ||
| 150 | + Objects.equals(this.path2, other.path1)); | ||
| 151 | + } | ||
| 152 | + return false; | ||
| 153 | + } | ||
| 154 | +<<<<<<< HEAD | ||
| 155 | + | ||
| 156 | + /** | ||
| 157 | + * Returns number of paths inside this path pair object. | ||
| 158 | + * | ||
| 159 | + * @return number of paths | ||
| 160 | + */ | ||
| 161 | +======= | ||
| 162 | +>>>>>>> Disjoint Path Pairs (Suurballe) utils | ||
| 163 | + public int size() { | ||
| 164 | + if (hasBackup()) { | ||
| 165 | + return 2; | ||
| 166 | + } | ||
| 167 | + return 1; | ||
| 168 | + } | ||
| 169 | +} |
| 1 | +package org.onlab.graph; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * Interface representing an "organism": a specific solution | ||
| 5 | + * to a problem where solutions can be evaluated in terms | ||
| 6 | + * of fitness. These organisms can be used to represent any | ||
| 7 | + * class of problem that genetic algorithms can be run on. | ||
| 8 | + */ | ||
| 9 | +interface GAOrganism { | ||
| 10 | + /** | ||
| 11 | + * A fitness function that determines how | ||
| 12 | + * optimal a given organism is. | ||
| 13 | + * | ||
| 14 | + * @return fitness of organism | ||
| 15 | + */ | ||
| 16 | + double fitness(); | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * A method that slightly mutates an organism. | ||
| 20 | + */ | ||
| 21 | + void mutate(); | ||
| 22 | + | ||
| 23 | + /** | ||
| 24 | + * Creates a new random organism. | ||
| 25 | + * | ||
| 26 | + * @return random GAOrganism | ||
| 27 | + */ | ||
| 28 | + GAOrganism random(); | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * Returns a child organism that is the result | ||
| 32 | + * of "crossing" this organism with another. | ||
| 33 | + * | ||
| 34 | + * @param other Other organism to cross with | ||
| 35 | + * @return child organism | ||
| 36 | + */ | ||
| 37 | + GAOrganism crossWith(GAOrganism other); | ||
| 38 | +} |
| 1 | +package org.onlab.graph; | ||
| 2 | + | ||
| 3 | +import java.util.ArrayList; | ||
| 4 | +import java.util.Collections; | ||
| 5 | +import java.util.List; | ||
| 6 | +import java.util.Random; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * Represents a population of GAOrganisms. This class can be used | ||
| 10 | + * to run a genetic algorithm on the population and return the fittest solutions. | ||
| 11 | + */ | ||
| 12 | +class GAPopulation<Organism extends GAOrganism> extends ArrayList<Organism> { | ||
| 13 | + Random r = new Random(); | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * Steps the population through one generation. The 75% least fit | ||
| 17 | + * organisms are killed off and replaced with the children of the | ||
| 18 | + * 25% (as well as some "random" newcomers). | ||
| 19 | + */ | ||
| 20 | + void step() { | ||
| 21 | + Collections.sort(this, (org1, org2) -> { | ||
| 22 | + double d = org1.fitness() - org2.fitness(); | ||
| 23 | + if (d < 0) { | ||
| 24 | + return -1; | ||
| 25 | + } else if (d == 0) { | ||
| 26 | + return 0; | ||
| 27 | + } | ||
| 28 | + return 1; | ||
| 29 | + }); | ||
| 30 | + int maxSize = size(); | ||
| 31 | + for (int i = size() - 1; i > maxSize / 4; i--) { | ||
| 32 | + remove(i); | ||
| 33 | + } | ||
| 34 | + for (Organism org: this) { | ||
| 35 | + if (r.nextBoolean()) { | ||
| 36 | + org.mutate(); | ||
| 37 | + } | ||
| 38 | + } | ||
| 39 | + while (size() < maxSize * 4 / 5) { | ||
| 40 | + Organism org1 = get(r.nextInt(size())); | ||
| 41 | + Organism org2 = get(r.nextInt(size())); | ||
| 42 | + add((Organism) org1.crossWith(org2)); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + while (size() < maxSize) { | ||
| 46 | + Organism org1 = get(r.nextInt(size())); | ||
| 47 | + add((Organism) org1.random()); | ||
| 48 | + } | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * Runs GA for the specified number of iterations, and returns | ||
| 53 | + * a sample of the resulting population of solutions. | ||
| 54 | + * | ||
| 55 | + * @param generations Number of generations to run GA for | ||
| 56 | + * @param populationSize Population size of GA | ||
| 57 | + * @param sample Number of solutions to ask for | ||
| 58 | + * @param template Template GAOrganism to seed the population with | ||
| 59 | + * @return ArrayList containing sample number of organisms | ||
| 60 | + */ | ||
| 61 | + List<Organism> runGA(int generations, int populationSize, int sample, Organism template) { | ||
| 62 | + for (int i = 0; i < populationSize; i++) { | ||
| 63 | + add((Organism) template.random()); | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + for (int i = 0; i < generations; i++) { | ||
| 67 | + step(); | ||
| 68 | + } | ||
| 69 | + for (int i = size() - 1; i >= sample; i--) { | ||
| 70 | + remove(i); | ||
| 71 | + } | ||
| 72 | + return new ArrayList<>(this); | ||
| 73 | + } | ||
| 74 | +} | ||
| 75 | + |
| 1 | +/* | ||
| 2 | + * Copyright 2014 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +package org.onlab.graph; | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +import java.util.Map; | ||
| 22 | +import java.util.List; | ||
| 23 | +import java.util.HashMap; | ||
| 24 | +import java.util.HashSet; | ||
| 25 | +import java.util.Set; | ||
| 26 | +import java.util.Random; | ||
| 27 | + | ||
| 28 | + | ||
| 29 | +/** | ||
| 30 | + * SRLG Graph Search finds a pair of paths with disjoint risk groups; i.e | ||
| 31 | + * if one path goes through an edge in risk group 1, the other path will go | ||
| 32 | + * through no edges in risk group 1. | ||
| 33 | + */ | ||
| 34 | +public class SRLGGraphSearch<V extends Vertex, E extends Edge<V>> | ||
| 35 | + extends AbstractGraphPathSearch<V, E> { | ||
| 36 | + | ||
| 37 | + static final int ITERATIONS = 100; | ||
| 38 | + static final int POPSIZE = 50; | ||
| 39 | + | ||
| 40 | + boolean useSuurballe = false; | ||
| 41 | + | ||
| 42 | + static final double INF = 100000000.0; | ||
| 43 | + | ||
| 44 | + int numGroups; | ||
| 45 | + Map<E, Integer> riskGrouping; | ||
| 46 | + | ||
| 47 | + Graph<V, E> orig; | ||
| 48 | + V src, dst; | ||
| 49 | + EdgeWeight<V, E> weight; | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * Creates an SRLG graph search object with the given number | ||
| 53 | + * of groups and given risk mapping. | ||
| 54 | + * | ||
| 55 | + * @param groups the number of disjoint risk groups | ||
| 56 | + * @param grouping map linking edges to integral group assignments | ||
| 57 | + */ | ||
| 58 | + public SRLGGraphSearch(int groups, Map<E, Integer> grouping) { | ||
| 59 | + numGroups = groups; | ||
| 60 | + riskGrouping = grouping; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + /** | ||
| 64 | + * Creates an SRLG graph search object from a map, inferring | ||
| 65 | + * the number of groups and creating an integral mapping. | ||
| 66 | + * | ||
| 67 | + * @param grouping map linking edges to object group assignments, | ||
| 68 | + * with same-group status linked to equality | ||
| 69 | + */ | ||
| 70 | + public SRLGGraphSearch(Map<E, Object> grouping) { | ||
| 71 | + if (grouping == null) { | ||
| 72 | + useSuurballe = true; | ||
| 73 | + return; | ||
| 74 | + } | ||
| 75 | + numGroups = 0; | ||
| 76 | + HashMap<Object, Integer> tmpMap = new HashMap<>(); | ||
| 77 | + riskGrouping = new HashMap<>(); | ||
| 78 | + for (E key: grouping.keySet()) { | ||
| 79 | + Object value = grouping.get(key); | ||
| 80 | + if (!tmpMap.containsKey(value)) { | ||
| 81 | + tmpMap.put(value, numGroups); | ||
| 82 | + numGroups++; | ||
| 83 | + } | ||
| 84 | + riskGrouping.put(key, tmpMap.get(value)); | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + @Override | ||
| 89 | + public Result<V, E> search(Graph<V, E> graph, V src, V dst, | ||
| 90 | + EdgeWeight<V, E> weight, int maxPaths) { | ||
| 91 | + if (maxPaths == ALL_PATHS) { | ||
| 92 | + maxPaths = POPSIZE; | ||
| 93 | + } | ||
| 94 | + if (useSuurballe) { | ||
| 95 | + return new SuurballeGraphSearch<V, E>().search(graph, src, dst, weight, ALL_PATHS); | ||
| 96 | + } | ||
| 97 | + if (weight == null) { | ||
| 98 | + weight = edge -> 1; | ||
| 99 | + } | ||
| 100 | + checkArguments(graph, src, dst); | ||
| 101 | + orig = graph; | ||
| 102 | + this.src = src; | ||
| 103 | + this.dst = dst; | ||
| 104 | + this.weight = weight; | ||
| 105 | + List<Subset> best = new GAPopulation<Subset>() | ||
| 106 | + .runGA(ITERATIONS, POPSIZE, maxPaths, new Subset(new boolean[numGroups])); | ||
| 107 | + Set<DisjointPathPair> dpps = new HashSet<DisjointPathPair>(); | ||
| 108 | + for (Subset s: best) { | ||
| 109 | + dpps.addAll(s.buildPaths()); | ||
| 110 | + } | ||
| 111 | + Result<V, E> firstDijkstra = new DijkstraGraphSearch<V, E>() | ||
| 112 | + .search(orig, src, dst, weight, 1); | ||
| 113 | + return new Result<V, E>() { | ||
| 114 | + final DefaultResult search = (DefaultResult) firstDijkstra; | ||
| 115 | + | ||
| 116 | + public V src() { | ||
| 117 | + return src; | ||
| 118 | + } | ||
| 119 | + public V dst() { | ||
| 120 | + return dst; | ||
| 121 | + | ||
| 122 | + } | ||
| 123 | + public Set<Path<V, E>> paths() { | ||
| 124 | + Set<Path<V, E>> pathsD = new HashSet<>(); | ||
| 125 | + for (DisjointPathPair<V, E> path: dpps) { | ||
| 126 | + pathsD.add(path); | ||
| 127 | + } | ||
| 128 | + return pathsD; | ||
| 129 | + } | ||
| 130 | + public Map<V, Double> costs() { | ||
| 131 | + return search.costs(); | ||
| 132 | + | ||
| 133 | + } | ||
| 134 | + public Map<V, Set<E>> parents() { | ||
| 135 | + return search.parents(); | ||
| 136 | + | ||
| 137 | + } | ||
| 138 | + }; | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + //finds the shortest path in the graph given a subset of edge types to use | ||
| 142 | + private Result<V, E> findShortestPathFromSubset(boolean[] subset) { | ||
| 143 | + Graph<V, E> graph = orig; | ||
| 144 | + EdgeWeight<V, E> modified = new EdgeWeight<V, E>() { | ||
| 145 | + final boolean[] subsetF = subset; | ||
| 146 | + | ||
| 147 | + @Override | ||
| 148 | + public double weight(E edge) { | ||
| 149 | + if (subsetF[riskGrouping.get(edge)]) { | ||
| 150 | + return weight.weight(edge); | ||
| 151 | + } | ||
| 152 | + return INF; | ||
| 153 | + } | ||
| 154 | + }; | ||
| 155 | + | ||
| 156 | + Result<V, E> res = new DijkstraGraphSearch<V, E>().search(graph, src, dst, modified, 1); | ||
| 157 | + return res; | ||
| 158 | + } | ||
| 159 | + /** | ||
| 160 | + * A subset is a type of GA organism that represents a subset of allowed shortest | ||
| 161 | + * paths (and its complement). Its fitness is determined by the sum of the weights | ||
| 162 | + * of the first two shortest paths. | ||
| 163 | + */ | ||
| 164 | + class Subset implements GAOrganism { | ||
| 165 | + | ||
| 166 | + boolean[] subset; | ||
| 167 | + boolean[] not; | ||
| 168 | + Random r = new Random(); | ||
| 169 | + | ||
| 170 | + /** | ||
| 171 | + * Creates a Subset from the given subset array. | ||
| 172 | + * | ||
| 173 | + * @param sub subset array | ||
| 174 | + */ | ||
| 175 | + public Subset(boolean[] sub) { | ||
| 176 | + subset = sub.clone(); | ||
| 177 | + not = new boolean[subset.length]; | ||
| 178 | + for (int i = 0; i < subset.length; i++) { | ||
| 179 | + not[i] = !subset[i]; | ||
| 180 | + } | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | + @Override | ||
| 184 | + public double fitness() { | ||
| 185 | + Set<Path<V, E>> paths1 = findShortestPathFromSubset(subset).paths(); | ||
| 186 | + Set<Path<V, E>> paths2 = findShortestPathFromSubset(not).paths(); | ||
| 187 | + if (paths1.size() == 0 || paths2.size() == 0) { | ||
| 188 | + return INF; | ||
| 189 | + } | ||
| 190 | + return paths1.iterator().next().cost() + paths2.iterator().next().cost(); | ||
| 191 | + } | ||
| 192 | + | ||
| 193 | + @Override | ||
| 194 | + public void mutate() { | ||
| 195 | + int turns = r.nextInt((int) Math.sqrt(subset.length)); | ||
| 196 | + while (turns > 0) { | ||
| 197 | + int choose = r.nextInt(subset.length); | ||
| 198 | + subset[choose] = !subset[choose]; | ||
| 199 | + not[choose] = !not[choose]; | ||
| 200 | + turns--; | ||
| 201 | + } | ||
| 202 | + } | ||
| 203 | + | ||
| 204 | + @Override | ||
| 205 | + public GAOrganism crossWith(GAOrganism org) { | ||
| 206 | + if (!(org.getClass().equals(getClass()))) { | ||
| 207 | + return this; | ||
| 208 | + } | ||
| 209 | + Subset other = (Subset) (org); | ||
| 210 | + boolean[] sub = new boolean[subset.length]; | ||
| 211 | + for (int i = 0; i < subset.length; i++) { | ||
| 212 | + sub[i] = subset[i]; | ||
| 213 | + if (r.nextBoolean()) { | ||
| 214 | + sub[i] = other.subset[i]; | ||
| 215 | + } | ||
| 216 | + } | ||
| 217 | + return new Subset(sub); | ||
| 218 | + } | ||
| 219 | + | ||
| 220 | + @Override | ||
| 221 | + public GAOrganism random() { | ||
| 222 | + boolean[] sub = new boolean[subset.length]; | ||
| 223 | + for (int i = 0; i < sub.length; i++) { | ||
| 224 | + sub[i] = r.nextBoolean(); | ||
| 225 | + } | ||
| 226 | + return new Subset(sub); | ||
| 227 | + } | ||
| 228 | + | ||
| 229 | + /** | ||
| 230 | + * Builds the set of disjoint path pairs for a given subset | ||
| 231 | + * using Dijkstra's algorithm on both the subset and complement | ||
| 232 | + * and returning all pairs with one from each set. | ||
| 233 | + * | ||
| 234 | + * @return all shortest disjoint paths given this subset | ||
| 235 | + */ | ||
| 236 | + public Set<DisjointPathPair> buildPaths() { | ||
| 237 | + Set<DisjointPathPair> dpps = new HashSet<>(); | ||
| 238 | + for (Path<V, E> path1: findShortestPathFromSubset(subset).paths()) { | ||
| 239 | + if (path1.cost() >= INF) { | ||
| 240 | + continue; | ||
| 241 | + } | ||
| 242 | + for (Path<V, E> path2: findShortestPathFromSubset(not).paths()) { | ||
| 243 | + if (path2.cost() >= INF) { | ||
| 244 | + continue; | ||
| 245 | + } | ||
| 246 | + DisjointPathPair<V, E> dpp = new DisjointPathPair<>(path1, path2); | ||
| 247 | + dpps.add(dpp); | ||
| 248 | + } | ||
| 249 | + } | ||
| 250 | + return dpps; | ||
| 251 | + } | ||
| 252 | + } | ||
| 253 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onlab.graph; | ||
| 18 | + | ||
| 19 | +import java.util.ArrayList; | ||
| 20 | +import java.util.Set; | ||
| 21 | +import java.util.List; | ||
| 22 | +import java.util.Map; | ||
| 23 | +import java.util.HashMap; | ||
| 24 | +import java.util.HashSet; | ||
| 25 | +import java.util.stream.Collectors; | ||
| 26 | + | ||
| 27 | +/** | ||
| 28 | + * Suurballe shortest-path graph search algorithm capable of finding both | ||
| 29 | + * a shortest path, as well as a backup shortest path, between a source and a destination | ||
| 30 | + * such that the sum of the path lengths is minimized. | ||
| 31 | + */ | ||
| 32 | +public class SuurballeGraphSearch<V extends Vertex, E extends Edge<V>> extends DijkstraGraphSearch<V, E> { | ||
| 33 | + | ||
| 34 | + @Override | ||
| 35 | + public Result<V, E> search(Graph<V, E> graph, V src, V dst, | ||
| 36 | + EdgeWeight<V, E> weight, int maxPaths) { | ||
| 37 | + | ||
| 38 | + if (weight == null) { | ||
| 39 | + weight = edge -> 1; | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + List<DisjointPathPair<V, E>> dpps = new ArrayList<>(); | ||
| 43 | + | ||
| 44 | + final EdgeWeight weightf = weight; | ||
| 45 | + DefaultResult firstDijkstraS = (DefaultResult) super.search(graph, src, dst, weight, ALL_PATHS); | ||
| 46 | + DefaultResult firstDijkstra = (DefaultResult) super.search(graph, src, null, weight, ALL_PATHS); | ||
| 47 | + | ||
| 48 | + //choose an arbitrary shortest path to run Suurballe on | ||
| 49 | + Path<V, E> shortPath = null; | ||
| 50 | + if (firstDijkstraS.paths().size() == 0) { | ||
| 51 | + return firstDijkstraS; | ||
| 52 | + } | ||
| 53 | + for (Path p: firstDijkstraS.paths()) { | ||
| 54 | + shortPath = p; | ||
| 55 | + //transforms the graph so tree edges have 0 weight | ||
| 56 | + EdgeWeight<V, Edge<V>> modified = edge -> { | ||
| 57 | + if (classE().isInstance(edge)) { | ||
| 58 | + return weightf.weight((E) (edge)) + firstDijkstra.cost(edge.src()) | ||
| 59 | + - firstDijkstra.cost(edge.dst()); | ||
| 60 | + } | ||
| 61 | + return 0; | ||
| 62 | + }; | ||
| 63 | + EdgeWeight<V, E> modified2 = edge -> | ||
| 64 | + weightf.weight(edge) + firstDijkstra.cost(edge.src()) - firstDijkstra.cost(edge.dst()); | ||
| 65 | + | ||
| 66 | + //create a residual graph g' by removing all src vertices and reversing 0 length path edges | ||
| 67 | + MutableGraph<V, Edge<V>> gt = mutableCopy(graph); | ||
| 68 | + | ||
| 69 | + Map<Edge<V>, E> revToEdge = new HashMap<>(); | ||
| 70 | + graph.getEdgesTo(src).forEach(gt::removeEdge); | ||
| 71 | + for (E edge: shortPath.edges()) { | ||
| 72 | + gt.removeEdge(edge); | ||
| 73 | + Edge<V> reverse = new Edge<V>() { | ||
| 74 | + final Edge<V> orig = edge; | ||
| 75 | + public V src() { | ||
| 76 | + return orig.dst(); | ||
| 77 | + } | ||
| 78 | + public V dst() { | ||
| 79 | + return orig.src(); | ||
| 80 | + } | ||
| 81 | + public String toString() { | ||
| 82 | + return "ReversedEdge " + "src=" + src() + " dst=" + dst(); | ||
| 83 | + } | ||
| 84 | + }; | ||
| 85 | + revToEdge.put(reverse, edge); | ||
| 86 | + gt.addEdge(reverse); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + //rerun dijkstra on the temporary graph to get a second path | ||
| 90 | + Result<V, Edge<V>> secondDijkstra; | ||
| 91 | + secondDijkstra = new DijkstraGraphSearch<V, Edge<V>>().search(gt, src, dst, modified, ALL_PATHS); | ||
| 92 | + | ||
| 93 | + Path<V, Edge<V>> residualShortPath = null; | ||
| 94 | + if (secondDijkstra.paths().size() == 0) { | ||
| 95 | + dpps.add(new DisjointPathPair<V, E>(shortPath, null)); | ||
| 96 | + continue; | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + for (Path p2: secondDijkstra.paths()) { | ||
| 100 | + residualShortPath = p2; | ||
| 101 | + | ||
| 102 | + MutableGraph<V, E> roundTrip = mutableCopy(graph); | ||
| 103 | + | ||
| 104 | + List<E> tmp = roundTrip.getEdges().stream().collect(Collectors.toList()); | ||
| 105 | + | ||
| 106 | + tmp.forEach(roundTrip::removeEdge); | ||
| 107 | + | ||
| 108 | + shortPath.edges().forEach(roundTrip::addEdge); | ||
| 109 | + | ||
| 110 | + if (residualShortPath != null) { | ||
| 111 | + for (Edge<V> edge: residualShortPath.edges()) { | ||
| 112 | + if (classE().isInstance(edge)) { | ||
| 113 | + roundTrip.addEdge((E) edge); | ||
| 114 | + } else { | ||
| 115 | + roundTrip.removeEdge(revToEdge.get(edge)); | ||
| 116 | + } | ||
| 117 | + } | ||
| 118 | + } | ||
| 119 | + //Actually build the final result | ||
| 120 | + DefaultResult lastSearch = (DefaultResult) super.search(roundTrip, src, dst, weight, ALL_PATHS); | ||
| 121 | + Path<V, E> path1 = lastSearch.paths().iterator().next(); | ||
| 122 | + path1.edges().forEach(roundTrip::removeEdge); | ||
| 123 | + | ||
| 124 | + Set<Path<V, E>> bckpaths = super.search(roundTrip, src, dst, weight, ALL_PATHS).paths(); | ||
| 125 | + Path<V, E> backup = null; | ||
| 126 | + if (bckpaths.size() != 0) { | ||
| 127 | + backup = bckpaths.iterator().next(); | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + dpps.add(new DisjointPathPair<>(path1, backup)); | ||
| 131 | + } | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + for (int i = dpps.size() - 1; i > 0; i--) { | ||
| 135 | + if (dpps.get(i).size() <= 1) { | ||
| 136 | + dpps.remove(i); | ||
| 137 | + } | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + return new Result<V, E>() { | ||
| 141 | + final DefaultResult search = firstDijkstra; | ||
| 142 | + | ||
| 143 | + public V src() { | ||
| 144 | + return src; | ||
| 145 | + } | ||
| 146 | + public V dst() { | ||
| 147 | + return dst; | ||
| 148 | + } | ||
| 149 | + public Set<Path<V, E>> paths() { | ||
| 150 | + Set<Path<V, E>> pathsD = new HashSet<>(); | ||
| 151 | + int paths = 0; | ||
| 152 | + for (DisjointPathPair<V, E> path: dpps) { | ||
| 153 | + pathsD.add((Path<V, E>) path); | ||
| 154 | + paths++; | ||
| 155 | + if (paths == maxPaths) { | ||
| 156 | + break; | ||
| 157 | + } | ||
| 158 | + } | ||
| 159 | + return pathsD; | ||
| 160 | + } | ||
| 161 | + public Map<V, Double> costs() { | ||
| 162 | + return search.costs(); | ||
| 163 | + } | ||
| 164 | + public Map<V, Set<E>> parents() { | ||
| 165 | + return search.parents(); | ||
| 166 | + } | ||
| 167 | + }; | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + private Class<?> clazzV; | ||
| 171 | + | ||
| 172 | + public Class<?> classV() { | ||
| 173 | + return clazzV; | ||
| 174 | + } | ||
| 175 | + | ||
| 176 | + private Class<?> clazzE; | ||
| 177 | + | ||
| 178 | + public Class<?> classE() { | ||
| 179 | + return clazzE; | ||
| 180 | + } | ||
| 181 | + /** | ||
| 182 | + * Creates a mutable copy of an immutable graph. | ||
| 183 | + * | ||
| 184 | + * @param graph immutable graph | ||
| 185 | + * @return mutable copy | ||
| 186 | + */ | ||
| 187 | + public MutableGraph mutableCopy(Graph<V, E> graph) { | ||
| 188 | + clazzV = graph.getVertexes().iterator().next().getClass(); | ||
| 189 | + clazzE = graph.getEdges().iterator().next().getClass(); | ||
| 190 | + return new MutableAdjacencyListsGraph<V, E>(graph.getVertexes(), graph.getEdges()); | ||
| 191 | + } | ||
| 192 | +} | ||
| 193 | + |
| 1 | +/* | ||
| 2 | + * Copyright 2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onlab.graph; | ||
| 18 | + | ||
| 19 | +import org.junit.Test; | ||
| 20 | +import java.util.Set; | ||
| 21 | +import java.util.HashSet; | ||
| 22 | +import java.util.Map; | ||
| 23 | +import java.util.HashMap; | ||
| 24 | + | ||
| 25 | +import static com.google.common.collect.ImmutableSet.of; | ||
| 26 | +import static org.junit.Assert.assertTrue; | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | +/** | ||
| 31 | + * Test of the Suurballe backup path algorithm. | ||
| 32 | + */ | ||
| 33 | +public class SRLGGraphSearchTest extends BreadthFirstSearchTest { | ||
| 34 | + @Override | ||
| 35 | + protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() { | ||
| 36 | + return new SRLGGraphSearch<TestVertex, TestEdge>(null); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + public void setWeights() { | ||
| 40 | + weight = new EdgeWeight<TestVertex, TestEdge>() { | ||
| 41 | + @Override | ||
| 42 | + public double weight(TestEdge edge) { | ||
| 43 | + return edge.weight(); | ||
| 44 | + } | ||
| 45 | + }; | ||
| 46 | + } | ||
| 47 | + public void setDefaultWeights() { | ||
| 48 | + weight = null; | ||
| 49 | + } | ||
| 50 | + @Override | ||
| 51 | + public void defaultGraphTest() { | ||
| 52 | + | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + @Override | ||
| 56 | + public void defaultHopCountWeight() { | ||
| 57 | + | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + @Test | ||
| 61 | + public void onePathPair() { | ||
| 62 | + setDefaultWeights(); | ||
| 63 | + TestEdge aB = new TestEdge(A, B, 1); | ||
| 64 | + TestEdge bC = new TestEdge(B, C, 1); | ||
| 65 | + TestEdge aD = new TestEdge(A, D, 1); | ||
| 66 | + TestEdge dC = new TestEdge(D, C, 1); | ||
| 67 | + Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D), | ||
| 68 | + of(aB, bC, aD, dC)); | ||
| 69 | + Map<TestEdge, Integer> riskProfile = new HashMap<TestEdge, Integer>(); | ||
| 70 | + riskProfile.put(aB, 0); | ||
| 71 | + riskProfile.put(bC, 0); | ||
| 72 | + riskProfile.put(aD, 1); | ||
| 73 | + riskProfile.put(dC, 1); | ||
| 74 | + SRLGGraphSearch<TestVertex, TestEdge> search = | ||
| 75 | + new SRLGGraphSearch<TestVertex, TestEdge>(2, riskProfile); | ||
| 76 | + Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, C, weight, GraphPathSearch.ALL_PATHS).paths(); | ||
| 77 | + System.out.println("\n\n\n" + paths + "\n\n\n"); | ||
| 78 | + assertTrue("one disjoint path pair found", paths.size() == 1); | ||
| 79 | + checkIsDisjoint(paths.iterator().next(), riskProfile); | ||
| 80 | + } | ||
| 81 | + public void checkIsDisjoint(Path<TestVertex, TestEdge> p, Map<TestEdge, Integer> risks) { | ||
| 82 | + assertTrue("The path is not a DisjointPathPair", (p instanceof DisjointPathPair)); | ||
| 83 | + DisjointPathPair<TestVertex, TestEdge> q = (DisjointPathPair) p; | ||
| 84 | + Set<Integer> p1Risks = new HashSet<Integer>(); | ||
| 85 | + Set<Integer> p2Risks = new HashSet<Integer>(); | ||
| 86 | + for (TestEdge e: q.edges()) { | ||
| 87 | + p1Risks.add(risks.get(e)); | ||
| 88 | + } | ||
| 89 | + if (!q.hasBackup()) { | ||
| 90 | + return; | ||
| 91 | + } | ||
| 92 | + Path<TestVertex, TestEdge> pq = q.path2; | ||
| 93 | + for (TestEdge e: pq.edges()) { | ||
| 94 | + assertTrue("The paths are not disjoint", !p1Risks.contains(risks.get(e))); | ||
| 95 | + } | ||
| 96 | + } | ||
| 97 | + @Test | ||
| 98 | + public void complexGraphTest() { | ||
| 99 | + setDefaultWeights(); | ||
| 100 | + TestEdge aB = new TestEdge(A, B, 1); | ||
| 101 | + TestEdge bC = new TestEdge(B, C, 1); | ||
| 102 | + TestEdge aD = new TestEdge(A, D, 1); | ||
| 103 | + TestEdge dC = new TestEdge(D, C, 1); | ||
| 104 | + TestEdge cE = new TestEdge(C, E, 1); | ||
| 105 | + TestEdge bE = new TestEdge(B, E, 1); | ||
| 106 | + Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D, E), | ||
| 107 | + of(aB, bC, aD, dC, cE, bE)); | ||
| 108 | + Map<TestEdge, Integer> riskProfile = new HashMap<TestEdge, Integer>(); | ||
| 109 | + riskProfile.put(aB, 0); | ||
| 110 | + riskProfile.put(bC, 0); | ||
| 111 | + riskProfile.put(aD, 1); | ||
| 112 | + riskProfile.put(dC, 1); | ||
| 113 | + riskProfile.put(cE, 2); | ||
| 114 | + riskProfile.put(bE, 3); | ||
| 115 | + SRLGGraphSearch<TestVertex, TestEdge> search = | ||
| 116 | + new SRLGGraphSearch<TestVertex, TestEdge>(4, riskProfile); | ||
| 117 | + Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, E, weight, GraphPathSearch.ALL_PATHS).paths(); | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + @Test | ||
| 121 | + public void multiplePathGraphTest() { | ||
| 122 | + setDefaultWeights(); | ||
| 123 | + TestEdge aB = new TestEdge(A, B, 1); | ||
| 124 | + TestEdge bE = new TestEdge(B, E, 1); | ||
| 125 | + TestEdge aD = new TestEdge(A, D, 1); | ||
| 126 | + TestEdge dE = new TestEdge(D, E, 1); | ||
| 127 | + TestEdge aC = new TestEdge(A, C, 1); | ||
| 128 | + TestEdge cE = new TestEdge(C, E, 1); | ||
| 129 | + Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D, E), | ||
| 130 | + of(aB, bE, aD, dE, aC, cE)); | ||
| 131 | + Map<TestEdge, Integer> riskProfile = new HashMap<TestEdge, Integer>(); | ||
| 132 | + riskProfile.put(aB, 0); | ||
| 133 | + riskProfile.put(bE, 1); | ||
| 134 | + riskProfile.put(aD, 2); | ||
| 135 | + riskProfile.put(dE, 3); | ||
| 136 | + riskProfile.put(aC, 4); | ||
| 137 | + riskProfile.put(cE, 5); | ||
| 138 | + SRLGGraphSearch<TestVertex, TestEdge> search = | ||
| 139 | + new SRLGGraphSearch<TestVertex, TestEdge>(6, riskProfile); | ||
| 140 | + Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, E, weight, GraphPathSearch.ALL_PATHS).paths(); | ||
| 141 | + assertTrue("> one disjoint path pair found", paths.size() >= 1); | ||
| 142 | + checkIsDisjoint(paths.iterator().next(), riskProfile); | ||
| 143 | + } | ||
| 144 | + @Test | ||
| 145 | + public void onePath() { | ||
| 146 | + setDefaultWeights(); | ||
| 147 | + TestEdge aB = new TestEdge(A, B, 1); | ||
| 148 | + TestEdge bC = new TestEdge(B, C, 1); | ||
| 149 | + TestEdge aD = new TestEdge(A, D, 1); | ||
| 150 | + TestEdge dC = new TestEdge(D, C, 1); | ||
| 151 | + Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D), | ||
| 152 | + of(aB, bC, aD, dC)); | ||
| 153 | + Map<TestEdge, Integer> riskProfile = new HashMap<TestEdge, Integer>(); | ||
| 154 | + riskProfile.put(aB, 0); | ||
| 155 | + riskProfile.put(bC, 0); | ||
| 156 | + riskProfile.put(aD, 1); | ||
| 157 | + riskProfile.put(dC, 0); | ||
| 158 | + SRLGGraphSearch<TestVertex, TestEdge> search = | ||
| 159 | + new SRLGGraphSearch<TestVertex, TestEdge>(2, riskProfile); | ||
| 160 | + Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, C, weight, GraphPathSearch.ALL_PATHS).paths(); | ||
| 161 | + System.out.println(paths); | ||
| 162 | + assertTrue("no disjoint path pairs found", paths.size() == 0); | ||
| 163 | + } | ||
| 164 | + @Test | ||
| 165 | + public void noPath() { | ||
| 166 | + setDefaultWeights(); | ||
| 167 | + TestEdge aB = new TestEdge(A, B, 1); | ||
| 168 | + TestEdge bC = new TestEdge(B, C, 1); | ||
| 169 | + TestEdge aD = new TestEdge(A, D, 1); | ||
| 170 | + TestEdge dC = new TestEdge(D, C, 1); | ||
| 171 | + Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D, E), | ||
| 172 | + of(aB, bC, aD, dC)); | ||
| 173 | + Map<TestEdge, Integer> riskProfile = new HashMap<>(); | ||
| 174 | + riskProfile.put(aB, 0); | ||
| 175 | + riskProfile.put(bC, 0); | ||
| 176 | + riskProfile.put(aD, 1); | ||
| 177 | + riskProfile.put(dC, 0); | ||
| 178 | + SRLGGraphSearch<TestVertex, TestEdge> search = | ||
| 179 | + new SRLGGraphSearch<>(2, riskProfile); | ||
| 180 | + Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, E, weight, GraphPathSearch.ALL_PATHS).paths(); | ||
| 181 | + assertTrue("no disjoint path pairs found", paths.size() == 0); | ||
| 182 | + } | ||
| 183 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2014 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onlab.graph; | ||
| 17 | + | ||
| 18 | +import org.junit.Test; | ||
| 19 | +import java.util.Set; | ||
| 20 | + | ||
| 21 | +import static com.google.common.collect.ImmutableSet.of; | ||
| 22 | +import static org.junit.Assert.assertEquals; | ||
| 23 | +//import static org.junit.Assert.assertTrue; | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +/** | ||
| 28 | + * Test of the Suurballe backup path algorithm. | ||
| 29 | + */ | ||
| 30 | +public class SuurballeGraphSearchTest extends BreadthFirstSearchTest { | ||
| 31 | + | ||
| 32 | + @Override | ||
| 33 | + protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() { | ||
| 34 | + return new SuurballeGraphSearch<>(); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + public void setWeights() { | ||
| 38 | + weight = new EdgeWeight<TestVertex, TestEdge>() { | ||
| 39 | + @Override | ||
| 40 | + public double weight(TestEdge edge) { | ||
| 41 | + return edge.weight(); | ||
| 42 | + } | ||
| 43 | + }; | ||
| 44 | + } | ||
| 45 | + public void setDefaultWeights() { | ||
| 46 | + weight = null; | ||
| 47 | + } | ||
| 48 | + @Override | ||
| 49 | + public void defaultGraphTest() { | ||
| 50 | + | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + @Override | ||
| 54 | + public void defaultHopCountWeight() { | ||
| 55 | + | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + @Test | ||
| 59 | + public void basicGraphTest() { | ||
| 60 | + setDefaultWeights(); | ||
| 61 | + Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D), | ||
| 62 | + of(new TestEdge(A, B, 1), | ||
| 63 | + new TestEdge(B, C, 1), | ||
| 64 | + new TestEdge(A, D, 1), | ||
| 65 | + new TestEdge(D, C, 1))); | ||
| 66 | + executeSearch(graphSearch(), graph, A, C, weight, 1, 4.0); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + @Test | ||
| 70 | + public void multiplePathOnePairGraphTest() { | ||
| 71 | + setWeights(); | ||
| 72 | + Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D, E), | ||
| 73 | + of(new TestEdge(A, B, 1), | ||
| 74 | + new TestEdge(B, C, 1), | ||
| 75 | + new TestEdge(A, D, 1), | ||
| 76 | + new TestEdge(D, C, 1), | ||
| 77 | + new TestEdge(B, E, 2), | ||
| 78 | + new TestEdge(C, E, 1))); | ||
| 79 | + executeSearch(graphSearch(), graph, A, E, weight, 1, 6.0); | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + @Test | ||
| 83 | + public void multiplePathsMultiplePairs() { | ||
| 84 | + setWeights(); | ||
| 85 | + Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D, E), | ||
| 86 | + of(new TestEdge(A, B, 1), | ||
| 87 | + new TestEdge(B, E, 1), | ||
| 88 | + new TestEdge(A, C, 1), | ||
| 89 | + new TestEdge(C, E, 1), | ||
| 90 | + new TestEdge(A, D, 1), | ||
| 91 | + new TestEdge(D, E, 1), | ||
| 92 | + new TestEdge(A, E, 2))); | ||
| 93 | + GraphPathSearch.Result<TestVertex, TestEdge> result = | ||
| 94 | + graphSearch().search(graph, A, E, weight, GraphPathSearch.ALL_PATHS); | ||
| 95 | + Set<Path<TestVertex, TestEdge>> paths = result.paths(); | ||
| 96 | + System.out.println("\n\n" + paths + "\n\n\ndone\n"); | ||
| 97 | + assertEquals("incorrect paths count", 3, paths.size()); | ||
| 98 | + DisjointPathPair<TestVertex, TestEdge> dpp = (DisjointPathPair<TestVertex, TestEdge>) paths.iterator().next(); | ||
| 99 | + assertEquals("incorrect disjoint paths per path", 2, dpp.size()); | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + @Test | ||
| 103 | + public void differingPrimaryAndBackupPathLengths() { | ||
| 104 | + setWeights(); | ||
| 105 | + Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D, E), | ||
| 106 | + of(new TestEdge(A, B, 1), | ||
| 107 | + new TestEdge(B, C, 1), | ||
| 108 | + new TestEdge(A, D, 1), | ||
| 109 | + new TestEdge(D, C, 1), | ||
| 110 | + new TestEdge(B, E, 1), | ||
| 111 | + new TestEdge(C, E, 1))); | ||
| 112 | + executeSearch(graphSearch(), graph, A, E, weight, 1, 5.0); | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + @Test | ||
| 116 | + public void onePath() { | ||
| 117 | + setWeights(); | ||
| 118 | + Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D), | ||
| 119 | + of(new TestEdge(A, B, 1), | ||
| 120 | + new TestEdge(B, C, 1), | ||
| 121 | + new TestEdge(A, C, 4), | ||
| 122 | + new TestEdge(C, D, 1))); | ||
| 123 | + GraphPathSearch.Result<TestVertex, TestEdge> result = | ||
| 124 | + graphSearch().search(graph, A, D, weight, GraphPathSearch.ALL_PATHS); | ||
| 125 | + Set<Path<TestVertex, TestEdge>> paths = result.paths(); | ||
| 126 | + assertEquals("incorrect paths count", 1, paths.size()); | ||
| 127 | + DisjointPathPair<TestVertex, TestEdge> dpp = (DisjointPathPair<TestVertex, TestEdge>) paths.iterator().next(); | ||
| 128 | + assertEquals("incorrect disjoint paths count", 1, dpp.size()); | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + @Test | ||
| 132 | + public void noPath() { | ||
| 133 | + setWeights(); | ||
| 134 | + Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D), | ||
| 135 | + of(new TestEdge(A, B, 1), | ||
| 136 | + new TestEdge(B, C, 1), | ||
| 137 | + new TestEdge(A, C, 4))); | ||
| 138 | + GraphPathSearch.Result<TestVertex, TestEdge> result = | ||
| 139 | + graphSearch().search(graph, A, D, weight, GraphPathSearch.ALL_PATHS); | ||
| 140 | + Set<Path<TestVertex, TestEdge>> paths = result.paths(); | ||
| 141 | + assertEquals("incorrect paths count", paths.size(), 0); | ||
| 142 | + } | ||
| 143 | + | ||
| 144 | + @Test | ||
| 145 | + public void disconnected() { | ||
| 146 | + setWeights(); | ||
| 147 | + Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D), | ||
| 148 | + of()); | ||
| 149 | + GraphPathSearch.Result<TestVertex, TestEdge> result = | ||
| 150 | + graphSearch().search(graph, A, D, weight, GraphPathSearch.ALL_PATHS); | ||
| 151 | + Set<Path<TestVertex, TestEdge>> paths = result.paths(); | ||
| 152 | + assertEquals("incorrect paths count", 0, paths.size()); | ||
| 153 | + } | ||
| 154 | +} |
-
Please register or login to post a comment