tinyopt 700
Tinyopt, a lightweight, header only optimization library
Loading...
Searching...
No Matches
cost.h
1// Copyright 2026 Julien Michot.
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include <sstream>
7
8#include <tinyopt/log.h>
9#include <tinyopt/math.h>
10#include <tinyopt/traits.h>
11
12namespace tinyopt {
13
14/***
15 * @brief Struct containing a cost and related informations
16 *
17 ***/
18struct Cost {
19 using Scalar = double;
20
21 Cost() = default;
22 Cost(Scalar cost_) : cost{cost_}, num_resisuals{1} {}
23 Cost(Scalar cost_, int num_resisuals_, float inlier_ratio_ = 1.0f, const std::string &log_ = "")
24 : cost{cost_}, num_resisuals{num_resisuals_}, inlier_ratio{inlier_ratio_}, log_str{log_} {}
25
26 // Constructor receiving a 'residuals' Vector/Matrix. The cost will be the L2/Frobenius norm.
27 template <typename Derived>
28 Cost(const MatrixBase<Derived> &residuals, float inlier_ratio_ = 1.0f,
29 const std::string &log_ = "")
30 : Cost(residuals.squaredNorm(), (int)residuals.size(), inlier_ratio_, log_) {}
31
32 template <typename Derived>
33 Cost &operator=(const MatrixBase<Derived> &residuals) {
34 cost = residuals.squaredNorm();
35 num_resisuals = (int)residuals.size();
36 return *this;
37 }
38
39 // Comparisons
40 bool operator<(const Cost &other) const { return cost < other.cost; }
41 bool operator<=(const Cost &other) const { return cost <= other.cost; }
42 bool operator<(Scalar other_cost) const { return cost < other_cost; }
43 bool operator<(float other_cost) const { return cost < other_cost; }
44 bool operator<=(Scalar other_cost) const { return cost <= other_cost; }
45 bool operator<=(float other_cost) const { return cost <= other_cost; }
46
47 // Casting operators
48 operator Scalar() const { return cost; }
49
51 Cost &operator+=(const Cost &other) {
52 cost += other.cost;
53 AddResiduals(other.num_resisuals, other.NumInliers());
54 if (!other.log_str.empty()) log_str += " " + other.log_str;
55 return *this;
56 }
57
59 template <typename Derived>
60 Cost &operator+=(const MatrixBase<Derived> &residuals) {
61 cost += residuals.squaredNorm();
62 AddResiduals(residuals.size(), residuals.size());
63 return *this;
64 }
65
66 friend std::ostream &operator<<(std::ostream &os, const Cost &cost) {
67 os << cost.toString();
68 return os;
69 }
70
71 std::string toString(const std::string &cost_label = "ε", bool print_inliers = false) const {
72 std::ostringstream oss;
73 oss << TINYOPT_FORMAT_NS::format("{}:{:.4e}, n:{}", cost_label, cost, num_resisuals);
74 if (num_resisuals > 1)
75 oss << TINYOPT_FORMAT_NS::format(", √{}/n:{:.2e}", cost_label,
76 std::sqrt(cost / num_resisuals));
77 if (print_inliers)
78 oss << TINYOPT_FORMAT_NS::format(", in:{:.2f}% ({})", inlier_ratio * 100.0f, NumInliers());
79 if (!log_str.empty()) oss << ", " << log_str;
80 return oss.str();
81 }
82
83 bool isValid() const { return num_resisuals > 0 && cost != std::numeric_limits<Scalar>::max(); }
84 int NumInliers() const { return (int)(num_resisuals * inlier_ratio); }
85 int NumOutliers() const { return (int)(num_resisuals * (1.0f - inlier_ratio)); }
86
87 void AddResiduals(int new_residuals, int new_inliers) {
88 if (num_resisuals + new_residuals > 0)
89 inlier_ratio = (NumInliers() + new_inliers) / (float)(num_resisuals + new_residuals);
90 num_resisuals += new_residuals;
91 }
92
93 Scalar cost = Scalar(0);
94 int num_resisuals = 0;
95 float inlier_ratio = 1.0f;
96 std::string log_str;
97};
98
99} // namespace tinyopt
Definition cost.h:18
float inlier_ratio
The ratio of inlier residuals (when robust norms are used).
Definition cost.h:95
Cost & operator+=(const Cost &other)
Accumulate another cost.
Definition cost.h:51
int num_resisuals
The number of residuals (for e.g. NLLS).
Definition cost.h:94
std::string log_str
Extra information that will be printed as part of the opt. iterations.
Definition cost.h:96
Cost & operator+=(const MatrixBase< Derived > &residuals)
Accumulate residuals considering all are inliers.
Definition cost.h:60
Scalar cost
The function cost.
Definition cost.h:93