Nikhil Cheerla
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
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 +}