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) {
// Response
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
// Universität Heidelberg
// 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
//
......@@ -25,18 +25,18 @@ import (
)
type TspSpec struct {
name string
problemType string
comment string
dimension int
edgeWeightType string
edgeWeightFormat string
data *TspData
Name string
ProblemType string
Comment string
Dimension int
EdgeWeightType string
EdgeWeightFormat string
Data *TspData
}
type TspData struct {
datatype string
values*[][] float64
Datatype string
Values *[][] float64
}
// NewTspSpec
......@@ -44,7 +44,7 @@ type TspData struct {
// Constructs empty TSP Specification
// ------------------------------------
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
......@@ -52,7 +52,7 @@ func NewTspSpec() *TspSpec {
// Constructs empty TSP Specification Data
// ------------------------------------
func NewTspData() *TspData {
return &TspData{datatype: "EDGE_WEIGHT_SECTION", values: &[][]float64{}}
return &TspData{Datatype: "EDGE_WEIGHT_SECTION", Values: &[][]float64{}}
}
// String
......@@ -60,7 +60,7 @@ func NewTspData() *TspData {
// Returns string representation of TSP Specification
// ------------------------------------
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
......@@ -68,12 +68,12 @@ func (t TspSpec) String() string {
// Returns string representation of TSP Data
// ------------------------------------
func (t TspData) String() string {
return fmt.Sprintf("Datatype: %s", t.datatype)
return fmt.Sprintf("Datatype: %s", t.Datatype)
}
// Read
// ------------------------------------
// Reads TSP data from .tsp file
// Reads TSP Data from .tsp file
// ------------------------------------
func Read(path string) (*TspSpec, error) {
file, err := os.Open(path)
......@@ -96,37 +96,37 @@ func Read(path string) (*TspSpec, error) {
strs := strings.Split(line, ":")
switch strings.ReplaceAll(strs[0]," ","") {
case "NAME": {
spec.name = strings.ReplaceAll(strs[1]," ","")
spec.Name = strings.ReplaceAll(strs[1]," ","")
break
}
case "TYPE": {
spec.problemType = strings.ReplaceAll(strs[1]," ","")
spec.ProblemType = strings.ReplaceAll(strs[1]," ","")
break
}
case "COMMENT": {
spec.comment = strings.ReplaceAll(strs[1]," ","")
spec.Comment = strings.ReplaceAll(strs[1]," ","")
break
}
case "DIMENSION": {
i, e := strconv.ParseInt(strings.ReplaceAll(strs[1]," ",""),10,64)
if(e == nil) {
spec.dimension = int(i)
spec.Dimension = int(i)
}
break
}
case "EDGE_WEIGHT_TYPE": {
spec.edgeWeightType = strings.ReplaceAll(strs[1]," ","")
spec.EdgeWeightType = strings.ReplaceAll(strs[1]," ","")
break
}
case "EDGE_WEIGHT_FORMAT": {
spec.edgeWeightFormat = strings.ReplaceAll(strs[1]," ","")
spec.EdgeWeightFormat = strings.ReplaceAll(strs[1]," ","")
break
}
}
} else {
// Sace Data as Multi Dimensional Array
if dataLine == -1 {
spec.data.datatype = strings.ReplaceAll(line," ","")
spec.Data.Datatype = strings.ReplaceAll(line," ","")
dataLine++
} else {
entries := strings.Split(line, " ")
......@@ -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)
}
......@@ -157,11 +157,11 @@ func Read(path string) (*TspSpec, error) {
}
func cordToMatrix(spec *TspSpec) {
arr := *spec.data.values
arr := *spec.Data.Values
outarr := [][]float64{}
switch spec.edgeWeightType {
case "EUC_3D":{
switch spec.EdgeWeightType {
case "EUC_2D":{
// entries in euclidean 3d space in form of [index, lat, long]
// distance calculation for points p1 to p2 with
// p1 = (x1, y1) and p2 = (x2, y2):
......@@ -176,7 +176,7 @@ func cordToMatrix(spec *TspSpec) {
break
}
case "EUC_2D":{
case "EUC_3D":{
// entries in euclidean 2d space in form of [index, lat, long]
// distance calculation for points p1 to p2 with
// p1 = (x1, y1), p2 = (x2, y2) and p3 = (z1, z2):
......@@ -192,8 +192,8 @@ func cordToMatrix(spec *TspSpec) {
}
}
spec.data.values = &outarr
spec.data.datatype = "EDGE_WEIGHT_SECTION"
spec.edgeWeightType = "EXPLICIT"
spec.edgeWeightFormat = "FULL_MATRIX"
spec.Data.Values = &outarr
spec.Data.Datatype = "EDGE_WEIGHT_SECTION"
spec.EdgeWeightType = "EXPLICIT"
spec.EdgeWeightFormat = "FULL_MATRIX"
}
......@@ -5,13 +5,19 @@
package tspsolver
import (
"errors"
"fmt"
"log"
"math"
"math/rand"
"pvs_tsp/tspreader"
"time"
)
type TspSolution struct {
path []int
length float64
strategy string
}
// NewTspSolution
......@@ -19,7 +25,7 @@ type TspSolution struct {
// Constructs empty TSP Solution
// ------------------------------------
func NewTspSolution() TspSolution{
return TspSolution{path: []int{}, length: 0}
return TspSolution{path: []int{}, length: 0, strategy: ""}
}
// String
......@@ -35,9 +41,10 @@ func (t TspSolution) String() string {
// returns full string representation of solution
// ------------------------------------
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 TSP
......@@ -45,5 +52,159 @@ func (t TspSolution) StringFull() string {
func Solve(spec tspreader.TspSpec) TspSolution {
// 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