Commit 7df196e2 authored by CedricPump's avatar CedricPump
Browse files

added EUC_2D and EUC_3D conversion

init solver
parent 0f45d4a9
// =======================================================
// Author Cedric Pump, Student, Technische Hochschule Lübeck
// =======================================================
package main
import (
......@@ -12,28 +16,45 @@ import (
"os"
"path/filepath"
"pvs_tsp/tspreader"
"pvs_tsp/tspsolver"
"strings"
)
// main executable
func main() {
startServer(8000)
}
// ------------------------------------
// startServer starts Rest server
// ------------------------------------
func startServer(port int) {
r := mux.NewRouter()
r.HandleFunc("/readtsp", postTsp).Methods("POST")
r.HandleFunc("/tsp", postTsp).Methods("POST")
r.HandleFunc("/", getUpload).Methods("GET")
r.HandleFunc("/upload", getUpload).Methods("GET")
http.ListenAndServe(fmt.Sprintf(":%d",port), r)
e := http.ListenAndServe(fmt.Sprintf(":%d",port), r)
if e != nil {
log.Fatal(e)
return
}
log.Printf("server running on http://localhost:%d", port)
log.Printf("usage: http://localhost:#{port}/upload")
}
// ------------------------------------
// getUpload returns static html page for uploading tsp file
// ------------------------------------
func getUpload(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "./index.html")
}
// ------------------------------------
// postTsp is endpoint to upload tsp file
// ------------------------------------
func postTsp(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
......@@ -57,14 +78,19 @@ func postTsp(w http.ResponseWriter, r *http.Request) {
defer f.Close()
f.Write(fileBytes)
spec := readtsp(filepath)
spec := readTsp(filepath)
sol := solveTsp(spec)
// Response
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(spec.String())
json.NewEncoder(w).Encode(sol.String())
}
func readtsp(path string) *tspreader.TspSpec {
// ------------------------------------
// readTsp reads tsp file and returns specification struct
// unzipping gz zip files is possible
// ------------------------------------
func readTsp(path string) tspreader.TspSpec {
if strings.HasSuffix(path,".gz") {
_ = UnGzip(path, filepath.Dir(path))
......@@ -75,30 +101,40 @@ func readtsp(path string) *tspreader.TspSpec {
log.Fatal(e.Error())
}
return spec
return *spec
}
// ------------------------------------
// solveTsp solves tsp
// ------------------------------------
func solveTsp(spec tspreader.TspSpec) tspsolver.TspSolution{
return tspsolver.Solve(spec)
}
func UnGzip(source, target string) error {
reader, err := os.Open(source)
if err != nil {
return err
// UnGzip
// ------------------------------------
// unzips .gz files
// ------------------------------------
func UnGzip(file, targetpath string) error {
reader, e := os.Open(file)
if e != nil {
return e
}
defer reader.Close()
archive, err := gzip.NewReader(reader)
if err != nil {
return err
r, e := gzip.NewReader(reader)
if e != nil {
return e
}
defer archive.Close()
defer r.Close()
target = filepath.Join(target, archive.Name)
writer, err := os.Create(target)
if err != nil {
return err
targetpath = filepath.Join(targetpath, r.Name)
w, e := os.Create(targetpath)
if e != nil {
return e
}
defer writer.Close()
defer w.Close()
_, err = io.Copy(writer, archive)
return err
_, e = io.Copy(w, r)
return e
}
\ No newline at end of file
// =======================================================
// 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/
//
// Documentation: http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/tsp95.pdf
//
// Author Cedric Pump, Student, Technische Hochschule Lübeck
// =======================================================
package tspreader
import (
......@@ -5,6 +18,7 @@ import (
"errors"
"fmt"
"log"
"math"
"os"
"strconv"
"strings"
......@@ -25,23 +39,42 @@ type TspData struct {
values*[][] float64
}
func NewTspData() *TspSpec {
return &TspSpec{name: "", problemType: "TSP", comment: "", dimension: 0, edgeWeightType: "", data: NewTspDataArray()}
// NewTspSpec
// ------------------------------------
// Constructs empty TSP Specification
// ------------------------------------
func NewTspSpec() *TspSpec {
return &TspSpec{name: "", problemType: "TSP", comment: "", dimension: 0, edgeWeightType: "", data: NewTspData()}
}
func NewTspDataArray() *TspData {
// NewTspData
// ------------------------------------
// Constructs empty TSP Specification Data
// ------------------------------------
func NewTspData() *TspData {
return &TspData{datatype: "EDGE_WEIGHT_SECTION", values: &[][]float64{}}
}
// String
// ------------------------------------
// 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)
}
// String
// ------------------------------------
// Returns string representation of TSP Data
// ------------------------------------
func (t TspData) String() string {
return fmt.Sprintf("Datatype: %s", t.datatype)
}
// Read Reads TSP data from .tsp file
// Read
// ------------------------------------
// Reads TSP data from .tsp file
// ------------------------------------
func Read(path string) (*TspSpec, error) {
file, err := os.Open(path)
if(err != nil) {
......@@ -50,12 +83,13 @@ func Read(path string) (*TspSpec, error) {
}
scanner := bufio.NewScanner(file)
spec := NewTspData()
spec := NewTspSpec()
dataLine := -1
arr := [][]float64{}
for scanner.Scan() {
line := scanner.Text()
line := ""
for scanner.Scan() && line != "EOF" {
line = scanner.Text()
// handle Specification Headers
if strings.Contains(line,":") {
......@@ -63,24 +97,30 @@ func Read(path string) (*TspSpec, error) {
switch strings.ReplaceAll(strs[0]," ","") {
case "NAME": {
spec.name = strings.ReplaceAll(strs[1]," ","")
break
}
case "TYPE": {
spec.problemType = strings.ReplaceAll(strs[1]," ","")
break
}
case "COMMENT": {
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)
}
break
}
case "EDGE_WEIGHT_TYPE": {
spec.edgeWeightType = strings.ReplaceAll(strs[1]," ","")
break
}
case "EDGE_WEIGHT_FORMAT": {
spec.edgeWeightFormat = strings.ReplaceAll(strs[1]," ","")
break
}
}
} else {
......@@ -91,21 +131,69 @@ func Read(path string) (*TspSpec, error) {
} else {
entries := strings.Split(line, " ")
arr = append(arr, []float64{})
if entries[0] != "EOF" {
arr = append(arr, []float64{})
for _, e := range entries{
f, err := strconv.ParseFloat(e, 64)
if err == nil {
arr[dataLine] = append(arr[dataLine], f)
for _, e := range entries {
f, err := strconv.ParseFloat(e, 64)
if err == nil {
arr[dataLine] = append(arr[dataLine], f)
}
}
dataLine++
}
dataLine++
}
}
}
spec.data.values = &arr
if spec.data.datatype != "EDGE_WEIGHT_SECTION" {
cordToMatrix(spec)
}
// return specification
return spec, nil
}
func cordToMatrix(spec *TspSpec) {
arr := *spec.data.values
outarr := [][]float64{}
switch spec.edgeWeightType {
case "EUC_3D":{
// 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):
// d = √[( y2 – y1)² + ( x1 – x2)²]
for i, node1 := range arr{
outarr = append(outarr, []float64{})
for _, node2 := range arr {
dist := math.Sqrt(math.Pow(node1[1] - node2[1],2) + math.Pow(node1[2] - node2[2],2))
outarr[i] = append(outarr[i], dist)
}
}
break
}
case "EUC_2D":{
// 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):
// d = d = ((x2 - x1)2 + (y2 - y1)2 + (z2 - z1)2)1/2
for i, node1 := range arr{
outarr = append(outarr, []float64{})
for _, node2 := range arr {
dist := math.Sqrt(math.Pow(node1[1] - node2[1],2) + math.Pow(node1[2] - node2[2],2) + math.Pow(node1[3] - node2[3],2))
outarr[i] = append(outarr[i], dist)
}
}
break
}
}
spec.data.values = &outarr
spec.data.datatype = "EDGE_WEIGHT_SECTION"
spec.edgeWeightType = "EXPLICIT"
spec.edgeWeightFormat = "FULL_MATRIX"
}
// =======================================================
// Author Cedric Pump, Student, Technische Hochschule Lübeck
// =======================================================
package tspsolver
import (
"fmt"
"pvs_tsp/tspreader"
)
type TspSolution struct {
path []int
length float64
}
// NewTspSolution
// ------------------------------------
// Constructs empty TSP Solution
// ------------------------------------
func NewTspSolution() TspSolution{
return TspSolution{path: []int{}, length: 0}
}
// String
// ------------------------------------
// returns string representation of solution
// ------------------------------------
func (t TspSolution) String() string {
return fmt.Sprintf("solution - length: %f", t.length)
}
// StringFull
// ------------------------------------
// returns full string representation of solution
// ------------------------------------
func (t TspSolution) StringFull() string {
return fmt.Sprintf("solution - length: %f path: %+q", t.length, t.path)
}
// Solve
// ------------------------------------
// solve TSP
// ------------------------------------
func Solve(spec tspreader.TspSpec) TspSolution {
// do tsp magic here
return NewTspSolution()
}
\ 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