aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/linear_regression/unimodal.cpp
blob: 729011012a01c78cd89febb9727376811c34529f (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));
}