From d70208d98aa53ff5ead9a5f28bbbfe1e6c5bcad9 Mon Sep 17 00:00:00 2001 From: Jake Poznanski Date: Wed, 27 Aug 2025 18:22:05 +0000 Subject: [PATCH] Moving test code around, adding format reward since some runs stop outputting the front matter thing in grpo training --- olmocr/bench/synth/test_mine.py | 1025 ----------------------------- olmocr/train/grpo_train.py | 68 +- tests/test_mine_html_templates.py | 1021 ++++++++++++++++++++++++++++ 3 files changed, 1088 insertions(+), 1026 deletions(-) delete mode 100644 olmocr/bench/synth/test_mine.py diff --git a/olmocr/bench/synth/test_mine.py b/olmocr/bench/synth/test_mine.py deleted file mode 100644 index 925a095..0000000 --- a/olmocr/bench/synth/test_mine.py +++ /dev/null @@ -1,1025 +0,0 @@ -import unittest - -from .mine_html_templates import generate_tests_from_html - - -class TestMineTests(unittest.TestCase): - def test_absent_nested(self): - html_content = """ - - - - - - New Paradigm for Nuclear Safety - - -
- -
- -
-

New Paradigm for Nuclear Safety

- -
-

Thursday, April 25, 2013

-

Japan Nuclear Safety Institute

-

Shojiro Matsuura, Chairman

-
-
- - - -""" - tests = generate_tests_from_html(html_content, "0", 1) - - self.assertEqual(len([test for test in tests if test["type"] == "absent"]), 2) - - def test_text_basic(self): - html_content = """ - - - - - - - Bone Morphology Description - - -
-

The posterior end exhibits a curved process to articulate with the angular. Aside from the process, the rest of the posterior end has slight curvatures for articulation, but is mostly uniform. Ventral border of the bone is mostly straight, with slight curvature (FIG. 20).

- -

Lateral- A spine runs from the anterior-most tip, reduces in height ~3/4 way down toward posterior, and terminates at the center of the posterior notch. A fossa is present on the dorsal side of the spine. The posterior end exhibits more relief than in medial view, with the medial side of the posterior process extending past the posterior notch.

- -

Ontogeny- Anterior tip is sharply pointed in AR12 and AR1 with AR2 being rounded, though this could be due to breakage. Anterior dorsal margin is straight and flat in AR12; AR2 shows little curvature and AR1 shows the most curvature; curving outward dorsally. Dorsal incisure is anteroposteriorly oriented in AR12, in AR2 there is some ventral curvature, and in AR1 there is a posteroventral curvature. Both AR1 and AR3 are curved on the ventral margin while AR12 is mostly straight. Posterior end of AR1 exhibits four undulations, ventral process is not yet extended. A fossa is present dorsal to the ventral process, not seen on AR12 or AR2. In medial view the lateral ridge is visible posteriorly in AR1 and AR2l the ridge does not fully extend anteriorly. In lateral view of the posterior the ventral process is present on AR2, but not fully extended posteriorly. Tip of the anterodorsal process is sharply pointed in AR1 and AR2, rounded in AR12. A short ridge is present on the dorsal edge of the dorsal process of AR1. The short ridge on the posterodorsal process of AR2 is slightly more ventral than in AR1. On AR12 the ridge is long and positioned most ventral. The lateral ridge is closest to the ventral margin in AR1. In AR2 the ridge is positioned more dorsally and in AR12 the ridge terminates and the anterior tip. The section of bone ventral to the lateral ridge appears to thin with age. The posterior notch on AR12 is curved anteriorly and the medial side of the notch extends posteriorly

-
- - - -""" - - tests = generate_tests_from_html(html_content, "0", 1) - self.assertGreater(len(tests), 5) - - def test_big_headers(self): - html_content = """ - - - - - - - FORANE 427A Comparative Data - - - -
-

Comparative data

-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ParametersR-22FORANE® 427A
Evaporating temperature2.7 °C1.1 °C
Condensing temperature40.3 °C44.0 °C
Suction temperature7.1 °C9.2 °C
Suction pressure5.4 bar5.0 bar
Discharge temperature69.5 °C71.1 °C
Discharge pressure15.5 bar17.1 bar
Cooling power431 KW376 KW
Power consumption122 kW124 kW
Residual mineral oil-11%
- -

During this field test, very satisfactory running conditions were reached immediately. The temperature set points were easily achieved with similar energy consumption as compared to R-22 despite a high level of residual mineral oil in the circuit. The performance of the installation continues to satisfy the customer's requirements after more than one year of service.

- -

FORANE® 427A consequently fully satisfies the requirements of the European regulations while enabling existing equipment to continue to perform well without the need for any long and costly plant modifications.

- -

The versatility of FORANE® 427A is also appreciated as it can be used to retrofit low temperature refrigeration equipment as well as air-conditioning installations, resulting in only one retrofit refrigerant for all R-22 units.

- -

Combining environmental friendliness, high performance and simplicity is today a reality with FORANE® 427A !

-
- - - -""" - - tests = generate_tests_from_html(html_content, "0", 1) - - self.assertFalse(any(test for test in tests if test["type"] == "absent" and "Comparative data" in test["text"])) - - def test_page_num(self): - html_content = """ - - - - - - Academic Paper - Page 47 - - -
-
- -

Figure 4.3: The COVID-19 pandemic resulted in meaningful increase in the support for other groups' protests among Panamanians.

- -
-

4.2.2 Demographically-Informed Opinion Assignment

- -

Our model does not endow opinions randomly; instead, we leverage data to assign activists in a more realistic fashion. We use Latinobarómetro survey data from 2020 and 2023, both of which contain the three measurements of support for protest. Then, we explored which demographic groups were more likely to be activists; these are young adults and individuals at either extreme of the financial spectrum. We use this insight to influence the assignment of opinions: our logistic equations make it so that individuals with these characteristics are more likely to be labeled as activists as the probabilistic endowment happens. The code ensures that the proportion of activists overall remains exactly as desired and that there are activists who do not belong to these identified groups

-
- -
-

4.2.3 Identity Factored into Social Influence

- -

The similarity formula for Panama is built as follows, taking in nine demographic factors stored as node attributes. These are gender, age, nationality, financial status, highest level of education, level of employment, geographical region, party affiliation, and ethnicity (respectively encoded as gend, age, nation, fin, edu, emp, region, paff, and ethni). Each one of these factors has an associated weight; in this model, all factors were weighted as 0.10, except for level of education and financial status which received 0.15. Our code establishes logical rules to compare the two individuals on each dimension and return a factor by which to multiply the weight. These factors can be absolute or relative, based on the demographic dimension in question. For example, the logical conditions for gender returns 1 if same or 0 if different, while age returns a float value between 0 and 1 according to how close in age the individuals are. Once the pairwise similarity

-
-
- - - -""" - - tests = generate_tests_from_html(html_content, "0", 1) - - self.assertEqual(len([test for test in tests if test["type"] == "absent"]), 1) - - def test_div_footer(self): - html_content = """ - - - - - - - Being Thai: A Narrow Identity in a Wide World - - - -
-
- -
-
- - - -

hard to create a political and cultural narrative that appeals to old ideas about being Thai at this moment of perceived vulnerability.

- -

The Concept of "Thainess"

- -

Thainess is a political notion that originally evolved to support an authoritarian government and was then re-shaped for periods of more democratic rule.13 Thailand has long oscillated between dictatorship and democracy and, in either case, a sense of the "Thai style" (baeb Thai) is commonly invoked. Under these conditions a military coup may be thought to "advance Thai-style democracy".14 This is obviously fraught with difficulties and requires government agencies, most notably the Ministry of Culture, to work hard on shaping national identity.15 Thailand's geographical and cultural diversity means that there are inevitable deviations. Some of these have been astutely handled, especially in the northeastern provinces where the Lao-speaking minority has been integrated as chao isan. Nowadays it is only at the margins that their "Isan-ness" remains a contested sub-category of Thainess.16 In earlier generations there were more explicit challenges to the suggestion of Isan as Thai.17 Similar defiance has emerged in both the northern provinces18 and in the Malay Muslim majority areas of the far south.19 At various times there have been suggestions, as reported by the anthropologist Nick Tapp, that "Thainess" was disintegrating.20 It is in response to these persistent challenges that Prayuth's military government has sought to create its own revised version of the national ideal.

- -

For the military government the codification of Thailand's core values has created new opportunities to stamp its preferred identity on society. In a key speech soon after he took power in 2014, Prayuth identified disunity as a problem in Thai society that would, in his words, "urgently require inclusive cooperation from people of all levels, gender and age".21 His approach was to "define clear core values of Thai people so that we can build a strong nation". These values draw on cultural ideas that have existed for many decades and have enjoyed the favour of previous military rulers. The full list of these twelve values is:

- -
    -
  1. Upholding the three main pillars of the country: the nation, the religion and the monarchy;
  2. -
  3. Showing honesty, sacrifice and patience, with a positive attitude for the interest of the public;
  4. -
  5. Practicing filial piety towards parents, guardians and teachers;
  6. -
  7. Seeking both direct and indirect knowledge and education;
  8. -
- -
-
- - - -""" - - tests = generate_tests_from_html(html_content, "0", 1) - - self.assertEqual(len([test for test in tests if test["type"] == "absent"]), 4) - - def test_table(self): - html_content = """ - - - - - - Distribuição da população na estrutura socioocupacional - Brasil 2000 - - - -
-
-
Alexandre Gori Maia e Waldir José de Quadros ■ 417
-
- -

Apêndice A - Distribuição da população na estrutura socioocupacional - Brasil 2000

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Grupo OcupacionalClasse OcupacionalSuperiorMédioBaixoInteriorÍnfimoTotal
N (1.000s)%N (1.000s)%N (1.000s)%N (1.000s)%N (1.000s)%N (1.000s)%
EmpregadoresA-1 Empregadores (> 10)60867,318520,4869,6161,880,9903100
A-2 Empregadores (<= 10)1.55536,91.10726,31.03624,73418,11714,14.213100
Total2.16242,31.29225,31.12622,03577,01793,55.116100
ProfissionaisC Profissionais Autônomos1.64321,71.51320,02.07327,41.22516,21.10814,77.562100
D Profissionais Assalariados4.43813,36.03018,011.55034,57.02721,04.38913,133.434100
Total6.08114,87.54318,413.62333,28.25220,15.49713,440.995100
Massa Não-AgrícolaF Trabalhadores Autônomos6573,51.7549,25.56129,25.27127,75.78830,419.030100
G Trabalhadores Assalariados2820,71.6574,310.36327,113.00234,012.96833,938.272100
I Trabalhadores Domésticos100,11041,697714,71.81027,33.73356,36.633100
Total9481,53.5155,516.90126,420.08331,422.48935,263.936100
Massa AgrícolaH-1 Proprietários Conta Própria1882,03643,81.38714,41.88919,75.77960,29.608100
H-2 Trabalhadores Autônomos50,5141,5727,615216,170374,3946100
H-3 Trabalhadores Assalariados170,2580,67948,42.26023,96.32266,99.451100
Total2101,04362,22.25311,34.30121,512.80564,020.005100
Não-remuneradosNão-remunerados Não-Agrícolas136,8168,12814,02210,911960,2198100
Não-remunerados Agrícolas50,1130,3591,63529,43.30288,53.731100
Sem Ocupação Com Renda1.5676,02.3308,95.39520,76.82126,29.96438,226.078100
Sem Ocupação Sem Renda8.0941008.094100
Ignorados17710,320211,836421,133719,664037,21.720100
- -

Fonte: Censo Demográfico 2000, microdados. IBGE. Elaboração dos autores.

- - - -""" - - tests = generate_tests_from_html(html_content, "0", 1) - - self.assertTrue(len(tests) > 10) - - def test_sup(self): - html_content = """ - - - - - - A ROSE BY ANY OTHER NAME - - - -
-
2016]
-
A ROSE BY ANY OTHER NAME
-
1083
-
- -
-

cases were decided within a year of each other (2000 and 2001, respectively). Save the Manatee Club largely consists of a truncated version of the Consolidated-Tomoka analysis, with minor adjustments to conform the opinion to the 1999 amendments. Day Cruise, on the other hand, closely analyzes the 1999 version of section 120.52(8). However, it is Save the Manatee Club that has come to dominate Florida court opinions on rulemaking challenges and not the more detailed Day Cruise analysis.78 The following Sections will discuss the facts of the two cases, examine the differences between their analyses of section 120.52(8), and finally conclude with an opinion on which analysis is better to apply in section 120.52(8) rulemaking challenges.

- -

A. Southwest Florida Water Management District v. Save the Manatee Club, Inc.

- -

After the legislature amended the APA, the First DCA analyzed the statutory language of section 120.52(8) again in Southwest Florida Water Management District v. Save the Manatee Club, Inc.79 Save the Manatee Club concerned the Southwest Florida Water Management District's (the "District's") authority to create exemptions to environmental resource permitting requirements.80 South Shores Partners, Ltd. ("South Shores") applied "for a permit to develop a 720-acre tract of land in Southwest Hillsborough County."81 As part of the development project, South Shores wanted "to build a connecting waterway between the [existing] canal system [on the property] and the [Tampa] Bay."82 The Save the Manatee Club believed that the resulting increase in power boat traffic in this new waterway would "endanger the manatee and its habitat."83

- -

The District has the authority to grant either a general permit or an environmental resource permit to a development project, depending on the type of project involved.84 When granting an environmental resource permit, the District must consider "[t]he impact a proposed development will have on wildlife" as a factor; it does not have to do so when it grants a general permit.85 The District granted South

-
- - - -""" - - tests = generate_tests_from_html(html_content, "0", 1) - - superscript_map = { - "0": "⁰", - "1": "¹", - "2": "²", - "3": "³", - "4": "⁴", - "5": "⁵", - "6": "⁶", - "7": "⁷", - "8": "⁸", - "9": "⁹", - "+": "⁺", - "-": "⁻", - "=": "⁼", - "(": "⁽", - ")": "⁾", - "n": "ⁿ", - "i": "ⁱ", - } - - for test in tests: - for sup in superscript_map.values(): - self.assertTrue(sup not in test.get("text", "")) - self.assertTrue(sup not in test.get("before", "")) - self.assertTrue(sup not in test.get("after", "")) - - def test_katex_autorender(self): - """Test that KaTeX math expressions are properly auto-rendered when using the render_pdf_with_playwright function.""" - import asyncio - import os - import tempfile - - from ..synth.mine_html_templates import render_pdf_with_playwright - - # Create HTML with LaTeX expressions - html_content = """ - - - - - KaTeX Auto-Render Test - - -

Math Expressions Test

- -

Inline math expression: \(E = mc^2\)

- -

Block math expression:

-

\[ - \\frac{d}{dx}(x^n) = nx^{n-1} - \]

- -

Another complex equation:

-

\[ - \int_{a}^{b} f(x) \, dx = F(b) - F(a) - \]

- - - """ - - # Create a temporary file to store the rendered PDF - with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp_file: - output_pdf_path = tmp_file.name - - # Render the HTML to PDF - render_success = asyncio.run(render_pdf_with_playwright(html_content=html_content, output_pdf_path=output_pdf_path, png_width=800, png_height=600)) - - # Check if rendering was successful - self.assertTrue(render_success, "PDF rendering should succeed") - - # Verify PDF was created and has content - self.assertTrue(os.path.exists(output_pdf_path), "PDF file should exist") - self.assertTrue(os.path.getsize(output_pdf_path) > 0, "PDF file should have content") - - # The actual validation of KaTeX rendering would require visual inspection or text extraction, - # but at minimum we can verify the file was created successfully - - print(output_pdf_path) - - def test_line_numbers(self): - html_content = """ - - - - - - House Amendment Bill No. CS/CS/SB 7030 - - -
-
HOUSE AMENDMENT
-
Bill No. CS/CS/SB 7030, 1st Eng. (2019)
-
- -
Amendment No.
- -
-
-
Senate
-
House
-
-
.
-
- -
- -
- -
-
- 1 -
Representative Jenne offered the following:
-
-
- 2 -
-
-
- 3 -
Amendment
-
-
- 4 -
Remove lines 274-280 and insert:
-
-
- 5 -
c.3. Pass an initial a psychological evaluation, and
-
-
- 6 -
subsequent yearly psychological evaluations before each school
-
-
- 7 -
year, administered by a psychologist licensed under chapter 490
-
-
- 8 -
and designated by the Department of Law Enforcement and submit
-
-
- 9 -
the results of such evaluations the evaluation to the sheriff's
-
-
- 10 -
office. The Department of Law Enforcement is authorized to
-
-
- 11 -
provide the sheriff's office with mental health and substance
-
-
- 12 -
abuse data for compliance with this paragraph.
-
-
- - - -""" - - tests = generate_tests_from_html(html_content, "0", 1) - - for test in tests: - if test["type"] == "order": - self.assertTrue(len([c for c in test["before"] if not c.isdigit()]) > 0) diff --git a/olmocr/train/grpo_train.py b/olmocr/train/grpo_train.py index f42ffc3..575204f 100644 --- a/olmocr/train/grpo_train.py +++ b/olmocr/train/grpo_train.py @@ -32,6 +32,8 @@ from io import BytesIO from olmocr.data.renderpdf import render_pdf_to_base64png from olmocr.prompts import build_no_anchoring_v4_yaml_prompt from olmocr.bench.tests import load_single_test +from olmocr.train.dataloader import FrontMatterParser +from olmocr.prompts import PageResponse # Configure logging logging.basicConfig( @@ -455,6 +457,56 @@ def medoid_reward(prompts, completions: list[str] | list[list[dict]], **kwargs): return rewards +def reward_format(prompts, completions: list[str] | list[list[dict]], **kwargs): + """ + Reward function that checks if completions can be successfully parsed by FrontMatterParser. + + Returns 1.0 if the completion can be parsed without errors, 0.0 otherwise. + This ensures the model generates properly formatted YAML front matter that can be + parsed into a PageResponse object. + + Args: + prompts: List of prompts + completions: List of generated completions (model outputs) + **kwargs: Additional arguments + + Returns: + List of reward scores: 1.0 for successful parsing, 0.0 for errors + """ + logger.info(f"Running format reward function for {len(completions)} completions") + + rewards = [] + parser = FrontMatterParser(front_matter_class=PageResponse) + + for i, completion in enumerate(completions): + # Extract text from completion + if isinstance(completion, list): + model_response_markdown = completion[0]["content"] if completion else "" + elif isinstance(completion, str): + model_response_markdown = completion + else: + model_response_markdown = "" + + try: + # Try to parse the completion using the same logic as in pipeline.py + front_matter, text = parser._extract_front_matter_and_text(model_response_markdown) + page_response = parser._parse_front_matter(front_matter, text) + + # If we get here without exception, parsing succeeded + rewards.append(1.0) + logger.debug(f"Completion {i}: Successfully parsed format") + + except Exception as e: + # Any parsing error results in 0 reward + rewards.append(0.0) + logger.debug(f"Completion {i}: Failed to parse format - {type(e).__name__}: {str(e)}") + + success_count = sum(1 for r in rewards if r == 1.0) + logger.info(f"Format rewards: {success_count}/{len(rewards)} successfully parsed") + + return rewards + + def olmocr_bench_reward(prompts, completions: list[str] | list[list[dict]], completion_ids: list[list[int]], pdf_path: list[str], jsonl_file: list[str], test_ids: list[list[str]], **kwargs): """ Reward function that runs unit tests on completions and returns average pass rate. @@ -640,6 +692,14 @@ def main(): default=None, help="Use bench edit distance reward with optional weight (default: 1.0)" ) + parser.add_argument( + "--reward_format", + nargs='?', + const=1.0, + type=float, + default=None, + help="Use format validation reward with optional weight (default: 1.0)" + ) args = parser.parse_args() @@ -739,8 +799,14 @@ def main(): reward_names.append("bench_edit_distance") logger.info(f"Added bench edit distance reward function with weight {args.reward_bench_edit_distance}") + if args.reward_format is not None: + reward_funcs.append(reward_format) + reward_weights.append(args.reward_format) + reward_names.append("format") + logger.info(f"Added format validation reward function with weight {args.reward_format}") + if not reward_funcs: - logger.error("No reward function specified. Use at least one of: --reward_bench, --reward_medoid, --reward_bench_edit_distance") + logger.error("No reward function specified. Use at least one of: --reward_bench, --reward_medoid, --reward_bench_edit_distance, --reward_format") return # Log summary of reward configuration diff --git a/tests/test_mine_html_templates.py b/tests/test_mine_html_templates.py index c4ed5b0..e3d7361 100644 --- a/tests/test_mine_html_templates.py +++ b/tests/test_mine_html_templates.py @@ -11,6 +11,1027 @@ from olmocr.bench.synth.mine_html_templates import ( ) from olmocr.bench.tests import TestType +class TestMineTests(unittest.TestCase): + def test_absent_nested(self): + html_content = """ + + + + + + New Paradigm for Nuclear Safety + + +
+ +
+ +
+

New Paradigm for Nuclear Safety

+ +
+

Thursday, April 25, 2013

+

Japan Nuclear Safety Institute

+

Shojiro Matsuura, Chairman

+
+
+ + + +""" + tests = generate_tests_from_html(html_content, "0", 1) + + self.assertEqual(len([test for test in tests if test["type"] == "absent"]), 2) + + def test_text_basic(self): + html_content = """ + + + + + + + Bone Morphology Description + + +
+

The posterior end exhibits a curved process to articulate with the angular. Aside from the process, the rest of the posterior end has slight curvatures for articulation, but is mostly uniform. Ventral border of the bone is mostly straight, with slight curvature (FIG. 20).

+ +

Lateral- A spine runs from the anterior-most tip, reduces in height ~3/4 way down toward posterior, and terminates at the center of the posterior notch. A fossa is present on the dorsal side of the spine. The posterior end exhibits more relief than in medial view, with the medial side of the posterior process extending past the posterior notch.

+ +

Ontogeny- Anterior tip is sharply pointed in AR12 and AR1 with AR2 being rounded, though this could be due to breakage. Anterior dorsal margin is straight and flat in AR12; AR2 shows little curvature and AR1 shows the most curvature; curving outward dorsally. Dorsal incisure is anteroposteriorly oriented in AR12, in AR2 there is some ventral curvature, and in AR1 there is a posteroventral curvature. Both AR1 and AR3 are curved on the ventral margin while AR12 is mostly straight. Posterior end of AR1 exhibits four undulations, ventral process is not yet extended. A fossa is present dorsal to the ventral process, not seen on AR12 or AR2. In medial view the lateral ridge is visible posteriorly in AR1 and AR2l the ridge does not fully extend anteriorly. In lateral view of the posterior the ventral process is present on AR2, but not fully extended posteriorly. Tip of the anterodorsal process is sharply pointed in AR1 and AR2, rounded in AR12. A short ridge is present on the dorsal edge of the dorsal process of AR1. The short ridge on the posterodorsal process of AR2 is slightly more ventral than in AR1. On AR12 the ridge is long and positioned most ventral. The lateral ridge is closest to the ventral margin in AR1. In AR2 the ridge is positioned more dorsally and in AR12 the ridge terminates and the anterior tip. The section of bone ventral to the lateral ridge appears to thin with age. The posterior notch on AR12 is curved anteriorly and the medial side of the notch extends posteriorly

+
+ + + +""" + + tests = generate_tests_from_html(html_content, "0", 1) + self.assertGreater(len(tests), 5) + + def test_big_headers(self): + html_content = """ + + + + + + + FORANE 427A Comparative Data + + + +
+

Comparative data

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParametersR-22FORANE® 427A
Evaporating temperature2.7 °C1.1 °C
Condensing temperature40.3 °C44.0 °C
Suction temperature7.1 °C9.2 °C
Suction pressure5.4 bar5.0 bar
Discharge temperature69.5 °C71.1 °C
Discharge pressure15.5 bar17.1 bar
Cooling power431 KW376 KW
Power consumption122 kW124 kW
Residual mineral oil-11%
+ +

During this field test, very satisfactory running conditions were reached immediately. The temperature set points were easily achieved with similar energy consumption as compared to R-22 despite a high level of residual mineral oil in the circuit. The performance of the installation continues to satisfy the customer's requirements after more than one year of service.

+ +

FORANE® 427A consequently fully satisfies the requirements of the European regulations while enabling existing equipment to continue to perform well without the need for any long and costly plant modifications.

+ +

The versatility of FORANE® 427A is also appreciated as it can be used to retrofit low temperature refrigeration equipment as well as air-conditioning installations, resulting in only one retrofit refrigerant for all R-22 units.

+ +

Combining environmental friendliness, high performance and simplicity is today a reality with FORANE® 427A !

+
+ + + +""" + + tests = generate_tests_from_html(html_content, "0", 1) + + self.assertFalse(any(test for test in tests if test["type"] == "absent" and "Comparative data" in test["text"])) + + def test_page_num(self): + html_content = """ + + + + + + Academic Paper - Page 47 + + +
+
+ +

Figure 4.3: The COVID-19 pandemic resulted in meaningful increase in the support for other groups' protests among Panamanians.

+ +
+

4.2.2 Demographically-Informed Opinion Assignment

+ +

Our model does not endow opinions randomly; instead, we leverage data to assign activists in a more realistic fashion. We use Latinobarómetro survey data from 2020 and 2023, both of which contain the three measurements of support for protest. Then, we explored which demographic groups were more likely to be activists; these are young adults and individuals at either extreme of the financial spectrum. We use this insight to influence the assignment of opinions: our logistic equations make it so that individuals with these characteristics are more likely to be labeled as activists as the probabilistic endowment happens. The code ensures that the proportion of activists overall remains exactly as desired and that there are activists who do not belong to these identified groups

+
+ +
+

4.2.3 Identity Factored into Social Influence

+ +

The similarity formula for Panama is built as follows, taking in nine demographic factors stored as node attributes. These are gender, age, nationality, financial status, highest level of education, level of employment, geographical region, party affiliation, and ethnicity (respectively encoded as gend, age, nation, fin, edu, emp, region, paff, and ethni). Each one of these factors has an associated weight; in this model, all factors were weighted as 0.10, except for level of education and financial status which received 0.15. Our code establishes logical rules to compare the two individuals on each dimension and return a factor by which to multiply the weight. These factors can be absolute or relative, based on the demographic dimension in question. For example, the logical conditions for gender returns 1 if same or 0 if different, while age returns a float value between 0 and 1 according to how close in age the individuals are. Once the pairwise similarity

+
+
+ + + +""" + + tests = generate_tests_from_html(html_content, "0", 1) + + self.assertEqual(len([test for test in tests if test["type"] == "absent"]), 1) + + def test_div_footer(self): + html_content = """ + + + + + + + Being Thai: A Narrow Identity in a Wide World + + + +
+
+ +
+
+ + + +

hard to create a political and cultural narrative that appeals to old ideas about being Thai at this moment of perceived vulnerability.

+ +

The Concept of "Thainess"

+ +

Thainess is a political notion that originally evolved to support an authoritarian government and was then re-shaped for periods of more democratic rule.13 Thailand has long oscillated between dictatorship and democracy and, in either case, a sense of the "Thai style" (baeb Thai) is commonly invoked. Under these conditions a military coup may be thought to "advance Thai-style democracy".14 This is obviously fraught with difficulties and requires government agencies, most notably the Ministry of Culture, to work hard on shaping national identity.15 Thailand's geographical and cultural diversity means that there are inevitable deviations. Some of these have been astutely handled, especially in the northeastern provinces where the Lao-speaking minority has been integrated as chao isan. Nowadays it is only at the margins that their "Isan-ness" remains a contested sub-category of Thainess.16 In earlier generations there were more explicit challenges to the suggestion of Isan as Thai.17 Similar defiance has emerged in both the northern provinces18 and in the Malay Muslim majority areas of the far south.19 At various times there have been suggestions, as reported by the anthropologist Nick Tapp, that "Thainess" was disintegrating.20 It is in response to these persistent challenges that Prayuth's military government has sought to create its own revised version of the national ideal.

+ +

For the military government the codification of Thailand's core values has created new opportunities to stamp its preferred identity on society. In a key speech soon after he took power in 2014, Prayuth identified disunity as a problem in Thai society that would, in his words, "urgently require inclusive cooperation from people of all levels, gender and age".21 His approach was to "define clear core values of Thai people so that we can build a strong nation". These values draw on cultural ideas that have existed for many decades and have enjoyed the favour of previous military rulers. The full list of these twelve values is:

+ +
    +
  1. Upholding the three main pillars of the country: the nation, the religion and the monarchy;
  2. +
  3. Showing honesty, sacrifice and patience, with a positive attitude for the interest of the public;
  4. +
  5. Practicing filial piety towards parents, guardians and teachers;
  6. +
  7. Seeking both direct and indirect knowledge and education;
  8. +
+ +
+
+ + + +""" + + tests = generate_tests_from_html(html_content, "0", 1) + + self.assertEqual(len([test for test in tests if test["type"] == "absent"]), 4) + + def test_table(self): + html_content = """ + + + + + + Distribuição da população na estrutura socioocupacional - Brasil 2000 + + + +
+
+
Alexandre Gori Maia e Waldir José de Quadros ■ 417
+
+ +

Apêndice A - Distribuição da população na estrutura socioocupacional - Brasil 2000

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Grupo OcupacionalClasse OcupacionalSuperiorMédioBaixoInteriorÍnfimoTotal
N (1.000s)%N (1.000s)%N (1.000s)%N (1.000s)%N (1.000s)%N (1.000s)%
EmpregadoresA-1 Empregadores (> 10)60867,318520,4869,6161,880,9903100
A-2 Empregadores (<= 10)1.55536,91.10726,31.03624,73418,11714,14.213100
Total2.16242,31.29225,31.12622,03577,01793,55.116100
ProfissionaisC Profissionais Autônomos1.64321,71.51320,02.07327,41.22516,21.10814,77.562100
D Profissionais Assalariados4.43813,36.03018,011.55034,57.02721,04.38913,133.434100
Total6.08114,87.54318,413.62333,28.25220,15.49713,440.995100
Massa Não-AgrícolaF Trabalhadores Autônomos6573,51.7549,25.56129,25.27127,75.78830,419.030100
G Trabalhadores Assalariados2820,71.6574,310.36327,113.00234,012.96833,938.272100
I Trabalhadores Domésticos100,11041,697714,71.81027,33.73356,36.633100
Total9481,53.5155,516.90126,420.08331,422.48935,263.936100
Massa AgrícolaH-1 Proprietários Conta Própria1882,03643,81.38714,41.88919,75.77960,29.608100
H-2 Trabalhadores Autônomos50,5141,5727,615216,170374,3946100
H-3 Trabalhadores Assalariados170,2580,67948,42.26023,96.32266,99.451100
Total2101,04362,22.25311,34.30121,512.80564,020.005100
Não-remuneradosNão-remunerados Não-Agrícolas136,8168,12814,02210,911960,2198100
Não-remunerados Agrícolas50,1130,3591,63529,43.30288,53.731100
Sem Ocupação Com Renda1.5676,02.3308,95.39520,76.82126,29.96438,226.078100
Sem Ocupação Sem Renda8.0941008.094100
Ignorados17710,320211,836421,133719,664037,21.720100
+ +

Fonte: Censo Demográfico 2000, microdados. IBGE. Elaboração dos autores.

+ + + +""" + + tests = generate_tests_from_html(html_content, "0", 1) + + self.assertTrue(len(tests) > 10) + + def test_sup(self): + html_content = """ + + + + + + A ROSE BY ANY OTHER NAME + + + +
+
2016]
+
A ROSE BY ANY OTHER NAME
+
1083
+
+ +
+

cases were decided within a year of each other (2000 and 2001, respectively). Save the Manatee Club largely consists of a truncated version of the Consolidated-Tomoka analysis, with minor adjustments to conform the opinion to the 1999 amendments. Day Cruise, on the other hand, closely analyzes the 1999 version of section 120.52(8). However, it is Save the Manatee Club that has come to dominate Florida court opinions on rulemaking challenges and not the more detailed Day Cruise analysis.78 The following Sections will discuss the facts of the two cases, examine the differences between their analyses of section 120.52(8), and finally conclude with an opinion on which analysis is better to apply in section 120.52(8) rulemaking challenges.

+ +

A. Southwest Florida Water Management District v. Save the Manatee Club, Inc.

+ +

After the legislature amended the APA, the First DCA analyzed the statutory language of section 120.52(8) again in Southwest Florida Water Management District v. Save the Manatee Club, Inc.79 Save the Manatee Club concerned the Southwest Florida Water Management District's (the "District's") authority to create exemptions to environmental resource permitting requirements.80 South Shores Partners, Ltd. ("South Shores") applied "for a permit to develop a 720-acre tract of land in Southwest Hillsborough County."81 As part of the development project, South Shores wanted "to build a connecting waterway between the [existing] canal system [on the property] and the [Tampa] Bay."82 The Save the Manatee Club believed that the resulting increase in power boat traffic in this new waterway would "endanger the manatee and its habitat."83

+ +

The District has the authority to grant either a general permit or an environmental resource permit to a development project, depending on the type of project involved.84 When granting an environmental resource permit, the District must consider "[t]he impact a proposed development will have on wildlife" as a factor; it does not have to do so when it grants a general permit.85 The District granted South

+
+ + + +""" + + tests = generate_tests_from_html(html_content, "0", 1) + + superscript_map = { + "0": "⁰", + "1": "¹", + "2": "²", + "3": "³", + "4": "⁴", + "5": "⁵", + "6": "⁶", + "7": "⁷", + "8": "⁸", + "9": "⁹", + "+": "⁺", + "-": "⁻", + "=": "⁼", + "(": "⁽", + ")": "⁾", + "n": "ⁿ", + "i": "ⁱ", + } + + for test in tests: + for sup in superscript_map.values(): + self.assertTrue(sup not in test.get("text", "")) + self.assertTrue(sup not in test.get("before", "")) + self.assertTrue(sup not in test.get("after", "")) + + def test_katex_autorender(self): + """Test that KaTeX math expressions are properly auto-rendered when using the render_pdf_with_playwright function.""" + import asyncio + import os + import tempfile + + from olmocr.bench.synth.mine_html_templates import render_pdf_with_playwright + + # Create HTML with LaTeX expressions + html_content = """ + + + + + KaTeX Auto-Render Test + + +

Math Expressions Test

+ +

Inline math expression: \(E = mc^2\)

+ +

Block math expression:

+

\[ + \\frac{d}{dx}(x^n) = nx^{n-1} + \]

+ +

Another complex equation:

+

\[ + \int_{a}^{b} f(x) \, dx = F(b) - F(a) + \]

+ + + """ + + # Create a temporary file to store the rendered PDF + with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp_file: + output_pdf_path = tmp_file.name + + # Render the HTML to PDF + render_success = asyncio.run(render_pdf_with_playwright(html_content=html_content, output_pdf_path=output_pdf_path, png_width=800, png_height=600)) + + # Check if rendering was successful + self.assertTrue(render_success, "PDF rendering should succeed") + + # Verify PDF was created and has content + self.assertTrue(os.path.exists(output_pdf_path), "PDF file should exist") + self.assertTrue(os.path.getsize(output_pdf_path) > 0, "PDF file should have content") + + # The actual validation of KaTeX rendering would require visual inspection or text extraction, + # but at minimum we can verify the file was created successfully + + print(output_pdf_path) + + def test_line_numbers(self): + html_content = """ + + + + + + House Amendment Bill No. CS/CS/SB 7030 + + +
+
HOUSE AMENDMENT
+
Bill No. CS/CS/SB 7030, 1st Eng. (2019)
+
+ +
Amendment No.
+ +
+
+
Senate
+
House
+
+
.
+
+ +
+ +
+ +
+
+ 1 +
Representative Jenne offered the following:
+
+
+ 2 +
+
+
+ 3 +
Amendment
+
+
+ 4 +
Remove lines 274-280 and insert:
+
+
+ 5 +
c.3. Pass an initial a psychological evaluation, and
+
+
+ 6 +
subsequent yearly psychological evaluations before each school
+
+
+ 7 +
year, administered by a psychologist licensed under chapter 490
+
+
+ 8 +
and designated by the Department of Law Enforcement and submit
+
+
+ 9 +
the results of such evaluations the evaluation to the sheriff's
+
+
+ 10 +
office. The Department of Law Enforcement is authorized to
+
+
+ 11 +
provide the sheriff's office with mental health and substance
+
+
+ 12 +
abuse data for compliance with this paragraph.
+
+
+ + + +""" + + tests = generate_tests_from_html(html_content, "0", 1) + + for test in tests: + if test["type"] == "order": + self.assertTrue(len([c for c in test["before"] if not c.isdigit()]) > 0) + class TestMathExtraction(unittest.TestCase): """Test the math extraction functionality in mine_html_templates.py"""