-
Notifications
You must be signed in to change notification settings - Fork 0
/
algorithm.go
109 lines (95 loc) · 2.69 KB
/
algorithm.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package generateplan
import (
"errors"
"math"
"github.com/obcode/plexams.go/graph/model"
"github.com/rs/zerolog/log"
)
type AlgorithmConfig struct {
Population int
MutationPropability float64
Selection Selection
Recombination Recombination
SelectivePressure float64 // = 1.3 // only for ranked_based_selection
NoImprovement int
CapacityStudent int
}
type Algorithm struct {
config *AlgorithmConfig
validation *Validation
generation *Generation
bestPlan *Plan
semesterConfig *model.SemesterConfig
examGroups []*model.ExamGroup
}
type Validation struct {
sameDay int
sameOrAdjacentSlots int
adjacentDays int
}
func (algorithm *Algorithm) newPlan() *Plan {
newPlan := &Plan{exams: []*Exam{}}
for _, examGroup := range algorithm.examGroups {
newPlan.exams = append(newPlan.exams, newExam(examGroup))
}
return newPlan
}
func InitalizeAlgorithm(semesterConfig *model.SemesterConfig, examGroups []*model.ExamGroup, pop int, pm float64, sel Selection, rec Recombination, sp float64) *Algorithm {
return &Algorithm{
config: &AlgorithmConfig{
Population: pop,
MutationPropability: 1 - math.Pow(1-pm, 1./float64(len(examGroups))),
Selection: sel,
Recombination: rec,
SelectivePressure: sp,
NoImprovement: 100,
CapacityStudent: 60,
},
validation: &Validation{
sameDay: 5,
sameOrAdjacentSlots: 10,
adjacentDays: 1,
},
semesterConfig: semesterConfig,
examGroups: examGroups,
}
}
func (algorithm *Algorithm) reset() {
algorithm.bestPlan = nil
}
func (algorithm *Algorithm) NRuns(n int) ([]*model.PlanEntry, error) {
var bestPlan *Plan
for i := 0; i < n; i++ {
newPlan := algorithm.run()
if bestPlan == nil || bestPlan.fitness < newPlan.fitness {
bestPlan = newPlan
}
log.Debug().Int("i", i).Float64("fitness", bestPlan.fitness).Msg("best plan found in run")
algorithm.reset()
}
// plan := algorithm.moveSlotsToFront(bestPlan)
plan := bestPlan
if !plan.validate() {
return nil, errors.New("No Valid Plan found")
}
var exportPlan []*model.PlanEntry
for _, exam := range plan.exams {
exportPlan = append(exportPlan,
&model.PlanEntry{DayNumber: exam.day, SlotNumber: exam.slot, Ancode: exam.examGroup.ExamGroupCode, Locked: false})
}
return exportPlan, nil
}
func (algorithm *Algorithm) run() *Plan {
algorithm.initialGeneration()
var bestGenFitness float64 = 0
counter := 0
for counter < algorithm.config.NoImprovement {
algorithm.nextGeneration()
counter++
if algorithm.generation.fitness > bestGenFitness {
bestGenFitness = algorithm.generation.fitness
counter = 0
}
}
return algorithm.bestPlan
}