Skip to main content

scaled_work

Function scaled_work 

Source
fn scaled_work(factor: u128, work: u128) -> u128
Examples found in repository?
crates/competitive/src/math/min_plus_convolution/selector.rs (lines 182-185)
161fn select_algorithm<T>(
162    a_len: usize,
163    b_len: usize,
164    a_characteristics: &InputCharacteristics<T>,
165    b_characteristics: &InputCharacteristics<T>,
166) -> Algorithm
167where
168    T: Signed + TryFrom<usize>,
169    T::Unsigned: TryInto<usize>,
170{
171    let output = a_len.saturating_add(b_len).saturating_sub(1) as u128;
172    let mut selected = ((a_len as u128) * (b_len as u128), Algorithm::Naive);
173    let mut consider = |work: u128, algorithm| {
174        if work < selected.0 {
175            selected = (work, algorithm);
176        }
177    };
178
179    consider(
180        // min_plus/sparse: 50% finite inputs are already over 10% faster than
181        // the INF-skipping naive scan, while dense pair enumeration loses.
182        scaled_work(
183            3,
184            (a_characteristics.finite_count as u128) * (b_characteristics.finite_count as u128),
185        ),
186        Algorithm::Sparse,
187    );
188    if let (Some(a_extrema), Some(b_extrema)) =
189        (a_characteristics.extrema, b_characteristics.extrema)
190        && let Some(requirements) =
191            bounded_requirements_from_extrema(a_len, b_len, a_extrema, b_extrema)
192    {
193        // min_plus/bounded: small transforms need a wider margin for encoding
194        // overhead; at 2^20 and above the NTT wins from a lower work ratio.
195        consider(
196            scaled_work(
197                if requirements.transform_len < 1 << 20 {
198                    8
199                } else {
200                    6
201                },
202                (requirements.transform_len as u128) * (requirements.transform_len.ilog2() as u128),
203            ),
204            Algorithm::BoundedNtt,
205        );
206    }
207
208    if a_characteristics.is_convex && b_characteristics.is_convex {
209        consider(output, Algorithm::ConvexMerge);
210    } else if a_characteristics.is_convex {
211        consider(
212            scaled_work(2, output),
213            Algorithm::ConvexDivideAndConquerLeft,
214        );
215    } else if b_characteristics.is_convex {
216        consider(
217            scaled_work(2, output),
218            Algorithm::ConvexDivideAndConquerRight,
219        );
220    }
221    if a_characteristics.is_concave && b_characteristics.is_concave {
222        consider(output, Algorithm::ConcaveBoth);
223    } else if a_characteristics.is_concave || b_characteristics.is_concave {
224        consider(
225            scaled_work(8, output.saturating_mul(output.max(1).ilog2() as u128 + 1)),
226            if a_characteristics.is_concave {
227                Algorithm::ConcaveEnvelopeLeft
228            } else {
229                Algorithm::ConcaveEnvelopeRight
230            },
231        );
232    }
233    let increasing = a_characteristics.is_nondecreasing && b_characteristics.is_nondecreasing;
234    let decreasing = a_characteristics.is_nonincreasing && b_characteristics.is_nonincreasing;
235    if increasing || decreasing {
236        consider(
237            scaled_work(
238                4,
239                a_characteristics
240                    .run_count
241                    .saturating_mul(b_characteristics.run_count) as u128,
242            ) + output,
243            if decreasing {
244                Algorithm::MonotoneRunsDecreasing
245            } else {
246                Algorithm::MonotoneRunsIncreasing
247            },
248        );
249    }
250    let piecewise = match (
251        a_characteristics.finite_count == a_len,
252        b_characteristics.finite_count == b_len,
253    ) {
254        (true, true) if a_characteristics.piece_count < b_characteristics.piece_count => {
255            Some((a_characteristics.piece_count, true))
256        }
257        (true, true) => Some((b_characteristics.piece_count, false)),
258        (true, false) => Some((a_characteristics.piece_count, true)),
259        (false, true) => Some((b_characteristics.piece_count, false)),
260        (false, false) => None,
261    };
262    if let Some((pieces, structured_is_left)) = piecewise {
263        if pieces == 1 {
264            consider(
265                output,
266                if structured_is_left {
267                    Algorithm::LinearLeft
268                } else {
269                    Algorithm::LinearRight
270                },
271            );
272        } else {
273            consider(
274                scaled_work(4, (pieces as u128).saturating_mul(output)),
275                if structured_is_left {
276                    Algorithm::PiecewiseLinearLeft
277                } else {
278                    Algorithm::PiecewiseLinearRight
279                },
280            );
281        }
282    }
283    selected.1
284}