Maestro 0.2.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
MultipleLinearRegression.h
Go to the documentation of this file.
1
11
12#pragma once
13
14#ifndef __MULTIPLE_LINEAR_REGRESSION_H__
15#define __MULTIPLE_LINEAR_REGRESSION_H__
16
17#include <cmath>
18#include <vector>
19#include <Eigen/Eigen>
20
21namespace Utils {
22
23 // WARNING: it doesn't let it go lower than the minimum value, if the prediction is lower, the min value is returned!
24 // set "TrueLinearRegression" to true if you want to use the real linear regression
26 public:
28
29 MultipleLinearRegression(const Eigen::VectorXd& initialWeights, double initialBias = 0.0, bool initialTrueLinearRegression = false)
30 : W(initialWeights), b(initialBias), trueLinearRegression(initialTrueLinearRegression) {}
31
32 void SetSamples(const std::vector<std::vector<double>>& x, const std::vector<double>& y)
33 {
34 assert(x.size() == y.size());
35 assert(!x.empty());
36
37 if (x.empty() || y.empty())
38 return;
39
40 const size_t n = std::min(x.size(), y.size());
41 const size_t m = x[0].size();
42
43 // if x is extended with 1 (for the bias term), then it's just a matrix thing, like this:
44 // W = (X^t * X)^-1 * X^t * y
45 // but from there the real W must be extracted and also b is going to be saved separately
46
47 Eigen::MatrixXd X;
48 X.resize(n, m + 1);
49 X.col(0).setOnes();
50
51 for (size_t i = 0; i < n; ++i)
52 for (size_t j = 1; j <= m; ++j)
53 X(i, j) = x[i][j - 1];
54
55 Eigen::VectorXd Y;
56 Y.resize(n);
57 for (size_t i = 0; i < n; ++i)
58 Y(i) = y[i];
59
60 Eigen::MatrixXd Wa;
61
62 /*
63 Eigen::MatrixXd Xt = X.transpose();
64 Eigen::MatrixXd XtX = Xt * X;
65
66 if (abs(XtX.determinant()) < 1E-10)
67 Wa = XtX.completeOrthogonalDecomposition().pseudoInverse() * Xt * Y;
68 else
69 Wa = XtX.inverse() * Xt * Y;
70 */
71
72 if (alpha > 0.)
73 {
74 // Ridge (L2) regularization: minimize ||X * w - Y||^2 + lambda * ||w||^2.
75 // The penalty strength is derived from the data so it adapts to the
76 // (unscaled) feature magnitudes: lambda = alpha * trace(X^t * X) / m,
77 // using only the feature columns (the bias column is left unregularized).
78 // It is solved by augmenting the system with sqrt(lambda) * I rows (and
79 // zeros in Y), which keeps the well-conditioned QR solve instead of
80 // forming X^t * X.
81 double trace = 0.;
82 for (size_t j = 1; j <= m; ++j)
83 trace += X.col(j).squaredNorm();
84
85 const double lambda = (m > 0) ? alpha * trace / static_cast<double>(m) : 0.;
86
87 Eigen::MatrixXd Xa(n + m, m + 1);
88 Xa.topRows(n) = X;
89 Xa.bottomRows(m).setZero();
90
91 const double sqrtLambda = std::sqrt(lambda);
92 for (size_t j = 0; j < m; ++j)
93 Xa(n + j, j + 1) = sqrtLambda;
94
95 Eigen::VectorXd Ya(n + m);
96 Ya.head(n) = Y;
97 Ya.tail(m).setZero();
98
99 Wa = Xa.colPivHouseholderQr().solve(Ya);
100 }
101 else
102 Wa = X.colPivHouseholderQr().solve(Y);
103
104 b = Wa(0);
105 W.resize(m);
106 for (size_t i = 0; i < m; ++i)
107 W(i) = Wa(i + 1);
108 //std::cout << "W: " << W << std::endl;
109 //std::cout << "b: " << b << std::endl;
110 }
111
112 double Predict(const std::vector<double>& x) const
113 {
114 assert(x.size() == static_cast<size_t>(W.rows()));
115
116 if (x.size() != static_cast<size_t>(W.size()))
117 return 0.;
118
119 Eigen::RowVectorXd xRow;
120 xRow.resize(x.size());
121 for (size_t i = 0; i < x.size(); ++i)
122 xRow(i) = x[i];
123
124 const auto val = xRow * W + b;
125
126 if (trueLinearRegression)
127 return val;
128
129 const auto m = 1E-12;
130 if (val < m)
131 return m;
132
133 return val;
134 }
135
137 {
138 trueLinearRegression = reg;
139 }
140
141 // Ridge (L2) regularization factor (alpha). The effective penalty is derived
142 // from the data as alpha * trace(X^t * X) / m, so it adapts to the (unscaled)
143 // feature magnitudes. Set to 0 to disable. Applied before SetSamples.
144 // A small value such as 1e-6 stabilizes collinear/rank-deficient fits without
145 // materially biasing the weights.
146 void SetRegularization(double reg)
147 {
148 alpha = reg;
149 }
150
151 const Eigen::VectorXd& GetWeights() const { return W; }
152 double GetBias() const { return b; }
153 bool IsTrueLinearRegression() const { return trueLinearRegression; }
154 double GetRegularization() const { return alpha; }
155
156 private:
157 Eigen::VectorXd W;
158 double b = 0.;
159
160 bool trueLinearRegression = false;
161 double alpha = 1e-6;
162 };
163
164}
165
166#endif // __MULTIPLE_LINEAR_REGRESSION_H__
void SetSamples(const std::vector< std::vector< double > > &x, const std::vector< double > &y)
double Predict(const std::vector< double > &x) const
MultipleLinearRegression(const Eigen::VectorXd &initialWeights, double initialBias=0.0, bool initialTrueLinearRegression=false)
const Eigen::VectorXd & GetWeights() const
Definition Alias.h:22