correlation of a fit from colPivHouseholderQr().solve - c++

I have some C++ code that is getting a bunch of X,Y values and doing
a linear fit
Eigen::Matrix<float, Eigen::Dynamic, 2> DX;
Eigen::Matrix<float, Eigen::Dynamic, 1> DY;
For loop over the data values (edited a bit because my data source
is a bit more complicated than simple arrays):
{
DX(i,0) = x[i];
DX(i,1) = 1;
DY(i,0) = y[i];
}
then
Eigen::Vector2f Dsolution = DX.colPivHouseholderQr().solve(DY);
// linear solution is in Dsolution[0] and Dsolution[1]
I need the correlation coefficient from that calculation.
How do I obtain it?
Most Eigen stuff is about two floors above my head, so you may need to spell it out in an elementary way.
The fundamental issue is that I'm running this routine on multiple data sets
and I need some indication of the quality of data as regards to internal noise and variance.
Thanks!

I'm assuming you are looking to compute the R² coefficient of your least-square fitting.
Linear least squares
First, let's recap what you're doing. In your Dsolution vector are two coefficients (lets call them a and b, which are your estimated parameters for an affine model between your xs and your y s). This means that for each x[i] your model's estimate for the corresponding y[i] is estimated_y[i] = a * x[i] + b.
a and b are computed by minimizing the sum of the squares of the difference between the observed y[i] and their estimated value a*x[i] + b, also called the residuals. It turns out that you can simply do that by solving a linear problem, which is why you use Eigen's solve() to find them.
Computing R²
Now we want to compute R², which is an indicator of how "good" your fit is.
If we follow the definition from Wikipedia linked above, to compute R² you need to :
Compute the average of the observed values y_avg
Compute the total sum of squares i.e. the sum of the square differences between the observed values and their average (this is like the variance but you don't divide by the number of samples)
Compute the total sum of squared residuals by summing the square of differences between the predicted and observed value of each y
Then R² is 1 - (sum_residuals_squares / sum_squares)
Eigen code
Let's see how we can do this with Eigen :
float r_squared(const MatrixX2f& DX, const VectorXf& DY, const Vector2f& model)
{
// Compute average
const float y_avg = DY.mean();
// Compute total sum of squares
const int N = DX.rows();
const float sum_squares = (DY - (y_avg * VectorXf::Ones(N))).squaredNorm();
// Compute predicted values
const VectorXf estimated_DY = DX * model;
// Compute sum of residual squared
const float sum_residuals_square = (DY - estimated_DY).squaredNorm();
return 1 - (sum_residuals_square / sum_squares);
}
The trick used in both sum of squares's expression is to use the squared norm function, because the squared norm of a vector is the sum of squares of its components. We do it twice because we have two sum of squares to compute.
In the first case, we created a vector of size N full of ones that we multiply by y_avg, to get a vector whose elements are all y_avg. Then each element of DY minus that vector will be y[i] - y_avg, and we compute the square norm to get the total sum of squares.
In the second case, we first compute the predicted y's by using your linear model, and then compute the difference with the observed values, using the squared norm to compute the sum of squared differences.

Related

Matrix multiplication very slow in Eigen

I have implemented a Gauss-Newton optimization process which involves calculating the increment by solving a linearized system Hx = b. The H matrx is calculated by H = J.transpose() * W * J and b is calculated from b = J.transpose() * (W * e) where e is the error vector. Jacobian here is a n-by-6 matrix where n is in thousands and stays unchanged across iterations and W is a n-by-n diagonal weight matrix which will change across iterations (some diagonal elements will be set to zero). However I encountered a speed issue.
When I do not add the weight matrix W, namely H = J.transpose()*J and b = J.transpose()*e, my Gauss-Newton process can run very fast in 0.02 sec for 30 iterations. However when I add the W matrix which is defined outside the iteration loop, it becomes so slow (0.3~0.7 sec for 30 iterations) and I don't understand if it is my coding problem or it normally takes this long.
Everything here are Eigen matrices and vectors.
I defined my W matrix using .asDiagonal() function in Eigen library from a vector of inverse variances. then just used it in the calculation for H ad b. Then it gets very slow. I wish to get some hints about the potential reasons for this huge slowdown.
EDIT:
There are only two matrices. Jacobian is definitely dense. Weight matrix is generated from a vector by the function vec.asDiagonal() which comes from the dense library so I assume it is also dense.
The code is really simple and the only difference that's causing the time change is the addition of the weight matrix. Here is a code snippet:
for (int iter=0; iter<max_iter; ++iter) {
// obtain error vector
error = ...
// calculate H and b - the fast one
Eigen::MatrixXf H = J.transpose() * J;
Eigen::VectorXf b = J.transpose() * error;
// calculate H and b - the slow one
Eigen::MatrixXf H = J.transpose() * weight_ * J;
Eigen::VectorXf b = J.transpose() * (weight_ * error);
// obtain delta and update state
del = H.ldlt().solve(b);
T <- T(del) // this is pseudo code, meaning update T with del
}
It is in a function in a class, and weight matrix now for debug purposes is defined as a class variable that can be accessed by the function and is defined before the function is called.
I guess that weight_ is declared as a dense MatrixXf? If so, then replace it by w.asDiagonal() everywhere you use weight_, or make the later an alias to the asDiagonal expression:
auto weight = w.asDiagonal();
This way Eigen will knows that weight is a diagonal matrix and computations will be optimized as expected.
Because the matrix multiplication is just the diagonal, you can change it to use coefficient wise multiplication like so:
MatrixXd m;
VectorXd w;
w.setLinSpaced(5, 2, 6);
m.setOnes(5,5);
std::cout << (m.array().rowwise() * w.array().transpose()).matrix() << "\n";
Likewise, the matrix vector product can be written as:
(w.array() * error.array()).matrix()
This avoids the zero elements in the matrix. Without an MCVE for me to base this on, YMMV...

How to approximate Euclidean distance on the integer plane, without overflow?

I'm working on a platform that has only integer arithmetic. The application uses geographic information, and I'm representing points by (x, y) coordinates where x and y are distances measured in meters.
As an approximation, I want to compute the Euclidean distance between two points. But to do this I have to square distances, and with 32-bit integers, the largest distance I can represent is 32 kilometers. Not good.
My needs are more on the order of 1000 kilometers. But I'd like to be able to resolve distances on a scale smaller than 30 meters.
Hence my question: how can I compute Euclidean distance, using only integer arithmetic, without overflow, on distances whose squares don't fit in a single word?
ETA: I would like to be able to compute distances, but I might settle for being able to compare them.
Perhaps comparing the octagonal distance approximation would be sufficient?
Slightly more up to date is this article on fast approximate distance functions.
I would recommend to use fixed point calculation using integers and then the distance approximation is already not too complicated.
fixed point calculation
distance approximation
Fast Approximate Distance Functions by Rafael Baptista
First step is to choose some fixed point representation for our needs:
For example in case we need a number range for 1000km with 1m resolution we can use 20bits that would be 2^20 = 1,048,576. So we have around 10bits for fractions.
Then we need to implement the approximation we choose:
For example in case we select the following approximation:
h ≈ b (1 + 0.337 (a/b)) = b + 0.337 a AND assuming 0 ≤ a ≤ b
We will implement as follows:
int32_t dx = (x1 > x2 ? x1 - x2 : x2 - x1);
int32_t dy = (y1 > y2 ? y1 - y2 : y2 - y1);
int32_t a = dx > dy ? dy : dx;
int32_t b = dx > dy ? dx : dy;
int32_t h = b + (345 * a >> 10); /* 345.088 = 0.337 * 2^10 */
About overflow:
Adding two <+20.0> positive numbers will result a maximum of <+21.0> number. That is Ok.
The multiplication is also safe while we use numbers in a range of -1..1. In this case the result will also remain in the same range. In our case <+20.0> * <+0.10> will result <+20.10> numbers. That we convert back to <+20.0>.
There is one step here we need to pay attention. During the multiplication we will get temporary a number with <+20.10> that is already near to our 32bits limit.
Exact calculation
We can also calculate the exact distance using the following consideration:
h = b sqrt(1 + (a/b)^2) AND assuming 0 < b ≤ a
In tis case we also need to calculate the square root:
square root
In case the a/b still significantly larger than one or too large to calculate the square of it, we can simplify the calculation to:
h = a
See the implementation here
I would leave the square root out of play, so that I can approximate the Euclidean distance. However, when comparing distances, this approach gives you 100% accuracy, since the comparison would be the same if you squared the distances.
I am pretty sure about that, since I had use that approach when searching for nearest neighbours in high dimensional spaces. You can check my code and the theory in kd-GeRaF.

c++ normalize a vector to a double?

I am trying to follow an algebraic equation, and convert it to c++.
I am stuck on:
Calculate the radius as r = ||dp||
where dp is a vector, and:
dp = (dx,dy)
According to my google searching, the vertical bars in r = ||dp|| mean I need to normalize the vector.
I have:
std::vector<double> dpVector;
dpVector.push_back(dx);
dpVector.push_back(dy);
How should I be normalizing this so that it returns a double as 'r'?
||dp|| is the euclidean norm of the vector dp. Take a look at this link for a more complete explanation:
https://en.wikipedia.org/wiki/Euclidean_distance
The euclidean norm is computed as follow: ||dp|| = sqrt(dp.dp), where . represents the dot product.
In C++, this would equate to ||dp|| = std::sqrt(dx*dx + dy*dy). If dp had more dimensions, you would be better off using a linear algebra library for the dot product.
A normalized vector is one that has a length of 1, that is not what you want if you are looking for a length. Calculating the length is the first step for normalizing a vector, but I don't think you need the final step!
To calculate the length you need Pythagoras's Theorem. I'm not going to go into a full description but basically you take the square root of the square of both sides.
In other words multiply dx and dy by themselves, add them together, then square root the result.
r = std::sqrt(dx*dx + dy*dy);
If you really did want to normalize the vector then all you do as the final step is to divide dx and dy both by r. This gives a resulting unit vector of length 1.
You're probably looking for the euclidean norm which is the geometric length of the vector and a scalar value.
double r = std::sqrt(dx*dx + dy*dy);
In contrast to that, normalization of a vector represents the same direction with it length (its euclidean norm ;)) being set to 1. This is again a vector.
Fixed-dimensional vector objects (especially with low dimensionality) lend themselves to be represented as a class type.
A simple example:
namespace wse
{
struct v2d { double x, y; };
inline double dot(v2d const &a, v2d const &b)
{
return a.x*b.x + a.y*b.y;
}
inline double len(v2d const &v) { return std::sqrt(dot(v,v)); }
}
// ...
wse::v2d dp{2.4, 3.4};
// ... Euclidean norm:
auto r = len(dp);
// Normalized vector
wse::v2d normalized_dp{dp.x/r, dp.y/r};

Scale x and y velocities to between -MAX and MAX in c++

I am trying to scale some x and y velocity values to be between -MAX and MAX and maintain their proportions. The numbers can be negative, zero, or positive. This is being used to enforce a speed limit on x and y velocities. Here's what I've got:
if(abs(velocities.x) <= MAX_TRANSLATIONAL_VELOCITY && abs(velocities.y) <= MAX_TRANSLATIONAL_VELOCITY)
return;
float higher = max(abs(velocities.x), abs(velocities.y));
velocities.x = (velocities.x / higher) * MAX_TRANSLATIONAL_VELOCITY;
velocities.y = (velocities.y / higher) * MAX_TRANSLATIONAL_VELOCITY;
This is not really working and the robots I'm applying it to are kind of spazzing out. Is there a standard way to accomplish this?
Thanks.
To normalize a vector you shouldn't divide its components by the maximum of any of them but by their magnitude which is the euclidean norm of the vector.
Actually you shouldn't check a single component, first you calculate magnitude, then if it's over MAX_MAGNITUDE, you normalize the vector and multiply it by MAX_MAGNITUDE.
float magnitude = sqrt(v.x*v.x + v.y*v.y);
if (magnitude > MAX_MAGNITUDE)
{
v /= magnitude; // I'm assuming overloaded operators here
v *= MAX_MAGNITUDE;
}

how to use Savitzky-Golay smooth coefficient to calculate derivatives

Savitzky-Golay smoothing filter can be used to calculate the coefficients so as to calculate the smoothed y-values by applying the coefficients to the adjacent values. The smoothed curve looks great.
According to the papers, the coefficients can also be used to calculate the derivatives up to 5th order. The coefficients calculation parameter ld would need to be set to the order of derivatives. For the first derivative, the appropriate setting is ld=1, and the value of the derivative is the accumulated sum divided by the sampling interval h.
My question is: how to use the obtained coefficients to calculate the accumulated sum? how is the derivative calculated? any sample code?
To calculate the derivatives using Savitzky-Golay smoothing filter, the polynomial coefficients computation has a parameter b, the value b[derivative] must be set to 1.0, the array be will be used in the LU decomposition call.
The key to get derivatives right is to understand the polynomial formula: Y = a0 + a1 * z + a2 * z^2 + ... + ak * z^k. The values a0, a1, a2, ..., ak are actually the smoothed values within the moving window, z = (x - x0) / h, for the centre point of the moving window, we can assume z = 0 since x = x0.
Therefore, in the derivative calculations:
dY/dx = a1/h; and d2Y/dx2 = 2a2/h^2.
Where a1, a2 are the smoothed values of y by using the coefficients calculated on the corresponding derivatives.