53#ifndef DP_OPTIMIZATIONS_H
54#define DP_OPTIMIZATIONS_H
67namespace dp_optimization_detail {
70#if defined(_MSC_VER) && !defined(__clang__)
78 std::conditional_t<std::is_floating_point_v<T>,
85 if constexpr (std::numeric_limits<T>::has_infinity)
86 return std::numeric_limits<T>::infinity();
88 return std::numeric_limits<T>::max() / 4;
91template <
typename Target,
typename Source>
94 if (val >=
static_cast<Source>(std::numeric_limits<Target>::max()))
95 return std::numeric_limits<Target>::max();
96 if (val <=
static_cast<Source>(std::numeric_limits<Target>::min()))
97 return std::numeric_limits<Target>::min();
98 return static_cast<Target>(val);
104template <
typename Cost>
136template <
typename Cost,
class Transition_Cost_Fn>
141 const Cost inf = dp_optimization_detail::default_inf<Cost>())
146 for (
size_t i = 0; i <= n; ++i)
155 for (
size_t g = 0; g <=
groups; ++g)
158 for (
size_t i = 0; i <= n; ++i)
163 for (
size_t g = 1; g <=
groups; ++g)
165 for (
size_t i = 0; i <= n; ++i)
170 auto solve = [&](
auto &&self,
const size_t left,
const size_t right,
176 const size_t mid = std::midpoint(left, right);
189 if (
tc >= inf
or prev[
k] > inf -
tc)
210 solve(solve, g, n, g - 1, n - 1);
221template <
typename Cost>
251template <
typename Cost,
class Interval_Cost_Fn>
255 const Cost inf = dp_optimization_detail::default_inf<Cost>())
259 for (
size_t i = 0; i <= n; ++i)
262 for (
size_t j = 0; j <= n; ++j)
269 for (
size_t i = 0; i <= n; ++i)
272 for (
size_t j = 0; j <= n; ++j)
277 for (
size_t i = 0; i <= n; ++i)
283 dp(i)(i + 1) = Cost{};
284 opt(i)(i + 1) = i + 1;
288 for (
size_t len = 2; len <= n; ++len)
289 for (
size_t i = 0; i + len <= n; ++i)
291 const size_t j = i + len;
293 size_t left = opt[i][j - 1];
294 size_t right = opt[i + 1][j];
301 <<
"knuth_optimize_interval: invalid opt bounds at [" << i <<
", " << j <<
")";
308 for (
size_t k = left;
k <= right; ++
k)
310 const Cost d1 = dp[i][
k];
311 const Cost d2 = dp[
k][j];
313 if (d1 >= inf
or d2 >= inf
or w >= inf
or d1 > inf - d2
or (d1 + d2) > inf -
w)
344 const size_t n = weights.
size();
348 for (
size_t i = 0; i < n; ++i)
351 <<
"optimal_merge_knuth: prefix sum overflow";
358 }, std::numeric_limits<size_t>::max() / 4);
372 static_assert(std::is_signed_v<T>,
"Convex_Hull_Trick requires a signed type");
396 return static_cast<long double>(b.intercept - a.intercept) /
397 static_cast<long double>(a.slope - b.slope);
408 return lines_.size() == 0;
436 <<
"Convex_Hull_Trick::add_line: slopes must be non-increasing";
470 starts_.
append(-std::numeric_limits<long double>::infinity());
482 size_t hi =
lines_.size() - 1;
483 const auto xd =
static_cast<long double>(x);
486 if (
const size_t mid = std::midpoint(lo, hi + 1);
starts_[
mid] <= xd)
491 return lines_[lo].value_at(x);
498 <<
"Convex_Hull_Trick::query_monotone: no lines available";
517 static_assert(std::is_integral_v<T>
and std::is_signed_v<T>,
518 "Li_Chao_Tree requires a signed integral coordinate/value type");
539 size_t left = std::numeric_limits<size_t>::max();
540 size_t right = std::numeric_limits<size_t>::max();
543 static constexpr size_t NIL = std::numeric_limits<size_t>::max();
558 const T mid = std::midpoint(
l,
r);
561 std::swap(line,
nodes_[idx].line);
593 return static_cast<T>(
ret);
595 const T mid = std::midpoint(
l,
r);
601 return dp_optimization_detail::clamped_cast<T>(
ret);
608 <<
"Li_Chao_Tree: invalid domain [" <<
x_left_ <<
", " <<
x_right_ <<
"]";
642 <<
"Li_Chao_Tree::query: x=" << x <<
" outside domain [" <<
x_left_ <<
", " <<
x_right_ <<
"]";
650template <
typename Cost>
676template <
typename Cost>
680 const Cost inf = dp_optimization_detail::default_inf<Cost>())
682 const size_t n = base_cost.
size();
687 <<
"monotone_queue_min_dp: window must be > 0 when n > 1";
695 dp(0) = base_cost[0];
699 for (
size_t i = 1; i < n; ++i)
701 const size_t min_valid = i > window ? i - window : 0;
707 <<
"monotone_queue_min_dp: no valid predecessor for i=" << i;
710 const Cost
bc = base_cost[i];
751 static_assert(std::is_integral_v<T>
and std::is_signed_v<T>,
752 "min_weighted_squared_distance_1d requires signed integral T");
755 <<
"min_weighted_squared_distance_1d: xs and weights size mismatch";
757 const size_t n =
xs.
size();
763 for (
size_t i = 1; i < n; ++i)
773 for (
size_t j = 0; j < n; ++j)
777 const T b =
static_cast<T>(
px *
px +
static_cast<PromotedT>(weights[j]));
782 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)
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
std::conditional_t< std::is_floating_point_v< T >, T, std::conditional_t<(sizeof(T)< 8), long long, _promoted_int_t > > promoted_t
__int128_t _promoted_int_t
constexpr T default_inf() noexcept
constexpr Target clamped_cast(Source val) noexcept
Main namespace for Aleph-w library functions.
DynList< T > intercept(const Container< T > &c1, const Container< T > &c2)
Return intersection of two containers as a DynList.
Array< T > min_weighted_squared_distance_1d(const Array< T > &xs, const Array< T > &weights)
Weighted squared-distance lower envelope on a line.
and
Check uniqueness with explicit hash + equality functors.
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.