finish optimizer interface and remove commented code
This commit is contained in:
parent
927b81ea97
commit
f3c0bf46d4
2 changed files with 54 additions and 42 deletions
|
@ -103,6 +103,16 @@ public:
|
||||||
bool stop_condition() { return m_stop_condition(); }
|
bool stop_condition() { return m_stop_condition(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper class to use optimization methods involving gradient.
|
||||||
|
template<size_t N> struct ScoreGradient {
|
||||||
|
double score;
|
||||||
|
std::optional<std::array<double, N>> gradient;
|
||||||
|
|
||||||
|
ScoreGradient(double s, const std::array<double, N> &grad)
|
||||||
|
: score{s}, gradient{grad}
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
// Helper to be used in static_assert.
|
// Helper to be used in static_assert.
|
||||||
template<class T> struct always_false { enum { value = false }; };
|
template<class T> struct always_false { enum { value = false }; };
|
||||||
|
|
||||||
|
@ -112,13 +122,13 @@ public:
|
||||||
|
|
||||||
Optimizer(const StopCriteria &)
|
Optimizer(const StopCriteria &)
|
||||||
{
|
{
|
||||||
static_assert(always_false<Method>::value,
|
static_assert (always_false<Method>::value,
|
||||||
"Optimizer unimplemented for given method!");
|
"Optimizer unimplemented for given method!");
|
||||||
}
|
}
|
||||||
|
|
||||||
Optimizer<Method, Enable> &to_min() { return *this; }
|
Optimizer<Method> &to_min() { return *this; }
|
||||||
Optimizer<Method, Enable> &to_max() { return *this; }
|
Optimizer<Method> &to_max() { return *this; }
|
||||||
Optimizer<Method, Enable> &set_criteria(const StopCriteria &) { return *this; }
|
Optimizer<Method> &set_criteria(const StopCriteria &) { return *this; }
|
||||||
StopCriteria get_criteria() const { return {}; };
|
StopCriteria get_criteria() const { return {}; };
|
||||||
|
|
||||||
template<class Func, size_t N>
|
template<class Func, size_t N>
|
||||||
|
@ -156,35 +166,20 @@ struct IsNLoptAlg<NLoptAlgComb<a1, a2>> {
|
||||||
template<class M, class T = void>
|
template<class M, class T = void>
|
||||||
using NLoptOnly = std::enable_if_t<IsNLoptAlg<M>::value, T>;
|
using NLoptOnly = std::enable_if_t<IsNLoptAlg<M>::value, T>;
|
||||||
|
|
||||||
// Convert any collection to tuple. This is useful for object functions taking
|
// Helper to convert C style array to std::array. The copy should be optimized
|
||||||
// an argument list of doubles. Make things cleaner on the call site of
|
// away with modern compilers.
|
||||||
// optimize().
|
template<size_t N, class T> auto to_arr(const T *a)
|
||||||
template<size_t I, std::size_t N, class T, class C> struct to_tuple_ {
|
|
||||||
static auto call(const C &c)
|
|
||||||
{
|
|
||||||
return std::tuple_cat(std::tuple<T>(c[N-I]),
|
|
||||||
to_tuple_<I-1, N, T, C>::call(c));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<size_t N, class T, class C> struct to_tuple_<0, N, T, C> {
|
|
||||||
static auto call(const C &c) { return std::tuple<>(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
// C array to tuple
|
|
||||||
template<std::size_t N, class T> auto carray_tuple(const T *v)
|
|
||||||
{
|
|
||||||
return to_tuple_<N, N, T, const T*>::call(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper to convert C style array to std::array
|
|
||||||
template<size_t N, class T> auto to_arr(const T (&a) [N])
|
|
||||||
{
|
{
|
||||||
std::array<T, N> r;
|
std::array<T, N> r;
|
||||||
std::copy(std::begin(a), std::end(a), std::begin(r));
|
std::copy(a, a + N, std::begin(r));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<size_t N, class T> auto to_arr(const T (&a) [N])
|
||||||
|
{
|
||||||
|
return to_arr<N>(static_cast<const T *>(a));
|
||||||
|
}
|
||||||
|
|
||||||
enum class OptDir { MIN, MAX }; // Where to optimize
|
enum class OptDir { MIN, MAX }; // Where to optimize
|
||||||
|
|
||||||
struct NLopt { // Helper RAII class for nlopt_opt
|
struct NLopt { // Helper RAII class for nlopt_opt
|
||||||
|
@ -227,9 +222,19 @@ protected:
|
||||||
nlopt_force_stop(std::get<2>(*tdata));
|
nlopt_force_stop(std::get<2>(*tdata));
|
||||||
|
|
||||||
auto fnptr = std::get<0>(*tdata);
|
auto fnptr = std::get<0>(*tdata);
|
||||||
auto funval = carray_tuple<N>(params);
|
auto funval = to_arr<N>(params);
|
||||||
|
|
||||||
return std::apply(*fnptr, funval);
|
double scoreval = 0.;
|
||||||
|
using RetT = decltype((*fnptr)(funval));
|
||||||
|
if constexpr (std::is_convertible_v<RetT, ScoreGradient<N>>) {
|
||||||
|
ScoreGradient<N> score = (*fnptr)(funval);
|
||||||
|
for (size_t i = 0; i < n; ++i) gradient[i] = (*score.gradient)[i];
|
||||||
|
scoreval = score.score;
|
||||||
|
} else {
|
||||||
|
scoreval = (*fnptr)(funval);
|
||||||
|
}
|
||||||
|
|
||||||
|
return scoreval;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
|
@ -354,12 +359,18 @@ public:
|
||||||
|
|
||||||
template<size_t N> Bounds<N> bounds(const Bound (&b) [N]) { return detail::to_arr(b); }
|
template<size_t N> Bounds<N> bounds(const Bound (&b) [N]) { return detail::to_arr(b); }
|
||||||
template<size_t N> Input<N> initvals(const double (&a) [N]) { return detail::to_arr(a); }
|
template<size_t N> Input<N> initvals(const double (&a) [N]) { return detail::to_arr(a); }
|
||||||
|
template<size_t N> auto score_gradient(double s, const double (&grad)[N])
|
||||||
|
{
|
||||||
|
return ScoreGradient<N>(s, detail::to_arr(grad));
|
||||||
|
}
|
||||||
|
|
||||||
// Predefinded NLopt algorithms that are used in the codebase
|
// Predefinded NLopt algorithms that are used in the codebase
|
||||||
using AlgNLoptGenetic = detail::NLoptAlgComb<NLOPT_GN_ESCH>;
|
using AlgNLoptGenetic = detail::NLoptAlgComb<NLOPT_GN_ESCH>;
|
||||||
using AlgNLoptSubplex = detail::NLoptAlg<NLOPT_LN_SBPLX>;
|
using AlgNLoptSubplex = detail::NLoptAlg<NLOPT_LN_SBPLX>;
|
||||||
using AlgNLoptSimplex = detail::NLoptAlg<NLOPT_LN_NELDERMEAD>;
|
using AlgNLoptSimplex = detail::NLoptAlg<NLOPT_LN_NELDERMEAD>;
|
||||||
|
|
||||||
|
// TODO: define others if needed...
|
||||||
|
|
||||||
// Helper defs for pre-crafted global and local optimizers that work well.
|
// Helper defs for pre-crafted global and local optimizers that work well.
|
||||||
using DefaultGlobalOptimizer = Optimizer<AlgNLoptGenetic>;
|
using DefaultGlobalOptimizer = Optimizer<AlgNLoptGenetic>;
|
||||||
using DefaultLocalOptimizer = Optimizer<AlgNLoptSubplex>;
|
using DefaultLocalOptimizer = Optimizer<AlgNLoptSubplex>;
|
||||||
|
|
|
@ -496,7 +496,7 @@ bool SupportTreeBuildsteps::create_ground_pillar(const Vec3d &hjp,
|
||||||
search_widening_path(jp, dir, radius, m_cfg.head_back_radius_mm);
|
search_widening_path(jp, dir, radius, m_cfg.head_back_radius_mm);
|
||||||
|
|
||||||
if (diffbr && diffbr->endp.z() > jp_gnd) {
|
if (diffbr && diffbr->endp.z() > jp_gnd) {
|
||||||
auto &br = m_builder.add_diffbridge(diffbr.value());
|
auto &br = m_builder.add_diffbridge(*diffbr);
|
||||||
if (head_id >= 0) m_builder.head(head_id).bridge_id = br.id;
|
if (head_id >= 0) m_builder.head(head_id).bridge_id = br.id;
|
||||||
endp = diffbr->endp;
|
endp = diffbr->endp;
|
||||||
radius = diffbr->end_r;
|
radius = diffbr->end_r;
|
||||||
|
@ -589,7 +589,9 @@ std::optional<DiffBridge> SupportTreeBuildsteps::search_widening_path(
|
||||||
double fallback_ratio = radius / m_cfg.head_back_radius_mm;
|
double fallback_ratio = radius / m_cfg.head_back_radius_mm;
|
||||||
|
|
||||||
auto oresult = solver.to_max().optimize(
|
auto oresult = solver.to_max().optimize(
|
||||||
[this, jp, radius, new_radius](double plr, double azm, double t) {
|
[this, jp, radius, new_radius](const opt::Input<3> &input) {
|
||||||
|
auto &[plr, azm, t] = input;
|
||||||
|
|
||||||
auto d = spheric_to_dir(plr, azm).normalized();
|
auto d = spheric_to_dir(plr, azm).normalized();
|
||||||
double ret = pinhead_mesh_intersect(jp, d, radius, new_radius, t)
|
double ret = pinhead_mesh_intersect(jp, d, radius, new_radius, t)
|
||||||
.distance();
|
.distance();
|
||||||
|
@ -705,24 +707,22 @@ void SupportTreeBuildsteps::filter()
|
||||||
// viable normal that doesn't collide with the model
|
// viable normal that doesn't collide with the model
|
||||||
// geometry and its very close to the default.
|
// geometry and its very close to the default.
|
||||||
|
|
||||||
// stc.stop_score = w; // space greater than w is enough
|
|
||||||
Optimizer<AlgNLoptGenetic> solver(get_criteria(m_cfg));
|
Optimizer<AlgNLoptGenetic> solver(get_criteria(m_cfg));
|
||||||
solver.seed(0);
|
solver.seed(0); // we want deterministic behavior
|
||||||
//solver.seed(0); // we want deterministic behavior
|
|
||||||
|
|
||||||
auto oresult = solver.to_max().optimize(
|
auto oresult = solver.to_max().optimize(
|
||||||
[this, pin_r, back_r, hp](double plr, double azm, double l)
|
[this, pin_r, back_r, hp](const opt::Input<3> &input)
|
||||||
{
|
{
|
||||||
|
auto &[plr, azm, l] = input;
|
||||||
|
|
||||||
auto dir = spheric_to_dir(plr, azm).normalized();
|
auto dir = spheric_to_dir(plr, azm).normalized();
|
||||||
|
|
||||||
double score = pinhead_mesh_intersect(
|
return pinhead_mesh_intersect(
|
||||||
hp, dir, pin_r, back_r, l).distance();
|
hp, dir, pin_r, back_r, l).distance();
|
||||||
|
|
||||||
return score;
|
|
||||||
},
|
},
|
||||||
initvals({polar, azimuth, (lmin + lmax) / 2.}), // start with what we have
|
initvals({polar, azimuth, (lmin + lmax) / 2.}), // start with what we have
|
||||||
bounds({
|
bounds({
|
||||||
{PI - m_cfg.bridge_slope, PI}, // Must not exceed the tilt limit
|
{PI - m_cfg.bridge_slope, PI}, // Must not exceed the slope limit
|
||||||
{-PI, PI}, // azimuth can be a full search
|
{-PI, PI}, // azimuth can be a full search
|
||||||
{lmin, lmax}
|
{lmin, lmax}
|
||||||
}));
|
}));
|
||||||
|
@ -924,7 +924,8 @@ bool SupportTreeBuildsteps::connect_to_ground(Head &head)
|
||||||
double r_back = head.r_back_mm;
|
double r_back = head.r_back_mm;
|
||||||
Vec3d hjp = head.junction_point();
|
Vec3d hjp = head.junction_point();
|
||||||
auto oresult = solver.to_max().optimize(
|
auto oresult = solver.to_max().optimize(
|
||||||
[this, hjp, r_back](double plr, double azm) {
|
[this, hjp, r_back](const opt::Input<2> &input) {
|
||||||
|
auto &[plr, azm] = input;
|
||||||
Vec3d n = spheric_to_dir(plr, azm).normalized();
|
Vec3d n = spheric_to_dir(plr, azm).normalized();
|
||||||
return bridge_mesh_distance(hjp, n, r_back);
|
return bridge_mesh_distance(hjp, n, r_back);
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Reference in a new issue