Replace SA with deterministic steepest-ascent hill climbing
This commit is contained in:
147
main.go
147
main.go
@@ -10,7 +10,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"math"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -993,7 +992,81 @@ func handleSolve(db *sql.DB) http.HandlerFunc {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
for restart := 0; restart < 20; restart++ {
|
uniqueGroups := make([]int, 0, len(groups))
|
||||||
|
for root := range groups {
|
||||||
|
uniqueGroups = append(uniqueGroups, root)
|
||||||
|
}
|
||||||
|
sort.Ints(uniqueGroups)
|
||||||
|
|
||||||
|
hillClimb := func(assignment []int) int {
|
||||||
|
currentScore := score(assignment)
|
||||||
|
for {
|
||||||
|
bestDelta := 0
|
||||||
|
bestMove := -1
|
||||||
|
bestTarget := -1
|
||||||
|
bestSwapJ := -1
|
||||||
|
|
||||||
|
for gi, gRoot := range uniqueGroups {
|
||||||
|
grp := groups[gRoot]
|
||||||
|
gRoom := assignment[grp[0]]
|
||||||
|
|
||||||
|
for room := 0; room < numRooms; room++ {
|
||||||
|
if room == gRoom { continue }
|
||||||
|
if roomCount(assignment, room)+len(grp) > roomSize { continue }
|
||||||
|
for _, m := range grp { assignment[m] = room }
|
||||||
|
if feasible(assignment) {
|
||||||
|
delta := score(assignment) - currentScore
|
||||||
|
if delta > bestDelta {
|
||||||
|
bestDelta = delta
|
||||||
|
bestMove = gi
|
||||||
|
bestTarget = room
|
||||||
|
bestSwapJ = -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, m := range grp { assignment[m] = gRoom }
|
||||||
|
}
|
||||||
|
|
||||||
|
for gj := gi + 1; gj < len(uniqueGroups); gj++ {
|
||||||
|
grp2 := groups[uniqueGroups[gj]]
|
||||||
|
g2Room := assignment[grp2[0]]
|
||||||
|
if gRoom == g2Room { continue }
|
||||||
|
newGRoom := roomCount(assignment, gRoom) - len(grp) + len(grp2)
|
||||||
|
newG2Room := roomCount(assignment, g2Room) - len(grp2) + len(grp)
|
||||||
|
if newGRoom > roomSize || newG2Room > roomSize { continue }
|
||||||
|
for _, m := range grp { assignment[m] = g2Room }
|
||||||
|
for _, m := range grp2 { assignment[m] = gRoom }
|
||||||
|
if feasible(assignment) {
|
||||||
|
delta := score(assignment) - currentScore
|
||||||
|
if delta > bestDelta {
|
||||||
|
bestDelta = delta
|
||||||
|
bestMove = gi
|
||||||
|
bestTarget = -1
|
||||||
|
bestSwapJ = gj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, m := range grp { assignment[m] = gRoom }
|
||||||
|
for _, m := range grp2 { assignment[m] = g2Room }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if bestDelta <= 0 { break }
|
||||||
|
|
||||||
|
grp := groups[uniqueGroups[bestMove]]
|
||||||
|
gRoom := assignment[grp[0]]
|
||||||
|
if bestSwapJ < 0 {
|
||||||
|
for _, m := range grp { assignment[m] = bestTarget }
|
||||||
|
} else {
|
||||||
|
grp2 := groups[uniqueGroups[bestSwapJ]]
|
||||||
|
g2Room := assignment[grp2[0]]
|
||||||
|
for _, m := range grp { assignment[m] = g2Room }
|
||||||
|
for _, m := range grp2 { assignment[m] = gRoom }
|
||||||
|
}
|
||||||
|
currentScore += bestDelta
|
||||||
|
}
|
||||||
|
return currentScore
|
||||||
|
}
|
||||||
|
|
||||||
|
for restart := 0; restart < 50; restart++ {
|
||||||
if restart == 0 {
|
if restart == 0 {
|
||||||
copy(assignment, initialAssignment)
|
copy(assignment, initialAssignment)
|
||||||
} else {
|
} else {
|
||||||
@@ -1035,75 +1108,11 @@ func handleSolve(db *sql.DB) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentScore := score(assignment)
|
s := hillClimb(assignment)
|
||||||
if currentScore > bestScore {
|
if s > bestScore {
|
||||||
bestScore = currentScore
|
bestScore = s
|
||||||
copy(bestAssignment, assignment)
|
copy(bestAssignment, assignment)
|
||||||
}
|
}
|
||||||
|
|
||||||
temp := 10.0
|
|
||||||
cooling := 0.9995
|
|
||||||
iterations := 50000
|
|
||||||
|
|
||||||
for iter := 0; iter < iterations; iter++ {
|
|
||||||
i := rand.Intn(n)
|
|
||||||
iRoot := ufFind(i)
|
|
||||||
iGroup := groups[iRoot]
|
|
||||||
iRoom := assignment[i]
|
|
||||||
|
|
||||||
if rand.Intn(2) == 0 {
|
|
||||||
targetRoom := rand.Intn(numRooms)
|
|
||||||
if targetRoom == iRoom { continue }
|
|
||||||
newCount := roomCount(assignment, targetRoom) + len(iGroup)
|
|
||||||
if newCount > roomSize { continue }
|
|
||||||
for _, m := range iGroup { assignment[m] = targetRoom }
|
|
||||||
if !feasible(assignment) {
|
|
||||||
for _, m := range iGroup { assignment[m] = iRoom }
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
newScore := score(assignment)
|
|
||||||
delta := newScore - currentScore
|
|
||||||
if delta >= 0 || rand.Float64() < math.Exp(float64(delta)/temp) {
|
|
||||||
currentScore = newScore
|
|
||||||
if currentScore > bestScore {
|
|
||||||
bestScore = currentScore
|
|
||||||
copy(bestAssignment, assignment)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for _, m := range iGroup { assignment[m] = iRoom }
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
j := rand.Intn(n)
|
|
||||||
if assignment[j] == iRoom { continue }
|
|
||||||
jRoot := ufFind(j)
|
|
||||||
if iRoot == jRoot { continue }
|
|
||||||
jGroup := groups[jRoot]
|
|
||||||
jRoom := assignment[j]
|
|
||||||
newRoomI := roomCount(assignment, iRoom) - len(iGroup) + len(jGroup)
|
|
||||||
newRoomJ := roomCount(assignment, jRoom) - len(jGroup) + len(iGroup)
|
|
||||||
if newRoomI > roomSize || newRoomJ > roomSize { continue }
|
|
||||||
for _, m := range iGroup { assignment[m] = jRoom }
|
|
||||||
for _, m := range jGroup { assignment[m] = iRoom }
|
|
||||||
if !feasible(assignment) {
|
|
||||||
for _, m := range iGroup { assignment[m] = iRoom }
|
|
||||||
for _, m := range jGroup { assignment[m] = jRoom }
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
newScore := score(assignment)
|
|
||||||
delta := newScore - currentScore
|
|
||||||
if delta >= 0 || rand.Float64() < math.Exp(float64(delta)/temp) {
|
|
||||||
currentScore = newScore
|
|
||||||
if currentScore > bestScore {
|
|
||||||
bestScore = currentScore
|
|
||||||
copy(bestAssignment, assignment)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for _, m := range iGroup { assignment[m] = iRoom }
|
|
||||||
for _, m := range jGroup { assignment[m] = jRoom }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
temp *= cooling
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type roomMember struct {
|
type roomMember struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user