rework
This commit is contained in:
32 files changed
+75060
-630
No files matched your search
@@ -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
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in new issue
Block a user