54# ifndef DP_OPTIMIZATIONS_H
55# define DP_OPTIMIZATIONS_H
61# include <type_traits>
69 namespace dp_optimization_detail
72 using promoted_t = std::conditional_t<std::is_floating_point_v<T>,
T,
78 if constexpr (std::numeric_limits<T>::has_infinity)
79 return std::numeric_limits<T>::infinity();
81 return std::numeric_limits<T>::max() / 4;
84 template <
typename Target,
typename Source>
87 if (val >=
static_cast<Source>(std::numeric_limits<Target>::max()))
88 return std::numeric_limits<Target>::max();
89 if (val <=
static_cast<Source>(std::numeric_limits<Target>::min()))
90 return std::numeric_limits<Target>::min();
91 return static_cast<Target>(val);
98 template <
typename Cost>
131 template <
typename Cost,
class Transition_Cost_Fn>
137 dp_optimization_detail::default_inf<Cost>())
142 for (
size_t i = 0; i <= n; ++i)
151 for (
size_t g = 0; g <=
groups; ++g)
154 for (
size_t i = 0; i <= n; ++i)
156 split.append(std::move(row));
159 for (
size_t g = 1; g <=
groups; ++g)
161 for (
size_t i = 0; i <= n; ++i)
166 auto solve = [&](
auto && self,
167 const size_t left,
const size_t right,
173 const size_t mid = std::midpoint(left, right);
186 if (
tc >= inf
or prev[
k] > inf -
tc)
207 solve(solve, g, n, g - 1, n - 1);
223 template <
typename Cost>
254 template <
typename Cost,
class Interval_Cost_Fn>
259 dp_optimization_detail::default_inf<Cost>())
263 for (
size_t i = 0; i <= n; ++i)
266 for (
size_t j = 0; j <= n; ++j)
268 dp.
append(std::move(row));
273 for (
size_t i = 0; i <= n; ++i)
276 for (
size_t j = 0; j <= n; ++j)
278 opt.
append(std::move(row));
281 for (
size_t i = 0; i <= n; ++i)
287 dp(i)(i + 1) =
Cost{};
288 opt(i)(i + 1) = i + 1;
292 for (
size_t len = 2; len <= n; ++len)
293 for (
size_t i = 0; i + len <= n; ++i)
295 const size_t j = i + len;
297 size_t left = opt[i][j - 1];
298 size_t right = opt[i + 1][j];
305 <<
"knuth_optimize_interval: invalid opt bounds at ["
306 << i <<
", " << j <<
")";
313 for (
size_t k = left;
k <= right; ++
k)
315 const Cost d1 = dp[i][
k];
316 const Cost d2 = dp[
k][j];
318 if (d1 >= inf
or d2 >= inf
or w >= inf
or d1 > inf - d2
or (d1 + d2) > inf -
w)
335 n == 0 ?
Cost{} : dp[0][n],
355 const size_t n =
weights.size();
359 for (
size_t i = 0; i < n; ++i)
362 std::numeric_limits<size_t>::max() -
weights[i])
363 <<
"optimal_merge_knuth: prefix sum overflow";
369 [&](
const size_t i,
const size_t j) ->
size_t
373 std::numeric_limits<size_t>::max() / 4
386 template <
typename T>
389 static_assert(std::is_signed_v<T>,
"Convex_Hull_Trick requires a signed type");
412 const Line & b)
noexcept
414 return static_cast<long double>(b.intercept - a.intercept)
415 /
static_cast<long double>(a.slope - b.slope);
447 <<
"Convex_Hull_Trick::add_line: slopes must be non-increasing";
481 starts_.
append(-std::numeric_limits<long double>::infinity());
491 <<
"Convex_Hull_Trick::query: no lines available";
494 size_t hi =
lines_.size() - 1;
495 const auto xd =
static_cast<long double>(x);
498 if (
const size_t mid = std::midpoint(lo, hi + 1);
starts_[
mid] <= xd)
503 return lines_[lo].value_at(x);
510 <<
"Convex_Hull_Trick::query_monotone: no lines available";
528 template <
typename T>
531 static_assert(std::is_integral_v<T>
and std::is_signed_v<T>,
532 "Li_Chao_Tree requires a signed integral coordinate/value type");
553 size_t left = std::numeric_limits<size_t>::max();
554 size_t right = std::numeric_limits<size_t>::max();
557 static constexpr size_t NIL = std::numeric_limits<size_t>::max();
572 const T mid = std::midpoint(
l,
r);
575 std::swap(line,
nodes_[idx].line);
603 const T l,
const T r,
609 return static_cast<T>(
ret);
611 const T mid = std::midpoint(
l,
r);
617 return dp_optimization_detail::clamped_cast<T>(
ret);
625 <<
"Li_Chao_Tree: invalid domain [" <<
x_left_ <<
", " <<
x_right_ <<
"]";
652 <<
"Li_Chao_Tree::query: no lines available";
654 <<
"Li_Chao_Tree::query: x=" << x
664 template <
typename Cost>
691 template <
typename Cost>
696 dp_optimization_detail::default_inf<Cost>())
698 const size_t n = base_cost.
size();
703 <<
"monotone_queue_min_dp: window must be > 0 when n > 1";
711 dp(0) = base_cost[0];
715 for (
size_t i = 1; i < n; ++i)
717 const size_t min_valid = i > window ? i - window : 0;
723 <<
"monotone_queue_min_dp: no valid predecessor for i=" << i;
726 const Cost bc = base_cost[i];
764 template <
typename T>
769 static_assert(std::is_integral_v<T>
and std::is_signed_v<T>,
770 "min_weighted_squared_distance_1d requires signed integral T");
773 <<
"min_weighted_squared_distance_1d: xs and weights size mismatch";
775 const size_t n =
xs.
size();
781 for (
size_t i = 1; i < n; ++i)
791 for (
size_t j = 0; j < n; ++j)
800 for (
size_t i = 0; i < n; ++i)
Exception handling system with formatted messages for Aleph-w.
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
#define ah_runtime_error_if(C)
Throws std::runtime_error if condition holds.
Simple dynamic array with automatic resizing and functional operations.
static Array create(size_t n)
Create an array with n logical elements.
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
void swap(Array &s) noexcept
Swap this with s
T & append(const T &data)
Append a copy of data
void reserve(size_t cap)
Reserves cap cells into the array.
Convex Hull Trick for minimum queries.
static long double intersection_x(const Line &a, const Line &b) noexcept
bool is_empty() const noexcept
T query_monotone(const T x)
Query minimum with non-decreasing x (amortized O(1)).
void reset_query_cursor() noexcept
T query(const T x) const
Query minimum value at arbitrary x (O(log n)).
size_t size() const noexcept
void add_line(const T slope, const T intercept)
Insert a new line; slopes must be non-increasing.
Array< long double > starts_
Li Chao tree for min line queries on an integral x-domain.
void add_line(const T slope, const T intercept)
static constexpr size_t NIL
T query_impl(const size_t idx, const T l, const T r, const T x) const
bool is_empty() const noexcept
void add_line_impl(const size_t idx, const T l, const T r, Line line)
size_t node_count() const noexcept
size_t new_node(const Line &line)
Li_Chao_Tree(const T x_left, const T x_right)
std::conditional_t< std::is_floating_point_v< T >, T, std::conditional_t<(sizeof(T)< 8), long long, __int128_t > > promoted_t
constexpr T default_inf() noexcept
constexpr Target clamped_cast(Source val) noexcept
Main namespace for Aleph-w library functions.
and
Check uniqueness with explicit hash + equality functors.
DynList< T > intercept(const Container< T > &c1, const Container< T > &c2)
Array< T > min_weighted_squared_distance_1d(const Array< T > &xs, const Array< T > &weights)
Weighted squared-distance lower envelope on a line.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
std::decay_t< typename HeadC::Item_Type > T
Knuth_Optimization_Result< size_t > optimal_merge_knuth(const Array< size_t > &weights)
Optimal adjacent merge cost via Knuth optimization.
static void prefix(Node *root, DynList< Node * > &acc)
Monotone_Queue_DP_Result< Cost > monotone_queue_min_dp(const Array< Cost > &base_cost, const size_t window, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize windowed min-transition DP with a monotone queue.
std::vector< std::string > & split(const std::string &s, const char delim, std::vector< std::string > &elems)
Split a std::string by a single delimiter character.
Knuth_Optimization_Result< Cost > knuth_optimize_interval(const size_t n, Interval_Cost_Fn interval_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize interval DP with Knuth optimization.
T value_at(const T x) const noexcept
Result of divide-and-conquer partition DP optimization.
Array< Cost > last_row
Last DP layer (size n+1).
Array< Array< size_t > > split
Best split index per layer/state.
Cost optimal_cost
Final optimum at state (groups, n).
Result of Knuth interval-DP optimization.
Array< Array< Cost > > dp
Interval DP table.
Cost optimal_cost
Final optimum at interval [0, n).
Array< Array< size_t > > opt
Argmin table used by Knuth bounds.
T value_at(const T x) const noexcept
Result of monotone-queue windowed DP transition.
Array< Cost > dp
DP values.
Array< size_t > parent
Chosen predecessor index for each i.
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
Dynamic array container with automatic resizing.