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