// @generated by scripts/extraction/learned/export_rust.py -- do not edit.
//
// Copyright (c) 2026 Innovation Trigger B.V.
//
// PDFluent is available under two licences, at your option: the GNU AGPLv3, or
// the PDFluent Commercial Licence. See the LICENSE file in this repository --
// that file travels with the copy you received, which a URL does not.
//! The `heading_lines` model: 217 trees, 6510 splits, depth at most 8, in 2 part(s).
//!
//! Model sha256 (of model.json): 2bb011e4634d2949f421e16ebf08b21c88a294ed1580c4fec6c7d5741c8ae997
mod part_00;
mod part_01;
/// The sha256 of the LightGBM dump this code was generated from.
pub const MODEL_SHA256: &str = "2bb011e4634d2949f421e16ebf08b21c88a294ed1580c4fec6c7d5741c8ae997";
/// The input, in order: `x[i]` is `FEATURES[i]`, NaN when missing.
pub const FEATURES: [&str; 105] = ["marker_bullet", "marker_ordered", "marker_figure", "first_token_chars", "first_gap_em", "indent_em", "indent_vs_prev_em", "prev_short_em", "prev_ends_terminal", "prev_runs_on", "width_frac", "size_ratio", "bold", "line_index", "lines_in_block", "gap_above_em", "block_is_list", "block_size_ratio", "first_is_lone_symbol", "same_head_on_page", "block_is_table_cell", "max_gap_em", "prev_block_ends_colon", "of_block_size_ratio", "of_block_bold", "of_block_italic", "of_block_all_caps", "of_block_n_chars", "of_block_n_words", "of_block_n_lines", "of_block_x_frac", "of_block_width_frac", "of_block_y_frac", "of_block_gap_above_em", "of_block_gap_below_em", "of_block_ends_terminal", "of_block_ends_colon", "of_block_section_number", "of_block_has_marker", "of_block_has_caption", "of_block_first_on_page", "of_block_last_on_page", "of_block_prev_ends_terminal", "of_block_prev_size_ratio", "of_block_next_x_frac", "of_block_next_size_ratio", "of_block_repeats_in_document", "of_block_font_is_the_body_face", "of_block_title_case", "of_block_number_kind", "of_block_number_depth", "of_block_width_vs_column", "of_block_ends_comma", "up2_marker_bullet", "up2_marker_ordered", "up2_first_token_chars", "up2_indent_em", "up2_prev_ends_terminal", "up2_width_frac", "up2_size_ratio", "up2_bold", "up2_gap_above_em", "up2_block_is_list", "up2_block_is_table_cell", "up2_max_gap_em", "up2_same_block", "up1_marker_bullet", "up1_marker_ordered", "up1_first_token_chars", "up1_indent_em", "up1_prev_ends_terminal", "up1_width_frac", "up1_size_ratio", "up1_bold", "up1_gap_above_em", "up1_block_is_list", "up1_block_is_table_cell", "up1_max_gap_em", "up1_same_block", "down1_marker_bullet", "down1_marker_ordered", "down1_first_token_chars", "down1_indent_em", "down1_prev_ends_terminal", "down1_width_frac", "down1_size_ratio", "down1_bold", "down1_gap_above_em", "down1_block_is_list", "down1_block_is_table_cell", "down1_max_gap_em", "down1_same_block", "down2_marker_bullet", "down2_marker_ordered", "down2_first_token_chars", "down2_indent_em", "down2_prev_ends_terminal", "down2_width_frac", "down2_size_ratio", "down2_bold", "down2_gap_above_em", "down2_block_is_list", "down2_block_is_table_cell", "down2_max_gap_em", "down2_same_block"];
/// The probability at or above which the decision is taken, chosen on the
/// validation documents and recorded in the model's manifest.
pub const THRESHOLD: f64 = 0.45_f64;
/// LightGBM's numerical decision, missing values included.
#[inline(always)]
fn go_left(value: f64, threshold: f64, default_left: bool, missing: u8) -> bool {
// 0: None, 1: Zero, 2: NaN -- LightGBM's MissingType.
let value = if missing != 2 && value.is_nan() { 0.0 } else { value };
if (missing == 1 && value.abs() <= 1e-35) || (missing == 2 && value.is_nan()) {
return default_left;
}
value <= threshold
}
/// The raw margin: the sum of the trees, before the sigmoid.
pub fn predict_margin(x: &[f64; 105]) -> f64 {
let acc = 0.0;
let acc = part_00::add(x, acc);
part_01::add(x, acc)
}