Formula Number Processing#
Formula number processing converts standalone equation-label blocks (e.g., (1), (2)) detected by the layout model into LaTeX \tag{} suffixes appended to the corresponding display-formula content. The entire mechanism lives in mineru/backend/utils/formula_number.py.
Block Type#
PP-DocLayoutV2 introduces BlockType.FORMULA_NUMBER ("formula_number") as a dedicated layout class for equation labels . These blocks are produced alongside INTERLINE_EQUATION (pipeline) or EQUATION (hybrid/VLM) blocks during detection.
Core Functions#
All logic is in formula_number.py. Key entry points:
| Function | Purpose |
|---|---|
extract_formula_number_text | Pulls the label text from a formula_number block; prefers a top-level "content" string, falls back to iterating lines → spans. |
normalize_formula_tag_content | Strips surrounding parentheses and converts full-width characters to half-width. |
build_tagged_formula_content | Assembles the final string: cleans the formula body (via isolated_formula_clean) then appends \tag{<label>}. Returns None if the formula body is empty. |
append_formula_number_tag | Pipeline-specific writer: finds the INTERLINE_EQUATION span inside a block and mutates its "content" field. |
_append_hybrid_formula_number_tag | Hybrid-specific writer: writes directly to equation_block["content"] (VLM blocks have a flat content field, no span nesting). |
Matching Algorithm#
_optimize_formula_number_sequence implements the shared matching logic used by both backends. It scans blocks in order and, for each FORMULA_NUMBER block, applies two adjacency rules :
- Previous block is an equation → append the tag to the previous block.
- Next block is an equation, and the block after that is not another formula number → append the tag to the next block.
If neither rule matches, the formula_number block is downgraded to BlockType.TEXT by _downgrade_formula_number_to_text so it is not silently lost.
Backend Integration#
Pipeline Backend#
optimize_formula_number_blocks iterates pdf_info_list, processing each page's "preproc_blocks" list. It is the first step in finalize_middle_json_from_preproc() in model_json_to_middle_json.py, running before para_split, table merging, and title leveling .
Hybrid Backend#
optimize_hybrid_formula_number_blocks operates on the raw model_list (a list-of-lists per page) produced after VLM extraction with layout. It is called in both doc_analyze() (sync) and aio_doc_analyze() (async) in hybrid_analyze.py immediately after batch_extract_with_layout returns results.
The key structural difference: pipeline blocks contain a lines → spans tree, while hybrid VLM blocks hold a flat "content" string — hence the two separate tag-writer callbacks.
Output Format#
A successfully tagged equation's content field becomes:
<latex_body>\tag{<number>}
For example, the raw label (3.14) would be normalized to 3.14 and the equation content extended to E = mc^2\tag{3.14}. An unmatched formula_number block is reclassified as text and flows through normal paragraph processing.