Toggle navigation
Toggle navigation
This project
Loading...
Sign in
홍길동
/
onos
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
alshabib
2014-09-02 11:01:48 -0700
Browse Files
Options
Browse Files
Download
Plain Diff
Commit
6e746f312d98a24a516f0747a8fee395b91083ed
6e746f31
2 parents
3cbf3124
41c3fccb
Merge branch 'master' of
ssh://gerrit.onlab.us:29418/onos-next
Show whitespace changes
Inline
Side-by-side
Showing
39 changed files
with
2286 additions
and
4 deletions
net/api/src/main/java/org/onlab/onos/event/AbstractListenerRegistry.java
net/core/trivial/src/main/java/org/onlab/onos/event/impl/SimpleEventDispatcher.java
net/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceManager.java
pom.xml
utils/misc/pom.xml
utils/misc/src/main/java/org/onlab/graph/AbstractEdge.java
utils/misc/src/main/java/org/onlab/graph/AbstractGraphPathSearch.java
utils/misc/src/main/java/org/onlab/graph/AdjacencyListsGraph.java
utils/misc/src/main/java/org/onlab/graph/BellmanFordGraphSearch.java
utils/misc/src/main/java/org/onlab/graph/BreadthFirstSearch.java
utils/misc/src/main/java/org/onlab/graph/DefaultMutablePath.java
utils/misc/src/main/java/org/onlab/graph/DefaultPath.java
utils/misc/src/main/java/org/onlab/graph/DepthFirstSearch.java
utils/misc/src/main/java/org/onlab/graph/DijkstraGraphSearch.java
utils/misc/src/main/java/org/onlab/graph/Edge.java
utils/misc/src/main/java/org/onlab/graph/EdgeWeight.java
utils/misc/src/main/java/org/onlab/graph/Graph.java
utils/misc/src/main/java/org/onlab/graph/GraphPathSearch.java
utils/misc/src/main/java/org/onlab/graph/GraphSearch.java
utils/misc/src/main/java/org/onlab/graph/Heap.java
utils/misc/src/main/java/org/onlab/graph/MutableGraph.java
utils/misc/src/main/java/org/onlab/graph/MutablePath.java
utils/misc/src/main/java/org/onlab/graph/Path.java
utils/misc/src/main/java/org/onlab/graph/Vertex.java
utils/misc/src/main/javadoc/org/onlab/graph/package.html
utils/misc/src/main/javadoc/org/onlab/util/package.html
utils/misc/src/test/java/org/onlab/graph/AbstractEdgeTest.java
utils/misc/src/test/java/org/onlab/graph/AbstractGraphPathSearchTest.java
utils/misc/src/test/java/org/onlab/graph/AdjacencyListsGraphTest.java
utils/misc/src/test/java/org/onlab/graph/BellmanFordGraphSearchTest.java
utils/misc/src/test/java/org/onlab/graph/BreadthFirstSearchTest.java
utils/misc/src/test/java/org/onlab/graph/DefaultMutablePathTest.java
utils/misc/src/test/java/org/onlab/graph/DefaultPathTest.java
utils/misc/src/test/java/org/onlab/graph/DepthFirstSearchTest.java
utils/misc/src/test/java/org/onlab/graph/DijkstraGraphSearchTest.java
utils/misc/src/test/java/org/onlab/graph/GraphTest.java
utils/misc/src/test/java/org/onlab/graph/HeapTest.java
utils/misc/src/test/java/org/onlab/graph/TestEdge.java
utils/misc/src/test/java/org/onlab/graph/TestVertex.java
net/api/src/main/java/org/onlab/onos/event/AbstractListenerRegistry.java
View file @
6e746f3
...
...
@@ -45,7 +45,7 @@ public class AbstractListenerRegistry<E extends Event, L extends EventListener<E
for
(
L
listener
:
listeners
)
{
try
{
listener
.
event
(
event
);
}
catch
(
Throwable
error
)
{
}
catch
(
Exception
error
)
{
reportProblem
(
event
,
error
);
}
}
...
...
net/core/trivial/src/main/java/org/onlab/onos/event/impl/SimpleEventDispatcher.java
View file @
6e746f3
...
...
@@ -82,7 +82,7 @@ public class SimpleEventDispatcher extends DefaultEventSinkRegistry
log
.
warn
(
"No sink registered for event class {}"
,
event
.
getClass
());
}
}
catch
(
Throwable
e
)
{
}
catch
(
Exception
e
)
{
log
.
warn
(
"Error encountered while dispatching event:"
,
e
);
}
}
...
...
net/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceManager.java
View file @
6e746f3
...
...
@@ -141,7 +141,6 @@ public class SimpleDeviceManager
public
void
updatePorts
(
DeviceId
deviceId
,
List
<
PortDescription
>
portDescriptions
)
{
checkNotNull
(
deviceId
,
DEVICE_ID_NULL
);
checkNotNull
(
portDescriptions
,
"Port descriptions list cannot be null"
);
// FIXME: fix the interface to accept DeviceId separately
log
.
info
(
"Device {} ports updated: {}"
,
portDescriptions
);
List
<
DeviceEvent
>
events
=
store
.
updatePorts
(
deviceId
,
portDescriptions
);
for
(
DeviceEvent
event
:
events
)
{
...
...
pom.xml
View file @
6e746f3
...
...
@@ -306,7 +306,7 @@
<group>
<title>
Utilities
</title>
<packages>
org.onlab.
util:org.onlab.util.
*
org.onlab.*
</packages>
</group>
<group>
...
...
utils/misc/pom.xml
View file @
6e746f3
...
...
@@ -17,6 +17,12 @@
<description>
Miscellaneous ON.Lab utilities
</description>
<dependencies>
<dependency>
<groupId>
com.google.guava
</groupId>
<artifactId>
guava-testlib
</artifactId>
<version>
17.0
</version>
<scope>
test
</scope>
</dependency>
</dependencies>
</project>
...
...
utils/misc/src/main/java/org/onlab/graph/AbstractEdge.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
java.util.Objects
;
import
static
com
.
google
.
common
.
base
.
Preconditions
.
checkNotNull
;
/**
* Abstract graph edge implementation.
*/
public
abstract
class
AbstractEdge
<
V
extends
Vertex
>
implements
Edge
<
V
>
{
private
final
V
src
;
private
final
V
dst
;
/**
* Creates a new edge between the specified source and destination vertexes.
*
* @param src source vertex
* @param dst destination vertex
*/
public
AbstractEdge
(
V
src
,
V
dst
)
{
this
.
src
=
checkNotNull
(
src
,
"Source vertex cannot be null"
);
this
.
dst
=
checkNotNull
(
dst
,
"Destination vertex cannot be null"
);
}
@Override
public
V
src
()
{
return
src
;
}
@Override
public
V
dst
()
{
return
dst
;
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
src
,
dst
);
}
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
obj
instanceof
AbstractEdge
)
{
final
AbstractEdge
other
=
(
AbstractEdge
)
obj
;
return
Objects
.
equals
(
this
.
src
,
other
.
src
)
&&
Objects
.
equals
(
this
.
dst
,
other
.
dst
);
}
return
false
;
}
@Override
public
String
toString
()
{
return
com
.
google
.
common
.
base
.
Objects
.
toStringHelper
(
this
)
.
add
(
"src"
,
src
)
.
add
(
"dst"
,
dst
)
.
toString
();
}
}
utils/misc/src/main/java/org/onlab/graph/AbstractGraphPathSearch.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.Iterator
;
import
java.util.Map
;
import
java.util.Set
;
import
static
com
.
google
.
common
.
base
.
Preconditions
.
checkArgument
;
import
static
com
.
google
.
common
.
base
.
Preconditions
.
checkNotNull
;
/**
* Basis for various graph path search algorithm implementations.
*
* @param <V> vertex type
* @param <E> edge type
*/
public
abstract
class
AbstractGraphPathSearch
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
implements
GraphPathSearch
<
V
,
E
>
{
private
double
samenessThreshold
=
0.000000001
;
/**
* Sets a new sameness threshold for comparing cost values; default is
* is {@code 0.000000001}.
*
* @param threshold fractional double value
*/
public
void
setSamenessThreshold
(
double
threshold
)
{
samenessThreshold
=
threshold
;
}
/**
* Returns the current sameness threshold for comparing cost values.
*
* @return current threshold
*/
public
double
samenessThreshold
()
{
return
samenessThreshold
;
}
/**
* Default path search result that uses the DefaultPath to convey paths
* in a graph.
*/
protected
class
DefaultResult
implements
Result
<
V
,
E
>
{
private
final
V
src
;
private
final
V
dst
;
protected
final
Set
<
Path
<
V
,
E
>>
paths
=
new
HashSet
<>();
protected
final
Map
<
V
,
Double
>
costs
=
new
HashMap
<>();
protected
final
Map
<
V
,
Set
<
E
>>
parents
=
new
HashMap
<>();
/**
* Creates the result of path search.
*
* @param src path source
* @param dst optional path destination
*/
public
DefaultResult
(
V
src
,
V
dst
)
{
checkNotNull
(
src
,
"Source cannot be null"
);
this
.
src
=
src
;
this
.
dst
=
dst
;
}
@Override
public
V
src
()
{
return
src
;
}
@Override
public
V
dst
()
{
return
dst
;
}
@Override
public
Set
<
Path
<
V
,
E
>>
paths
()
{
return
paths
;
}
@Override
public
Map
<
V
,
Double
>
costs
()
{
return
costs
;
}
@Override
public
Map
<
V
,
Set
<
E
>>
parents
()
{
return
parents
;
}
/**
* Indicates whether or not the given vertex has a cost yet.
*
* @param v vertex to test
* @return true if the vertex has cost already
*/
boolean
hasCost
(
V
v
)
{
return
costs
.
get
(
v
)
!=
null
;
}
/**
* Returns the current cost to reach the specified vertex.
*
* @return cost to reach the vertex
*/
double
cost
(
V
v
)
{
Double
c
=
costs
.
get
(
v
);
return
c
==
null
?
Double
.
MAX_VALUE
:
c
;
}
/**
* Updates the cost of the vertex using its existing cost plus the
* cost to traverse the specified edge.
*
* @param v vertex
* @param edge edge through which vertex is reached
* @param cost current cost to reach the vertex from the source
* @param replace true to indicate that any accrued edges are to be
* cleared; false to indicate that the edge should be
* added to the previously accrued edges as they yield
* the same cost
*/
void
updateVertex
(
V
v
,
E
edge
,
double
cost
,
boolean
replace
)
{
costs
.
put
(
v
,
cost
);
if
(
edge
!=
null
)
{
Set
<
E
>
edges
=
parents
.
get
(
v
);
if
(
edges
==
null
)
{
edges
=
new
HashSet
<>();
parents
.
put
(
v
,
edges
);
}
if
(
replace
)
{
edges
.
clear
();
}
edges
.
add
(
edge
);
}
}
/**
* Removes the set of parent edges for the specified vertex.
*
* @param v vertex
*/
void
removeVertex
(
V
v
)
{
parents
.
remove
(
v
);
}
/**
* If possible, relax the specified edge using the supplied base cost
* and edge-weight function.
*
* @param e edge to be relaxed
* @param cost base cost to reach the edge destination vertex
* @param ew optional edge weight function
* @return true if the edge was relaxed; false otherwise
*/
boolean
relaxEdge
(
E
e
,
double
cost
,
EdgeWeight
<
V
,
E
>
ew
)
{
V
v
=
e
.
dst
();
double
oldCost
=
cost
(
v
);
double
newCost
=
cost
+
(
ew
==
null
?
1.0
:
ew
.
weight
(
e
));
boolean
relaxed
=
newCost
<
oldCost
;
boolean
same
=
Math
.
abs
(
newCost
-
oldCost
)
<
samenessThreshold
;
if
(
same
||
relaxed
)
{
updateVertex
(
v
,
e
,
newCost
,
!
same
);
}
return
relaxed
;
}
/**
* Builds a set of paths for the specified src/dst vertex pair.
*/
protected
void
buildPaths
()
{
Set
<
V
>
destinations
=
new
HashSet
<>();
if
(
dst
==
null
)
{
destinations
.
addAll
(
costs
.
keySet
());
}
else
{
destinations
.
add
(
dst
);
}
// Build all paths between the source and all requested destinations.
for
(
V
v
:
destinations
)
{
// Ignore the source, if it is among the destinations.
if
(!
v
.
equals
(
src
))
{
buildAllPaths
(
this
,
src
,
v
);
}
}
}
}
/**
* Builds a set of all paths between the source and destination using the
* graph search result by applying breadth-first search through the parent
* edges and vertex costs.
*
* @param result graph search result
* @param src source vertex
* @param dst destination vertex
*/
private
void
buildAllPaths
(
DefaultResult
result
,
V
src
,
V
dst
)
{
DefaultMutablePath
<
V
,
E
>
basePath
=
new
DefaultMutablePath
<>();
basePath
.
setCost
(
result
.
cost
(
dst
));
Set
<
DefaultMutablePath
<
V
,
E
>>
pendingPaths
=
new
HashSet
<>();
pendingPaths
.
add
(
basePath
);
while
(!
pendingPaths
.
isEmpty
())
{
Set
<
DefaultMutablePath
<
V
,
E
>>
frontier
=
new
HashSet
<>();
for
(
DefaultMutablePath
<
V
,
E
>
path
:
pendingPaths
)
{
// For each pending path, locate its first vertex since we
// will be moving backwards from it.
V
firstVertex
=
firstVertex
(
path
,
dst
);
// If the first vertex is our expected source, we have reached
// the beginning, so add the this path to the result paths.
if
(
firstVertex
.
equals
(
src
))
{
path
.
setCost
(
result
.
cost
(
dst
));
result
.
paths
.
add
(
new
DefaultPath
<>(
path
.
edges
(),
path
.
cost
()));
}
else
{
// If we have not reached the beginning, i.e. the source,
// fetch the set of edges leading to the first vertex of
// this pending path; if there are none, abandon processing
// this path for good.
Set
<
E
>
firstVertexParents
=
result
.
parents
.
get
(
firstVertex
);
if
(
firstVertexParents
==
null
||
firstVertexParents
.
isEmpty
())
{
break
;
}
// Now iterate over all the edges and for each of them
// cloning the current path and then insert that edge to
// the path and then add that path to the pending ones.
// When processing the last edge, modify the current
// pending path rather than cloning a new one.
Iterator
<
E
>
edges
=
firstVertexParents
.
iterator
();
while
(
edges
.
hasNext
())
{
E
edge
=
edges
.
next
();
boolean
isLast
=
!
edges
.
hasNext
();
DefaultMutablePath
<
V
,
E
>
pendingPath
=
isLast
?
path
:
new
DefaultMutablePath
<>(
path
);
pendingPath
.
insertEdge
(
edge
);
frontier
.
add
(
pendingPath
);
}
}
}
// All pending paths have been scanned so promote the next frontier
pendingPaths
=
frontier
;
}
}
// Returns the first vertex of the specified path. This is either the source
// of the first edge or, if there are no edges yet, the given destination.
private
V
firstVertex
(
Path
<
V
,
E
>
path
,
V
dst
)
{
return
path
.
edges
().
isEmpty
()
?
dst
:
path
.
edges
().
get
(
0
).
src
();
}
/**
* Checks the specified path search arguments for validity.
*
* @param graph graph; must not be null
* @param src source vertex; must not be null and belong to graph
* @param dst optional target vertex; must belong to graph
*/
protected
void
checkArguments
(
Graph
<
V
,
E
>
graph
,
V
src
,
V
dst
)
{
checkNotNull
(
graph
,
"Graph cannot be null"
);
checkNotNull
(
src
,
"Source cannot be null"
);
Set
<
V
>
vertices
=
graph
.
getVertexes
();
checkArgument
(
vertices
.
contains
(
src
),
"Source not in the graph"
);
checkArgument
(
dst
==
null
||
vertices
.
contains
(
dst
),
"Destination not in graph"
);
}
}
utils/misc/src/main/java/org/onlab/graph/AdjacencyListsGraph.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
com.google.common.collect.ImmutableSet
;
import
com.google.common.collect.ImmutableSetMultimap
;
import
java.util.Objects
;
import
java.util.Set
;
import
static
com
.
google
.
common
.
base
.
Preconditions
.
checkNotNull
;
/**
* Immutable graph implemented using adjacency lists.
*
* @param <V> vertex type
* @param <E> edge type
*/
public
class
AdjacencyListsGraph
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
implements
Graph
<
V
,
E
>
{
private
final
Set
<
V
>
vertexes
;
private
final
Set
<
E
>
edges
;
private
final
ImmutableSetMultimap
<
V
,
E
>
sources
;
private
final
ImmutableSetMultimap
<
V
,
E
>
destinations
;
/**
* Creates a graph comprising of the specified vertexes and edges.
*
* @param vertexes set of graph vertexes
* @param edges set of graph edges
*/
public
AdjacencyListsGraph
(
Set
<
V
>
vertexes
,
Set
<
E
>
edges
)
{
checkNotNull
(
vertexes
,
"Vertex set cannot be null"
);
checkNotNull
(
edges
,
"Edge set cannot be null"
);
// Record ingress/egress edges for each vertex.
ImmutableSetMultimap
.
Builder
<
V
,
E
>
srcMap
=
ImmutableSetMultimap
.
builder
();
ImmutableSetMultimap
.
Builder
<
V
,
E
>
dstMap
=
ImmutableSetMultimap
.
builder
();
// Also make sure that all edge end-points are added as vertexes
ImmutableSet
.
Builder
<
V
>
actualVertexes
=
ImmutableSet
.
builder
();
actualVertexes
.
addAll
(
vertexes
);
for
(
E
edge
:
edges
)
{
srcMap
.
put
(
edge
.
src
(),
edge
);
actualVertexes
.
add
(
edge
.
src
());
dstMap
.
put
(
edge
.
dst
(),
edge
);
actualVertexes
.
add
(
edge
.
dst
());
}
// Make an immutable copy of the edge and vertex sets
this
.
edges
=
ImmutableSet
.
copyOf
(
edges
);
this
.
vertexes
=
actualVertexes
.
build
();
// Build immutable copies of sources and destinations edge maps
sources
=
srcMap
.
build
();
destinations
=
dstMap
.
build
();
}
@Override
public
Set
<
V
>
getVertexes
()
{
return
vertexes
;
}
@Override
public
Set
<
E
>
getEdges
()
{
return
edges
;
}
@Override
public
Set
<
E
>
getEdgesFrom
(
V
src
)
{
return
sources
.
get
(
src
);
}
@Override
public
Set
<
E
>
getEdgesTo
(
V
dst
)
{
return
destinations
.
get
(
dst
);
}
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
obj
instanceof
AdjacencyListsGraph
)
{
AdjacencyListsGraph
that
=
(
AdjacencyListsGraph
)
obj
;
return
this
.
getClass
()
==
that
.
getClass
()
&&
Objects
.
equals
(
this
.
vertexes
,
that
.
vertexes
)
&&
Objects
.
equals
(
this
.
edges
,
that
.
edges
);
}
return
false
;
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
vertexes
,
edges
);
}
@Override
public
String
toString
()
{
return
com
.
google
.
common
.
base
.
Objects
.
toStringHelper
(
this
)
.
add
(
"vertexes"
,
vertexes
)
.
add
(
"edges"
,
edges
)
.
toString
();
}
}
utils/misc/src/main/java/org/onlab/graph/BellmanFordGraphSearch.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
/**
* Bellman-Ford graph search algorithm for locating shortest-paths in
* directed graphs that may contain negative cycles.
*/
public
class
BellmanFordGraphSearch
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
extends
AbstractGraphPathSearch
<
V
,
E
>
{
@Override
public
Result
<
V
,
E
>
search
(
Graph
<
V
,
E
>
graph
,
V
src
,
V
dst
,
EdgeWeight
<
V
,
E
>
weight
)
{
checkArguments
(
graph
,
src
,
dst
);
// Prepare the graph search result.
DefaultResult
result
=
new
DefaultResult
(
src
,
dst
);
// The source vertex has cost 0, of course.
result
.
updateVertex
(
src
,
null
,
0.0
,
true
);
int
max
=
graph
.
getVertexes
().
size
()
-
1
;
for
(
int
i
=
0
;
i
<
max
;
i
++)
{
// Relax, if possible, all egress edges of the current vertex.
for
(
E
edge
:
graph
.
getEdges
())
{
if
(
result
.
hasCost
(
edge
.
src
()))
{
result
.
relaxEdge
(
edge
,
result
.
cost
(
edge
.
src
()),
weight
);
}
}
}
// Remove any vertexes reached by traversing edges with negative weights.
for
(
E
edge
:
graph
.
getEdges
())
{
if
(
result
.
hasCost
(
edge
.
src
()))
{
if
(
result
.
relaxEdge
(
edge
,
result
.
cost
(
edge
.
src
()),
weight
))
{
result
.
removeVertex
(
edge
.
dst
());
}
}
}
// Finally, but the paths on the search result and return.
result
.
buildPaths
();
return
result
;
}
}
utils/misc/src/main/java/org/onlab/graph/BreadthFirstSearch.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
java.util.HashSet
;
import
java.util.Set
;
/**
* Implementation of the BFS algorithm.
*/
public
class
BreadthFirstSearch
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
extends
AbstractGraphPathSearch
<
V
,
E
>
{
@Override
public
Result
<
V
,
E
>
search
(
Graph
<
V
,
E
>
graph
,
V
src
,
V
dst
,
EdgeWeight
<
V
,
E
>
weight
)
{
checkArguments
(
graph
,
src
,
dst
);
// Prepare the graph result.
DefaultResult
result
=
new
DefaultResult
(
src
,
dst
);
// Setup the starting frontier with the source as the sole vertex.
Set
<
V
>
frontier
=
new
HashSet
<>();
result
.
updateVertex
(
src
,
null
,
0.0
,
true
);
frontier
.
add
(
src
);
boolean
reachedEnd
=
false
;
while
(!
reachedEnd
&&
!
frontier
.
isEmpty
())
{
// Prepare the next frontier.
Set
<
V
>
next
=
new
HashSet
<>();
// Visit all vertexes in the current frontier.
for
(
V
vertex
:
frontier
)
{
double
cost
=
result
.
cost
(
vertex
);
// Visit all egress edges of the current frontier vertex.
for
(
E
edge
:
graph
.
getEdgesFrom
(
vertex
))
{
V
nextVertex
=
edge
.
dst
();
if
(!
result
.
hasCost
(
nextVertex
))
{
// If this vertex has not been visited yet, update it.
double
newCost
=
cost
+
(
weight
==
null
?
1.0
:
weight
.
weight
(
edge
));
result
.
updateVertex
(
nextVertex
,
edge
,
newCost
,
true
);
// If we have reached our intended destination, bail.
if
(
nextVertex
.
equals
(
dst
))
{
reachedEnd
=
true
;
break
;
}
next
.
add
(
nextVertex
);
}
if
(
reachedEnd
)
{
break
;
}
}
}
// Promote the next frontier.
frontier
=
next
;
}
// Finally, but the paths on the search result and return.
result
.
buildPaths
();
return
result
;
}
}
utils/misc/src/main/java/org/onlab/graph/DefaultMutablePath.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
com.google.common.collect.ImmutableList
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Objects
;
import
static
com
.
google
.
common
.
base
.
Preconditions
.
checkArgument
;
import
static
com
.
google
.
common
.
base
.
Preconditions
.
checkNotNull
;
/**
* Simple concrete implementation of a directed graph path.
*/
public
class
DefaultMutablePath
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
implements
MutablePath
<
V
,
E
>
{
private
final
List
<
E
>
edges
=
new
ArrayList
<>();
private
double
cost
=
0.0
;
/**
* Creates a new empty path.
*/
public
DefaultMutablePath
()
{
}
/**
* Creates a new path as a copy of another path.
*
* @param path path to be copied
*/
public
DefaultMutablePath
(
Path
<
V
,
E
>
path
)
{
checkNotNull
(
path
,
"Path cannot be null"
);
this
.
cost
=
path
.
cost
();
edges
.
addAll
(
path
.
edges
());
}
@Override
public
V
src
()
{
return
edges
.
isEmpty
()
?
null
:
edges
.
get
(
0
).
src
();
}
@Override
public
V
dst
()
{
return
edges
.
isEmpty
()
?
null
:
edges
.
get
(
edges
.
size
()
-
1
).
dst
();
}
@Override
public
double
cost
()
{
return
cost
;
}
@Override
public
List
<
E
>
edges
()
{
return
ImmutableList
.
copyOf
(
edges
);
}
@Override
public
void
setCost
(
double
cost
)
{
this
.
cost
=
cost
;
}
@Override
public
Path
<
V
,
E
>
toImmutable
()
{
return
new
DefaultPath
<>(
edges
,
cost
);
}
@Override
public
void
insertEdge
(
E
edge
)
{
checkNotNull
(
edge
,
"Edge cannot be null"
);
checkArgument
(
edges
.
isEmpty
()
||
src
().
equals
(
edge
.
dst
()),
"Edge destination must be the same as the current path source"
);
edges
.
add
(
0
,
edge
);
}
@Override
public
void
appendEdge
(
E
edge
)
{
checkNotNull
(
edge
,
"Edge cannot be null"
);
checkArgument
(
edges
.
isEmpty
()
||
dst
().
equals
(
edge
.
src
()),
"Edge source must be the same as the current path destination"
);
edges
.
add
(
edge
);
}
@Override
public
void
removeEdge
(
E
edge
)
{
checkArgument
(
edge
.
src
().
equals
(
edge
.
dst
())
||
edges
.
indexOf
(
edge
)
==
0
||
edges
.
lastIndexOf
(
edge
)
==
edges
.
size
()
-
1
,
"Edge must be at start or end of path, or it must be a cyclic edge"
);
edges
.
remove
(
edge
);
}
@Override
public
String
toString
()
{
return
com
.
google
.
common
.
base
.
Objects
.
toStringHelper
(
this
)
.
add
(
"src"
,
src
())
.
add
(
"dst"
,
dst
())
.
add
(
"cost"
,
cost
)
.
add
(
"edges"
,
edges
)
.
toString
();
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
edges
,
cost
);
}
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
obj
instanceof
DefaultMutablePath
)
{
final
DefaultMutablePath
other
=
(
DefaultMutablePath
)
obj
;
return
Objects
.
equals
(
this
.
cost
,
other
.
cost
)
&&
Objects
.
equals
(
this
.
edges
,
other
.
edges
);
}
return
false
;
}
}
utils/misc/src/main/java/org/onlab/graph/DefaultPath.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
com.google.common.collect.ImmutableList
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Objects
;
import
static
com
.
google
.
common
.
base
.
Preconditions
.
checkArgument
;
import
static
com
.
google
.
common
.
base
.
Preconditions
.
checkNotNull
;
/**
* Simple concrete implementation of a directed graph path.
*/
public
class
DefaultPath
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
implements
Path
<
V
,
E
>
{
private
final
V
src
;
private
final
V
dst
;
private
final
List
<
E
>
edges
;
private
double
cost
=
0.0
;
/**
* Creates a new path from the specified list of edges and cost.
*
* @param edges list of path edges
* @param cost path cost as a unit-less number
*/
public
DefaultPath
(
List
<
E
>
edges
,
double
cost
)
{
checkNotNull
(
edges
,
"Edges list must not be null"
);
checkArgument
(!
edges
.
isEmpty
(),
"There must be at least one edge"
);
this
.
edges
=
ImmutableList
.
copyOf
(
edges
);
this
.
src
=
edges
.
get
(
0
).
src
();
this
.
dst
=
edges
.
get
(
edges
.
size
()
-
1
).
dst
();
this
.
cost
=
cost
;
}
@Override
public
V
src
()
{
return
src
;
}
@Override
public
V
dst
()
{
return
dst
;
}
@Override
public
double
cost
()
{
return
cost
;
}
@Override
public
List
<
E
>
edges
()
{
return
Collections
.
unmodifiableList
(
edges
);
}
@Override
public
String
toString
()
{
return
com
.
google
.
common
.
base
.
Objects
.
toStringHelper
(
this
)
.
add
(
"src"
,
src
)
.
add
(
"dst"
,
dst
)
.
add
(
"cost"
,
cost
)
.
add
(
"edges"
,
edges
)
.
toString
();
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
src
,
dst
,
edges
,
cost
);
}
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
obj
instanceof
DefaultPath
)
{
final
DefaultPath
other
=
(
DefaultPath
)
obj
;
return
Objects
.
equals
(
this
.
src
,
other
.
src
)
&&
Objects
.
equals
(
this
.
dst
,
other
.
dst
)
&&
Objects
.
equals
(
this
.
cost
,
other
.
cost
)
&&
Objects
.
equals
(
this
.
edges
,
other
.
edges
);
}
return
false
;
}
}
utils/misc/src/main/java/org/onlab/graph/DepthFirstSearch.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.Stack
;
/**
* DFS graph search algorithm implemented via iteration rather than recursion.
*/
public
class
DepthFirstSearch
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
extends
AbstractGraphPathSearch
<
V
,
E
>
{
/**
* Graph edge types as classified by the DFS algorithm.
*/
public
static
enum
EdgeType
{
TREE_EDGE
,
FORWARD_EDGE
,
BACK_EDGE
,
CROSS_EDGE
}
@Override
public
SpanningTreeResult
search
(
Graph
<
V
,
E
>
graph
,
V
src
,
V
dst
,
EdgeWeight
<
V
,
E
>
weight
)
{
checkArguments
(
graph
,
src
,
dst
);
// Prepare the search result.
SpanningTreeResult
result
=
new
SpanningTreeResult
(
src
,
dst
);
// The source vertex has cost 0, of course.
result
.
updateVertex
(
src
,
null
,
0.0
,
true
);
// Track finished vertexes and keep a stack of vertexes that have been
// started; start this stack with the source on it.
Set
<
V
>
finished
=
new
HashSet
<>();
Stack
<
V
>
stack
=
new
Stack
<>();
stack
.
push
(
src
);
while
(!
stack
.
isEmpty
())
{
V
vertex
=
stack
.
peek
();
if
(
vertex
.
equals
(
dst
))
{
// If we have reached our destination, bail.
break
;
}
double
cost
=
result
.
cost
(
vertex
);
boolean
tangent
=
false
;
// Visit all egress edges of the current vertex.
for
(
E
edge
:
graph
.
getEdgesFrom
(
vertex
))
{
// If we have seen the edge already, skip it.
if
(
result
.
isEdgeMarked
(
edge
))
{
continue
;
}
// Examine the destination of the current edge.
V
nextVertex
=
edge
.
dst
();
if
(!
result
.
hasCost
(
nextVertex
))
{
// If this vertex have not finished this vertex yet,
// not started it, then start it as a tree-edge.
result
.
markEdge
(
edge
,
EdgeType
.
TREE_EDGE
);
double
newCost
=
cost
+
(
weight
==
null
?
1.0
:
weight
.
weight
(
edge
));
result
.
updateVertex
(
nextVertex
,
edge
,
newCost
,
true
);
stack
.
push
(
nextVertex
);
tangent
=
true
;
break
;
}
else
if
(!
finished
.
contains
(
nextVertex
))
{
// We started the vertex, but did not yet finish it, so
// it must be a back-edge.
result
.
markEdge
(
edge
,
EdgeType
.
BACK_EDGE
);
}
else
{
// The target has been finished already, so what we have
// here is either a forward-edge or a cross-edge.
result
.
markEdge
(
edge
,
isForwardEdge
(
result
,
edge
)
?
EdgeType
.
FORWARD_EDGE
:
EdgeType
.
CROSS_EDGE
);
}
}
// If we have not been sent on a tangent search and reached the
// end of the current scan normally, mark the node as finished
// and pop it off the vertex stack.
if
(!
tangent
)
{
finished
.
add
(
vertex
);
stack
.
pop
();
}
}
// Finally, but the paths on the search result and return.
result
.
buildPaths
();
return
result
;
}
/**
* Determines whether the specified edge is a forward edge using the
* accumulated set of parent edges for each vertex.
*
* @param result search result
* @param edge edge to be classified
* @return true if the edge is a forward edge
*/
protected
boolean
isForwardEdge
(
DefaultResult
result
,
E
edge
)
{
// Follow the parent edges until we hit the edge source vertex
V
target
=
edge
.
src
();
V
vertex
=
edge
.
dst
();
Set
<
E
>
parentEdges
;
while
((
parentEdges
=
result
.
parents
.
get
(
vertex
))
!=
null
)
{
for
(
E
parentEdge
:
parentEdges
)
{
vertex
=
parentEdge
.
src
();
if
(
vertex
.
equals
(
target
))
{
return
true
;
}
}
}
return
false
;
}
/**
* Graph search result which includes edge classification for building
* a spanning tree.
*/
public
class
SpanningTreeResult
extends
DefaultResult
{
protected
final
Map
<
E
,
EdgeType
>
edges
=
new
HashMap
<>();
/**
* Creates a new spanning tree result.
*
* @param src search source
* @param dst optional search destination
*/
public
SpanningTreeResult
(
V
src
,
V
dst
)
{
super
(
src
,
dst
);
}
/**
* Returns the map of edge type.
*
* @return edge to edge type bindings
*/
public
Map
<
E
,
EdgeType
>
edges
()
{
return
edges
;
}
/**
* Indicates whether or not the edge has been marked with type.
*
* @param edge edge to test
* @return true if the edge has been marked already
*/
boolean
isEdgeMarked
(
E
edge
)
{
return
edges
.
containsKey
(
edge
);
}
/**
* Marks the edge with the specified type.
*
* @param edge edge to mark
* @param type edge type
*/
void
markEdge
(
E
edge
,
EdgeType
type
)
{
edges
.
put
(
edge
,
type
);
}
}
}
utils/misc/src/main/java/org/onlab/graph/DijkstraGraphSearch.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
java.util.ArrayList
;
import
java.util.Comparator
;
import
java.util.Set
;
/**
* Dijkstra shortest-path graph search algorithm capable of finding not just
* one, but all shortest paths between the source and destinations.
*/
public
class
DijkstraGraphSearch
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
extends
AbstractGraphPathSearch
<
V
,
E
>
{
@Override
public
Result
<
V
,
E
>
search
(
Graph
<
V
,
E
>
graph
,
V
src
,
V
dst
,
EdgeWeight
<
V
,
E
>
weight
)
{
checkArguments
(
graph
,
src
,
dst
);
// Use the default result to remember cumulative costs and parent
// edges to each each respective vertex.
DefaultResult
result
=
new
DefaultResult
(
src
,
dst
);
// Cost to reach the source vertex is 0 of course.
result
.
updateVertex
(
src
,
null
,
0.0
,
false
);
// Use the min priority queue to progressively find each nearest
// vertex until we reach the desired destination, if one was given,
// or until we reach all possible destinations.
Heap
<
V
>
minQueue
=
createMinQueue
(
graph
.
getVertexes
(),
new
PathCostComparator
(
result
));
while
(!
minQueue
.
isEmpty
())
{
// Get the nearest vertex
V
nearest
=
minQueue
.
extractExtreme
();
if
(
nearest
.
equals
(
dst
))
{
break
;
}
// Find its cost and use it to determine if the vertex is reachable.
double
cost
=
result
.
cost
(
nearest
);
if
(
cost
<
Double
.
MAX_VALUE
)
{
// If the vertex is reachable, relax all its egress edges.
for
(
E
e
:
graph
.
getEdgesFrom
(
nearest
))
{
result
.
relaxEdge
(
e
,
cost
,
weight
);
}
}
// Re-prioritize the min queue.
minQueue
.
heapify
();
}
// Now construct a set of paths from the results.
result
.
buildPaths
();
return
result
;
}
// Compares path weights using their accrued costs; used for sorting the
// min priority queue.
private
final
class
PathCostComparator
implements
Comparator
<
V
>
{
private
final
DefaultResult
result
;
private
PathCostComparator
(
DefaultResult
result
)
{
this
.
result
=
result
;
}
@Override
public
int
compare
(
V
v1
,
V
v2
)
{
double
delta
=
result
.
cost
(
v2
)
-
result
.
cost
(
v1
);
return
delta
<
0
?
-
1
:
(
delta
>
0
?
1
:
0
);
}
}
// Creates a min priority queue from the specified vertexes and comparator.
private
Heap
<
V
>
createMinQueue
(
Set
<
V
>
vertexes
,
Comparator
<
V
>
comparator
)
{
return
new
Heap
<>(
new
ArrayList
<>(
vertexes
),
comparator
);
}
}
utils/misc/src/main/java/org/onlab/graph/Edge.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
/**
* Representation of a graph edge.
*
* @param <V> vertex type
*/
public
interface
Edge
<
V
extends
Vertex
>
{
/**
* Returns the edge source vertex.
*
* @return source vertex
*/
V
src
();
/**
* Returns the edge destination vertex.
*
* @return destination vertex
*/
V
dst
();
}
utils/misc/src/main/java/org/onlab/graph/EdgeWeight.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
/**
* Abstraction of a graph edge weight function.
*/
public
interface
EdgeWeight
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
{
/**
* Returns the weight of the given edge as a unit-less number.
*
* @param edge edge to be weighed
* @return edge weight as a unit-less number
*/
double
weight
(
E
edge
);
}
utils/misc/src/main/java/org/onlab/graph/Graph.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
java.util.Set
;
/**
* Abstraction of a directed graph structure.
*
* @param <V> vertex type
* @param <E> edge type
*/
public
interface
Graph
<
V
extends
Vertex
,
E
extends
Edge
>
{
/**
* Returns the set of vertexes comprising the graph.
*
* @return set of vertexes
*/
Set
<
V
>
getVertexes
();
/**
* Returns the set of edges comprising the graph.
*
* @return set of edges
*/
Set
<
E
>
getEdges
();
/**
* Returns all edges leading out from the specified source vertex.
*
* @param src source vertex
* @return set of egress edges; empty if no such edges
*/
Set
<
E
>
getEdgesFrom
(
V
src
);
/**
* Returns all edges leading towards the specified destination vertex.
*
* @param dst destination vertex
* @return set of ingress vertexes; empty if no such edges
*/
Set
<
E
>
getEdgesTo
(
V
dst
);
}
utils/misc/src/main/java/org/onlab/graph/GraphPathSearch.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
java.util.Map
;
import
java.util.Set
;
/**
* Representation of a graph path search algorithm.
*
* @param <V> vertex type
* @param <E> edge type
*/
public
interface
GraphPathSearch
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
{
/**
* Abstraction of a path search result.
*/
public
interface
Result
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
{
/**
* Returns the search source.
*
* @return search source
*/
public
V
src
();
/**
* Returns the search destination, if was was given.
*
* @return optional search destination
*/
public
V
dst
();
/**
* Returns the set of paths produced as a result of the graph search.
*
* @return set of paths
*/
Set
<
Path
<
V
,
E
>>
paths
();
/**
* Returns bindings of each vertex to its parent edges in the path.
*
* @return map of vertex to its parent edge bindings
*/
public
Map
<
V
,
Set
<
E
>>
parents
();
/**
* Return a bindings of each vertex to its cost in the path.
*
* @return map of vertex to path cost bindings
*/
public
Map
<
V
,
Double
>
costs
();
}
/**
* Searches the specified graph.
*
* @param graph graph to be searched
* @param src optional source vertex
* @param dst optional destination vertex; if null paths to all vertex
* destinations will be searched
* @param weight optional edge-weight; if null cost of each edge will be
* assumed to be 1.0
* @return search results
*/
Result
<
V
,
E
>
search
(
Graph
<
V
,
E
>
graph
,
V
src
,
V
dst
,
EdgeWeight
<
V
,
E
>
weight
);
}
utils/misc/src/main/java/org/onlab/graph/GraphSearch.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
/**
* Representation of a graph search algorithm and its outcome.
*
* @param <V> vertex type
* @param <E> edge type
*/
public
interface
GraphSearch
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
{
/**
* Notion of a graph search result.
*/
public
interface
Result
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
{
}
/**
* Searches the specified graph.
*
* @param graph graph to be searched
* @param weight optional edge-weight; if null cost of each edge will be
* assumed to be 1.0
*
* @return search results
*/
Result
search
(
Graph
<
V
,
E
>
graph
,
EdgeWeight
<
V
,
E
>
weight
);
}
utils/misc/src/main/java/org/onlab/graph/Heap.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
com.google.common.collect.ImmutableList
;
import
java.util.Comparator
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.Objects
;
import
static
com
.
google
.
common
.
base
.
Preconditions
.
checkNotNull
;
/**
* Implementation of an array-backed heap structure whose sense of order is
* imposed by the provided comparator.
* <p/>
* While this provides similar functionality to {@link java.util.PriorityQueue}
* data structure, one key difference is that external entities can control
* when to restore the heap property, which is done through invocation of the
* {@link #heapify} method.
* <p/>
* This class is not thread-safe and care must be taken to prevent concurrent
* modifications.
*
* @param <T> type of the items on the heap
*/
public
class
Heap
<
T
>
{
private
final
List
<
T
>
data
;
private
final
Comparator
<
T
>
comparator
;
/**
* Creates a new heap backed by the specified list. In the interest of
* efficiency, the list should be array-backed. Also, for the same reason,
* the data is not copied and therefore, the caller must assure that the
* backing data is not altered in any way.
*
* @param data backing data list
* @param comparator comparator for ordering the heap items
*/
public
Heap
(
List
<
T
>
data
,
Comparator
<
T
>
comparator
)
{
this
.
data
=
checkNotNull
(
data
,
"Data cannot be null"
);
this
.
comparator
=
checkNotNull
(
comparator
,
"Comparator cannot be null"
);
heapify
();
}
/**
* Restores the heap property by re-arranging the elements in the backing
* array as necessary following any heap modifications.
*/
public
void
heapify
()
{
for
(
int
i
=
data
.
size
()
/
2
;
i
>=
0
;
i
--)
{
heapify
(
i
);
}
}
/**
* Returns the current size of the heap.
*
* @return number of items in the heap
*/
public
int
size
()
{
return
data
.
size
();
}
/**
* Returns true if there are no items in the heap.
*
* @return true if heap is empty
*/
public
boolean
isEmpty
()
{
return
data
.
isEmpty
();
}
/**
* Returns the most extreme item in the heap.
*
* @return heap extreme or null if the heap is empty
*/
public
T
extreme
()
{
return
data
.
isEmpty
()
?
null
:
data
.
get
(
0
);
}
/**
* Extracts and returns the most extreme item from the heap.
*
* @return heap extreme or null if the heap is empty
*/
public
T
extractExtreme
()
{
if
(!
isEmpty
())
{
T
extreme
=
extreme
();
data
.
set
(
0
,
data
.
get
(
data
.
size
()
-
1
));
data
.
remove
(
data
.
size
()
-
1
);
heapify
();
return
extreme
;
}
return
null
;
}
/**
* Inserts the specified item into the heap and returns the modified heap.
*
* @param item item to be inserted
* @return the heap self
* @throws IllegalArgumentException if the heap is already full
*/
public
Heap
<
T
>
insert
(
T
item
)
{
data
.
add
(
item
);
bubbleUp
();
return
this
;
}
/**
* Returns iterator to traverse the heap level-by-level. This iterator
* does not permit removal of items.
*
* @return non-destructive heap iterator
*/
public
Iterator
<
T
>
iterator
()
{
return
ImmutableList
.
copyOf
(
data
).
iterator
();
}
// Bubbles up the last item in the heap to its proper position to restore
// the heap property.
private
void
bubbleUp
()
{
int
child
=
data
.
size
()
-
1
;
while
(
child
>
0
)
{
int
parent
=
child
/
2
;
if
(
comparator
.
compare
(
data
.
get
(
child
),
data
.
get
(
parent
))
<
0
)
{
break
;
}
swap
(
child
,
parent
);
child
=
parent
;
}
}
// Restores the heap property of the specified heap layer.
private
void
heapify
(
int
i
)
{
int
left
=
2
*
i
+
1
;
int
right
=
2
*
i
;
int
extreme
=
i
;
if
(
left
<
data
.
size
()
&&
comparator
.
compare
(
data
.
get
(
extreme
),
data
.
get
(
left
))
<
0
)
{
extreme
=
left
;
}
if
(
right
<
data
.
size
()
&&
comparator
.
compare
(
data
.
get
(
extreme
),
data
.
get
(
right
))
<
0
)
{
extreme
=
right
;
}
if
(
extreme
!=
i
)
{
swap
(
i
,
extreme
);
heapify
(
extreme
);
}
}
// Swaps two heap items identified by their respective indexes.
private
void
swap
(
int
i
,
int
k
)
{
T
aux
=
data
.
get
(
i
);
data
.
set
(
i
,
data
.
get
(
k
));
data
.
set
(
k
,
aux
);
}
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
obj
instanceof
Heap
)
{
Heap
that
=
(
Heap
)
obj
;
return
this
.
getClass
()
==
that
.
getClass
()
&&
Objects
.
equals
(
this
.
comparator
,
that
.
comparator
)
&&
Objects
.
deepEquals
(
this
.
data
,
that
.
data
);
}
return
false
;
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
comparator
,
data
);
}
@Override
public
String
toString
()
{
return
com
.
google
.
common
.
base
.
Objects
.
toStringHelper
(
this
)
.
add
(
"data"
,
data
)
.
add
(
"comparator"
,
comparator
)
.
toString
();
}
}
utils/misc/src/main/java/org/onlab/graph/MutableGraph.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
/**
* Abstraction of a mutable graph that can be constructed gradually.
*/
public
interface
MutableGraph
<
V
extends
Vertex
,
E
extends
Edge
>
extends
Graph
<
V
,
E
>
{
/**
* Adds the specified vertex to this graph.
*
* @param vertex new vertex
*/
void
addVertex
(
V
vertex
);
/**
* Removes the specified vertex from the graph.
*
* @param vertex vertex to be removed
*/
void
removeVertex
(
V
vertex
);
/**
* Adds the specified edge to this graph. If the edge vertexes are not
* already in the graph, they will be added as well.
*
* @param edge new edge
*/
void
addEdge
(
E
edge
);
/**
* Removes the specified edge from the graph.
*
* @param edge edge to be removed
*/
void
removeEdge
(
E
edge
);
/**
* Returns an immutable copy of this graph.
*
* @return immutable copy
*/
Graph
<
V
,
E
>
toImmutable
();
}
utils/misc/src/main/java/org/onlab/graph/MutablePath.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
/**
* Abstraction of a mutable path that allows gradual construction.
*/
public
interface
MutablePath
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
extends
Path
<
V
,
E
>
{
/**
* Inserts a new edge at the beginning of this path. The edge must be
* adjacent to the prior start of the path.
*
* @param edge edge to be inserted
*/
void
insertEdge
(
E
edge
);
/**
* Appends a new edge at the end of the this path. The edge must be
* adjacent to the prior end of the path.
*
* @param edge edge to be inserted
*/
void
appendEdge
(
E
edge
);
/**
* Removes the specified edge. This edge must be either at the start or
* at the end of the path, or it must be a cyclic edge in order not to
* violate the contiguous path property.
*
* @param edge edge to be removed
*/
void
removeEdge
(
E
edge
);
/**
* Sets the total path cost as a unit-less double.
*
* @param cost new path cost
*/
void
setCost
(
double
cost
);
/**
* Returns an immutable copy of this path.
*
* @return immutable copy
*/
Path
<
V
,
E
>
toImmutable
();
}
utils/misc/src/main/java/org/onlab/graph/Path.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
java.util.List
;
/**
* Representation of a path in a graph as a sequence of edges. Paths are
* assumed to be continuous, where adjacent edges must share a vertex.
*
* @param <V> vertex type
* @param <E> edge type
*/
public
interface
Path
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
extends
Edge
<
V
>
{
/**
* Returns the list of edges comprising the path. Adjacent edges will
* share the same vertex, meaning that a source of one edge, will be the
* same as the destination of the prior edge.
*
* @return list of path edges
*/
List
<
E
>
edges
();
/**
* Returns the total cost of the path as a unit-less number.
*
* @return path cost as a unit-less number
*/
double
cost
();
}
utils/misc/src/main/java/org/onlab/graph/Vertex.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
/**
* Representation of a graph vertex.
*/
public
interface
Vertex
{
}
utils/misc/src/main/javadoc/org/onlab/graph/package.html
0 → 100644
View file @
6e746f3
<body>
Graph abstractions and graph path finding algorithms.
</body>
\ No newline at end of file
utils/misc/src/main/javadoc/org/onlab/util/package.html
0 → 100644
View file @
6e746f3
<body>
Miscellaneous domain-agnostic utilities.
</body>
\ No newline at end of file
utils/misc/src/test/java/org/onlab/graph/AbstractEdgeTest.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
com.google.common.testing.EqualsTester
;
import
org.junit.Test
;
/**
* Test of the base edge implementation.
*/
public
class
AbstractEdgeTest
{
@Test
public
void
equality
()
{
TestVertex
v1
=
new
TestVertex
(
"1"
);
TestVertex
v2
=
new
TestVertex
(
"2"
);
new
EqualsTester
()
.
addEqualityGroup
(
new
TestEdge
(
v1
,
v2
,
1
),
new
TestEdge
(
v1
,
v2
,
1
))
.
addEqualityGroup
(
new
TestEdge
(
v2
,
v1
,
1
))
.
testEquals
();
}
}
utils/misc/src/test/java/org/onlab/graph/AbstractGraphPathSearchTest.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
org.junit.Test
;
import
static
com
.
google
.
common
.
collect
.
ImmutableSet
.
of
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
/**
* Base for all graph search tests.
*/
public
abstract
class
AbstractGraphPathSearchTest
extends
GraphTest
{
/**
* Creates a test-specific graph search to exercise.
*
* @return graph search
*/
protected
abstract
AbstractGraphPathSearch
<
TestVertex
,
TestEdge
>
graphSearch
();
@Test
(
expected
=
IllegalArgumentException
.
class
)
public
void
noSuchSourceArgument
()
{
graphSearch
().
search
(
new
AdjacencyListsGraph
<>(
of
(
B
,
C
),
of
(
new
TestEdge
(
B
,
C
,
1
))),
A
,
H
,
weight
);
}
@Test
(
expected
=
NullPointerException
.
class
)
public
void
nullGraphArgument
()
{
graphSearch
().
search
(
null
,
A
,
H
,
weight
);
}
@Test
(
expected
=
NullPointerException
.
class
)
public
void
nullSourceArgument
()
{
graphSearch
().
search
(
new
AdjacencyListsGraph
<>(
of
(
B
,
C
),
of
(
new
TestEdge
(
B
,
C
,
1
))),
null
,
H
,
weight
);
}
@Test
public
void
samenessThreshold
()
{
AbstractGraphPathSearch
<
TestVertex
,
TestEdge
>
search
=
graphSearch
();
search
.
setSamenessThreshold
(
0.3
);
assertEquals
(
"incorrect threshold"
,
0.3
,
search
.
samenessThreshold
(),
0.01
);
}
}
utils/misc/src/test/java/org/onlab/graph/AdjacencyListsGraphTest.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
com.google.common.collect.ImmutableSet
;
import
com.google.common.testing.EqualsTester
;
import
org.junit.Test
;
import
java.util.Set
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
/**
* Tests of the graph implementation.
*/
public
class
AdjacencyListsGraphTest
{
private
static
final
TestVertex
A
=
new
TestVertex
(
"A"
);
private
static
final
TestVertex
B
=
new
TestVertex
(
"B"
);
private
static
final
TestVertex
C
=
new
TestVertex
(
"C"
);
private
static
final
TestVertex
D
=
new
TestVertex
(
"D"
);
private
static
final
TestVertex
E
=
new
TestVertex
(
"E"
);
private
static
final
TestVertex
F
=
new
TestVertex
(
"F"
);
private
static
final
TestVertex
G
=
new
TestVertex
(
"G"
);
private
final
Set
<
TestEdge
>
edges
=
ImmutableSet
.
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
B
,
C
,
1
),
new
TestEdge
(
C
,
D
,
1
),
new
TestEdge
(
D
,
A
,
1
),
new
TestEdge
(
B
,
D
,
1
));
@Test
public
void
equality
()
{
Set
<
TestVertex
>
vertexes
=
ImmutableSet
.
of
(
A
,
B
,
C
,
D
,
E
,
F
);
Set
<
TestVertex
>
vertexes2
=
ImmutableSet
.
of
(
A
,
B
,
C
,
D
,
E
,
F
,
G
);
AdjacencyListsGraph
<
TestVertex
,
TestEdge
>
graph
=
new
AdjacencyListsGraph
<>(
vertexes
,
edges
);
AdjacencyListsGraph
<
TestVertex
,
TestEdge
>
same
=
new
AdjacencyListsGraph
<>(
vertexes
,
edges
);
AdjacencyListsGraph
<
TestVertex
,
TestEdge
>
different
=
new
AdjacencyListsGraph
<>(
vertexes2
,
edges
);
new
EqualsTester
()
.
addEqualityGroup
(
graph
,
same
)
.
addEqualityGroup
(
different
)
.
testEquals
();
}
@Test
public
void
basics
()
{
Set
<
TestVertex
>
vertexes
=
ImmutableSet
.
of
(
A
,
B
,
C
,
D
,
E
,
F
);
AdjacencyListsGraph
<
TestVertex
,
TestEdge
>
graph
=
new
AdjacencyListsGraph
<>(
vertexes
,
edges
);
assertEquals
(
"incorrect vertex count"
,
6
,
graph
.
getVertexes
().
size
());
assertEquals
(
"incorrect edge count"
,
5
,
graph
.
getEdges
().
size
());
assertEquals
(
"incorrect egress edge count"
,
1
,
graph
.
getEdgesFrom
(
A
).
size
());
assertEquals
(
"incorrect ingress edge count"
,
1
,
graph
.
getEdgesTo
(
A
).
size
());
assertEquals
(
"incorrect ingress edge count"
,
1
,
graph
.
getEdgesTo
(
C
).
size
());
assertEquals
(
"incorrect egress edge count"
,
2
,
graph
.
getEdgesFrom
(
B
).
size
());
assertEquals
(
"incorrect ingress edge count"
,
2
,
graph
.
getEdgesTo
(
D
).
size
());
}
}
utils/misc/src/test/java/org/onlab/graph/BellmanFordGraphSearchTest.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
org.junit.Test
;
import
java.util.HashSet
;
import
java.util.Set
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
/**
* Test of the Bellman-Ford algorithm.
*/
public
class
BellmanFordGraphSearchTest
extends
BreadthFirstSearchTest
{
@Override
protected
AbstractGraphPathSearch
<
TestVertex
,
TestEdge
>
graphSearch
()
{
return
new
BellmanFordGraphSearch
<>();
}
@Test
@Override
public
void
defaultGraphTest
()
{
executeDefaultTest
(
7
,
5
,
5.0
);
}
@Test
public
void
defaultHopCountWeight
()
{
weight
=
null
;
executeDefaultTest
(
10
,
3
,
3.0
);
}
@Test
public
void
searchGraphWithNegativeCycles
()
{
Set
<
TestVertex
>
vertexes
=
new
HashSet
<>(
vertices
());
vertexes
.
add
(
Z
);
Set
<
TestEdge
>
edges
=
new
HashSet
<>(
edges
());
edges
.
add
(
new
TestEdge
(
G
,
Z
,
1.0
));
edges
.
add
(
new
TestEdge
(
Z
,
G
,
-
2.0
));
g
=
new
AdjacencyListsGraph
<>(
vertexes
,
edges
);
GraphPathSearch
<
TestVertex
,
TestEdge
>
search
=
graphSearch
();
Set
<
Path
<
TestVertex
,
TestEdge
>>
paths
=
search
.
search
(
g
,
A
,
H
,
weight
).
paths
();
assertEquals
(
"incorrect paths count"
,
1
,
paths
.
size
());
Path
p
=
paths
.
iterator
().
next
();
assertEquals
(
"incorrect src"
,
A
,
p
.
src
());
assertEquals
(
"incorrect dst"
,
H
,
p
.
dst
());
assertEquals
(
"incorrect path length"
,
5
,
p
.
edges
().
size
());
assertEquals
(
"incorrect path cost"
,
5.0
,
p
.
cost
(),
0.1
);
paths
=
search
.
search
(
g
,
A
,
G
,
weight
).
paths
();
assertEquals
(
"incorrect paths count"
,
0
,
paths
.
size
());
paths
=
search
.
search
(
g
,
A
,
null
,
weight
).
paths
();
printPaths
(
paths
);
assertEquals
(
"incorrect paths count"
,
6
,
paths
.
size
());
}
}
utils/misc/src/test/java/org/onlab/graph/BreadthFirstSearchTest.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
org.junit.Test
;
import
java.util.Set
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
/**
* Test of the BFS and similar path search algorithms.
*/
public
class
BreadthFirstSearchTest
extends
AbstractGraphPathSearchTest
{
@Override
protected
AbstractGraphPathSearch
<
TestVertex
,
TestEdge
>
graphSearch
()
{
return
new
BreadthFirstSearch
<>();
}
@Test
public
void
defaultGraphTest
()
{
executeDefaultTest
(
7
,
3
,
8.0
);
}
@Test
public
void
defaultHopCountWeight
()
{
weight
=
null
;
executeDefaultTest
(
7
,
3
,
3.0
);
}
// Executes the default test
protected
void
executeDefaultTest
(
int
pathCount
,
int
pathLength
,
double
pathCost
)
{
g
=
new
AdjacencyListsGraph
<>(
vertices
(),
edges
());
GraphPathSearch
<
TestVertex
,
TestEdge
>
search
=
graphSearch
();
Set
<
Path
<
TestVertex
,
TestEdge
>>
paths
=
search
.
search
(
g
,
A
,
H
,
weight
).
paths
();
assertEquals
(
"incorrect paths count"
,
1
,
paths
.
size
());
Path
p
=
paths
.
iterator
().
next
();
assertEquals
(
"incorrect src"
,
A
,
p
.
src
());
assertEquals
(
"incorrect dst"
,
H
,
p
.
dst
());
assertEquals
(
"incorrect path length"
,
pathLength
,
p
.
edges
().
size
());
assertEquals
(
"incorrect path cost"
,
pathCost
,
p
.
cost
(),
0.1
);
paths
=
search
.
search
(
g
,
A
,
null
,
weight
).
paths
();
printPaths
(
paths
);
assertEquals
(
"incorrect paths count"
,
pathCount
,
paths
.
size
());
}
// Executes the search and validates its results.
protected
void
executeSearch
(
GraphPathSearch
<
TestVertex
,
TestEdge
>
search
,
Graph
<
TestVertex
,
TestEdge
>
graph
,
TestVertex
src
,
TestVertex
dst
,
EdgeWeight
<
TestVertex
,
TestEdge
>
weight
,
int
pathCount
,
double
pathCost
)
{
GraphPathSearch
.
Result
<
TestVertex
,
TestEdge
>
result
=
search
.
search
(
graph
,
src
,
dst
,
weight
);
Set
<
Path
<
TestVertex
,
TestEdge
>>
paths
=
result
.
paths
();
printPaths
(
paths
);
assertEquals
(
"incorrect paths count"
,
pathCount
,
paths
.
size
());
if
(
pathCount
>
0
)
{
Path
<
TestVertex
,
TestEdge
>
path
=
paths
.
iterator
().
next
();
assertEquals
(
"incorrect path cost"
,
pathCost
,
path
.
cost
(),
0.1
);
}
}
}
utils/misc/src/test/java/org/onlab/graph/DefaultMutablePathTest.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
com.google.common.testing.EqualsTester
;
import
org.junit.Test
;
import
static
com
.
google
.
common
.
collect
.
ImmutableList
.
of
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertNull
;
/**
* Test of the default mutable path.
*/
public
class
DefaultMutablePathTest
extends
DefaultPathTest
{
@Test
public
void
equality
()
{
DefaultPath
<
TestVertex
,
TestEdge
>
p1
=
new
DefaultPath
<>(
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
B
,
C
,
1
)),
2.0
);
DefaultPath
<
TestVertex
,
TestEdge
>
p2
=
new
DefaultPath
<>(
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
B
,
D
,
1
)),
2.0
);
new
EqualsTester
().
addEqualityGroup
(
new
DefaultMutablePath
<>(
p1
),
new
DefaultMutablePath
<>(
p1
))
.
addEqualityGroup
(
new
DefaultMutablePath
<>(
p2
))
.
testEquals
();
}
@Test
public
void
empty
()
{
MutablePath
<
TestVertex
,
TestEdge
>
p
=
new
DefaultMutablePath
<>();
assertNull
(
"src should be null"
,
p
.
src
());
assertNull
(
"dst should be null"
,
p
.
dst
());
assertEquals
(
"incorrect edge count"
,
0
,
p
.
edges
().
size
());
assertEquals
(
"incorrect path cost"
,
0.0
,
p
.
cost
(),
0.1
);
}
@Test
public
void
pathCost
()
{
MutablePath
<
TestVertex
,
TestEdge
>
p
=
new
DefaultMutablePath
<>();
p
.
setCost
(
4
);
assertEquals
(
"incorrect path cost"
,
4.0
,
p
.
cost
(),
0.1
);
}
private
void
validatePath
(
Path
<
TestVertex
,
TestEdge
>
p
,
TestVertex
src
,
TestVertex
dst
,
int
length
)
{
validatePath
(
p
,
src
,
dst
,
length
,
0.0
);
}
@Test
public
void
insertEdge
()
{
MutablePath
<
TestVertex
,
TestEdge
>
p
=
new
DefaultMutablePath
<>();
p
.
insertEdge
(
new
TestEdge
(
B
,
C
,
1
));
p
.
insertEdge
(
new
TestEdge
(
A
,
B
,
1
));
validatePath
(
p
,
A
,
C
,
2
);
}
@Test
public
void
appendEdge
()
{
MutablePath
<
TestVertex
,
TestEdge
>
p
=
new
DefaultMutablePath
<>();
p
.
appendEdge
(
new
TestEdge
(
A
,
B
,
1
));
p
.
appendEdge
(
new
TestEdge
(
B
,
C
,
1
));
validatePath
(
p
,
A
,
C
,
2
);
}
@Test
public
void
removeEdge
()
{
MutablePath
<
TestVertex
,
TestEdge
>
p
=
new
DefaultMutablePath
<>();
p
.
appendEdge
(
new
TestEdge
(
A
,
B
,
1
));
p
.
appendEdge
(
new
TestEdge
(
B
,
C
,
1
));
p
.
appendEdge
(
new
TestEdge
(
C
,
C
,
2
));
p
.
appendEdge
(
new
TestEdge
(
C
,
D
,
1
));
validatePath
(
p
,
A
,
D
,
4
);
p
.
removeEdge
(
new
TestEdge
(
A
,
B
,
1
));
validatePath
(
p
,
B
,
D
,
3
);
p
.
removeEdge
(
new
TestEdge
(
C
,
C
,
2
));
validatePath
(
p
,
B
,
D
,
2
);
p
.
removeEdge
(
new
TestEdge
(
C
,
D
,
1
));
validatePath
(
p
,
B
,
C
,
1
);
}
@Test
public
void
toImmutable
()
{
MutablePath
<
TestVertex
,
TestEdge
>
p
=
new
DefaultMutablePath
<>();
p
.
appendEdge
(
new
TestEdge
(
A
,
B
,
1
));
p
.
appendEdge
(
new
TestEdge
(
B
,
C
,
1
));
validatePath
(
p
,
A
,
C
,
2
);
assertEquals
(
"immutables should equal"
,
p
.
toImmutable
(),
p
.
toImmutable
());
validatePath
(
p
.
toImmutable
(),
A
,
C
,
2
);
}
}
utils/misc/src/test/java/org/onlab/graph/DefaultPathTest.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
com.google.common.testing.EqualsTester
;
import
org.junit.Test
;
import
java.util.List
;
import
static
com
.
google
.
common
.
collect
.
ImmutableList
.
of
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
/**
* Test of the default path.
*/
public
class
DefaultPathTest
extends
GraphTest
{
@Test
public
void
equality
()
{
List
<
TestEdge
>
edges
=
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
B
,
C
,
1
));
new
EqualsTester
().
addEqualityGroup
(
new
DefaultPath
<>(
edges
,
2.0
),
new
DefaultPath
<>(
edges
,
2.0
))
.
addEqualityGroup
(
new
DefaultPath
<>(
edges
,
3.0
))
.
testEquals
();
}
@Test
public
void
basics
()
{
Path
<
TestVertex
,
TestEdge
>
p
=
new
DefaultPath
<>(
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
B
,
C
,
1
)),
2.0
);
validatePath
(
p
,
A
,
C
,
2
,
2.0
);
}
// Validates the path against expected attributes
protected
void
validatePath
(
Path
<
TestVertex
,
TestEdge
>
p
,
TestVertex
src
,
TestVertex
dst
,
int
length
,
double
cost
)
{
assertEquals
(
"incorrect path length"
,
length
,
p
.
edges
().
size
());
assertEquals
(
"incorrect source"
,
src
,
p
.
src
());
assertEquals
(
"incorrect destination"
,
dst
,
p
.
dst
());
assertEquals
(
"incorrect path cost"
,
cost
,
p
.
cost
(),
0.1
);
}
}
utils/misc/src/test/java/org/onlab/graph/DepthFirstSearchTest.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
org.junit.Test
;
import
java.util.Set
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
static
org
.
onlab
.
graph
.
DepthFirstSearch
.
EdgeType
;
/**
* Test of the DFS algorithm.
*/
public
class
DepthFirstSearchTest
extends
AbstractGraphPathSearchTest
{
@Override
protected
DepthFirstSearch
<
TestVertex
,
TestEdge
>
graphSearch
()
{
return
new
DepthFirstSearch
<>();
}
@Test
public
void
defaultGraphTest
()
{
executeDefaultTest
(
3
,
6
,
5.0
,
12.0
);
executeBroadSearch
();
}
@Test
public
void
defaultHopCountWeight
()
{
weight
=
null
;
executeDefaultTest
(
3
,
6
,
3.0
,
6.0
);
executeBroadSearch
();
}
protected
void
executeDefaultTest
(
int
minLength
,
int
maxLength
,
double
minCost
,
double
maxCost
)
{
g
=
new
AdjacencyListsGraph
<>(
vertices
(),
edges
());
DepthFirstSearch
<
TestVertex
,
TestEdge
>
search
=
graphSearch
();
DepthFirstSearch
<
TestVertex
,
TestEdge
>.
SpanningTreeResult
result
=
search
.
search
(
g
,
A
,
H
,
weight
);
Set
<
Path
<
TestVertex
,
TestEdge
>>
paths
=
result
.
paths
();
assertEquals
(
"incorrect path count"
,
1
,
paths
.
size
());
Path
path
=
paths
.
iterator
().
next
();
System
.
out
.
println
(
path
);
assertEquals
(
"incorrect src"
,
A
,
path
.
src
());
assertEquals
(
"incorrect dst"
,
H
,
path
.
dst
());
int
l
=
path
.
edges
().
size
();
assertTrue
(
"incorrect path length "
+
l
,
minLength
<=
l
&&
l
<=
maxLength
);
assertTrue
(
"incorrect path cost "
+
path
.
cost
(),
minCost
<=
path
.
cost
()
&&
path
.
cost
()
<=
maxCost
);
System
.
out
.
println
(
result
.
edges
());
printPaths
(
paths
);
}
public
void
executeBroadSearch
()
{
g
=
new
AdjacencyListsGraph
<>(
vertices
(),
edges
());
DepthFirstSearch
<
TestVertex
,
TestEdge
>
search
=
graphSearch
();
// Perform narrow path search to a specific destination.
DepthFirstSearch
<
TestVertex
,
TestEdge
>.
SpanningTreeResult
result
=
search
.
search
(
g
,
A
,
null
,
weight
);
assertEquals
(
"incorrect paths count"
,
7
,
result
.
paths
().
size
());
int
[]
types
=
new
int
[]{
0
,
0
,
0
,
0
};
for
(
EdgeType
t
:
result
.
edges
().
values
())
{
types
[
t
.
ordinal
()]
+=
1
;
}
assertEquals
(
"incorrect tree-edge count"
,
7
,
types
[
EdgeType
.
TREE_EDGE
.
ordinal
()]);
assertEquals
(
"incorrect back-edge count"
,
1
,
types
[
EdgeType
.
BACK_EDGE
.
ordinal
()]);
assertEquals
(
"incorrect cross-edge & forward-edge count"
,
4
,
types
[
EdgeType
.
FORWARD_EDGE
.
ordinal
()]
+
types
[
EdgeType
.
CROSS_EDGE
.
ordinal
()]);
}
}
utils/misc/src/test/java/org/onlab/graph/DijkstraGraphSearchTest.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
org.junit.Test
;
import
java.util.Set
;
import
static
com
.
google
.
common
.
collect
.
ImmutableSet
.
of
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
/**
* Test of the Dijkstra algorithm.
*/
public
class
DijkstraGraphSearchTest
extends
BreadthFirstSearchTest
{
@Override
protected
AbstractGraphPathSearch
<
TestVertex
,
TestEdge
>
graphSearch
()
{
return
new
DijkstraGraphSearch
<>();
}
@Test
@Override
public
void
defaultGraphTest
()
{
executeDefaultTest
(
7
,
5
,
5.0
);
}
@Test
@Override
public
void
defaultHopCountWeight
()
{
weight
=
null
;
executeDefaultTest
(
10
,
3
,
3.0
);
}
@Test
public
void
noPath
()
{
g
=
new
AdjacencyListsGraph
<>(
of
(
A
,
B
,
C
,
D
),
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
B
,
A
,
1
),
new
TestEdge
(
C
,
D
,
1
),
new
TestEdge
(
D
,
C
,
1
)));
GraphPathSearch
<
TestVertex
,
TestEdge
>
gs
=
graphSearch
();
Set
<
Path
<
TestVertex
,
TestEdge
>>
paths
=
gs
.
search
(
g
,
A
,
B
,
weight
).
paths
();
printPaths
(
paths
);
assertEquals
(
"incorrect paths count"
,
1
,
paths
.
size
());
assertEquals
(
"incorrect path cost"
,
1.0
,
paths
.
iterator
().
next
().
cost
(),
0.1
);
paths
=
gs
.
search
(
g
,
A
,
D
,
weight
).
paths
();
printPaths
(
paths
);
assertEquals
(
"incorrect paths count"
,
0
,
paths
.
size
());
paths
=
gs
.
search
(
g
,
A
,
null
,
weight
).
paths
();
printPaths
(
paths
);
assertEquals
(
"incorrect paths count"
,
1
,
paths
.
size
());
assertEquals
(
"incorrect path cost"
,
1.0
,
paths
.
iterator
().
next
().
cost
(),
0.1
);
}
@Test
public
void
simpleMultiplePath
()
{
g
=
new
AdjacencyListsGraph
<>(
of
(
A
,
B
,
C
,
D
),
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
A
,
C
,
1
),
new
TestEdge
(
B
,
D
,
1
),
new
TestEdge
(
C
,
D
,
1
)));
executeSearch
(
graphSearch
(),
g
,
A
,
D
,
weight
,
2
,
2.0
);
}
@Test
public
void
denseMultiplePath
()
{
g
=
new
AdjacencyListsGraph
<>(
of
(
A
,
B
,
C
,
D
,
E
,
F
,
G
),
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
A
,
C
,
1
),
new
TestEdge
(
B
,
D
,
1
),
new
TestEdge
(
C
,
D
,
1
),
new
TestEdge
(
D
,
E
,
1
),
new
TestEdge
(
D
,
F
,
1
),
new
TestEdge
(
E
,
G
,
1
),
new
TestEdge
(
F
,
G
,
1
),
new
TestEdge
(
A
,
G
,
4
)));
executeSearch
(
graphSearch
(),
g
,
A
,
G
,
weight
,
5
,
4.0
);
}
@Test
public
void
dualEdgeMultiplePath
()
{
g
=
new
AdjacencyListsGraph
<>(
of
(
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
),
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
A
,
C
,
3
),
new
TestEdge
(
B
,
D
,
2
),
new
TestEdge
(
B
,
C
,
1
),
new
TestEdge
(
B
,
E
,
4
),
new
TestEdge
(
C
,
E
,
1
),
new
TestEdge
(
D
,
H
,
5
),
new
TestEdge
(
D
,
E
,
1
),
new
TestEdge
(
E
,
F
,
1
),
new
TestEdge
(
F
,
D
,
1
),
new
TestEdge
(
F
,
G
,
1
),
new
TestEdge
(
F
,
H
,
1
),
new
TestEdge
(
A
,
E
,
3
),
new
TestEdge
(
B
,
D
,
1
)));
executeSearch
(
graphSearch
(),
g
,
A
,
E
,
weight
,
3
,
3.0
);
}
}
utils/misc/src/test/java/org/onlab/graph/GraphTest.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
java.util.Set
;
import
static
com
.
google
.
common
.
collect
.
ImmutableSet
.
of
;
/**
* Base class for various graph-related tests.
*/
public
class
GraphTest
{
static
final
TestVertex
A
=
new
TestVertex
(
"A"
);
static
final
TestVertex
B
=
new
TestVertex
(
"B"
);
static
final
TestVertex
C
=
new
TestVertex
(
"C"
);
static
final
TestVertex
D
=
new
TestVertex
(
"D"
);
static
final
TestVertex
E
=
new
TestVertex
(
"E"
);
static
final
TestVertex
F
=
new
TestVertex
(
"F"
);
static
final
TestVertex
G
=
new
TestVertex
(
"G"
);
static
final
TestVertex
H
=
new
TestVertex
(
"H"
);
static
final
TestVertex
Z
=
new
TestVertex
(
"Z"
);
protected
Graph
<
TestVertex
,
TestEdge
>
g
;
protected
EdgeWeight
<
TestVertex
,
TestEdge
>
weight
=
new
EdgeWeight
<
TestVertex
,
TestEdge
>()
{
@Override
public
double
weight
(
TestEdge
edge
)
{
return
edge
.
weight
();
}
};
protected
void
printPaths
(
Set
<
Path
<
TestVertex
,
TestEdge
>>
paths
)
{
for
(
Path
p
:
paths
)
{
System
.
out
.
println
(
p
);
}
}
protected
Set
<
TestVertex
>
vertices
()
{
return
of
(
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
);
}
protected
Set
<
TestEdge
>
edges
()
{
return
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
A
,
C
,
3
),
new
TestEdge
(
B
,
D
,
2
),
new
TestEdge
(
B
,
C
,
1
),
new
TestEdge
(
B
,
E
,
4
),
new
TestEdge
(
C
,
E
,
1
),
new
TestEdge
(
D
,
H
,
5
),
new
TestEdge
(
D
,
E
,
1
),
new
TestEdge
(
E
,
F
,
1
),
new
TestEdge
(
F
,
D
,
1
),
new
TestEdge
(
F
,
G
,
1
),
new
TestEdge
(
F
,
H
,
1
));
}
}
utils/misc/src/test/java/org/onlab/graph/HeapTest.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
com.google.common.collect.Ordering
;
import
com.google.common.testing.EqualsTester
;
import
org.junit.Test
;
import
java.util.ArrayList
;
import
java.util.Comparator
;
import
static
com
.
google
.
common
.
collect
.
ImmutableList
.
of
;
import
static
org
.
junit
.
Assert
.*;
/**
* Heap data structure tests.
*/
public
class
HeapTest
{
private
ArrayList
<
Integer
>
data
=
new
ArrayList
<>(
of
(
6
,
4
,
5
,
9
,
8
,
3
,
2
,
1
,
7
,
0
));
private
static
final
Comparator
<
Integer
>
MIN
=
Ordering
.
natural
().
reverse
();
private
static
final
Comparator
<
Integer
>
MAX
=
Ordering
.
natural
();
@Test
public
void
equality
()
{
new
EqualsTester
()
.
addEqualityGroup
(
new
Heap
<>(
data
,
MIN
),
new
Heap
<>(
data
,
MIN
))
.
addEqualityGroup
(
new
Heap
<>(
data
,
MAX
))
.
testEquals
();
}
@Test
public
void
empty
()
{
Heap
<
Integer
>
h
=
new
Heap
<>(
new
ArrayList
<
Integer
>(),
MIN
);
assertTrue
(
"should be empty"
,
h
.
isEmpty
());
assertEquals
(
"incorrect size"
,
0
,
h
.
size
());
assertNull
(
"no item expected"
,
h
.
extreme
());
assertNull
(
"no item expected"
,
h
.
extractExtreme
());
}
@Test
public
void
insert
()
{
Heap
<
Integer
>
h
=
new
Heap
<>(
data
,
MIN
);
assertEquals
(
"incorrect size"
,
10
,
h
.
size
());
h
.
insert
(
3
);
assertEquals
(
"incorrect size"
,
11
,
h
.
size
());
}
@Test
public
void
minQueue
()
{
Heap
<
Integer
>
h
=
new
Heap
<>(
data
,
MIN
);
assertFalse
(
"should not be empty"
,
h
.
isEmpty
());
assertEquals
(
"incorrect size"
,
10
,
h
.
size
());
assertEquals
(
"incorrect extreme"
,
(
Integer
)
0
,
h
.
extreme
());
for
(
int
i
=
0
,
n
=
h
.
size
();
i
<
n
;
i
++)
{
assertEquals
(
"incorrect element"
,
(
Integer
)
i
,
h
.
extractExtreme
());
}
assertTrue
(
"should be empty"
,
h
.
isEmpty
());
}
@Test
public
void
maxQueue
()
{
Heap
<
Integer
>
h
=
new
Heap
<>(
data
,
MAX
);
assertFalse
(
"should not be empty"
,
h
.
isEmpty
());
assertEquals
(
"incorrect size"
,
10
,
h
.
size
());
assertEquals
(
"incorrect extreme"
,
(
Integer
)
9
,
h
.
extreme
());
for
(
int
i
=
h
.
size
();
i
>
0
;
i
--)
{
assertEquals
(
"incorrect element"
,
(
Integer
)
(
i
-
1
),
h
.
extractExtreme
());
}
assertTrue
(
"should be empty"
,
h
.
isEmpty
());
}
@Test
public
void
iterator
()
{
Heap
<
Integer
>
h
=
new
Heap
<>(
data
,
MIN
);
assertTrue
(
"should have next element"
,
h
.
iterator
().
hasNext
());
}
}
utils/misc/src/test/java/org/onlab/graph/TestEdge.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
java.util.Objects
;
import
static
com
.
google
.
common
.
base
.
Objects
.
toStringHelper
;
/**
* Test edge.
*/
public
class
TestEdge
extends
AbstractEdge
<
TestVertex
>
{
private
final
double
weight
;
/**
* Creates a new edge between the specified source and destination vertexes.
*
* @param src source vertex
* @param dst destination vertex
* @param weight edge weight
*/
public
TestEdge
(
TestVertex
src
,
TestVertex
dst
,
double
weight
)
{
super
(
src
,
dst
);
this
.
weight
=
weight
;
}
/**
* Returns the edge weight.
*
* @return edge weight
*/
public
double
weight
()
{
return
weight
;
}
@Override
public
int
hashCode
()
{
return
31
*
super
.
hashCode
()
+
Objects
.
hash
(
weight
);
}
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
obj
instanceof
TestEdge
)
{
final
TestEdge
other
=
(
TestEdge
)
obj
;
return
super
.
equals
(
obj
)
&&
Objects
.
equals
(
this
.
weight
,
other
.
weight
);
}
return
false
;
}
@Override
public
String
toString
()
{
return
toStringHelper
(
this
).
add
(
"src"
,
src
()).
add
(
"dst"
,
dst
()).
add
(
"weight"
,
weight
).
toString
();
}
}
utils/misc/src/test/java/org/onlab/graph/TestVertex.java
0 → 100644
View file @
6e746f3
package
org
.
onlab
.
graph
;
import
java.util.Objects
;
/**
* Test vertex.
*/
public
class
TestVertex
implements
Vertex
{
private
final
String
name
;
public
TestVertex
(
String
name
)
{
this
.
name
=
name
;
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
name
);
}
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
obj
instanceof
TestVertex
)
{
final
TestVertex
other
=
(
TestVertex
)
obj
;
return
Objects
.
equals
(
this
.
name
,
other
.
name
);
}
return
false
;
}
@Override
public
String
toString
()
{
return
name
;
}
}
Please
register
or
login
to post a comment