This commit is contained in:
vls committed 2026-10-06 17:20:47 +02:00
1 parent cc7ae6d49a
commit ec1e6846ab
32 files changed
+75060 -630

No files matched your search

-2
View File
@@ -1,7 +1,5 @@
#pragma once
#include <iostream>
#include "autoopt/optimization_problem.hpp"
namespace autoopt {
@@ -1,16 +1,25 @@
#pragma once
#include "autoopt/parameters.hpp"
#include "autoopt/quadric.hpp"
namespace autoopt {
template <typename T>
struct ellipse {
T left_arm;
T right_arm;
T entrance_angle;
struct ellipse_new : curve_base {
// T focal_length;
ellipse_new() : curve_base() {
initial = Eigen::VectorXd::Zero(4);
delta = Eigen::VectorXd::Zero(4);
param_names =
std::vector<const char*>{"left arm", "right arm", "entrance angle", "rotation"};
}
constexpr quadric<T> to_quadric() const {
template <typename T>
quadric<T> grapher_from_params(const Eigen::VectorX<T>& params) const {
T left_arm = params(0);
T right_arm = params(1);
T entrance_angle = params(2);
T alpha = params(3);
T a = (left_arm + right_arm) / T{2};
T a2 = a * a;
@@ -43,8 +52,8 @@ struct ellipse {
T E = -B * c_x - T{2} * C * c_y;
T F = A * c_x * c_x + B * c_x * c_y + C * c_y * c_y - a2 * b2;
return quadric<T>(A, B, C, D, E, F);
return quadric<T>(A, B, C, D, E, F).rotated_by(alpha);
}
};
} // namespace autoopt
} // namespace autoopt
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include <vector>
#include <Eigen/Eigen>
#include <generator>
#include <filesystem>
#include <fstream>
namespace autoopt {
struct raw_data {
Eigen::VectorXd _xs;
std::vector<Eigen::VectorXd> _yss;
};
std::generator<std::pair<double, double>> parse_dat_file(
const std::filesystem::path& filename);
std::pair<std::vector<double>, std::vector<double>> parse_row(auto& iter,
auto sentinel);
raw_data read_data(const std::filesystem::path& filename);
}
-16
View File
@@ -1,16 +0,0 @@
#pragma once
#include <eigen3/Eigen/Eigen>
namespace autoopt {
Eigen::VectorX<double> fit_ellipse(
const std::vector<std::pair<double, double>>& data,
const Eigen::VectorX<double>& inital_params,
const Eigen::VectorX<double>& delta);
Eigen::VectorX<double> fit_parabola(
const std::vector<std::pair<double, double>>& data,
const Eigen::VectorX<double>& inital_params,
const Eigen::VectorX<double>& delta);
} // namespace autoopt
+2 -4
View File
@@ -1,7 +1,5 @@
#pragma once
#include <cstddef>
#include "autoopt/derivative.hpp"
namespace autoopt {
@@ -76,7 +74,7 @@ struct log_barrier_optimization_problem
auto base_grad = _base_problem.gradient(params);
Eigen::VectorX<T> barrier_grad = autoopt::gradient<T>(
[this]<typename U>(const Eigen::VectorX<U>& p) {
return barrier_term<U>(p);
return this->barrier_term<U>(p);
},
params);
Eigen::VectorX<T> total_grad(params.size());
@@ -88,7 +86,7 @@ struct log_barrier_optimization_problem
auto base_hess = _base_problem.hessian(params);
Eigen::MatrixX<T> barrier_hess = autoopt::hessian<T>(
[this]<typename U>(const Eigen::VectorX<U>& p) {
return barrier_term<U>(p);
return this->barrier_term<U>(p);
},
params);
Eigen::MatrixX<T> total_hess(params.size(), params.size());
+64
View File
@@ -0,0 +1,64 @@
#pragma once
#include <filesystem>
#include <functional>
#include <variant>
#include <vector>
#include "autoopt/parabola_new.hpp"
#include "autoopt/ellipse_new.hpp"
#include "autoopt/importer.hpp"
namespace autoopt {
enum CurveType {
Parabola,
Ellipse
};
using curves = std::variant<parabola_new, ellipse_new>;
struct optimizer {
public:
void import_file(std::filesystem::path file_path);
void set_lower_bound(double lb);
void set_upper_bound(double ub);
void set_curve_type(int curve_type);
void set_initial(size_t i, double value);
void set_delta(size_t i, double value);
void flip_curve();
void calc_fit();
void set_plot_input_cb(std::function<void(Eigen::VectorXd xs, std::vector<Eigen::VectorXd> yss)> cb);
void set_plot_slope_cb(std::function<void(Eigen::VectorXd xs, Eigen::VectorXd ys, Eigen::VectorXd ys_curve)> cb);
void set_init_bounds_cb(std::function<void(double lb, double ub, double step)> cb);
void set_update_table_cb(std::function<void(std::vector<std::tuple<std::string, double, double>> entries)> cb);
void set_plot_error_cb(std::function<void(Eigen::VectorXd xs, Eigen::VectorXd ys)> cb);
private:
struct data {
raw_data _raw;
double lb, ub;
};
std::optional<data> _data;
std::optional<test_data> _test_data;
curves _curve;
std::optional<std::pair<Eigen::VectorXd, double>> _fit_result;
std::function<void(Eigen::VectorXd xs, std::vector<Eigen::VectorXd> yss)> _plot_input_cb;
std::function<void(double lb, double ub, double step)> _init_bounds_cb;
std::function<void(Eigen::VectorXd xs, Eigen::VectorXd ys, Eigen::VectorXd ys_curve)> _plot_slope_cb;
std::function<void(std::vector<std::tuple<std::string, double, double>> entries)> _param_table_cb;
std::function<void(Eigen::VectorXd xs, Eigen::VectorXd ys)> _plot_error_cb;
void update_test_data();
void init_bounds_cb();
void plot_input_cb();
void plot_slope_cb();
void update_table_cb();
void plot_error_cb();
};
} // namespace autoopt
-27
View File
@@ -1,27 +0,0 @@
#pragma once
#include "autoopt/quadric.hpp"
namespace autoopt
{
template <typename T>
struct parabola {
// T focal_length;
T exit_arm;
T entrance_angle;
quadric<T> to_quadric() const {
// T a = T{1} / (T{4} * focal_length);
// T x = T{2} * focal_length / std::tan(entrance_angle);
// T y = a * x * x;
T x = exit_arm * std::sin(T{2.0} * entrance_angle);
T f = T{0.5} * (T{1.0} - std::cos(T{2.0} * entrance_angle)) * exit_arm;
T a = T{1.0} / (T{4.0} * f);
T y = a * x * x;
quadric<T> q = quadric(a, T{0}, T{0}, T{0}, T{-1.0}, T{0});
return q.translated_by(-x, -y).rotated_by(entrance_angle - T{M_PI_2});
}
};
} // namespace autoopt
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#include "autoopt/parameters.hpp"
#include "autoopt/quadric.hpp"
namespace autoopt {
struct parabola_new : curve_base {
// T focal_length;
parabola_new() : curve_base() {
initial = Eigen::VectorXd::Zero(3);
delta = Eigen::VectorXd::Zero(3);
param_names =
std::vector<const char*>{"focus", "entrance angle", "rotation"};
}
template <typename T>
quadric<T> grapher_from_params(const Eigen::VectorX<T>& params) const {
T exit_arm = params(0);
T entrance_angle = params(1);
T alpha = params(2);
T x = exit_arm * std::sin(T{2.0} * entrance_angle);
T f = T{0.5} * (T{1.0} - std::cos(T{2.0} * entrance_angle)) * exit_arm;
T a = T{1.0} / (T{4.0} * f);
T y = a * x * x;
quadric<T> q = quadric(a, T{0}, T{0}, T{0}, T{-1.0}, T{0});
return q.translated_by(-x, -y).rotated_by(entrance_angle - T{M_PI_2} +
alpha);
}
};
} // namespace autoopt
+76
View File
@@ -0,0 +1,76 @@
#pragma once
#include <Eigen/Eigen>
#include <autoopt/btls.hpp>
#include <autoopt/optimization_problem.hpp>
#include <cmath>
#include <cstddef>
#include <optional>
#include <utility>
#include <vector>
#include "autoopt/util.hpp"
namespace autoopt {
struct test_data {
Eigen::VectorXd _xs;
Eigen::VectorXd _ys;
double _center;
size_t size() const { return _xs.size(); }
std::pair<double, double> operator[](size_t i) const {
return {_xs(i) - _center, _ys(i)};
};
};
struct curve_base {
Eigen::VectorXd initial;
Eigen::VectorXd delta;
std::vector<const char*> param_names;
bool flip = false;
std::pair<Eigen::VectorXd, double> fit(this auto&& self,
const test_data& measurements) {
auto opt_func = [&]<typename T>(const Eigen::VectorX<T>& params) {
auto grapher = self.template grapher_from_params<T>(params);
T error{0.0};
for (size_t i = 0; i < measurements.size(); i++) {
auto [x, y] = measurements[i];
T distance = T{self.flip ? -1.0 : 1.0} *
std::atan(grapher.slope_at(T{self.flip ? -x : x})) -
T{arcsec2rad(y)};
error = error + distance * distance;
}
return error / T(measurements.size());
};
auto_diff_optimization_problem problem(opt_func, self.initial);
log_barrier_optimization_problem lb_problem(problem, self.delta, 1e-4);
while (lb_problem._barrier_strength > 1e-20) {
btls(lb_problem);
lb_problem._barrier_strength *= 1e-2;
}
Eigen::VectorX<double> fitted_params = problem.x();
return {fitted_params, std::sqrt(problem.objective(fitted_params))};
}
Eigen::VectorXd plot(this auto&& self, const test_data& measurements,
std::optional<Eigen::VectorXd> params = {}) {
auto grapher = self.template grapher_from_params<double>(
params.value_or(self.initial));
Eigen::VectorXd ys(measurements.size());
for (size_t i = 0; i < measurements.size(); i++) {
double x = measurements[i].first;
ys(i) = rad2arcsec((self.flip ? -1.0 : 1.0) *
atan(grapher.slope_at(self.flip ? -x : x)));
}
return ys;
}
};
} // namespace autoopt
+79
View File
@@ -0,0 +1,79 @@
#include <array>
#include <cstdint>
#include <functional>
#include <tuple>
namespace autoopt {
template <typename T>
struct source {
T _value;
std::uint64_t _version = 0;
source() = default;
explicit source(T value) : _value(std::move(value)) {}
virtual T& get() { return _value; };
bool set(T value) {
if (value == _value) return false;
_value = std::move(value);
++_version;
return true;
}
};
template <typename O, typename... Is>
struct transform : source<O> {
std::function<O(Is&...)> _func;
std::tuple<source<Is>&...> _sources;
std::array<std::uint64_t, sizeof...(Is)> _versions{};
transform(std::function<O(Is&...)> func, source<Is>&... sources)
: _func(func), _sources(sources...) {
this->_value = std::apply([&](source<Is>&... sources) {
return _func(sources.get()...);
}, _sources);
this->_versions = current_versions();
}
virtual O& get() override {
auto cur_versions = current_versions();
if (_versions == cur_versions) return this->_value;
O next = std::apply([&](source<Is>&... sources) {
return _func(sources.get()...);
}, _sources);
if (next != this->_value) {
this->_value = next;
++this->_version;
}
return this->_value;
}
private:
std::array<std::uint64_t, sizeof...(Is)> current_versions() {
return std::apply([&](source<Is>&... sources){
return std::array<std::uint64_t, sizeof...(Is)>{sources._version...};
}, _sources);
}
};
template <typename T>
struct sink {
source<T>& _upstream;
std::uint64_t _version;
std::function<void(T&)> _cb;
void maybe_update() {
if (_version != _upstream._version) {
_cb(_upstream.get());
_version = _upstream._version;
}
}
};
} // namespace autoopt