Commit fd029285 authored by CedricPump's avatar CedricPump
Browse files

- added serial solver

parent 7df196e2
...@@ -83,7 +83,7 @@ func postTsp(w http.ResponseWriter, r *http.Request) { ...@@ -83,7 +83,7 @@ func postTsp(w http.ResponseWriter, r *http.Request) {
// Response // Response
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(sol.String()) json.NewEncoder(w).Encode(sol.StringFull())
} }
// ------------------------------------ // ------------------------------------
......
// ======================================================= // =======================================================
// read tsp data saved in data format of // read tsp Data saved in Data format of
// Gerhard Reinelt // Gerhard Reinelt
// Universität Heidelberg // Universität Heidelberg
// Institut für Informatik // Institut für Informatik
// data: http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/tsp/ // Data: http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/tsp/
// //
// Documentation: http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/tsp95.pdf // Documentation: http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/tsp95.pdf
// //
...@@ -25,18 +25,18 @@ import ( ...@@ -25,18 +25,18 @@ import (
) )
type TspSpec struct { type TspSpec struct {
name string Name string
problemType string ProblemType string
comment string Comment string
dimension int Dimension int
edgeWeightType string EdgeWeightType string
edgeWeightFormat string EdgeWeightFormat string
data *TspData Data *TspData
} }
type TspData struct { type TspData struct {
datatype string Datatype string
values*[][] float64 Values *[][] float64
} }
// NewTspSpec // NewTspSpec
...@@ -44,7 +44,7 @@ type TspData struct { ...@@ -44,7 +44,7 @@ type TspData struct {
// Constructs empty TSP Specification // Constructs empty TSP Specification
// ------------------------------------ // ------------------------------------
func NewTspSpec() *TspSpec { func NewTspSpec() *TspSpec {
return &TspSpec{name: "", problemType: "TSP", comment: "", dimension: 0, edgeWeightType: "", data: NewTspData()} return &TspSpec{Name: "", ProblemType: "TSP", Comment: "", Dimension: 0, EdgeWeightType: "", Data: NewTspData()}
} }
// NewTspData // NewTspData
...@@ -52,7 +52,7 @@ func NewTspSpec() *TspSpec { ...@@ -52,7 +52,7 @@ func NewTspSpec() *TspSpec {
// Constructs empty TSP Specification Data // Constructs empty TSP Specification Data
// ------------------------------------ // ------------------------------------
func NewTspData() *TspData { func NewTspData() *TspData {
return &TspData{datatype: "EDGE_WEIGHT_SECTION", values: &[][]float64{}} return &TspData{Datatype: "EDGE_WEIGHT_SECTION", Values: &[][]float64{}}
} }
// String // String
...@@ -60,7 +60,7 @@ func NewTspData() *TspData { ...@@ -60,7 +60,7 @@ func NewTspData() *TspData {
// Returns string representation of TSP Specification // Returns string representation of TSP Specification
// ------------------------------------ // ------------------------------------
func (t TspSpec) String() string { func (t TspSpec) String() string {
return fmt.Sprintf("%s [%s] - %s %s %d", t.name, t.problemType, t.edgeWeightType, t.edgeWeightFormat, t.dimension) return fmt.Sprintf("%s [%s] - %s %s %d", t.Name, t.ProblemType, t.EdgeWeightType, t.EdgeWeightFormat, t.Dimension)
} }
// String // String
...@@ -68,12 +68,12 @@ func (t TspSpec) String() string { ...@@ -68,12 +68,12 @@ func (t TspSpec) String() string {
// Returns string representation of TSP Data // Returns string representation of TSP Data
// ------------------------------------ // ------------------------------------
func (t TspData) String() string { func (t TspData) String() string {
return fmt.Sprintf("Datatype: %s", t.datatype) return fmt.Sprintf("Datatype: %s", t.Datatype)
} }
// Read // Read
// ------------------------------------ // ------------------------------------
// Reads TSP data from .tsp file // Reads TSP Data from .tsp file
// ------------------------------------ // ------------------------------------
func Read(path string) (*TspSpec, error) { func Read(path string) (*TspSpec, error) {
file, err := os.Open(path) file, err := os.Open(path)
...@@ -96,37 +96,37 @@ func Read(path string) (*TspSpec, error) { ...@@ -96,37 +96,37 @@ func Read(path string) (*TspSpec, error) {
strs := strings.Split(line, ":") strs := strings.Split(line, ":")
switch strings.ReplaceAll(strs[0]," ","") { switch strings.ReplaceAll(strs[0]," ","") {
case "NAME": { case "NAME": {
spec.name = strings.ReplaceAll(strs[1]," ","") spec.Name = strings.ReplaceAll(strs[1]," ","")
break break
} }
case "TYPE": { case "TYPE": {
spec.problemType = strings.ReplaceAll(strs[1]," ","") spec.ProblemType = strings.ReplaceAll(strs[1]," ","")
break break
} }
case "COMMENT": { case "COMMENT": {
spec.comment = strings.ReplaceAll(strs[1]," ","") spec.Comment = strings.ReplaceAll(strs[1]," ","")
break break
} }
case "DIMENSION": { case "DIMENSION": {
i, e := strconv.ParseInt(strings.ReplaceAll(strs[1]," ",""),10,64) i, e := strconv.ParseInt(strings.ReplaceAll(strs[1]," ",""),10,64)
if(e == nil) { if(e == nil) {
spec.dimension = int(i) spec.Dimension = int(i)
} }
break break
} }
case "EDGE_WEIGHT_TYPE": { case "EDGE_WEIGHT_TYPE": {
spec.edgeWeightType = strings.ReplaceAll(strs[1]," ","") spec.EdgeWeightType = strings.ReplaceAll(strs[1]," ","")
break break
} }
case "EDGE_WEIGHT_FORMAT": { case "EDGE_WEIGHT_FORMAT": {
spec.edgeWeightFormat = strings.ReplaceAll(strs[1]," ","") spec.EdgeWeightFormat = strings.ReplaceAll(strs[1]," ","")
break break
} }
} }
} else { } else {
// Sace Data as Multi Dimensional Array // Sace Data as Multi Dimensional Array
if dataLine == -1 { if dataLine == -1 {
spec.data.datatype = strings.ReplaceAll(line," ","") spec.Data.Datatype = strings.ReplaceAll(line," ","")
dataLine++ dataLine++
} else { } else {
entries := strings.Split(line, " ") entries := strings.Split(line, " ")
...@@ -146,9 +146,9 @@ func Read(path string) (*TspSpec, error) { ...@@ -146,9 +146,9 @@ func Read(path string) (*TspSpec, error) {
} }
} }
spec.data.values = &arr spec.Data.Values = &arr
if spec.data.datatype != "EDGE_WEIGHT_SECTION" { if spec.Data.Datatype != "EDGE_WEIGHT_SECTION" {
cordToMatrix(spec) cordToMatrix(spec)
} }
...@@ -157,11 +157,11 @@ func Read(path string) (*TspSpec, error) { ...@@ -157,11 +157,11 @@ func Read(path string) (*TspSpec, error) {
} }
func cordToMatrix(spec *TspSpec) { func cordToMatrix(spec *TspSpec) {
arr := *spec.data.values arr := *spec.Data.Values
outarr := [][]float64{} outarr := [][]float64{}
switch spec.edgeWeightType { switch spec.EdgeWeightType {
case "EUC_3D":{ case "EUC_2D":{
// entries in euclidean 3d space in form of [index, lat, long] // entries in euclidean 3d space in form of [index, lat, long]
// distance calculation for points p1 to p2 with // distance calculation for points p1 to p2 with
// p1 = (x1, y1) and p2 = (x2, y2): // p1 = (x1, y1) and p2 = (x2, y2):
...@@ -176,7 +176,7 @@ func cordToMatrix(spec *TspSpec) { ...@@ -176,7 +176,7 @@ func cordToMatrix(spec *TspSpec) {
break break
} }
case "EUC_2D":{ case "EUC_3D":{
// entries in euclidean 2d space in form of [index, lat, long] // entries in euclidean 2d space in form of [index, lat, long]
// distance calculation for points p1 to p2 with // distance calculation for points p1 to p2 with
// p1 = (x1, y1), p2 = (x2, y2) and p3 = (z1, z2): // p1 = (x1, y1), p2 = (x2, y2) and p3 = (z1, z2):
...@@ -192,8 +192,8 @@ func cordToMatrix(spec *TspSpec) { ...@@ -192,8 +192,8 @@ func cordToMatrix(spec *TspSpec) {
} }
} }
spec.data.values = &outarr spec.Data.Values = &outarr
spec.data.datatype = "EDGE_WEIGHT_SECTION" spec.Data.Datatype = "EDGE_WEIGHT_SECTION"
spec.edgeWeightType = "EXPLICIT" spec.EdgeWeightType = "EXPLICIT"
spec.edgeWeightFormat = "FULL_MATRIX" spec.EdgeWeightFormat = "FULL_MATRIX"
} }
...@@ -5,13 +5,19 @@ ...@@ -5,13 +5,19 @@
package tspsolver package tspsolver
import ( import (
"errors"
"fmt" "fmt"
"log"
"math"
"math/rand"
"pvs_tsp/tspreader" "pvs_tsp/tspreader"
"time"
) )
type TspSolution struct { type TspSolution struct {
path []int path []int
length float64 length float64
strategy string
} }
// NewTspSolution // NewTspSolution
...@@ -19,7 +25,7 @@ type TspSolution struct { ...@@ -19,7 +25,7 @@ type TspSolution struct {
// Constructs empty TSP Solution // Constructs empty TSP Solution
// ------------------------------------ // ------------------------------------
func NewTspSolution() TspSolution{ func NewTspSolution() TspSolution{
return TspSolution{path: []int{}, length: 0} return TspSolution{path: []int{}, length: 0, strategy: ""}
} }
// String // String
...@@ -35,9 +41,10 @@ func (t TspSolution) String() string { ...@@ -35,9 +41,10 @@ func (t TspSolution) String() string {
// returns full string representation of solution // returns full string representation of solution
// ------------------------------------ // ------------------------------------
func (t TspSolution) StringFull() string { func (t TspSolution) StringFull() string {
return fmt.Sprintf("solution - length: %f path: %+q", t.length, t.path) return fmt.Sprintf("solution - length: %f path: [%d, %d, ... %d] strategy: %s", t.length, t.path[0], t.path[1], t.path[len(t.path)-1], t.strategy)
} }
// Solve // Solve
// ------------------------------------ // ------------------------------------
// solve TSP // solve TSP
...@@ -45,5 +52,159 @@ func (t TspSolution) StringFull() string { ...@@ -45,5 +52,159 @@ func (t TspSolution) StringFull() string {
func Solve(spec tspreader.TspSpec) TspSolution { func Solve(spec tspreader.TspSpec) TspSolution {
// do tsp magic here // do tsp magic here
return NewTspSolution() // strategies:
// - Random
// - Nearest Neighbor
// - Ant Colony Optimization
solrand := SolveRandom(spec, 1000000)
solnear := SolveNearest(spec)
log.Println("done")
if solrand.length < solnear.length {
return solrand
} else {
return solnear
}
}
// SolveRandom
// ------------------------------------
// solve TSP
// ------------------------------------
func SolveRandom(spec tspreader.TspSpec, turns int) TspSolution {
bestsol := TspSolution{[]int{}, math.MaxFloat64, ""}
for turn := 0; turn < turns; turn++ {
sol := NewTspSolution()
sol.strategy = "Random"
var locs []int
for i := 0; i < spec.Dimension; i++ {
locs = append(locs, i)
}
// select random start
rand.Seed(time.Now().Unix())
n := rand.Int() % len(locs)
node := locs[n];
sol.path = append(sol.path, node)
locs = removeCopy(locs,n)
// until all node are taken
for len(sol.path) < spec.Dimension {
dists := (*spec.Data.Values)[node]
n := rand.Int() % len(locs)
node = locs[n]
index := indexOf(locs,node)
dist := dists[node]
sol.path = append(sol.path, node)
sol.length = sol.length + dist
locs = removeElementCopy(locs,index)
}
if sol.length < bestsol.length {
bestsol = sol
}
log.Println(bestsol.length)
}
return bestsol
}
// SolveNearest
// ------------------------------------
// solve TSP
// ------------------------------------
func SolveNearest(spec tspreader.TspSpec) TspSolution {
bestsol := TspSolution{[]int{}, math.MaxFloat64, ""}
for turn := 0; turn < spec.Dimension; turn++ {
sol := NewTspSolution()
sol.strategy = "NearestNeighbor"
var locs []int
for i := 0; i < spec.Dimension; i++ {
locs = append(locs, i)
}
// start at 0
n := turn
node := locs[n];
sol.path = append(sol.path, node)
locs = removeCopy(locs,n)
// until all node are taken
for len(sol.path) < spec.Dimension {
dists := (*spec.Data.Values)[node]
var err error
var dist float64
node, dist, err = minNotZero(dists,locs)
if err != nil {
panic(err)
}
sol.path = append(sol.path, node)
sol.length = sol.length + dist
index := indexOf(locs,node)
locs = removeElementCopy(locs,index)
}
if sol.length < bestsol.length {
bestsol = sol
}
log.Println(bestsol.length)
}
return bestsol
}
func removeCopy(slice []int, i int) []int {
copy(slice[i:], slice[i+1:])
return slice[:len(slice)-1]
}
func removeElementCopy(slice []int, i int) []int {
copy(slice[i:], slice[i+1:])
return slice[:len(slice)-1]
}
func minNotZero(slice []float64, locs []int) (int, float64, error) {
if len(slice) == 0 {
return 0, 0, errors.New("slice is empty")
}
min := math.MaxFloat64
minIndex := -1
for i, e := range slice {
if indexOf(locs,i) > -1 {
if e < min && e != 0 {
min = e
minIndex = i
}
}
}
return minIndex, min, nil
}
func indexOf(slice []int, item int) int {
for i, _ := range slice {
if slice[i] == item {
return i
}
}
return -1
} }
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment