kbm.cpp
Go to the documentation of this file.
1/* *********************
2 * @file kbm.cpp
3 *
4 * @author Stefan Ulbrich
5 * @date 2013-2014
6 *
7 * @brief This file contains the implementation the Kinematic Bezier Maps minus the methods related to subdivision.
8 * *********************/
9#include "kbm.h"
10
11#include <assert.h>
12
13#include <algorithm> // std::sort
14#include <cmath>
15#include <fstream>
16#include <iomanip>
17#include <sstream>
18#include <string>
19#include <vector>
20
23
25{
26 std::ostream&
27 operator<<(std::ostream& os, const KBM::ErrorValuesType& et)
28 {
29 os << "Mean: " << et.Mean << ", STD:" << et.STD << ", Median: " << et.Median
30 << ", IQR: " << et.IQR << ", Max: " << et.Max << std::endl;
31 return os;
32 }
33
34 KBM::KBM(const KBM& other)
35 {
36 this->nControlPoints = other.nControlPoints;
37 this->nDoF = other.nDoF;
38 this->dim = other.dim;
39 this->controlNet = other.controlNet;
40 this->spreadAngles = other.spreadAngles;
41 this->index = other.index;
42 this->center = other.center;
43 this->partialDerivatives = other.partialDerivatives;
44 }
45
46 KBM::KBM(int nDoF, int dim, Real spreadAngle)
47 {
48 this->nDoF = nDoF;
49 this->dim = dim;
50 //this->spreadAngle = spreadAngle;
51 //this->spreadAngles = std::vector<Real>(nDoF,spreadAngle);
52 this->spreadAngles = Vector::Constant(nDoF, spreadAngle);
53 this->nControlPoints = pow(3.0, this->nDoF);
54 // ARMARX_DEBUG_S << "Creating KBM with" << this->nDoF << " degrees of freedom and " << this->dim << " output dimensions." << std::endl;
55 this->controlNet = Matrix::Zero(this->dim, this->nControlPoints);
56 this->createIndices();
57 this->center = Vector::Zero(this->nDoF);
58 this->partialDerivatives =
59 std::vector<Matrix>(this->nDoF, Matrix::Zero(this->dim, this->nControlPoints));
60 }
61
63 KBM::getErrors(const Matrix& proprioception, const Matrix& shape)
64 {
65 int nSamples = shape.cols();
66 // ARMARX_DEBUG_S << this->spreadAngle << std::endl;
67 ErrorValuesType error_values;
68
69 Matrix errors = this->controlNet * this->createSLE(proprioception) - shape;
70 //ARMARX_DEBUG_S << errors;
71 std::vector<Real> summed_squared_errors(nSamples, 0.0f);
72
73 error_values.Mean = 0; //mean squared error
74
75 for (int iSamples = 0; iSamples < nSamples; iSamples++)
76 {
77 Real sum = 0.0;
78
79 for (int iDim = 0; iDim < this->dim; iDim++)
80 {
81 sum += pow(errors(iDim, iSamples), 2);
82 //ARMARX_DEBUG_S << pow(errors(iDim,iSamples),2) << std::endl;
83 }
84
85 summed_squared_errors[iSamples] = sqrt(sum);
86 error_values.Mean += sqrt(sum);
87 }
88
89 error_values.Mean /= nSamples;
90 std::sort(summed_squared_errors.begin(), summed_squared_errors.end());
91 //for (int i =0; i<summed_squared_errors.size(); i++) ARMARX_DEBUG_S << summed_squared_errors[i] << std::endl;
92 error_values.Median = summed_squared_errors[nSamples / 2];
93 error_values.IQR =
94 summed_squared_errors[(nSamples * 3) / 4] - summed_squared_errors[nSamples / 4];
95 error_values.STD = 0;
96 error_values.Max =
97 *std::max_element(summed_squared_errors.begin(), summed_squared_errors.end());
98 //ARMARX_DEBUG_S << error_values << std::endl;
99 return error_values;
100 }
101
102 void
103 KBM::createIndices()
104 {
105
106 this->index.resize(nControlPoints, nDoF);
107
108 for (int iControlPoints = 0; iControlPoints < nControlPoints; iControlPoints++)
109 {
110 int decimal = iControlPoints; //-1;
111
112 //ARMARX_DEBUG_S << decimal << std::endl;
113 for (int iDoF = 0; iDoF < nDoF; iDoF++)
114 {
115 //ARMARX_DEBUG_S << iDoF << std::endl;
116 this->index(iControlPoints, iDoF) = decimal % 3;
117 //ARMARX_DEBUG_S << this->index(iControlPoints,iDoF) << " ";
118 decimal /= 3;
119 }
120
121 //ARMARX_DEBUG_S<<std::endl;
122 }
123
124 //ARMARX_DEBUG_S << this->index << std::endl;
125 }
126
127 Matrix
128 KBM::createSLE(const Matrix& proprioception, int dim, Real a1, Real a2, bool project) const
129 {
130 assert(proprioception.rows() == nDoF);
131 int nSamples = proprioception.cols();
132 Matrix SLE(nControlPoints, nSamples);
133
134
135 Real bincoeff[] = {1, 2, 1};
136
137 for (int iSamples = 0; iSamples < nSamples; iSamples++)
138 {
139 Real weight = 0;
140
141 for (int iControlPoints = 0; iControlPoints < nControlPoints; iControlPoints++)
142 {
143 SLE(iControlPoints, iSamples) = 1.0;
144
145 // ARMARX_DEBUG_S << SLE;
146 for (int iDoF = 0; iDoF < this->nDoF; iDoF++)
147 {
148 int idx = this->index(iControlPoints, iDoF);
149
150 if (dim != iDoF)
151 {
152 Real t = std::tan((proprioception(iDoF, iSamples) - center(iDoF)) / 2.0) /
153 tan(this->spreadAngles[iDoF] / 2.0) / 2.0 +
154 0.5;
155 Real gamma;
156
157 if (idx == 1)
158 {
159 gamma = std::cos(this->spreadAngles[iDoF]);
160 }
161 else
162 {
163 gamma = 1;
164 }
165
166 //ARMARX_DEBUG_S << idx << " "<< t << " " << this->spreadAngle << " " << gamma << std::endl;
167 SLE(iControlPoints, iSamples) *=
168 gamma * bincoeff[idx] * pow(t, idx) *
169 pow(1.0 - t, 2 - idx); // Bernstein polynomial
170 }
171 else //Blossom
172 {
173 Real t1 =
174 std::tan(a1 / 2.0) / tan(this->spreadAngles[iDoF] / 2.0) / 2.0 + 0.5;
175 Real t2 =
176 std::tan(a2 / 2.0) / tan(this->spreadAngles[iDoF] / 2.0) / 2.0 + 0.5;
177
178 switch (idx)
179 {
180 case 0:
181 SLE(iControlPoints, iSamples) *= (1 - t1) * (1 - t2);
182 break;
183
184 case 1:
185 SLE(iControlPoints, iSamples) *= ((1 - t1) * t2 + (1 - t2) * t1) *
186 std::cos(this->spreadAngles[iDoF]);
187 break;
188
189 case 2:
190 SLE(iControlPoints, iSamples) *= t1 * t2;
191 break;
192 }
193 }
194 }
195
196 //ARMARX_DEBUG_S << SLE;
197 weight += SLE(iControlPoints, iSamples);
198 }
199
200 //ARMARX_DEBUG_S << "Weight: " << weight << std::endl;
201 if (project)
202 for (int iControlPoints = 0; iControlPoints < nControlPoints; iControlPoints++)
203 {
204 SLE(iControlPoints, iSamples) /= weight;
205 }
206 }
207
208 //ARMARX_DEBUG_S << SLE << std::endl;
209 return SLE;
210 }
211
212 void
213 KBM::batch(const Matrix& proprioception,
214 const Matrix& shape,
215 Optimization method,
216 Real threshold)
217 {
218 assert(proprioception.cols() == shape.cols());
219 assert(proprioception.rows() == this->nDoF);
220 assert(shape.rows() == this->dim);
221 Matrix SLE = this->createSLE(proprioception);
222
223 switch (method)
224 {
225 case KBM::STANDARD:
226 this->controlNet =
227 SLE.transpose().householderQr().solve(shape.transpose()).transpose();
228 break;
229
230 case KBM::PLS:
231 this->controlNet = PLS::solve(SLE, shape, threshold);
232 break;
233 }
234
235 // ARMARX_DEBUG_S << "Control Net:\n" << this->controlNet << std::endl;
236 }
237
238 void
239 KBM::online(const Matrix& proprioception, const Matrix& shape, Real learnRate)
240 {
241 assert(proprioception.cols() == shape.cols());
242 assert(proprioception.rows() == this->nDoF);
243 // ARMARX_IMPORTANT_S << VAROUT(shape.rows()) << VAROUT(this->dim);
244 ARMARX_CHECK_EXPRESSION(shape.rows() == this->dim)
245 << armarx::ValueToString(shape.rows()) + " " + armarx::ValueToString(this->dim);
246
247 //ARMARX_DEBUG_S << "proprioception: " << proprioception<<std::endl;
248 //ARMARX_DEBUG_S << "shape: " << shape<<std::endl;
249 int nSamples = proprioception.cols();
250 Matrix SLE = createSLE(proprioception);
251
252 //ARMARX_DEBUG_S << this->dim << std::endl;
253 for (int iSamples = 0; iSamples < nSamples; iSamples++)
254 {
255 for (int iDim = 0; iDim < this->dim; iDim++)
256 {
257 Vector temp = SLE.col(iSamples);
258 Real delta = shape(iDim, iSamples) - this->controlNet.row(iDim).dot(temp);
259 Matrix update(this->nControlPoints, 1);
260 update =
261 delta * SLE.col(iSamples) * (1.0 / SLE.col(iSamples).dot(SLE.col(iSamples)));
262 //ARMARX_DEBUG_S << iSamples << std::endl << iDim << std::endl << delta << std::endl << update << std::endl;
263 this->controlNet.row(iDim) += learnRate * update.transpose();
264 }
265 }
266 }
267
268 bool
269 KBM::restore(std::string fileName)
270 {
271 std::ifstream file(fileName.c_str());
272
273 if (!file.is_open())
274 {
275 // ARMARX_DEBUG_S << "Could not open file: " << fileName << std::endl;
276 return false;
277 }
278
279 std::vector<double> values;
280
281 // ARMARX_DEBUG_S << "Reading " << fileName << std::endl;
282 int lastCols = -1; //Compare the number of columns in each row.
283 int rows = 0;
284 std::string line;
285
286 while (getline(file, line))
287 {
288 int cols = 0;
289 std::stringstream linestream(line);
290 std::string value;
291
292 while (getline(linestream, value, ','))
293 {
294 values.push_back(strtod(value.c_str(), NULL));
295 cols++;
296 }
297
298 rows++;
299
300
301 // check if number of columns changes.
302 if (lastCols >= 0)
303 {
304 assert(lastCols == cols);
305 }
306
307 lastCols = cols;
308 }
309
310 //ARMARX_DEBUG_S << values.size() << std::endl;
311 assert(this->dim == rows && "Incompatible output dimensions");
312 assert(this->nControlPoints == lastCols && "Incompatible input dimensions");
313
314 for (int i = 0; i < this->dim; i++)
315 for (int j = 0; j < this->nControlPoints; j++)
316 {
317 this->controlNet(i, j) =
318 values[i * this->nControlPoints +
319 j]; // Not nice, but we checked the dimensions so this is safe.
320 }
321
322 //ARMARX_DEBUG_S << this->controlNet << std::endl;
323 ARMARX_DEBUG_S << "done (rows: " << rows << ", Cols: " << lastCols
324 << ", nDoF: " << this->nDoF << ", dim: " << this->dim << ")" << std::endl;
325 return true;
326 }
327
328 void
330 {
331 this->controlNet = Matrix::Zero(this->dim, this->nControlPoints);
332 }
333
334 //ColumnVector crossproduct(const ColumnVector &a, const ColumnVector &b){
335 // ColumnVector result(3);
336 // result(1) = a(2)*b(3)-a(3)*b(2);
337 // result(2) = a(3)*b(1)-a(1)*b(3);
338 // result(3) = a(1)*b(2)-a(2)*b(1);
339 // return result;
340 //}
341
342 Matrix
343 KBM::predict(const Matrix& proprioception, int dim) const
344 {
345 if (dim == 0)
346 {
347 return controlNet * createSLE(proprioception);
348 }
349 else
350 {
351 //e = bez.controlNet * (blossom(bez,proprioception,dim,-bez.spreadAngle,proprioception(dim))-blossom(bez,proprioception,dim,bez.spreadAngle,proprioception(dim))#
352 //e2 = bez.controlNet * (blossom(bez,proprioception,dim,-bez.spreadAngle,proprioception(dim)+diff)-blossom(bez,proprioception,dim,bez.spreadAngle,proprioception(#
353 //e = cross(e1,e2);
354 //e = cross(e3,e1);
355 //frame(:3,:) = [e1/norm(e1) e2/norm(e2) e3/norm(e3) o];))))
356 Vector o = controlNet * createSLE(proprioception);
357 Vector3 e1 =
358 this->controlNet *
359 (createSLE(
360 proprioception, dim, (-1) * this->spreadAngles[dim], proprioception(dim, 0)) -
361 createSLE(proprioception, dim, this->spreadAngles[dim], proprioception(dim, 0)));
362 Real offset =
363 0.1; // pi/6 // Magic number: Small offset that generates another vector to define the plane.
364 Vector3 e2 = this->controlNet * (createSLE(proprioception,
365 dim,
366 (-1) * this->spreadAngles[dim],
367 proprioception(dim, 0) + offset) -
368 createSLE(proprioception,
369 dim,
370 this->spreadAngles[dim],
371 proprioception(dim, 0) + offset));
372 //ARMARX_DEBUG_S << e1 << e2 << "e1/2";
373 Vector3 e3;
374 e3 = e1.cross(e2);
375 e2 = e3.cross(e1);
376 Matrix result = Matrix::Zero(4, 4);
377 //ARMARX_DEBUG_S << e1 << ",\n" << e2 << ",\n" <<e3 << ",\n" <<o;
378 result.block(0, 0, 3, 1) = e1 / e1.norm();
379 result.block(0, 1, 3, 1) = e2 / e2.norm();
380 result.block(0, 2, 3, 1) = e3 / e3.norm();
381 result.block(0, 3, 3, 1) = o;
382 result(3, 3) = 1.0f;
383 return result;
384 }
385 }
386
387 void
389 {
390 for (int i = 0; i < this->nDoF; i++)
391 {
392 }
393 }
394
395 Vector
396 KBM::getPartialDerivative(const Vector& proprioception, int iDoF) const
397 {
398
399 Vector SLEa = this->createSLE(
400 proprioception, iDoF, this->spreadAngles[iDoF], proprioception[iDoF], false);
401 Vector SLEb = this->createSLE(
402 proprioception, iDoF, (-1) * this->spreadAngles[iDoF], proprioception[iDoF], false);
403 Vector SLEc = this->createSLE(proprioception, -1, 0.0f, 0.0f, false);
404
405 Vector SLE = ((SLEa - SLEb) * SLEc.sum() - (SLEa.sum() - SLEb.sum()) * SLEc) /
406 (SLEc.sum() * SLEc.sum());
407 return this->controlNet * SLE / cos(proprioception[iDoF] / 2.0f) /
408 cos(proprioception[iDoF] / 2.0f) / 2 / tan(this->spreadAngles[iDoF] / 2.0f);
409 }
410
411 Matrix
412 KBM::getJacobian(const Vector& proprioception) const
413 {
414 Matrix Jacobian(this->dim, this->nDoF);
415
416 for (int iDoF = 0; iDoF < this->nDoF; iDoF++)
417 {
418 Jacobian.col(iDoF) = this->getPartialDerivative(proprioception, iDoF);
419 }
420
421 return Jacobian;
422 }
423
424 Vector
426 {
427 return this->spreadAngles;
428 }
429
430 Vector
432 {
433 return this->center;
434 }
435
436 int
438 {
439 return this->nDoF;
440 }
441
442 int
444 {
445 return this->dim;
446 }
447
448 Matrix
450 {
451 return controlNet;
452 }
453
454 KBM_ptr
456 int dim,
457 const Vector& center,
458 const Vector& spreadAngles,
459 const Matrix& controlNet)
460 {
461 KBM_ptr kbm(new KBM(nDoF, dim, 0.0f));
462 kbm->controlNet = controlNet;
463 kbm->spreadAngles = spreadAngles;
464 kbm->center = center;
465 return kbm;
466 }
467
468 void
469 KBM::store(std::string fileName)
470 {
471 // ARMARX_DEBUG_S << "Storing to " << fileName << " ... " << std::flush;
472 std::ofstream file(fileName.c_str(), std::ofstream::trunc);
473 file << std::scientific << std::fixed
474 << std::setprecision(std::numeric_limits<double>::digits);
475
476 for (int iDim = 0; iDim < this->dim; iDim++)
477 {
478 for (int iControlPoints = 0; iControlPoints < this->nControlPoints - 1;
479 iControlPoints++)
480 {
481 file << this->controlNet(iDim, iControlPoints) << ",";
482 // ARMARX_DEBUG_S << this->controlNet(iDim,iControlPoints) << ",";
483 }
484
485 file << this->controlNet(iDim, nControlPoints - 1) << std::endl;
486 // ARMARX_DEBUG_S << this->controlNet(iDim,nControlPoints-1) << std::endl;
487 }
488
489 file.close();
490 // ARMARX_DEBUG_S << "Done." << std::endl;
491 }
492
493 KBM_ptr
494 KBM::createFromVirtualRobot(VirtualRobot::KinematicChainPtr chain,
495 VirtualRobot::SceneObjectPtr FoR,
496 const Vector& spreadAngles,
497 bool useOrientation)
498 {
499 Matrix controlNet;
500
501 if (!useOrientation)
502 {
503 controlNet = FoR->toLocalCoordinateSystem(chain->getTCP()->getGlobalPose())
504 .block(0, 3, 4, 1)
505 .cast<Real>();
506 }
507 else
508 {
509 controlNet.resize(12, 1);
510 Eigen::Transform<float, 3, Eigen::Affine> axis_x(
511 Eigen::Translation<float, 3>(1.0, 0.0, 0.0));
512 Eigen::Transform<float, 3, Eigen::Affine> axis_y(
513 Eigen::Translation<float, 3>(0.0, 1.0, 0.0));
514 controlNet.block(0, 0, 4, 1) =
515 FoR->toLocalCoordinateSystem(chain->getTCP()->getGlobalPose())
516 .block(0, 3, 4, 1)
517 .cast<Real>();
518 controlNet.block(4, 0, 4, 1) =
519 FoR->toLocalCoordinateSystem(chain->getTCP()->getGlobalPose() * axis_x.matrix())
520 .block(0, 3, 4, 1)
521 .cast<Real>();
522 controlNet.block(8, 0, 4, 1) =
523 FoR->toLocalCoordinateSystem(chain->getTCP()->getGlobalPose() * axis_y.matrix())
524 .block(0, 3, 4, 1)
525 .cast<Real>();
526 }
527
528 for (int i = chain->getSize() - 1; i >= 0; --i)
529 {
530 Matrix temp = controlNet;
531 controlNet.resize(controlNet.rows(), controlNet.cols() * 3);
532
533 VirtualRobot::RobotNodeRevolute* node =
534 dynamic_cast<VirtualRobot::RobotNodeRevolute*>(chain->getNode(i).get());
535 Vector3 axis = node->getJointRotationAxisInJointCoordSystem().cast<Real>();
536 Matrix4 toLocal, toGlobal;
537 toLocal = node->getGlobalPose().inverse().cast<Real>();
538 toGlobal = node->getGlobalPose().cast<Real>();
539 Real factor = 1.0f / cos(spreadAngles(i));
540 Eigen::Transform<Real, 3, Eigen::Affine> rotation(
541 Eigen::AngleAxis<Real>(spreadAngles(i), axis));
542 Eigen::Transform<Real, 3, Eigen::Affine> scaling;
543 Vector3 diag = axis + factor * (Vector3::Constant(1.0f) - axis);
544 scaling = Eigen::Scaling(diag);
545
546 for (int i = 0; i < temp.rows() / 4; i++)
547 {
548 controlNet.block(i * 4, 0, 4, temp.cols()) =
549 toGlobal * rotation.inverse() * toLocal * temp.block(i * 4, 0, 4, temp.cols());
550 controlNet.block(i * 4, temp.cols(), 4, temp.cols()) =
551 toGlobal * scaling * toLocal * temp.block(i * 4, 0, 4, temp.cols());
552 controlNet.block(i * 4, 2 * temp.cols(), 4, temp.cols()) =
553 toGlobal * rotation * toLocal * temp.block(i * 4, 0, 4, temp.cols());
554 }
555 }
556
557 Vector center = Vector::Constant(chain->getSize(), 0.0f);
558
559 if (!useOrientation)
560 {
561 return KBM::createKBM(chain->getSize(),
562 3,
563 center,
564 spreadAngles,
565 controlNet.block(0, 0, 3, controlNet.cols()));
566 }
567 else
568 {
569 Matrix reducedControlNet(9, controlNet.cols());
570 reducedControlNet.block(0, 0, 3, controlNet.cols()) =
571 controlNet.block(0, 0, 3, controlNet.cols());
572 reducedControlNet.block(3, 0, 3, controlNet.cols()) =
573 controlNet.block(4, 0, 3, controlNet.cols());
574 reducedControlNet.block(6, 0, 3, controlNet.cols()) =
575 controlNet.block(8, 0, 3, controlNet.cols());
576 return KBM::createKBM(chain->getSize(), 9, center, spreadAngles, reducedControlNet);
577 }
578 }
579
580
581} // namespace memoryx::KBM::Models
uint8_t index
Eigen::Matrix< T, 3, 3 > Matrix
Matrix predict(const Matrix &proprioception, int dim=0) const
Predicts a value of the FK given a set of joint angles.
Definition kbm.cpp:343
Vector getCenter() const
Return the center.
Definition kbm.cpp:431
void store(std::string fileName="")
stores the current KBM as a comma-separated matrix to disk.
Definition kbm.cpp:469
Matrix getJacobian(const Vector &proprioception) const
Computes the partial derivative with respect to a configuration.
Definition kbm.cpp:412
ErrorValuesType getErrors(const Matrix &proprioception, const Matrix &shape)
After learning this function gives various error measures over a given test set.online Proprioception...
Definition kbm.cpp:63
Vector getPartialDerivative(const Vector &proprioception, int iDoF) const
Computes a partial derivative with respect to a configuration and the specified degree of freedom.
Definition kbm.cpp:396
Optimization
Enum for the preferred optimization method during batch learning.
Definition kbm.h:86
static KBM_ptr createKBM(int nDoF, int dim, const Vector &center, const Vector &spreadAngles, const Matrix &controlNet)
Factory methods.
Definition kbm.cpp:455
static KBM_ptr createFromVirtualRobot(VirtualRobot::KinematicChainPtr chain, VirtualRobot::SceneObjectPtr FoR, const Vector &spreadAngles, bool useOrientation=false)
Definition kbm.cpp:494
void differentiate()
Prepares the calculus of the derivatives. Has to be called alwayes after learning.
Definition kbm.cpp:388
void online(const Matrix &proprioception, const Matrix &shape, Real learnRate=1.0)
Implements the online learning algorithm.
Definition kbm.cpp:239
Matrix getControlNet() const
Definition kbm.cpp:449
int getNDoF() const
Get the number of degrees of freedom (DoF).
Definition kbm.cpp:437
void reset()
Forgets all previously learned samples.
Definition kbm.cpp:329
Vector getSpreadAngles() const
Return the spread angles.
Definition kbm.cpp:425
void batch(const Matrix &proprioception, const Matrix &shape, Optimization method=KBM::STANDARD, Real threshold=0.0)
Implements the batch learning algorithm.
Definition kbm.cpp:213
KBM(const KBM &other)
Copy constructor.
Definition kbm.cpp:34
int getNDim() const
Definition kbm.cpp:443
bool restore(std::string fileName="")
loads a KBM with same input/output dimensions from disk (comma-separated values).
Definition kbm.cpp:269
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_DEBUG_S
The logging level for output that is only interesting while debugging.
Definition Logging.h:205
std::string ValueToString(const T &value)
Where the model representation for a Body Schema (especially the Kinematic B“ezier Maps) reside.
Definition inverse.cpp:23
std::ostream & operator<<(std::ostream &os, const KBM::ErrorValuesType &et)
Definition kbm.cpp:27
std::shared_ptr< KBM > KBM_ptr
Definition kbm.h:71
Matrix KBM_IMPORT_EXPORT solve(const Matrix &input, const Matrix output, Real threshold)
Solves a linear system of equations using the partial least squares algorithm.
Definition pls.cpp:33
Eigen::MatrixXd Matrix
Definition kbm.h:40
Eigen::VectorXd Vector
Definition kbm.h:41
double Real
Type definition of the underlying Realing point type.
Definition kbm.h:39
Eigen::Matrix4d Matrix4
Definition kbm.h:42
Eigen::Vector3d Vector3
Definition kbm.h:43
double dot(const Point &x, const Point &y)
Definition point.hpp:57
Return type of the evaluation (KBM::getErrors()) function providing insight in the statistics of the ...
Definition kbm.h:109
Real Median
Median of the error.
Definition kbm.h:115
Real STD
Standard deviation.
Definition kbm.h:113
Real IQR
Inerquartile range (50% of all errors): .
Definition kbm.h:117