fn scaled_work(factor: u128, work: u128) -> u128Examples 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}