aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/linear_regression/unimodal.cpp
blob: 1ed1bbd451a112da2219dd65917e6a8f1253e1a6 (plain) (blame)
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
#include "unimodal.h" 
 
#include "linear_regression.h" 
 
#include <util/generic/map.h> 
#include <util/generic/ymath.h> 
 
namespace { 
    double SimpleUnimodal(const double value) { 
        if (value > 5) { 
            return 0.; 
        } 
        return 1. / (value * value + 1.); 
    } 
 
    struct TOptimizationState { 
        double Mode = 0.; 
        double Normalizer = 1.; 
 
        double RegressionFactor = 0.; 
        double RegressionIntercept = 0.; 
 
        double SSE = 0.; 
 
        TOptimizationState(const TVector<double>& values) {
            SSE = InnerProduct(values, values); 
        } 
 
        double NoRegressionTransform(const double value) const { 
            const double arg = (value - Mode) / Normalizer; 
            return SimpleUnimodal(arg); 
        } 
 
        double RegressionTransform(const double value) const { 
            return NoRegressionTransform(value) * RegressionFactor + RegressionIntercept; 
        } 
    }; 
} 
 
double TGreedyParams::Point(const size_t step) const { 
    Y_ASSERT(step <= StepsCount); 
 
    const double alpha = (double)step / StepsCount; 
    return LowerBound * (1 - alpha) + UpperBound * alpha; 
} 
 
double MakeUnimodal(TVector<double>& values, const TOptimizationParams& optimizationParams) {
    TOptimizationState state(values); 
    TOptimizationState bestState = state; 
 
    for (size_t modeStep = 0; modeStep <= optimizationParams.ModeParams.StepsCount; ++modeStep) { 
        state.Mode = optimizationParams.ModeParams.Point(modeStep); 
        for (size_t normalizerStep = 0; normalizerStep <= optimizationParams.NormalizerParams.StepsCount; ++normalizerStep) { 
            state.Normalizer = optimizationParams.NormalizerParams.Point(normalizerStep); 
 
            TSLRSolver solver; 
            for (size_t i = 0; i < values.size(); ++i) { 
                solver.Add(state.NoRegressionTransform(i), values[i]); 
            } 
 
            state.SSE = solver.SumSquaredErrors(optimizationParams.RegressionShrinkage); 
            if (state.SSE >= bestState.SSE) { 
                continue; 
            } 
 
            bestState = state; 
            solver.Solve(bestState.RegressionFactor, bestState.RegressionIntercept, optimizationParams.RegressionShrinkage); 
        } 
    } 
 
    for (size_t i = 0; i < values.size(); ++i) { 
        values[i] = bestState.RegressionTransform(i); 
    } 
 
    const double residualSSE = bestState.SSE; 
    const double totalSSE = InnerProduct(values, values); 
 
    const double determination = 1. - residualSSE / totalSSE; 
 
    return determination; 
} 
 
double MakeUnimodal(TVector<double>& values) {
    return MakeUnimodal(values, TOptimizationParams::Default(values)); 
} 
 
double MakeUnimodal(TVector<double>& values, const TVector<double>& arguments, const TOptimizationParams& optimizationParams) {
    Y_ASSERT(values.size() == arguments.size()); 
 
    TMap<double, double> mapping;
    for (size_t i = 0; i < values.size(); ++i) { 
        mapping[arguments[i]] = values[i]; 
    } 
 
    TVector<double> preparedValues;
    preparedValues.reserve(mapping.size()); 
 
    for (auto&& argWithValue : mapping) { 
        preparedValues.push_back(argWithValue.second); 
    } 
 
    const double result = MakeUnimodal(preparedValues, optimizationParams); 
 
    size_t pos = 0; 
    for (auto&& argWithValue : mapping) { 
        argWithValue.second = preparedValues[pos++]; 
    } 
 
    for (size_t i = 0; i < values.size(); ++i) { 
        values[i] = mapping[arguments[i]]; 
    } 
 
    return result; 
} 
 
double MakeUnimodal(TVector<double>& values, const TVector<double>& arguments) {
    return MakeUnimodal(values, arguments, TOptimizationParams::Default(values, arguments)); 
}