blob: 82107ca478d6cb669ca9c1e108d288a3329eebe1 [file] [log] [blame]
/*
* Copyright 2015-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.graph;
import java.util.Map;
import java.util.List;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.Random;
/**
* SRLG Graph Search finds a pair of paths with disjoint risk groups; i.e
* if one path goes through an edge in risk group 1, the other path will go
* through no edges in risk group 1.
*/
public class SrlgGraphSearch<V extends Vertex, E extends Edge<V>>
extends AbstractGraphPathSearch<V, E> {
static final int ITERATIONS = 100;
static final int POPSIZE = 50;
boolean useSuurballe = false;
static final double INF = 100000000.0;
int numGroups;
Map<E, Integer> riskGrouping;
Graph<V, E> orig;
V src, dst;
EdgeWeigher<V, E> weigher;
/**
* Creates an SRLG graph search object with the given number
* of groups and given risk mapping.
*
* @param groups the number of disjoint risk groups
* @param grouping map linking edges to integral group assignments
*/
public SrlgGraphSearch(int groups, Map<E, Integer> grouping) {
numGroups = groups;
riskGrouping = grouping;
}
/**
* Creates an SRLG graph search object from a map, inferring
* the number of groups and creating an integral mapping.
*
* @param grouping map linking edges to object group assignments,
* with same-group status linked to equality
*/
public SrlgGraphSearch(Map<E, Object> grouping) {
if (grouping == null) {
useSuurballe = true;
return;
}
numGroups = 0;
HashMap<Object, Integer> tmpMap = new HashMap<>();
riskGrouping = new HashMap<>();
for (E key: grouping.keySet()) {
Object value = grouping.get(key);
if (!tmpMap.containsKey(value)) {
tmpMap.put(value, numGroups);
numGroups++;
}
riskGrouping.put(key, tmpMap.get(value));
}
}
@Override
protected Result<V, E> internalSearch(Graph<V, E> graph, V src, V dst,
EdgeWeigher<V, E> weigher, int maxPaths) {
if (maxPaths == ALL_PATHS) {
maxPaths = POPSIZE;
}
if (useSuurballe) {
return new SuurballeGraphSearch<V, E>().search(graph, src, dst, weigher, ALL_PATHS);
}
orig = graph;
this.src = src;
this.dst = dst;
this.weigher = weigher;
List<Subset> best = new GAPopulation<Subset>()
.runGA(ITERATIONS, POPSIZE, maxPaths, new Subset(new boolean[numGroups]));
Set<DisjointPathPair> dpps = new HashSet<DisjointPathPair>();
for (Subset s: best) {
dpps.addAll(s.buildPaths());
}
Result<V, E> firstDijkstra = new DijkstraGraphSearch<V, E>()
.search(orig, src, dst, weigher, 1);
return new Result<V, E>() {
final DefaultResult search = (DefaultResult) firstDijkstra;
public V src() {
return src;
}
public V dst() {
return dst;
}
public Set<Path<V, E>> paths() {
Set<Path<V, E>> pathsD = new HashSet<>();
for (DisjointPathPair<V, E> path: dpps) {
pathsD.add(path);
}
return pathsD;
}
public Map<V, Weight> costs() {
return search.costs();
}
public Map<V, Set<E>> parents() {
return search.parents();
}
};
}
//finds the shortest path in the graph given a subset of edge types to use
private Result<V, E> findShortestPathFromSubset(boolean[] subset) {
Graph<V, E> graph = orig;
EdgeWeigher<V, E> modified = new EdgeWeigher<V, E>() {
final boolean[] subsetF = subset;
@Override
public Weight weight(E edge) {
if (subsetF[riskGrouping.get(edge)]) {
return weigher.weight(edge);
}
return weigher.getNonViableWeight();
}
@Override
public Weight getInitialWeight() {
return weigher.getInitialWeight();
}
@Override
public Weight getNonViableWeight() {
return weigher.getNonViableWeight();
}
};
Result<V, E> res = new DijkstraGraphSearch<V, E>().search(graph, src, dst, modified, 1);
return res;
}
/**
* A subset is a type of GA organism that represents a subset of allowed shortest
* paths (and its complement). Its fitness is determined by the sum of the weights
* of the first two shortest paths.
*/
class Subset implements GAOrganism {
boolean[] subset;
boolean[] not;
Random r = new Random();
/**
* Creates a Subset from the given subset array.
*
* @param sub subset array
*/
public Subset(boolean[] sub) {
subset = sub.clone();
not = new boolean[subset.length];
for (int i = 0; i < subset.length; i++) {
not[i] = !subset[i];
}
}
@Override
public Comparable fitness() {
Set<Path<V, E>> paths1 = findShortestPathFromSubset(subset).paths();
Set<Path<V, E>> paths2 = findShortestPathFromSubset(not).paths();
if (paths1.isEmpty() || paths2.isEmpty()) {
return weigher.getNonViableWeight();
}
return paths1.iterator().next().cost().merge(paths2.iterator().next().cost());
}
@Override
public void mutate() {
int turns = r.nextInt((int) Math.sqrt(subset.length));
while (turns > 0) {
int choose = r.nextInt(subset.length);
subset[choose] = !subset[choose];
not[choose] = !not[choose];
turns--;
}
}
@Override
public GAOrganism crossWith(GAOrganism org) {
if (!(org.getClass().equals(getClass()))) {
return this;
}
Subset other = (Subset) (org);
boolean[] sub = new boolean[subset.length];
for (int i = 0; i < subset.length; i++) {
sub[i] = subset[i];
if (r.nextBoolean()) {
sub[i] = other.subset[i];
}
}
return new Subset(sub);
}
@Override
public GAOrganism random() {
boolean[] sub = new boolean[subset.length];
for (int i = 0; i < sub.length; i++) {
sub[i] = r.nextBoolean();
}
return new Subset(sub);
}
/**
* Builds the set of disjoint path pairs for a given subset
* using Dijkstra's algorithm on both the subset and complement
* and returning all pairs with one from each set.
*
* @return all shortest disjoint paths given this subset
*/
public Set<DisjointPathPair> buildPaths() {
Set<DisjointPathPair> dpps = new HashSet<>();
for (Path<V, E> path1: findShortestPathFromSubset(subset).paths()) {
for (Path<V, E> path2: findShortestPathFromSubset(not).paths()) {
DisjointPathPair<V, E> dpp = new DisjointPathPair<>(path1, path2);
dpps.add(dpp);
}
}
return dpps;
}
}
}