-
Notifications
You must be signed in to change notification settings - Fork 4
/
solution_format.go
127 lines (108 loc) · 3.05 KB
/
solution_format.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// © 2019-present nextmv.io inc
package nextroute
import (
"context"
"fmt"
"reflect"
"sync"
"time"
"github.com/nextmv-io/nextroute/common"
"github.com/nextmv-io/sdk/run"
"github.com/nextmv-io/sdk/run/schema"
"github.com/nextmv-io/sdk/run/statistics"
)
// FormatOptions are the options that influence the format of the output.
type FormatOptions struct {
Disable struct {
Progression bool `json:"progression" usage:"disable the progression series"`
} `json:"disable"`
}
// Format formats a solution in basic format using the map function
// toSolutionOutputFn to map a solution to a user specific format.
func Format(
ctx context.Context,
options any,
progressioner Progressioner,
toSolutionOutputFn func(Solution) any,
inputSolutions ...Solution,
) schema.Output {
solutions := common.Filter(
inputSolutions,
func(solution Solution) bool {
return solution != nil
},
)
output := schema.NewOutput(
options,
common.Map(solutions, toSolutionOutputFn)...,
)
output.Statistics = statistics.NewStatistics()
if start, ok := ctx.Value(run.Start).(time.Time); ok {
duration := time.Since(start).Seconds()
output.Statistics.Run = &statistics.Run{
Duration: &duration,
}
}
if data, ok := ctx.Value(run.Data).(*sync.Map); ok {
if iterations, ok := data.Load(Iterations); ok {
if iterations, ok := iterations.(int); ok {
output.Statistics.Run.Iterations = &iterations
}
}
}
if len(solutions) == 0 {
return output
}
solution := solutions[len(solutions)-1]
if progressioner == nil {
return output
}
progressionValues := progressioner.Progression()
if len(progressionValues) == 0 {
return output
}
seriesData := common.Map(
progressionValues,
func(progressionEntry ProgressionEntry) statistics.DataPoint {
return statistics.DataPoint{
X: statistics.Float64(progressionEntry.ElapsedSeconds),
Y: statistics.Float64(progressionEntry.Value),
}
},
)
iterationsSeriesData := common.Map(
progressionValues,
func(progressionEntry ProgressionEntry) statistics.DataPoint {
return statistics.DataPoint{
X: statistics.Float64(progressionEntry.ElapsedSeconds),
Y: statistics.Float64(progressionEntry.Iterations),
}
},
)
lastProgressionElement := progressionValues[len(progressionValues)-1]
lastProgressionValue := statistics.Float64(lastProgressionElement.Value)
output.Statistics.Result = &statistics.Result{
Duration: &lastProgressionElement.ElapsedSeconds,
Value: &lastProgressionValue,
}
r := reflect.ValueOf(options)
f := reflect.Indirect(r).FieldByName("Format")
if f.IsValid() && f.CanInterface() {
if format, ok := f.Interface().(FormatOptions); ok {
if format.Disable.Progression {
return output
}
}
}
output.Statistics.SeriesData = &statistics.SeriesData{
Value: statistics.Series{
Name: fmt.Sprintf("%v", solution.Model().Objective()),
DataPoints: seriesData,
},
}
output.Statistics.SeriesData.Custom = append(output.Statistics.SeriesData.Custom, statistics.Series{
Name: "iterations",
DataPoints: iterationsSeriesData,
})
return output
}