Skip to content

Commit

Permalink
example/tsp: WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
arl committed Mar 28, 2021
1 parent b3af300 commit 3b2f20e
Show file tree
Hide file tree
Showing 3 changed files with 292 additions and 47 deletions.
48 changes: 45 additions & 3 deletions _example/tsp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"flag"
"fmt"
"log"

"github.com/jaschaephraim/lrserver"
"gopkg.in/fsnotify.v1"
)

func checkf(err error, format string, a ...interface{}) {
Expand All @@ -14,13 +17,52 @@ func checkf(err error, format string, a ...interface{}) {
log.Fatalf("%s: %s", fmt.Sprintf(format, a...), err)
}

func liveReload() {
// Create file watcher
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatalln(err)
}
defer watcher.Close()

lr := lrserver.New(lrserver.DefaultName, lrserver.DefaultPort)
go lr.ListenAndServe()

go func() {
for {
select {
case event := <-watcher.Events:
if event.Op&fsnotify.Write == fsnotify.Write {
lr.Reload(event.Name)
}
case err := <-watcher.Errors:
lr.Alert(err.Error())
}
}
}()

err = watcher.Add("./example/tsp/index.html")
if err != nil {
log.Fatalln(err)
}

select {}
}

func main() {
// s := []int{1, 2, 3, 4, 5}
// Perm(s, func(p []int) { fmt.Println(p) })

host := "localhost:8080"
flag.StringVar(&host, "host", host, "http server [host]:[port]")
flag.Parse()

server := &server{host: host}
server.serve(host)
go liveReload()

println("starting algorithm")
server := newServer()
server.serve(host)
err := server.start()
if err != nil {
log.Fatal(err)
}
}
192 changes: 192 additions & 0 deletions _example/tsp/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
package main

import (
"fmt"
"log"
"math/rand"
"net/http"
"time"

"github.com/gorilla/websocket"
)

type point struct {
X, Y int
}

// a server shows the current state of the TSP via an HTTP server.
type server struct {
solutions chan []point // channel type is temporary (should probably be a channel of Individual)
}

func newServer() *server {
return &server{
solutions: make(chan []point),
}
}

func (s *server) serve(host string) {
log.Printf("Server starting, point your browser to http://%s\n", host)

http.Handle("/", http.FileServer(http.Dir("./example/tsp")))
http.HandleFunc("/ws", s.ws)

go http.ListenAndServe(host, nil)
}

func (s *server) start() error {
tick := time.NewTicker(500 * time.Millisecond)
for {
select {
case <-tick.C:
s.solutions <- randomPath(4)
}
}
}

const xmax, ymax = 200, 200

var updates int

func randomPath(length int) []point {
updates++
if updates%2 == 0 {
path := make([]point, length)
path[0] = point{X: 0, Y: 0}
path[1] = point{X: 0, Y: ymax}
path[2] = point{X: xmax, Y: ymax}
path[3] = point{X: xmax, Y: 0}
return path
}

path := make([]point, length)
for i := range path {
path[i].X = rand.Intn(xmax)
path[i].Y = rand.Intn(ymax)
}

return path
}

func (s *server) ws(w http.ResponseWriter, r *http.Request) {
upgrader := websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}

fmt.Println("ws start")
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
defer ws.Close()

if err = s.runTSP(ws); err != nil {
log.Println(err)
}

fmt.Println("ws end")
}

type initMessage struct {
Width, Height int
}

func (s *server) runTSP(conn *websocket.Conn) error {
conn.WriteJSON(initMessage{Width: xmax, Height: ymax})

for sol := range s.solutions {
if err := conn.WriteJSON(sol); err != nil {
return err
}
}

return nil
}

// Perm calls f with each permutation of a.
func Perm(a []int, f func([]int)) {
perm(a, f, 0)
}

// Permute the values at index i to len(a)-1.
func perm(a []int, f func([]int), i int) {
if i > len(a) {
f(a)
return
}
perm(a, f, i+1)
for j := i + 1; j < len(a); j++ {
a[i], a[j] = a[j], a[i]
perm(a, f, i+1)
a[i], a[j] = a[j], a[i]
}
}

/*
"github.com/arl/statsviz/websocket"
)
func init() {
http.Handle("/debug/statsviz/", Index)
http.HandleFunc("/debug/statsviz/ws", Ws)
}
// Index responds to a request for /debug/statsviz with the statsviz HTML page
// which shows a live visualization of the statistics sent by the application
// over the websocket handler Ws.
//
// The package initialization registers it as /debug/statsviz/.
var Index = http.StripPrefix("/debug/statsviz/", http.FileServer(assets))
// Ws upgrades the HTTP server connection to the WebSocket protocol and sends
// application statistics every second.
//
// If the upgrade fails, an HTTP error response is sent to the client.
// The package initialization registers it as /debug/statsviz/ws.
func Ws(w http.ResponseWriter, r *http.Request) {
upgrader.CheckOrigin = func(r *http.Request) bool { return true }
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("can't upgrade HTTP connection to Websocket protocol:", err)
return
}
defer ws.Close()
err = sendStats(ws)
if err != nil {
log.Println(err)
}
}
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
type stats struct {
Mem runtime.MemStats
NumGoroutine int
}
const defaultSendPeriod = time.Second
// sendStats indefinitely send runtime statistics on the websocket connection.
func sendStats(conn *websocket.Conn) error {
tick := time.NewTicker(defaultSendPeriod)
var stats stats
for {
select {
case <-tick.C:
runtime.ReadMemStats(&stats.Mem)
stats.NumGoroutine = runtime.NumGoroutine()
if err := conn.WriteJSON(stats); err != nil {
return err
}
}
}
}
*/
99 changes: 55 additions & 44 deletions _example/tsp/tsp.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
package main

/*
import (
"github.com/arl/evolve"
"github.com/arl/evolve/engine"
"github.com/arl/evolve/generator"
"github.com/arl/evolve/operator"
"github.com/arl/evolve/operator/xover"
"github.com/arl/evolve/pkg/bitstring"
"github.com/arl/evolve/selection"
)

func runTSP() error {
// define the crossover
xover := xover.New(xover.ListOrderCrossover)
check(xover.SetPoints(1))
check(xover.SetProb(0.7))
// Define the crossover operator.
xover := xover.New(xover.PMX)
xover.Points = generator.ConstInt(1)
xover.Probability = generator.ConstFloat64(0.7)

// define the mutation
// Define the mutation operator.
mut := mutation.NewBitstring()
check(mut.SetProb(0.01))
op := ListOrder{
Count: generator.NewPoisson(generator.ConstFloat64(1.5)),
Amount: generator.NewPoisson(generator.ConstFloat64(1.5)),
}

eval := evolve.EvaluatorFunc(
true, // natural fitness (higher is better)
Expand All @@ -27,45 +39,44 @@ func runTSP() error {
eng, err := engine.New(generator.Bitstring(nbits), eval, &epocher)
check(err)
}
*/

/*
{
Random rng = new MersenneTwisterRNG();
Random rng = new MersenneTwisterRNG();
// Set-up evolution pipeline (cross-over followed by mutation).
List<EvolutionaryOperator<List<String>>> operators = new ArrayList<EvolutionaryOperator<List<String>>>(2);
if (crossover)
{
operators.add(new ListOrderCrossover<String>());
}
if (mutation)
{
operators.add(new ListOrderMutation<String>(new PoissonGenerator(1.5, rng),
new PoissonGenerator(1.5, rng)));
}
// Set-up evolution pipeline (cross-over followed by mutation).
List<EvolutionaryOperator<List<String>>> operators = new ArrayList<EvolutionaryOperator<List<String>>>(2);
if (crossover)
{
operators.add(new ListOrderCrossover<String>());
}
if (mutation)
{
operators.add(new ListOrderMutation<String>(new PoissonGenerator(1.5, rng),
new PoissonGenerator(1.5, rng)));
}
EvolutionaryOperator<List<String>> pipeline = new EvolutionPipeline<List<String>>(operators);
CandidateFactory<List<String>> candidateFactory
= new ListPermutationFactory<String>(new LinkedList<String>(cities));
EvolutionEngine<List<String>> engine
= new GenerationalEvolutionEngine<List<String>>(candidateFactory,
pipeline,
new RouteEvaluator(distances),
selectionStrategy,
rng);
if (progressListener != null)
{
engine.addEvolutionObserver(new EvolutionObserver<List<String>>()
{
public void populationUpdate(PopulationData<? extends List<String>> data)
{
progressListener.updateProgress(((double) data.getGenerationNumber() + 1) / generationCount * 100);
}
});
}
return engine.evolve(populationSize,
eliteCount,
new GenerationCount(generationCount));
EvolutionaryOperator<List<String>> pipeline = new EvolutionPipeline<List<String>>(operators);
*/
CandidateFactory<List<String>> candidateFactory
= new ListPermutationFactory<String>(new LinkedList<String>(cities));
EvolutionEngine<List<String>> engine
= new GenerationalEvolutionEngine<List<String>>(candidateFactory,
pipeline,
new RouteEvaluator(distances),
selectionStrategy,
rng);
if (progressListener != null)
{
engine.addEvolutionObserver(new EvolutionObserver<List<String>>()
{
public void populationUpdate(PopulationData<? extends List<String>> data)
{
progressListener.updateProgress(((double) data.getGenerationNumber() + 1) / generationCount * 100);
}
});
}
return engine.evolve(populationSize,
eliteCount,
new GenerationCount(generationCount));
}*/

0 comments on commit 3b2f20e

Please sign in to comment.