Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/review_JS'
Browse files Browse the repository at this point in the history
  • Loading branch information
Philipp Sauter committed Oct 15, 2019
2 parents e65d775 + 95e4eb7 commit b027c0f
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 60 deletions.
9 changes: 6 additions & 3 deletions Oliver30/cmd/plot/plot.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ import (
)

var (
X = flag.Int("X", -1, "column to be plotted on X axis(first column is 0)")
// X TODO comment
X = flag.Int("X", -1, "column to be plotted on X axis(first column is 0)")
// Y TODO comment
Y = flag.Int("Y", -1, "column to be plotted on Y axis(first column is 0)")
i = flag.String("i", "", "name of the input file containing CSV formated data, the columns you want to parse need to be convertible to float64")
i = flag.String("i", "", "name of the input file containing CSV formated data, the columns you want to parse need to be convertible to float64")
o = flag.String("o", "", "name of the file where the PNG containing the plot should be saved")
title = flag.String("title", "", "title of the plot (optional)")
title = flag.String("title", "Prblem", "title of the plot (optional)")
)

// Abort TODO comment
func Abort() {
flag.Usage()
os.Exit(1)
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
This branch follows the implementation of the Ant System Algorithm as described in Dorigo et al. 96.
94 changes: 48 additions & 46 deletions aco.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// package aco provides the Ant System algorithm according to Dorigo, Maniezzo and Colorni 1996:
// Package aco provides the Ant System algorithm according to Dorigo, Maniezzo and Colorni 1996:
// The Ant System: Optimization by a colony of cooperating agents
// Marco Dorigo, Vittorio Maniezzo and Alberto Colorni
// IEEE Transactions on Systems, Man, and Cybernetics–Part B, Vol.26, No.1, 1996, pp.1-13
Expand Down Expand Up @@ -59,29 +59,37 @@ func cloneGraph(g Graph) Graph {
}

// GetEdge retrieves the edge (vi, vj) from graph.Edges where vi and vj are Vertex.Index.
// Vertex holds the integer index used to address the rows in the Graph.Edges matrix and a string Label.
type Vertex struct {
Index int
// Label has no meaning to the Ant System algorithm it is only used to output the result.
Label string
}

// Edge holds one edge of a Graph with Length information
type Edge struct {
Length float64
// Visibility increases the chance that an Ant takes this Edge. Usually Visibility = 1.0 / Length
Visibility float64 // Will be overwritten by Ant System Algorithm
// TODO TrailIntensity definition.
TrailIntensity float64 // Will be overwritten by Ant System Algorithm
}

// GetEdge retrieves the edge (vi, vj) from Graph.Edges where vi and vj are Vertex.Index.
// GetEdge(vi, vj) == GetEdge(vj, vi)
func (graph *Graph) GetEdge(vi, vj int) (*Edge, error) {
switch {
case vi == vj:
return nil, fmt.Errorf("vi == vj == %d; graph should not have circular Edges", vi)
case vj < vi:
return &graph.Edges[vi][vj], nil
case vj > vi:
return &graph.Edges[vj][vi], nil
default:
return nil, fmt.Errorf("this error should be impossible; none of the cases vi == vj, vj < vi or vj > vi have evaluated to true")
return &graph.Edges[vj][vi], nil
}
}

// Vertex holds the integer index used to address the rows in the Graph.Edges matrix and a string Label.
type Vertex struct {
Index int
// Label has no meaning to the Ant System algorithm it is only used to output the result.
Label string
}

// TODO can this be optimized?
// GetOutEdges returns a list of pointers to all Edges exiting from Vertex v
// TODO can this be optimized?
func (v *Vertex) GetOutEdges(g Graph) []*Edge {
// since g is fully connected without cyclical Edges, we can expect nVertices - 1 outgoing Edges
outEdges := make([]*Edge, 0, len(g.Vertices)-1)
Expand All @@ -101,11 +109,9 @@ func (v *Vertex) GetOutEdges(g Graph) []*Edge {
return outEdges
}

// Only used by CompNodeBranching
const epsilon = 0.000000000001

// CompNodeBranching computes the number of outgoing edges of Vertex v with a TrailIntensity > epsilon
func (v *Vertex) CompNodeBranching(g Graph) (nodeBranching int) {
const epsilon = 0.000000000001
outEdges := v.GetOutEdges(g)
nodeBranching = 0
for _, e := range outEdges {
Expand All @@ -116,14 +122,6 @@ func (v *Vertex) CompNodeBranching(g Graph) (nodeBranching int) {
return nodeBranching
}

// Edge holds one edge of a Graph with Length information
type Edge struct {
Length float64
// Visibility increases the chance that an Ant takes this Edge. Usually Visibility = 1.0 / Length
Visibility float64 // Will be overwritten by Ant System Algorithm
TrailIntensity float64 // Will be overwritten by Ant System Algorithm
}

// CompEuclid2dDist computes the euclidean distance between two 2 dimensional points a and b.
func CompEuclid2dDist(aX, aY, bX, bY float64) float64 {
abXdist := aX - bX
Expand All @@ -132,6 +130,7 @@ func CompEuclid2dDist(aX, aY, bX, bY float64) float64 {
return dist
}

// Tour TODO Not commented
type Tour []*Vertex

// EqualTour returns true if both tours contain the same vertices, in the same order and have the same total number of vertices
Expand Down Expand Up @@ -167,22 +166,21 @@ func EqualTour(a, b Tour) bool {
}
if toursForwardEqual {
return true
} else {
// same procedure in reverse
toursReverseEqual := true
bOffset = eqInd
for i := 0; i < len(a); i++ {
// if the last element of b has been reached, continue comparing from the first element onwards
if bOffset-i < 0 {
bOffset = len(a) + bOffset
}
if a[i] != b[bOffset-i] {
toursReverseEqual = false
break
}
}
// same procedure in reverse
toursReverseEqual := true
bOffset = eqInd
for i := 0; i < len(a); i++ {
// if the last element of b has been reached, continue comparing from the first element onwards
if bOffset-i < 0 {
bOffset = len(a) + bOffset
}
if a[i] != b[bOffset-i] {
toursReverseEqual = false
break
}
return toursReverseEqual
}
return toursReverseEqual
}
return false
}
Expand All @@ -204,6 +202,8 @@ type Ant struct {

// TODO generalize together with initialization
// TODO you can probably delete this

// EmptyTabuList TODO not commented
func (ant *Ant) EmptyTabuList() {
// TODO ant.TabuList = make(Tour, 0, nVertices)
ant.TabuList = make(Tour, 0)
Expand Down Expand Up @@ -236,9 +236,9 @@ func CheckFullyConnected(graph Graph) error {

if errMsg != "" {
return fmt.Errorf(errMsg)
} else {
return nil
}
return nil

}

// MoveToNextVertex chooses the town to go to with a probability that is a function of the town distance and of the amount of trail present on the connecting edge
Expand Down Expand Up @@ -320,7 +320,7 @@ func (ant *Ant) MoveToNextVertex(alpha, beta float64, graph Graph) error {
return nil
}

// CompTotTourLen computes the total length of this ant's tour
// CompTotLength computes the total length of this ant's tour
func CompTotLength(graph Graph, tour Tour) float64 {
var totLength float64 = 0
for i := 0; i < len(tour)-1; i++ {
Expand All @@ -344,10 +344,11 @@ func CompTotLength(graph Graph, tour Tour) float64 {
}

// LayTrailAntCycle when ant completes a tour, it lays a substance called trail on each edge visited.
// This is the main procedure used in the publication, referred to as ant-cycle, but they also proposed two alternatives LayTrailAntDensity and LayTrailAntQuantity on page 8
// This is the main procedure used in the publication, referred to as ant-cycle, but they also proposed two alternatives
// LayTrailAntDensity and LayTrailAntQuantity on page 8
// TODO [#B] This computation needs to be done concurrently without race conditions
func LayTrailAntCycle(Q float64, graph Graph, ant Ant) {
L_k := CompTotLength(graph, ant.TabuList)
LK := CompTotLength(graph, ant.TabuList)
for i := 0; i < len(ant.TabuList)-1; i++ {
v := ant.TabuList[i].Index
vNext := ant.TabuList[i+1].Index
Expand All @@ -356,7 +357,7 @@ func LayTrailAntCycle(Q float64, graph Graph, ant Ant) {
// TODO
panic(err)
}
edge.TrailIntensity += Q / L_k
edge.TrailIntensity += Q / LK
}
firstV := ant.TabuList[0].Index
lastV := ant.TabuList[len(ant.TabuList)-1].Index
Expand All @@ -365,7 +366,7 @@ func LayTrailAntCycle(Q float64, graph Graph, ant Ant) {
// TODO
panic(err)
}
edge.TrailIntensity += Q / L_k
edge.TrailIntensity += Q / LK
}

// CheckSolutionValid checks that all Vertices in proglemGraph are visited exactly once.
Expand Down Expand Up @@ -410,11 +411,12 @@ func CheckSolutionValid(solution Tour, proglemGraph Graph) error {

if errMsg == "" {
return nil
} else {
return fmt.Errorf(errMsg)
}
return fmt.Errorf(errMsg)

}

// CompTotPhermone TODO comment
func CompTotPhermone(g Graph) float64 {
var totPher float64 = 0
for ei := 0; ei < len(g.Edges); ei++ {
Expand Down
21 changes: 18 additions & 3 deletions aco_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,15 @@ func TestSquare(t *testing.T) {
// create square graph
squareGraph := Graph{
Vertices: []Vertex{
// It would have been more intuitive if the square vertices were label as this:
// 0 1
// 2 3
// instead of
// 0 1
// 3 2
{0, "0"},
{1, "1"},
{2, "2"},
{2, "3"},
{3, "2"},
},
Edges: [][]Edge{
Expand All @@ -264,6 +270,7 @@ func TestSquare(t *testing.T) {
{{1, 1, 0}, {sqrt2, invSqrt2, 0}, {1, 1, 0}},
},
}
fmt.Println(squareGraph)

var seed int64 = 0

Expand All @@ -273,6 +280,10 @@ func TestSquare(t *testing.T) {
seed,
os.Stdout,
)
for i := 0; i < len(solution); i++ {
fmt.Println(*solution[i])
}

if err != nil {
t.Error(err)
}
Expand All @@ -297,6 +308,7 @@ func TestSquare(t *testing.T) {
}
}

// This function generates a Graph representing a equidistant grid of nxn
func generateGridGraph(nGridNodesPerDim int, dist float64) Graph {
nGridNodes := nGridNodesPerDim * nGridNodesPerDim
g := Graph{
Expand All @@ -321,10 +333,12 @@ func generateGridGraph(nGridNodesPerDim int, dist float64) Graph {
return g
}

// TestCompTotLength checks whether the function CompTotLength returns the rigth length
func TestCompTotLength(t *testing.T) {
nGridNodesPerDim := 4
var dist float64 = 10
// For a graph that is an equidistant grid of n x n fully connected vertices with distance d between neighbouring vertices, where n is even, an optimal solution has length: d * n * n.
// For a graph that is an equidistant grid of n x n fully connected vertices with distance d between
// neighbouring vertices, where n is even, an optimal solution has length: d * n * n.

g := generateGridGraph(nGridNodesPerDim, dist)

Expand All @@ -349,7 +363,8 @@ func BenchmarkGrid(b *testing.B) {
// TODO generalize to parameter
nGridNodesPerDim := 8

// For a graph that is an equidistant grid of n x n fully connected vertices with distance d between neighbouring vertices, where n is even, an optimal solution has length: d * n * n.
// For a graph that is an equidistant grid of n x n fully connected vertices with distance d between
// neighbouring vertices, where n is even, an optimal solution has length: d * n * n.
var dist float64 = 1
optLen := dist * float64(nGridNodesPerDim*nGridNodesPerDim)

Expand Down
14 changes: 7 additions & 7 deletions cmd/acotsp/acotsp.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ package main
import (
"flag"
"fmt"
"io/ioutil"
"io"
"io/ioutil"
"os"
"time"

Expand All @@ -14,6 +14,7 @@ import (
"github.com/pkg/errors"
)


var (
tsp = flag.String("tsp", "", "TSP problem file in TSPLIB format")
log = flag.String("log", "", "(optional)file where progress should be logged")
Expand Down Expand Up @@ -72,21 +73,20 @@ func main() {
var nAnts int = len(g.Vertices)
trailUpdateFunc := aco.LayTrailAntCycle

s, _, err := aco.AntSystemAlgorithm(g, nAnts, *NCmax, *Q, *rho, *alpha, *beta, trailUpdateFunc, *seed, logWriter)
s, stagBehv, err := aco.AntSystemAlgorithm(g, nAnts, *NCmax, *Q, *rho, *alpha, *beta, trailUpdateFunc, *seed, logWriter)
if err != nil {
// TODO
panic(err)
}

fmt.Printf("%d,%f,%f,%f,%f,%f\n", *NCmax, *Q, *rho, *alpha, *beta, aco.CompTotLength(g, s))
fmt.Printf("solution: \n")
for i := 0; i < len(s); i++ {
fmt.Println(*(s[i]))
}

//TODO find a good ouptut format
/*
fmt.Printf("solution: %v\n", s)
fmt.Printf("solution length: %f\n", aco.CompTotLength(g, s))
if stagBehv {
fmt.Println("AS terminated with stagnation behaviour")
}
*/
}
}

0 comments on commit b027c0f

Please sign in to comment.