itp-interface 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- itp_interface/__init__.py +0 -0
- itp_interface/agent/__init__.py +0 -0
- itp_interface/agent/simple_proof_agent.py +100 -0
- itp_interface/coq_ser_api/__init__.py +165 -0
- itp_interface/coq_ser_api/contexts.py +283 -0
- itp_interface/coq_ser_api/coq_agent.py +459 -0
- itp_interface/coq_ser_api/coq_backend.py +135 -0
- itp_interface/coq_ser_api/coq_util.py +839 -0
- itp_interface/coq_ser_api/example.py +67 -0
- itp_interface/coq_ser_api/lsp_backend.py +375 -0
- itp_interface/coq_ser_api/py.typed +0 -0
- itp_interface/coq_ser_api/serapi_backend.py +841 -0
- itp_interface/coq_ser_api/util.py +145 -0
- itp_interface/coq_ser_api_old/__init__.py +2583 -0
- itp_interface/coq_ser_api_old/contexts.py +172 -0
- itp_interface/coq_ser_api_old/util.py +146 -0
- itp_interface/lean_server/__init__.py +0 -0
- itp_interface/lean_server/commands.py +484 -0
- itp_interface/lean_server/lean3_search_tool.py +358 -0
- itp_interface/lean_server/lean4_repl_interface.py +151 -0
- itp_interface/lean_server/lean4_utils.py +255 -0
- itp_interface/lean_server/lean_cmd_server.py +111 -0
- itp_interface/lean_server/lean_context.py +60 -0
- itp_interface/lean_server/lean_sync_server.py +174 -0
- itp_interface/lean_server/lean_utils.py +199 -0
- itp_interface/lean_server/py.typed +1 -0
- itp_interface/main/__init__.py +0 -0
- itp_interface/main/config/afp_data_gen.yaml +14 -0
- itp_interface/main/config/benchmark/CompCert.yaml +366 -0
- itp_interface/main/config/benchmark/GeoCoq.yaml +930 -0
- itp_interface/main/config/benchmark/UniMath.yaml +2690 -0
- itp_interface/main/config/benchmark/afp_isabelle.yaml +29200 -0
- itp_interface/main/config/benchmark/agent_proverbot_hard.yaml +247 -0
- itp_interface/main/config/benchmark/category-theory.yaml +470 -0
- itp_interface/main/config/benchmark/compcert_118_subset.yaml +148 -0
- itp_interface/main/config/benchmark/compcert_benchmark.yaml +36 -0
- itp_interface/main/config/benchmark/compcert_benchmark_hard.yaml +498 -0
- itp_interface/main/config/benchmark/compcert_benchmark_hard_1.yaml +55 -0
- itp_interface/main/config/benchmark/compcert_benchmark_hard_2.yaml +24 -0
- itp_interface/main/config/benchmark/compcert_benchmark_hard_3.yaml +95 -0
- itp_interface/main/config/benchmark/compcert_benchmark_hard_7_per_cent.yaml +78 -0
- itp_interface/main/config/benchmark/compcert_benchmark_test.yaml +38 -0
- itp_interface/main/config/benchmark/compcert_benchmark_train.yaml +340 -0
- itp_interface/main/config/benchmark/leandojo_novel_premises_test.yaml +2908 -0
- itp_interface/main/config/benchmark/leandojo_novel_premises_train.yaml +98645 -0
- itp_interface/main/config/benchmark/leandojo_novel_premises_val.yaml +2912 -0
- itp_interface/main/config/benchmark/leandojo_random.yaml +2889 -0
- itp_interface/main/config/benchmark/leandojo_random_test.yaml +2421 -0
- itp_interface/main/config/benchmark/leandojo_random_train.yaml +62729 -0
- itp_interface/main/config/benchmark/leandojo_random_val.yaml +2504 -0
- itp_interface/main/config/benchmark/math-comp.yaml +200 -0
- itp_interface/main/config/benchmark/miniF2F_test.yaml +12 -0
- itp_interface/main/config/benchmark/miniF2F_test_aime.yaml +27 -0
- itp_interface/main/config/benchmark/miniF2F_test_algebra.yaml +30 -0
- itp_interface/main/config/benchmark/miniF2F_test_amc12.yaml +57 -0
- itp_interface/main/config/benchmark/miniF2F_test_few_shot_hard.yaml +231 -0
- itp_interface/main/config/benchmark/miniF2F_test_imo.yaml +32 -0
- itp_interface/main/config/benchmark/miniF2F_test_induction.yaml +20 -0
- itp_interface/main/config/benchmark/miniF2F_test_mathd_algebra.yaml +82 -0
- itp_interface/main/config/benchmark/miniF2F_test_mathd_algebra_hard.yaml +72 -0
- itp_interface/main/config/benchmark/miniF2F_test_mathd_numbertheory.yaml +72 -0
- itp_interface/main/config/benchmark/miniF2F_test_numbertheory.yaml +20 -0
- itp_interface/main/config/benchmark/minicompcert_benchmark_1.yaml +14 -0
- itp_interface/main/config/benchmark/proverbot_hard.yaml +104 -0
- itp_interface/main/config/benchmark/re_prover.yaml +66 -0
- itp_interface/main/config/benchmark/re_prover_hard.yaml +41 -0
- itp_interface/main/config/benchmark/re_prover_very_hard.yaml +22 -0
- itp_interface/main/config/benchmark/reprover_with_retrieval.yaml +73 -0
- itp_interface/main/config/benchmark/reprover_with_retrieval_hard.yaml +30 -0
- itp_interface/main/config/benchmark/reprover_with_retrieval_neg.yaml +195 -0
- itp_interface/main/config/benchmark/simple_benchmark_1.yaml +24 -0
- itp_interface/main/config/benchmark/simple_benchmark_8.yaml +50 -0
- itp_interface/main/config/benchmark/simple_benchmark_9.yaml +65 -0
- itp_interface/main/config/benchmark/simple_benchmark_isabelle.yaml +18 -0
- itp_interface/main/config/benchmark/simple_benchmark_lean.yaml +12 -0
- itp_interface/main/config/benchmark/simple_benchmark_lean_training_data.yaml +12 -0
- itp_interface/main/config/benchmark/simple_rl_benchmark_lean.yaml +14 -0
- itp_interface/main/config/benchmark/stack_machine.yaml +13 -0
- itp_interface/main/config/benchmark/stack_machine_hard.yaml +15 -0
- itp_interface/main/config/category_theory_data_gen.yaml +14 -0
- itp_interface/main/config/category_theory_data_gen_random.yaml +16 -0
- itp_interface/main/config/compcert_data_gen_test.yaml +10 -0
- itp_interface/main/config/compcert_data_gen_train.yaml +7 -0
- itp_interface/main/config/env_settings/bm25_retrieval.yaml +2 -0
- itp_interface/main/config/env_settings/bm25_retrieval_no_dfns.yaml +2 -0
- itp_interface/main/config/env_settings/bm25_retrieval_only_local_no_dfns.yaml +2 -0
- itp_interface/main/config/env_settings/bm25_retrieval_with_print.yaml +2 -0
- itp_interface/main/config/env_settings/bm25_retrieval_with_print_only_local.yaml +2 -0
- itp_interface/main/config/env_settings/bm25_retrieval_with_print_only_local_no_dfns.yaml +2 -0
- itp_interface/main/config/env_settings/no_retrieval.yaml +2 -0
- itp_interface/main/config/experiments.yaml +12 -0
- itp_interface/main/config/geo_coq_data_gen.yaml +14 -0
- itp_interface/main/config/geo_coq_data_gen_random.yaml +16 -0
- itp_interface/main/config/leandojo_random_data_gen.yaml +16 -0
- itp_interface/main/config/math_comp_data_gen.yaml +14 -0
- itp_interface/main/config/math_comp_data_gen_random.yaml +16 -0
- itp_interface/main/config/mathlib_data_gen.yaml +14 -0
- itp_interface/main/config/repo/coq_repos.yaml +191 -0
- itp_interface/main/config/run_settings/default_coq_data_generation_transforms.yaml +24 -0
- itp_interface/main/config/run_settings/default_isabelle_data_generation_transforms.yaml +24 -0
- itp_interface/main/config/run_settings/default_lean4_data_generation_transforms.yaml +24 -0
- itp_interface/main/config/run_settings/default_lean_data_generation_transforms.yaml +24 -0
- itp_interface/main/config/simple_coq_data_gen.yaml +12 -0
- itp_interface/main/config/simple_coq_data_gen_random.yaml +17 -0
- itp_interface/main/config/simple_lean_data_gen.yaml +12 -0
- itp_interface/main/config/simple_rl_lean_data_gen.yaml +12 -0
- itp_interface/main/config/uni_math_data_gen.yaml +14 -0
- itp_interface/main/config.py +192 -0
- itp_interface/main/extract_benchmark_dataset.py +106 -0
- itp_interface/main/filter_dataset.py +107 -0
- itp_interface/main/install.py +92 -0
- itp_interface/main/merge_dataset.py +96 -0
- itp_interface/main/run_tool.py +444 -0
- itp_interface/pisa/.git +1 -0
- itp_interface/pisa/.gitignore +125 -0
- itp_interface/pisa/.idea/.gitignore +8 -0
- itp_interface/pisa/.idea/ClojureProjectResolveSettings.xml +6 -0
- itp_interface/pisa/.idea/codeStyles/Project.xml +7 -0
- itp_interface/pisa/.idea/codeStyles/codeStyleConfig.xml +5 -0
- itp_interface/pisa/.idea/inspectionProfiles/Project_Default.xml +16 -0
- itp_interface/pisa/.idea/libraries/sbt__com_google_android_annotations_4_1_1_4_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_google_api_grpc_proto_google_common_protos_1_17_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_google_code_findbugs_jsr305_3_0_2_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_google_code_gson_gson_2_8_6_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_google_errorprone_error_prone_annotations_2_3_4_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_google_guava_failureaccess_1_0_1_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_google_guava_guava_30_0_jre_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_google_guava_listenablefuture_9999_0_empty_to_avoid_conflict_with_guava_jar.xml +9 -0
- itp_interface/pisa/.idea/libraries/sbt__com_google_j2objc_j2objc_annotations_1_3_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_google_protobuf_protobuf_java_3_12_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_google_protobuf_protobuf_java_util_3_12_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_lihaoyi_fastparse_2_13_2_3_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_lihaoyi_geny_2_13_0_6_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_lihaoyi_sourcecode_2_13_0_2_1_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_thesamet_scalapb_lenses_2_13_0_10_9_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_thesamet_scalapb_scalapb_runtime_2_13_0_10_9_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_thesamet_scalapb_scalapb_runtime_grpc_2_13_0_10_9_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_thesamet_scalapb_zio_grpc_zio_grpc_core_2_13_0_4_2_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__com_thoughtworks_paranamer_paranamer_2_8_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__commons_io_commons_io_2_8_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__de_unruh_java_patterns_0_1_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__de_unruh_scala_isabelle_2_13_master_SNAPSHOT_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__dev_zio_izumi_reflect_2_13_1_0_0_M9_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__dev_zio_izumi_reflect_thirdparty_boopickle_shaded_2_13_1_0_0_M9_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__dev_zio_zio_2_13_1_0_3_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__dev_zio_zio_stacktracer_2_13_1_0_3_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__dev_zio_zio_streams_2_13_1_0_3_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_grpc_grpc_api_1_34_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_grpc_grpc_context_1_34_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_grpc_grpc_core_1_34_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_grpc_grpc_netty_1_34_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_grpc_grpc_protobuf_1_34_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_grpc_grpc_protobuf_lite_1_34_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_grpc_grpc_services_1_34_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_grpc_grpc_stub_1_34_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_netty_netty_buffer_4_1_51_Final_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_netty_netty_codec_4_1_51_Final_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_netty_netty_codec_http2_4_1_51_Final_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_netty_netty_codec_http_4_1_51_Final_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_netty_netty_codec_socks_4_1_51_Final_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_netty_netty_common_4_1_51_Final_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_netty_netty_handler_4_1_51_Final_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_netty_netty_handler_proxy_4_1_51_Final_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_netty_netty_resolver_4_1_51_Final_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_netty_netty_transport_4_1_51_Final_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__io_perfmark_perfmark_api_0_19_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__net_java_dev_jna_jna_5_3_1_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__net_liftweb_lift_json_2_13_3_4_3_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__org_apache_commons_commons_lang3_3_11_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__org_apache_commons_commons_text_1_9_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__org_checkerframework_checker_qual_3_5_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__org_codehaus_mojo_animal_sniffer_annotations_1_18_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__org_jetbrains_annotations_20_1_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__org_jline_jline_3_16_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__org_log4s_log4s_2_13_1_9_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__org_scala_lang_modules_scala_collection_compat_2_13_2_1_6_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__org_scala_lang_modules_scala_xml_2_13_1_3_0_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__org_scala_lang_scala_compiler_2_13_4_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__org_scala_lang_scala_library_2_13_4_jar.xml +23 -0
- itp_interface/pisa/.idea/libraries/sbt__org_scala_lang_scala_reflect_2_13_4_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__org_scala_lang_scalap_2_13_4_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__org_scalaz_scalaz_core_2_13_7_3_2_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__org_slf4j_slf4j_api_1_7_30_jar.xml +13 -0
- itp_interface/pisa/.idea/libraries/sbt__org_slf4j_slf4j_simple_1_7_30_jar.xml +13 -0
- itp_interface/pisa/.idea/misc.xml +7 -0
- itp_interface/pisa/.idea/modules/PISA-build.iml +127 -0
- itp_interface/pisa/.idea/modules/PISA.iml +94 -0
- itp_interface/pisa/.idea/modules.xml +9 -0
- itp_interface/pisa/.idea/other.xml +6 -0
- itp_interface/pisa/.idea/sbt.xml +20 -0
- itp_interface/pisa/.idea/scala_compiler.xml +6 -0
- itp_interface/pisa/.idea/uiDesigner.xml +124 -0
- itp_interface/pisa/.idea/vcs.xml +6 -0
- itp_interface/pisa/.scalafmt.conf +2 -0
- itp_interface/pisa/LICENSE +29 -0
- itp_interface/pisa/README.md +262 -0
- itp_interface/pisa/build.sbt +49 -0
- itp_interface/pisa/build.sh +26 -0
- itp_interface/pisa/command_generation/close_gaps.py +44 -0
- itp_interface/pisa/command_generation/conjecture_normal_order.py +62 -0
- itp_interface/pisa/command_generation/conjecturer_command_generator.py +36 -0
- itp_interface/pisa/command_generation/create_dirs.py +11 -0
- itp_interface/pisa/command_generation/find_std.py +67 -0
- itp_interface/pisa/command_generation/generate_build_commands_afp.py +15 -0
- itp_interface/pisa/command_generation/generate_build_commands_std.py +15 -0
- itp_interface/pisa/command_generation/generate_commands_afp.py +103 -0
- itp_interface/pisa/command_generation/generate_commands_mini.py +73 -0
- itp_interface/pisa/command_generation/generate_commands_std.py +69 -0
- itp_interface/pisa/command_generation/generate_hammer_extraction_text.py +5 -0
- itp_interface/pisa/command_generation/hammer_command_generator.py +40 -0
- itp_interface/pisa/command_generation/hp_search_command_generator.py +63 -0
- itp_interface/pisa/command_generation/oracle_command_generator.py +56 -0
- itp_interface/pisa/command_generation/search_command_generator.py +69 -0
- itp_interface/pisa/command_generation/summarise_problem_names.py +45 -0
- itp_interface/pisa/command_generation/tpu_hp_search.py +75 -0
- itp_interface/pisa/docker/Dockerfile +34 -0
- itp_interface/pisa/docker/docker_tutorial.md +64 -0
- itp_interface/pisa/eval_setup/copy_isabelle.py +42 -0
- itp_interface/pisa/eval_setup/copy_pisa_jars.py +18 -0
- itp_interface/pisa/mesh_transformer_utils/tokenization.py +86 -0
- itp_interface/pisa/project/build.properties +1 -0
- itp_interface/pisa/project/plugins.sbt +5 -0
- itp_interface/pisa/requirements.txt +4 -0
- itp_interface/pisa/scripts/extract_last_k_steps.py +28 -0
- itp_interface/pisa/scripts/extract_proof_corpus.py +26 -0
- itp_interface/pisa/scripts/gather_hammer_results.py +27 -0
- itp_interface/pisa/scripts/length_in_char_stats.py +20 -0
- itp_interface/pisa/scripts/mix.py +127 -0
- itp_interface/pisa/scripts/results_stat.py +52 -0
- itp_interface/pisa/scripts/test_array_job.sh +34 -0
- itp_interface/pisa/setup.sh +25 -0
- itp_interface/pisa/src/main/protobuf/server.proto +60 -0
- itp_interface/pisa/src/main/python/.idea/.gitignore +8 -0
- itp_interface/pisa/src/main/python/.idea/inspectionProfiles/Project_Default.xml +18 -0
- itp_interface/pisa/src/main/python/.idea/inspectionProfiles/profiles_settings.xml +6 -0
- itp_interface/pisa/src/main/python/.idea/misc.xml +4 -0
- itp_interface/pisa/src/main/python/.idea/modules.xml +8 -0
- itp_interface/pisa/src/main/python/.idea/python.iml +12 -0
- itp_interface/pisa/src/main/python/.idea/vcs.xml +6 -0
- itp_interface/pisa/src/main/python/conjecturing_parsing/conjecturer_postprocessing.py +59 -0
- itp_interface/pisa/src/main/python/data_extraction/extract_data.py +184 -0
- itp_interface/pisa/src/main/python/data_extraction/find_premises.py +221 -0
- itp_interface/pisa/src/main/python/data_extraction/process_data.py +129 -0
- itp_interface/pisa/src/main/python/legacy/PisaFlexibleClient.py +167 -0
- itp_interface/pisa/src/main/python/legacy/autof_test.py +74 -0
- itp_interface/pisa/src/main/python/legacy/cmd_client.py +23 -0
- itp_interface/pisa/src/main/python/legacy/convert_scala_dump_to_test_name_jsons.py +14 -0
- itp_interface/pisa/src/main/python/legacy/create_data_txt.py +72 -0
- itp_interface/pisa/src/main/python/legacy/create_finetune_tfrecords.py +311 -0
- itp_interface/pisa/src/main/python/legacy/demo.py +49 -0
- itp_interface/pisa/src/main/python/legacy/evaluate.py +108 -0
- itp_interface/pisa/src/main/python/legacy/extract_first_step.py +25 -0
- itp_interface/pisa/src/main/python/legacy/get_global_facts.py +35 -0
- itp_interface/pisa/src/main/python/legacy/mix_data.py +19 -0
- itp_interface/pisa/src/main/python/legacy/one_stage_extraction.py +111 -0
- itp_interface/pisa/src/main/python/legacy/prepare_episodic_transitions.py +137 -0
- itp_interface/pisa/src/main/python/legacy/prepare_translation_pairs.py +277 -0
- itp_interface/pisa/src/main/python/pisa_client.py +322 -0
- itp_interface/pisa/src/main/python/server_pb2.py +394 -0
- itp_interface/pisa/src/main/python/server_pb2_grpc.py +230 -0
- itp_interface/pisa/src/main/python/test_client.py +17 -0
- itp_interface/pisa/src/main/python/test_client2.py +79 -0
- itp_interface/pisa/src/main/python/utils/filters.py +59 -0
- itp_interface/pisa/src/main/python/utils/pisa_server_control.py +29 -0
- itp_interface/pisa/src/main/scala/pisa/agent/CheckSyntax.scala +257 -0
- itp_interface/pisa/src/main/scala/pisa/agent/DepThms.scala +29 -0
- itp_interface/pisa/src/main/scala/pisa/agent/PisaStat.scala +46 -0
- itp_interface/pisa/src/main/scala/pisa/agent/RefactorTest.scala +40 -0
- itp_interface/pisa/src/main/scala/pisa/agent/RepHammer.scala +95 -0
- itp_interface/pisa/src/main/scala/pisa/server/HammFacts.scala +63 -0
- itp_interface/pisa/src/main/scala/pisa/server/PisaOS.scala +881 -0
- itp_interface/pisa/src/main/scala/pisa/server/PisaOneStage.scala +540 -0
- itp_interface/pisa/src/main/scala/pisa/server/PisaOneStageServers.scala +1048 -0
- itp_interface/pisa/src/main/scala/pisa/utils/TheoryManager.scala +95 -0
- itp_interface/pisa/src/test/python/analyse_debug.py +33 -0
- itp_interface/pisa/src/test/python/extract_test_seq2seq.py +53 -0
- itp_interface/pisa/src/test/python/extract_test_theorem_ground_truth_indices.py +31 -0
- itp_interface/pisa/src/test/python/proof_originality.py +24 -0
- itp_interface/pisa/src/test/python/test_command_generator.py +25 -0
- itp_interface/pisa/src/test/python/test_model_sequence_accuracy.py +70 -0
- itp_interface/pisa/src/test/scala/pisa/Easy.scala +26 -0
- itp_interface/pisa/src/test/scala/pisa/TestCurl.scala +82 -0
- itp_interface/pisa/src/test/scala/pisa/TestIsa.scala +27 -0
- itp_interface/pisa/test.sh +19 -0
- itp_interface/pisa/universal_test_theorems.tar.gz +0 -0
- itp_interface/repo/build.py +78 -0
- itp_interface/repo/clone.py +79 -0
- itp_interface/repo/dataset_discovery.py +99 -0
- itp_interface/retrieval/__init__.py +0 -0
- itp_interface/retrieval/abstraction.py +35 -0
- itp_interface/retrieval/coq_bm25_reranker.py +153 -0
- itp_interface/retrieval/isabelle_bm25_reranker.py +86 -0
- itp_interface/retrieval/lean3_bm25_reranker.py +86 -0
- itp_interface/rl/__init__.py +0 -0
- itp_interface/rl/abstraction.py +168 -0
- itp_interface/rl/proof_action.py +172 -0
- itp_interface/rl/proof_state.py +149 -0
- itp_interface/rl/proof_tree.py +109 -0
- itp_interface/rl/simpl_proof_env_pool.py +16 -0
- itp_interface/rl/simple_proof_env.py +713 -0
- itp_interface/rl/simple_proof_env_pool.py +591 -0
- itp_interface/scripts/setup.sh +228 -0
- itp_interface/tools/__init__.py +0 -0
- itp_interface/tools/basic_utils.py +172 -0
- itp_interface/tools/bin_packing.py +61 -0
- itp_interface/tools/cache.py +93 -0
- itp_interface/tools/coq_build_spec.py +31 -0
- itp_interface/tools/coq_build_tool.py +319 -0
- itp_interface/tools/coq_context_helper.py +354 -0
- itp_interface/tools/coq_executor.py +508 -0
- itp_interface/tools/coq_local_data_generation_transform.py +158 -0
- itp_interface/tools/coq_parse_utils.py +154 -0
- itp_interface/tools/coq_raw_proofs.py +193 -0
- itp_interface/tools/coq_theorem_proof_pair_generation_transform.py +146 -0
- itp_interface/tools/coq_training_data_generator.py +76 -0
- itp_interface/tools/dynamic_coq_proof_exec.py +220 -0
- itp_interface/tools/dynamic_isabelle_proof_exec.py +229 -0
- itp_interface/tools/dynamic_lean4_proof_exec.py +236 -0
- itp_interface/tools/dynamic_lean_proof_exec.py +228 -0
- itp_interface/tools/isabelle_context_helper.py +66 -0
- itp_interface/tools/isabelle_executor.py +862 -0
- itp_interface/tools/isabelle_local_data_generation_transform.py +149 -0
- itp_interface/tools/isabelle_parse_utils.py +131 -0
- itp_interface/tools/isabelle_server.py +106 -0
- itp_interface/tools/lean4_context_helper.py +72 -0
- itp_interface/tools/lean4_local_data_generation_transform.py +122 -0
- itp_interface/tools/lean4_sync_executor.py +1193 -0
- itp_interface/tools/lean_cmd_executor.py +804 -0
- itp_interface/tools/lean_context_helper.py +327 -0
- itp_interface/tools/lean_dojo_data_generation_transform.py +206 -0
- itp_interface/tools/lean_executor.py +687 -0
- itp_interface/tools/lean_local_data_generation_transform.py +136 -0
- itp_interface/tools/lean_parse_utils.py +32 -0
- itp_interface/tools/log_utils.py +20 -0
- itp_interface/tools/proof_exec_callback.py +76 -0
- itp_interface/tools/ray_utils.py +265 -0
- itp_interface/tools/repl/.git +1 -0
- itp_interface/tools/repl/.github/workflows/ci.yml +24 -0
- itp_interface/tools/repl/.gitignore +7 -0
- itp_interface/tools/repl/.vscode/copyright.code-snippets +13 -0
- itp_interface/tools/repl/.vscode/extensions.json +13 -0
- itp_interface/tools/repl/.vscode/module-docstring.code-snippets +35 -0
- itp_interface/tools/repl/.vscode/settings.json +11 -0
- itp_interface/tools/repl/README.md +174 -0
- itp_interface/tools/repl/REPL/Frontend.lean +47 -0
- itp_interface/tools/repl/REPL/JSON.lean +186 -0
- itp_interface/tools/repl/REPL/Lean/ContextInfo.lean +9 -0
- itp_interface/tools/repl/REPL/Lean/Environment.lean +31 -0
- itp_interface/tools/repl/REPL/Lean/InfoTree/ToJson.lean +114 -0
- itp_interface/tools/repl/REPL/Lean/InfoTree.lean +272 -0
- itp_interface/tools/repl/REPL/Main.lean +323 -0
- itp_interface/tools/repl/REPL/Snapshots.lean +306 -0
- itp_interface/tools/repl/REPL/Util/Path.lean +36 -0
- itp_interface/tools/repl/REPL/Util/Pickle.lean +44 -0
- itp_interface/tools/repl/REPL.lean +4 -0
- itp_interface/tools/repl/lake-manifest.json +5 -0
- itp_interface/tools/repl/lakefile.lean +15 -0
- itp_interface/tools/repl/lean-toolchain +1 -0
- itp_interface/tools/repl/test/Mathlib/.gitignore +5 -0
- itp_interface/tools/repl/test/Mathlib/H20231110.sh +2 -0
- itp_interface/tools/repl/test/Mathlib/ReplMathlibTests.lean +1 -0
- itp_interface/tools/repl/test/Mathlib/lake-manifest.json +68 -0
- itp_interface/tools/repl/test/Mathlib/lakefile.lean +11 -0
- itp_interface/tools/repl/test/Mathlib/lean-toolchain +1 -0
- itp_interface/tools/repl/test/Mathlib/test/20240209.expected.out +20 -0
- itp_interface/tools/repl/test/Mathlib/test/20240209.in +3 -0
- itp_interface/tools/repl/test/Mathlib/test/20240209.lean +4 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231020.expected.out +8 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231020.in +8 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231020.lean +22 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231110.expected.out +4 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231110.in +4 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231115.expected.out +19 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231115.in +5 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231115_2.expected.out +18 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231115_2.in +4 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231115_3.expected.out +10 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231115_3.in +4 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231214.in +9 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231214.lean +30 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231215.expected.out +4 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231215.in +4 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231215_2.expected.out +14 -0
- itp_interface/tools/repl/test/Mathlib/test/H20231215_2.in +3 -0
- itp_interface/tools/repl/test/Mathlib/test/exact.expected.out +37 -0
- itp_interface/tools/repl/test/Mathlib/test/exact.in +10 -0
- itp_interface/tools/repl/test/Mathlib/test/import_Mathlib.lean +1 -0
- itp_interface/tools/repl/test/Mathlib/test/induction.expected.out +29 -0
- itp_interface/tools/repl/test/Mathlib/test/induction.in +10 -0
- itp_interface/tools/repl/test/Mathlib/test/induction.lean +6 -0
- itp_interface/tools/repl/test/Mathlib/test/on_goal.expected.out +22 -0
- itp_interface/tools/repl/test/Mathlib/test/on_goal.in +5 -0
- itp_interface/tools/repl/test/Mathlib/test/pickle.expected.out +16 -0
- itp_interface/tools/repl/test/Mathlib/test/pickle.in +6 -0
- itp_interface/tools/repl/test/Mathlib/test/pickle_2.expected.out +4 -0
- itp_interface/tools/repl/test/Mathlib/test/pickle_2.in +4 -0
- itp_interface/tools/repl/test/Mathlib/test.sh +41 -0
- itp_interface/tools/repl/test/all_tactics.expected.out +13 -0
- itp_interface/tools/repl/test/all_tactics.in +1 -0
- itp_interface/tools/repl/test/by_cases.expected.out +25 -0
- itp_interface/tools/repl/test/by_cases.in +8 -0
- itp_interface/tools/repl/test/by_cases.lean +4 -0
- itp_interface/tools/repl/test/calc.expected.out +32 -0
- itp_interface/tools/repl/test/calc.in +1 -0
- itp_interface/tools/repl/test/def_eval.expected.out +9 -0
- itp_interface/tools/repl/test/def_eval.in +3 -0
- itp_interface/tools/repl/test/enableInitializersExecution.expected.out +2 -0
- itp_interface/tools/repl/test/enableInitializersExecution.in +1 -0
- itp_interface/tools/repl/test/file.expected.out +8 -0
- itp_interface/tools/repl/test/file.in +1 -0
- itp_interface/tools/repl/test/file.lean +5 -0
- itp_interface/tools/repl/test/have_by_sorry.expected.out +28 -0
- itp_interface/tools/repl/test/have_by_sorry.in +6 -0
- itp_interface/tools/repl/test/import_lean.in +1 -0
- itp_interface/tools/repl/test/incomplete.expected.out +18 -0
- itp_interface/tools/repl/test/incomplete.in +3 -0
- itp_interface/tools/repl/test/incomplete.lean +0 -0
- itp_interface/tools/repl/test/infotree.expected.out +20 -0
- itp_interface/tools/repl/test/infotree.in +2 -0
- itp_interface/tools/repl/test/invalid_tactic.expected.out +20 -0
- itp_interface/tools/repl/test/invalid_tactic.in +3 -0
- itp_interface/tools/repl/test/name_generator.expected.out +53 -0
- itp_interface/tools/repl/test/name_generator.in +18 -0
- itp_interface/tools/repl/test/no_goal_sorry.expected.out +11 -0
- itp_interface/tools/repl/test/no_goal_sorry.in +1 -0
- itp_interface/tools/repl/test/no_goal_sorry_2.expected.out +12 -0
- itp_interface/tools/repl/test/no_goal_sorry_2.in +1 -0
- itp_interface/tools/repl/test/options.expected.out +17 -0
- itp_interface/tools/repl/test/options.in +6 -0
- itp_interface/tools/repl/test/pickle_environment.expected.out +8 -0
- itp_interface/tools/repl/test/pickle_environment.in +7 -0
- itp_interface/tools/repl/test/pickle_environment_with_imports.expected.out +10 -0
- itp_interface/tools/repl/test/pickle_environment_with_imports.in +9 -0
- itp_interface/tools/repl/test/pickle_open.expected.out +8 -0
- itp_interface/tools/repl/test/pickle_open.in +7 -0
- itp_interface/tools/repl/test/pickle_open_2.expected.out +4 -0
- itp_interface/tools/repl/test/pickle_open_2.in +3 -0
- itp_interface/tools/repl/test/pickle_open_scoped.expected.out +18 -0
- itp_interface/tools/repl/test/pickle_open_scoped.in +8 -0
- itp_interface/tools/repl/test/pickle_open_scoped_2.expected.out +14 -0
- itp_interface/tools/repl/test/pickle_open_scoped_2.in +3 -0
- itp_interface/tools/repl/test/pickle_proof_state_1.expected.out +26 -0
- itp_interface/tools/repl/test/pickle_proof_state_1.in +15 -0
- itp_interface/tools/repl/test/pickle_proof_state_2.expected.out +4 -0
- itp_interface/tools/repl/test/pickle_proof_state_2.in +3 -0
- itp_interface/tools/repl/test/pickle_proof_state_env.expected.out +26 -0
- itp_interface/tools/repl/test/pickle_proof_state_env.in +15 -0
- itp_interface/tools/repl/test/pickle_scoped_notation.in +16 -0
- itp_interface/tools/repl/test/pickle_scoped_notation_2.in +3 -0
- itp_interface/tools/repl/test/proof_step.expected.out +18 -0
- itp_interface/tools/repl/test/proof_step.in +7 -0
- itp_interface/tools/repl/test/readme.expected.out +16 -0
- itp_interface/tools/repl/test/readme.in +5 -0
- itp_interface/tools/repl/test/sorry_hypotheses.expected.out +16 -0
- itp_interface/tools/repl/test/sorry_hypotheses.in +4 -0
- itp_interface/tools/repl/test/synthesize_placeholder.expected.out +7 -0
- itp_interface/tools/repl/test/synthesize_placeholder.in +1 -0
- itp_interface/tools/repl/test/tactic_mode_sorry.expected.out +14 -0
- itp_interface/tools/repl/test/tactic_mode_sorry.in +3 -0
- itp_interface/tools/repl/test/tactic_sorry.expected.out +12 -0
- itp_interface/tools/repl/test/tactic_sorry.in +1 -0
- itp_interface/tools/repl/test/term_sorry.expected.out +12 -0
- itp_interface/tools/repl/test/term_sorry.in +1 -0
- itp_interface/tools/repl/test/trace_simp.expected.out +41 -0
- itp_interface/tools/repl/test/trace_simp.in +15 -0
- itp_interface/tools/repl/test/unfinished_tactic_block.expected.out +11 -0
- itp_interface/tools/repl/test/unfinished_tactic_block.in +1 -0
- itp_interface/tools/repl/test/unknown_environment.expected.out +2 -0
- itp_interface/tools/repl/test/unknown_environment.in +1 -0
- itp_interface/tools/repl/test/unknown_proof_state.expected.out +14 -0
- itp_interface/tools/repl/test/unknown_proof_state.in +3 -0
- itp_interface/tools/repl/test/unknown_tactic.expected.out +14 -0
- itp_interface/tools/repl/test/unknown_tactic.in +3 -0
- itp_interface/tools/repl/test/variables.expected.out +26 -0
- itp_interface/tools/repl/test/variables.in +5 -0
- itp_interface/tools/repl/test.sh +43 -0
- itp_interface/tools/run_data_generation_transforms.py +350 -0
- itp_interface/tools/theorem_details.py +25 -0
- itp_interface/tools/training_data.py +358 -0
- itp_interface/tools/training_data_format.py +599 -0
- itp_interface-1.0.0.dist-info/METADATA +78 -0
- itp_interface-1.0.0.dist-info/RECORD +485 -0
- itp_interface-1.0.0.dist-info/WHEEL +4 -0
- itp_interface-1.0.0.dist-info/entry_points.txt +3 -0
- itp_interface-1.0.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,1193 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
root_dir = f"{__file__.split('itp_interface')[0]}"
|
|
5
|
+
if root_dir not in sys.path:
|
|
6
|
+
sys.path.append(root_dir)
|
|
7
|
+
import os
|
|
8
|
+
import random
|
|
9
|
+
import logging
|
|
10
|
+
import re
|
|
11
|
+
import time
|
|
12
|
+
import json
|
|
13
|
+
import typing
|
|
14
|
+
import uuid
|
|
15
|
+
import bisect
|
|
16
|
+
import shutil
|
|
17
|
+
from itp_interface.lean_server.lean_context import ProofContext
|
|
18
|
+
from itp_interface.lean_server.lean4_utils import Lean4Utils
|
|
19
|
+
from itp_interface.tools.lean_parse_utils import LeanLineByLineReader
|
|
20
|
+
from itp_interface.tools.theorem_details import TheoremDetails
|
|
21
|
+
from itp_interface.lean_server.lean4_repl_interface import ProcessInterface
|
|
22
|
+
from typing import Iterator, List, Optional, Tuple, OrderedDict, Generator, Dict
|
|
23
|
+
|
|
24
|
+
class Lean4SyncExecutor:
|
|
25
|
+
theorem_start_regex = r"[\s]*(theorem|lemma|example)[\s]+"
|
|
26
|
+
# Non tactic mode support removed because of complications in parsing
|
|
27
|
+
# theorem_end_regex = r"(theorem|lemma|example) [\S|\s]*?(:=|\|)[\s]*?"
|
|
28
|
+
# theorem_regex = r"((((theorem|lemma) ([\S]*))|example)([\S|\s]*?)(:=|\|)[\s]*?)[\s]+"
|
|
29
|
+
# We ONLY support proofs which are written in tactic mode i.e. with := syntax
|
|
30
|
+
theorem_endings = r"(:=|(\|[\S|\s]*=>))"
|
|
31
|
+
theorem_end_regex = r"(theorem|lemma|example)([\s|\S]*?)(:=|=>)"
|
|
32
|
+
theorem_regex = r"((((theorem|lemma)[\s]+([\S]*))|example)([\S|\s]*?)(:=|=>)[\s]*?)[\s]+"
|
|
33
|
+
theorem_name_regex = r"(((theorem|lemma)[\s]+([\S]*))|example)"
|
|
34
|
+
remove_proof_regex = r"([\s|\S]*(:=|\|))[\s|\S]*?"
|
|
35
|
+
proof_context_separator = "⊢"
|
|
36
|
+
proof_context_regex = r"((\d+) goals)*([\s|\S]*?)\n\n"
|
|
37
|
+
goal_regex = rf"([\s|\S]*?){proof_context_separator}([\s|\S]*)"
|
|
38
|
+
theorem_match = re.compile(theorem_regex, re.MULTILINE)
|
|
39
|
+
theorem_name_match = re.compile(theorem_name_regex, re.MULTILINE)
|
|
40
|
+
proof_context_match = re.compile(proof_context_regex, re.MULTILINE)
|
|
41
|
+
goal_match = re.compile(goal_regex, re.MULTILINE)
|
|
42
|
+
theorem_start_match = re.compile(theorem_start_regex, re.MULTILINE)
|
|
43
|
+
theorem_end_match = re.compile(theorem_end_regex, re.MULTILINE)
|
|
44
|
+
remove_proof_match = re.compile(remove_proof_regex, re.MULTILINE)
|
|
45
|
+
proof_context_generation_tactic = "\nend"
|
|
46
|
+
proof_context_generation_tactic_curlies = "\n}"
|
|
47
|
+
proof_state_running_message = "tactic failed, there are unsolved goals\nstate:"
|
|
48
|
+
unsolved_message = "unsolved goals"
|
|
49
|
+
theorem_detection_message = "unexpected end of input; expected '{'"
|
|
50
|
+
extra_by = ' by\n'
|
|
51
|
+
def __init__(self,
|
|
52
|
+
project_root: Optional[str] = None,
|
|
53
|
+
prefix: Optional[str] = None,
|
|
54
|
+
main_file: Optional[str] = None,
|
|
55
|
+
use_hammer: bool = False,
|
|
56
|
+
timeout_in_sec: int = 60,
|
|
57
|
+
use_human_readable_proof_context: bool = True,
|
|
58
|
+
proof_step_iter: Optional[Iterator[str]] = None,
|
|
59
|
+
suppress_error_log: bool = False,
|
|
60
|
+
mathlib_root: Optional[str] = None,
|
|
61
|
+
enable_search: bool = False,
|
|
62
|
+
namespaces: Optional[List[str]] = None,
|
|
63
|
+
keep_local_context: bool = False,
|
|
64
|
+
logger: Optional[logging.Logger] = None):
|
|
65
|
+
assert proof_step_iter is None or isinstance(proof_step_iter, Iterator), \
|
|
66
|
+
"proof_step_iter must be an iterator"
|
|
67
|
+
assert main_file is not None or proof_step_iter is not None, \
|
|
68
|
+
"Either main_file or proof_step_iter must be provided"
|
|
69
|
+
assert main_file is None or proof_step_iter is None, \
|
|
70
|
+
"Only one of main_file or proof_step_iter must be provided"
|
|
71
|
+
assert main_file is None or (os.path.exists(main_file) and main_file.endswith(".lean")), \
|
|
72
|
+
f"main_file must be a valid path to a '.lean' file ({main_file})"
|
|
73
|
+
assert project_root is None or (os.path.exists(project_root) and os.path.isdir(project_root)), \
|
|
74
|
+
"project_root must be a valid path to a directory"
|
|
75
|
+
assert not use_hammer, "Hammer is not supported for Lean4"
|
|
76
|
+
self.use_human_readable_proof_context = use_human_readable_proof_context
|
|
77
|
+
self.project_root = project_root if project_root is not None else "."
|
|
78
|
+
self.main_file = main_file
|
|
79
|
+
self.ticks = str(time.time()).replace(".", "") # This ensures that the temp file name is unique and doesn't clash with other temp files
|
|
80
|
+
# This helps in running parallel instances of prover
|
|
81
|
+
self.random_num = str(random.randint(0, 100000000))
|
|
82
|
+
self.temp_filename_suffix = f"temptodel{self.ticks}{self.random_num}.lean"
|
|
83
|
+
self.temp_file = os.path.join(prefix, self.temp_filename_suffix) if prefix is not None else self.temp_filename_suffix
|
|
84
|
+
self.temp_file_full_path = os.path.join(self.project_root, self.temp_file)
|
|
85
|
+
self.temp_file_full_path = os.path.abspath(self.temp_file_full_path)
|
|
86
|
+
self.use_hammer = use_hammer
|
|
87
|
+
self.timeout_in_sec = min(timeout_in_sec, 120) # Maximum 120s timeout
|
|
88
|
+
self.current_stmt = None
|
|
89
|
+
self.line_num = 0
|
|
90
|
+
self.main_file_iter = proof_step_iter
|
|
91
|
+
self.suppress_error_log = suppress_error_log
|
|
92
|
+
self.process_interace : ProcessInterface = None
|
|
93
|
+
self.execution_complete = False
|
|
94
|
+
self._max_memory_in_mib = 40000 # 40 GiB is needed for mathlib to work seemlessly
|
|
95
|
+
self._lines_executed = []
|
|
96
|
+
self.proof_context : ProofContext = None
|
|
97
|
+
self.curr_lemma_name : Optional[str] = None
|
|
98
|
+
self.curr_lemma : Optional[str] = None
|
|
99
|
+
self.lean_error_messages : List[str] = []
|
|
100
|
+
self._proof_running = False
|
|
101
|
+
self._file_content = ""
|
|
102
|
+
self.local_file_lemmas: OrderedDict[str, str] = OrderedDict()
|
|
103
|
+
self.local_theorem_lemma_description: OrderedDict[str, str] = OrderedDict()
|
|
104
|
+
self._proof_start_idx: Optional[int] = None
|
|
105
|
+
self._import_end_idx: Optional[int] = None
|
|
106
|
+
self.logger = logger if logger is not None else logging.getLogger(__name__)
|
|
107
|
+
self.use_file = False
|
|
108
|
+
if mathlib_root is not None:
|
|
109
|
+
self._mathlib_root = mathlib_root
|
|
110
|
+
else:
|
|
111
|
+
self._mathlib_root = os.path.join(self.project_root, "_target", "deps", "mathlib")
|
|
112
|
+
self._mathlib_src_root = os.path.join(self._mathlib_root, "src")
|
|
113
|
+
self._enable_search = enable_search
|
|
114
|
+
self._theorem_started = False
|
|
115
|
+
self._content_till_last_theorem_stmt = None
|
|
116
|
+
self._last_theorem = None
|
|
117
|
+
self._last_env_idx = None
|
|
118
|
+
self._last_proof_state_idx = None
|
|
119
|
+
self._line_to_env_idx_map = {}
|
|
120
|
+
self._line_to_proof_state_idx_map = {}
|
|
121
|
+
self._anon_theorem_count = 0
|
|
122
|
+
self._namespaces = []
|
|
123
|
+
self._last_file_seek = 0
|
|
124
|
+
self._line_num_seek_map = {}
|
|
125
|
+
self._file_handle = None
|
|
126
|
+
self._in_tactic_mode = False
|
|
127
|
+
self._env_idx_last_thm = None
|
|
128
|
+
self._last_tactics = {}
|
|
129
|
+
self._last_tactic_line_idx = None
|
|
130
|
+
self._error_messages_so_far = set()
|
|
131
|
+
self._error_messages_since_last_thm = {}
|
|
132
|
+
self._run_exactly = False
|
|
133
|
+
self._lines_not_executed = []
|
|
134
|
+
self._extra_added: str = None
|
|
135
|
+
if self._enable_search:
|
|
136
|
+
pass
|
|
137
|
+
pass
|
|
138
|
+
|
|
139
|
+
def set_run_exactly(self):
|
|
140
|
+
self._run_exactly = True
|
|
141
|
+
|
|
142
|
+
def unset_run_exactly(self):
|
|
143
|
+
self._run_exactly = False
|
|
144
|
+
|
|
145
|
+
def run_exactly(self):
|
|
146
|
+
return self._run_exactly
|
|
147
|
+
|
|
148
|
+
def reset(self,
|
|
149
|
+
proof_step_iter: Optional[Iterator[str]] = None):
|
|
150
|
+
# Note: We CANNOT reset the main_file_iter as it is a generator
|
|
151
|
+
assert (proof_step_iter is not None and isinstance(proof_step_iter, Iterator)) or self.main_file is not None, \
|
|
152
|
+
"Either proof_step_iter must be provided or main_file must be set"
|
|
153
|
+
self.current_stmt = None
|
|
154
|
+
self.line_num = 0
|
|
155
|
+
self.main_file_iter = proof_step_iter if proof_step_iter is not None else self.main_file_iter
|
|
156
|
+
self.process_interace : ProcessInterface = None
|
|
157
|
+
self.execution_complete = False
|
|
158
|
+
self._lines_executed = []
|
|
159
|
+
self.proof_context : ProofContext = None
|
|
160
|
+
self.curr_lemma_name : Optional[str] = None
|
|
161
|
+
self.curr_lemma : Optional[str] = None
|
|
162
|
+
self.lean_error_messages : List[str] = []
|
|
163
|
+
self._proof_running = False
|
|
164
|
+
self._file_content = ""
|
|
165
|
+
self.local_file_lemmas: OrderedDict[str, str] = OrderedDict()
|
|
166
|
+
self.local_theorem_lemma_description: OrderedDict[str, str] = OrderedDict()
|
|
167
|
+
self._proof_start_idx: Optional[int] = None
|
|
168
|
+
self._import_end_idx: Optional[int] = None
|
|
169
|
+
self._theorem_started = False
|
|
170
|
+
self._content_till_last_theorem_stmt = None
|
|
171
|
+
self._last_theorem = None
|
|
172
|
+
self._last_env_idx = None
|
|
173
|
+
self._last_proof_state_idx = None
|
|
174
|
+
self._line_to_env_idx_map = {}
|
|
175
|
+
self._line_to_proof_state_idx_map = {}
|
|
176
|
+
self._anon_theorem_count = 0
|
|
177
|
+
self._namespaces = []
|
|
178
|
+
self._last_file_seek = 0
|
|
179
|
+
self._line_num_seek_map = {}
|
|
180
|
+
self._file_handle = None
|
|
181
|
+
self._in_tactic_mode = False
|
|
182
|
+
self._env_idx_last_thm = None
|
|
183
|
+
self._last_tactics = {}
|
|
184
|
+
self._last_tactic_line_idx = None
|
|
185
|
+
self._error_messages_so_far = set()
|
|
186
|
+
self._error_messages_since_last_thm = {}
|
|
187
|
+
if self._enable_search:
|
|
188
|
+
pass
|
|
189
|
+
pass
|
|
190
|
+
|
|
191
|
+
def __enter__(self):
|
|
192
|
+
tools_dir = os.path.dirname(__file__)
|
|
193
|
+
repl_path = os.path.join(tools_dir, "repl")
|
|
194
|
+
abs_path = os.path.abspath(repl_path)
|
|
195
|
+
path_to_repl_exec = os.path.join(abs_path, ".lake", "build", "bin", "repl")
|
|
196
|
+
if 'Mathlib' in self.project_root:
|
|
197
|
+
self.use_file = True
|
|
198
|
+
assert os.path.exists(path_to_repl_exec), f"Lean4 repl executable does not exist at {path_to_repl_exec}, you may need to build it"
|
|
199
|
+
self.process_interace = ProcessInterface(
|
|
200
|
+
command=f"lake env {path_to_repl_exec}",
|
|
201
|
+
cwd=self.project_root,
|
|
202
|
+
logger=self.logger,
|
|
203
|
+
log_level=self.logger.level)
|
|
204
|
+
if self.main_file_iter is None:
|
|
205
|
+
self.main_file_iter = LeanLineByLineReader(self.main_file, remove_comments=True, no_strip=True).instruction_step_generator()
|
|
206
|
+
return self
|
|
207
|
+
|
|
208
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
209
|
+
if self.process_interace is not None:
|
|
210
|
+
self.process_interace.close()
|
|
211
|
+
if self.main_file_iter is not None:
|
|
212
|
+
try:
|
|
213
|
+
self.main_file_iter.close() # Close the file handle
|
|
214
|
+
except:
|
|
215
|
+
pass
|
|
216
|
+
# delete if the main file is a temporary file
|
|
217
|
+
if self._file_handle is not None:
|
|
218
|
+
self._file_handle.close()
|
|
219
|
+
if os.path.exists(self.temp_file_full_path):
|
|
220
|
+
os.remove(self.temp_file_full_path)
|
|
221
|
+
|
|
222
|
+
def is_in_proof_mode(self):
|
|
223
|
+
return True if self.proof_context else (len(self.lean_error_messages) > 0) # It is still in proof mode if we encountered a wrong proof
|
|
224
|
+
|
|
225
|
+
def dry_run(self) -> bool:
|
|
226
|
+
try:
|
|
227
|
+
stmt = next(self.main_file_iter)
|
|
228
|
+
except StopIteration:
|
|
229
|
+
self.execution_complete = True
|
|
230
|
+
return False
|
|
231
|
+
self.current_stmt = stmt
|
|
232
|
+
self.line_num += 1
|
|
233
|
+
return True
|
|
234
|
+
|
|
235
|
+
def run_next(self) -> bool:
|
|
236
|
+
try:
|
|
237
|
+
lines = []
|
|
238
|
+
scanned_new_line = False
|
|
239
|
+
if self.run_exactly():
|
|
240
|
+
if len(self._lines_not_executed) > 0:
|
|
241
|
+
lines = self._lines_not_executed
|
|
242
|
+
next_line = lines[-1]
|
|
243
|
+
self._lines_not_executed = []
|
|
244
|
+
else:
|
|
245
|
+
next_line = next(self.main_file_iter)
|
|
246
|
+
lines.append(next_line)
|
|
247
|
+
scanned_new_line = True
|
|
248
|
+
if self._extra_added is not None:
|
|
249
|
+
# Check if the nextline begines with extra added ignoring space and tabs
|
|
250
|
+
if next_line.strip().startswith(self._extra_added.strip()):
|
|
251
|
+
# Remove the extra added in the next line and replace it with spaces
|
|
252
|
+
next_line = next_line.replace(self._extra_added, " " * len(self._extra_added), 1)
|
|
253
|
+
self._extra_added = None
|
|
254
|
+
else:
|
|
255
|
+
next_line = next(self.main_file_iter)
|
|
256
|
+
lines.append(next_line)
|
|
257
|
+
stmt = "\n".join(lines)
|
|
258
|
+
except StopIteration:
|
|
259
|
+
self.execution_complete = True
|
|
260
|
+
return False
|
|
261
|
+
self.current_stmt = next_line
|
|
262
|
+
self.line_num += 1
|
|
263
|
+
try:
|
|
264
|
+
idx = len(self._lines_executed)
|
|
265
|
+
self._run_stmt_on_lean_server(idx, stmt)
|
|
266
|
+
except:
|
|
267
|
+
if not self.suppress_error_log:
|
|
268
|
+
self.logger.error(f"Got an exception while running '{stmt}' on lean. File name: {self.main_file}")
|
|
269
|
+
self.logger.exception(f"Exception Log")
|
|
270
|
+
raise
|
|
271
|
+
if scanned_new_line:
|
|
272
|
+
self._lines_executed.append(next_line)
|
|
273
|
+
else:
|
|
274
|
+
self._lines_executed.append("") # Add an empty line to keep the line numbers in sync
|
|
275
|
+
return True
|
|
276
|
+
|
|
277
|
+
def needs_qed(self):
|
|
278
|
+
return self.proof_context is not None and len(self.proof_context.all_goals) == 0
|
|
279
|
+
|
|
280
|
+
def needs_cut_close(self):
|
|
281
|
+
return self.proof_context is not None and len(self.proof_context.fg_goals) == 0 and len(self.proof_context.all_goals) > 0
|
|
282
|
+
|
|
283
|
+
def run_next_without_exec(self) -> bool:
|
|
284
|
+
raise NotImplementedError
|
|
285
|
+
|
|
286
|
+
def run_all_without_exec(self) -> bool:
|
|
287
|
+
raise NotImplementedError
|
|
288
|
+
|
|
289
|
+
def find_all_theorems_names(self) -> List[Tuple[str, str]]:
|
|
290
|
+
raise NotImplementedError
|
|
291
|
+
|
|
292
|
+
def get_tokens_in_given_stmt(self, stmt: str, ignore_first_token: bool = False) -> Iterator[str]:
|
|
293
|
+
raise NotImplementedError
|
|
294
|
+
|
|
295
|
+
def tokenize(self, stmt: str) -> Iterator[str]:
|
|
296
|
+
raise NotImplementedError
|
|
297
|
+
|
|
298
|
+
def search_type_matching_defns(self, name: str) -> List:
|
|
299
|
+
raise NotImplementedError
|
|
300
|
+
|
|
301
|
+
def get_all_type_matching_defns(self, name: str) -> Iterator:
|
|
302
|
+
raise NotImplementedError
|
|
303
|
+
|
|
304
|
+
def search_exact(self, name: str) -> List:
|
|
305
|
+
raise NotImplementedError
|
|
306
|
+
|
|
307
|
+
def search_defn(self, name: str, match_until: Tuple[str], max_search_res: Optional[int] = None) -> List[Tuple[str, str, bool]]:
|
|
308
|
+
raise NotImplementedError
|
|
309
|
+
|
|
310
|
+
def run_without_executing(self, stmt: str):
|
|
311
|
+
while True:
|
|
312
|
+
try:
|
|
313
|
+
stmt = next(self.main_file_iter)
|
|
314
|
+
except StopIteration:
|
|
315
|
+
return
|
|
316
|
+
idx = len(self._lines_executed)
|
|
317
|
+
self._set_content_to_run(stmt)
|
|
318
|
+
if stmt.startswith("theorem") and self._import_end_idx is None:
|
|
319
|
+
self._import_end_idx = idx
|
|
320
|
+
self.current_stmt = stmt
|
|
321
|
+
self.line_num += 1
|
|
322
|
+
self._set_content_to_run(stmt)
|
|
323
|
+
self._lines_executed.append(stmt)
|
|
324
|
+
|
|
325
|
+
def run_lemma_without_executing(self):
|
|
326
|
+
while True:
|
|
327
|
+
try:
|
|
328
|
+
stmt = next(self.main_file_iter)
|
|
329
|
+
self.current_stmt = stmt
|
|
330
|
+
self.line_num += 1
|
|
331
|
+
if "Qed." in stmt or "Defined." in stmt or "Admitted." in stmt:
|
|
332
|
+
return True
|
|
333
|
+
except StopIteration:
|
|
334
|
+
return False
|
|
335
|
+
|
|
336
|
+
def run_till_next_lemma(self) -> Tuple[bool, Optional[str]]:
|
|
337
|
+
# Run the coq file until the next lemma is found
|
|
338
|
+
next_stmt = None
|
|
339
|
+
in_proof_mode = self.is_in_proof_mode()
|
|
340
|
+
if in_proof_mode or self.execution_complete:
|
|
341
|
+
# If we are already in proof mode, then we have already found a lemma
|
|
342
|
+
return False, next_stmt
|
|
343
|
+
prev_stmt = self.current_stmt
|
|
344
|
+
ran_last_cmd = self.run_next()
|
|
345
|
+
next_stmt = self.current_stmt
|
|
346
|
+
if not ran_last_cmd:
|
|
347
|
+
return False, None
|
|
348
|
+
assigned = False
|
|
349
|
+
while ran_last_cmd and not in_proof_mode:
|
|
350
|
+
if not assigned:
|
|
351
|
+
prev_stmt = next_stmt
|
|
352
|
+
ran_last_cmd = self.run_next()
|
|
353
|
+
in_proof_mode = self.is_in_proof_mode()
|
|
354
|
+
if not assigned:
|
|
355
|
+
next_stmt = self.current_stmt
|
|
356
|
+
if in_proof_mode:
|
|
357
|
+
assigned = True
|
|
358
|
+
lemma_name = next_stmt if next_stmt.startswith("Theorem") or next_stmt.startswith("Lemma") else prev_stmt
|
|
359
|
+
return in_proof_mode, lemma_name
|
|
360
|
+
|
|
361
|
+
def run_till_next_lemma_return_exec_stmt(self) -> Generator[str, None, None]:
|
|
362
|
+
# Run the coq file until the next lemma is found
|
|
363
|
+
next_stmt = None
|
|
364
|
+
in_proof_mode = self.is_in_proof_mode()
|
|
365
|
+
if in_proof_mode or self.execution_complete:
|
|
366
|
+
# If we are already in proof mode, then we have already found a lemma
|
|
367
|
+
yield from []
|
|
368
|
+
else:
|
|
369
|
+
ran_last_cmd = self.run_next()
|
|
370
|
+
next_stmt = self.current_stmt
|
|
371
|
+
if not ran_last_cmd:
|
|
372
|
+
yield from []
|
|
373
|
+
else:
|
|
374
|
+
yield next_stmt
|
|
375
|
+
while ran_last_cmd and not in_proof_mode:
|
|
376
|
+
ran_last_cmd = self.run_next()
|
|
377
|
+
next_stmt = self.current_stmt
|
|
378
|
+
if ran_last_cmd:
|
|
379
|
+
yield next_stmt
|
|
380
|
+
in_proof_mode = self.is_in_proof_mode()
|
|
381
|
+
|
|
382
|
+
def run_to_finish_lemma_return_exec(self) -> Generator[str, None, None]:
|
|
383
|
+
# Run the coq file until the next lemma is found
|
|
384
|
+
next_stmt = None
|
|
385
|
+
in_proof_mode = self.is_in_proof_mode()
|
|
386
|
+
if not in_proof_mode or self.execution_complete:
|
|
387
|
+
# If we are already in proof mode, then we have already found a lemma
|
|
388
|
+
yield from []
|
|
389
|
+
else:
|
|
390
|
+
ran_last_cmd = self.run_next()
|
|
391
|
+
next_stmt = self.current_stmt
|
|
392
|
+
if not ran_last_cmd:
|
|
393
|
+
yield from []
|
|
394
|
+
else:
|
|
395
|
+
yield next_stmt
|
|
396
|
+
while ran_last_cmd and in_proof_mode:
|
|
397
|
+
ran_last_cmd = self.run_next()
|
|
398
|
+
next_stmt = self.current_stmt
|
|
399
|
+
if ran_last_cmd:
|
|
400
|
+
yield next_stmt
|
|
401
|
+
in_proof_mode = self.is_in_proof_mode()
|
|
402
|
+
|
|
403
|
+
def run_to_finish_lemma(self) -> bool:
|
|
404
|
+
# Run the coq file and finish the current lemma
|
|
405
|
+
in_proof_mode = self.is_in_proof_mode()
|
|
406
|
+
if not in_proof_mode or self.execution_complete:
|
|
407
|
+
# If we are not in proof mode, then we are not finishing a lemma
|
|
408
|
+
return False
|
|
409
|
+
ran_last_cmd = self.run_next()
|
|
410
|
+
if not ran_last_cmd:
|
|
411
|
+
return False
|
|
412
|
+
while ran_last_cmd and in_proof_mode:
|
|
413
|
+
ran_last_cmd = self.run_next()
|
|
414
|
+
in_proof_mode = self.is_in_proof_mode()
|
|
415
|
+
return not in_proof_mode
|
|
416
|
+
|
|
417
|
+
def run_till_line_num(self, line_num: int):
|
|
418
|
+
assert line_num >= self.line_num
|
|
419
|
+
ran_last_cmd = True
|
|
420
|
+
while ran_last_cmd and self.line_num < line_num:
|
|
421
|
+
ran_last_cmd = self.run_next()
|
|
422
|
+
return self.line_num
|
|
423
|
+
|
|
424
|
+
def run_to_finish(self):
|
|
425
|
+
ran_last_cmd = True
|
|
426
|
+
while ran_last_cmd:
|
|
427
|
+
ran_last_cmd = self.run_next()
|
|
428
|
+
|
|
429
|
+
def get_lemma_name_if_running(self) -> Optional[str]:
|
|
430
|
+
if not self.is_in_proof_mode():
|
|
431
|
+
return None
|
|
432
|
+
else:
|
|
433
|
+
try:
|
|
434
|
+
return self.curr_lemma_name
|
|
435
|
+
except:
|
|
436
|
+
return None
|
|
437
|
+
|
|
438
|
+
def get_lemma_stmt_if_running(self) -> Optional[str]:
|
|
439
|
+
try:
|
|
440
|
+
return self.local_theorem_lemma_description[self.curr_lemma_name]
|
|
441
|
+
except:
|
|
442
|
+
return None
|
|
443
|
+
|
|
444
|
+
def get_current_lemma_name(self) -> Optional[str]:
|
|
445
|
+
if self.curr_lemma_name is None:
|
|
446
|
+
return None
|
|
447
|
+
else:
|
|
448
|
+
return self.curr_lemma_name
|
|
449
|
+
|
|
450
|
+
def _check_if_thm_read(self, idx: int, full_stmt: str) -> bool:
|
|
451
|
+
cmd = self._get_cmd_tactic_mode(idx, full_stmt)
|
|
452
|
+
self.process_interace.send_command(cmd)
|
|
453
|
+
timeout_in_secs = self.timeout_in_sec
|
|
454
|
+
response = self.process_interace.read_response(timeout_in_secs * 5)
|
|
455
|
+
relevant_msgs = []
|
|
456
|
+
parse_success = self._parse_response(idx, response, relevant_msgs)
|
|
457
|
+
if parse_success:
|
|
458
|
+
self._update_proof_context(idx, response, relevant_msgs)
|
|
459
|
+
return parse_success
|
|
460
|
+
|
|
461
|
+
def _parse_theorem_stmt(self, idx: int, stmt: str, do_full_check: bool = False, interesting_span: typing.Tuple[int, int] = None) -> str:
|
|
462
|
+
if interesting_span is not None:
|
|
463
|
+
span_start, span_end = interesting_span
|
|
464
|
+
full_stmt = stmt[span_start:span_end]
|
|
465
|
+
thm_name_matches = list(Lean4SyncExecutor.theorem_name_match.finditer(full_stmt))
|
|
466
|
+
if len(thm_name_matches) == 0:
|
|
467
|
+
return None
|
|
468
|
+
thm_end_style = '=>' if stmt.strip().endswith('=>') else ':='
|
|
469
|
+
thm_name_match = thm_name_matches[-1]
|
|
470
|
+
_, nspan_end = thm_name_match.span()
|
|
471
|
+
theorem_name = thm_name_match.group(4)
|
|
472
|
+
theorem_stmt = full_stmt[nspan_end:].strip().strip(thm_end_style)
|
|
473
|
+
else:
|
|
474
|
+
matches = list(Lean4SyncExecutor.theorem_match.finditer(stmt))
|
|
475
|
+
if len(matches) == 0:
|
|
476
|
+
return None
|
|
477
|
+
# We are only interested in the last theorem
|
|
478
|
+
match = matches[-1]
|
|
479
|
+
span_start, _ = match.span()
|
|
480
|
+
full_stmt = match.group(1)
|
|
481
|
+
theorem_name = match.group(5)
|
|
482
|
+
theorem_stmt = match.group(6)
|
|
483
|
+
thm_end_style = match.group(7)
|
|
484
|
+
if thm_end_style == "=>":
|
|
485
|
+
# Find the last '|' in the full_stmt
|
|
486
|
+
thm_end_idx = full_stmt.rfind('|')
|
|
487
|
+
if thm_end_idx == -1:
|
|
488
|
+
return None
|
|
489
|
+
else:
|
|
490
|
+
full_stmt = full_stmt[:thm_end_idx] + ' :='
|
|
491
|
+
thm_end_idx = theorem_stmt.rfind('|')
|
|
492
|
+
if thm_end_idx == -1:
|
|
493
|
+
return None
|
|
494
|
+
else:
|
|
495
|
+
theorem_stmt = theorem_stmt[:thm_end_idx]
|
|
496
|
+
if do_full_check:
|
|
497
|
+
check_stmt = stmt[:span_start] + full_stmt + Lean4SyncExecutor.extra_by
|
|
498
|
+
if self.run_exactly():
|
|
499
|
+
self._extra_added = Lean4SyncExecutor.extra_by
|
|
500
|
+
if not self._check_if_thm_read(idx, check_stmt):
|
|
501
|
+
return None
|
|
502
|
+
return theorem_name, theorem_stmt, full_stmt
|
|
503
|
+
|
|
504
|
+
def _execute_till_last_theorem(self, idx: int, full_stmt: str):
|
|
505
|
+
self._write_lean_file(idx, full_stmt)
|
|
506
|
+
self._run_file_on_lean_server(self.timeout_in_sec * 5)
|
|
507
|
+
|
|
508
|
+
def _stmt_has_lemma(self, idx: int, stmt: str, do_full_check: bool = False) -> bool:
|
|
509
|
+
# Match the theorem regex
|
|
510
|
+
has_content = self._content_till_last_theorem_stmt is not None
|
|
511
|
+
full_stmt = (stmt if self._content_till_last_theorem_stmt is None else self._content_till_last_theorem_stmt + '\n' + stmt) + '\n'
|
|
512
|
+
theorem_started = list(Lean4SyncExecutor.theorem_start_match.finditer(full_stmt))
|
|
513
|
+
theorem_ended = Lean4SyncExecutor.theorem_end_match.findall(full_stmt)
|
|
514
|
+
is_theorem_started = len(theorem_started) > 0
|
|
515
|
+
is_theorem_ended = len(theorem_ended) > 0
|
|
516
|
+
# Case one where the theorem has started and ended in the same line
|
|
517
|
+
self._content_till_last_theorem_stmt = full_stmt[:-1]
|
|
518
|
+
process_namespaces(full_stmt, self._namespaces, has_content)
|
|
519
|
+
if is_theorem_started and is_theorem_ended:
|
|
520
|
+
last_span_start, last_span_end = theorem_started[-1].span()
|
|
521
|
+
stmt_before_theorem = full_stmt[:last_span_start]
|
|
522
|
+
if len(stmt_before_theorem.strip()) > 0 and do_full_check:
|
|
523
|
+
# We need to run the statement before the theorem
|
|
524
|
+
self._execute_till_last_theorem(0, stmt_before_theorem)
|
|
525
|
+
self._content_till_last_theorem_stmt = self._content_till_last_theorem_stmt[last_span_start:]
|
|
526
|
+
last_span_end -= last_span_start
|
|
527
|
+
full_stmt = full_stmt[last_span_start:]
|
|
528
|
+
last_span_start = 0
|
|
529
|
+
# Look for all ':=' in the full_stmt
|
|
530
|
+
endings = [i for i in range(last_span_end, len(full_stmt)) if full_stmt.startswith(':=', i)]
|
|
531
|
+
last_thm = None
|
|
532
|
+
for ending in endings:
|
|
533
|
+
interesting_stmt = full_stmt[:ending] + ' := ' # We need to add ':=' to the end
|
|
534
|
+
if do_full_check and self.run_exactly():
|
|
535
|
+
remaining_stmt = full_stmt[ending + len(':='):]
|
|
536
|
+
else:
|
|
537
|
+
remaining_stmt = ''
|
|
538
|
+
interesting_span = (last_span_start, len(interesting_stmt))
|
|
539
|
+
# Make sure to remove the last tactic ran and add it again because we are changing the statement
|
|
540
|
+
if do_full_check:
|
|
541
|
+
self._backtrack_tactic_line(idx)
|
|
542
|
+
last_thm = self._parse_theorem_stmt(idx, interesting_stmt, do_full_check, interesting_span)
|
|
543
|
+
if last_thm is not None:
|
|
544
|
+
if do_full_check and self.run_exactly():
|
|
545
|
+
self._backtrack_tactic_line(idx)
|
|
546
|
+
# Remove the extra added
|
|
547
|
+
self._extra_added: str = None
|
|
548
|
+
self._lines_not_executed.append(full_stmt[:last_span_start] + last_thm[2])
|
|
549
|
+
self._lines_not_executed.append(remaining_stmt)
|
|
550
|
+
self._content_till_last_theorem_stmt = full_stmt[:last_span_start] + last_thm[2] + remaining_stmt
|
|
551
|
+
else:
|
|
552
|
+
self._content_till_last_theorem_stmt = full_stmt[:last_span_start] + last_thm[2] + Lean4SyncExecutor.extra_by
|
|
553
|
+
break
|
|
554
|
+
if last_thm is None:
|
|
555
|
+
endings = [i for i in range(last_span_end, len(full_stmt)) if full_stmt.startswith('=> ', i)]
|
|
556
|
+
for ending in endings:
|
|
557
|
+
interesting_stmt = full_stmt[:ending] + ' => ' # We need to add '=>' to the end
|
|
558
|
+
interesting_span = (last_span_start, len(interesting_stmt))
|
|
559
|
+
last_thm = self._parse_theorem_stmt(idx, interesting_stmt, do_full_check, interesting_span)
|
|
560
|
+
if last_thm is not None:
|
|
561
|
+
self._content_till_last_theorem_stmt = full_stmt[:last_span_start] + last_thm[2] + ' by\n'
|
|
562
|
+
break
|
|
563
|
+
else:
|
|
564
|
+
last_thm = None
|
|
565
|
+
self._theorem_started = last_thm is not None
|
|
566
|
+
is_theorem_started = self._theorem_started
|
|
567
|
+
is_theorem_ended = is_theorem_started and is_theorem_ended
|
|
568
|
+
if last_thm is not None:
|
|
569
|
+
self._last_theorem = last_thm
|
|
570
|
+
return is_theorem_started
|
|
571
|
+
|
|
572
|
+
def _get_env(self, idx) -> Optional[int]:
|
|
573
|
+
env_idx = None
|
|
574
|
+
if idx in self._line_to_env_idx_map:
|
|
575
|
+
env_idx = self._line_to_env_idx_map[idx]
|
|
576
|
+
else:
|
|
577
|
+
self._line_to_env_idx_map[idx] = self._last_env_idx
|
|
578
|
+
env_idx = self._last_env_idx
|
|
579
|
+
return env_idx
|
|
580
|
+
|
|
581
|
+
def _update_env(self, idx: int):
|
|
582
|
+
self._last_env_idx = idx
|
|
583
|
+
|
|
584
|
+
def _update_proof_state_idx(self, idx: int):
|
|
585
|
+
self._last_proof_state_idx = idx
|
|
586
|
+
|
|
587
|
+
def _should_start_proof(self, stmt: str) -> bool:
|
|
588
|
+
return self._theorem_started
|
|
589
|
+
|
|
590
|
+
def _remove_proof_add_sorry(self) -> str:
|
|
591
|
+
# Find the last ':= by' and replace it with 'sorry' and remove the rest of the proof
|
|
592
|
+
matches = list(Lean4SyncExecutor.theorem_end_match.finditer(self._content_till_last_theorem_stmt))
|
|
593
|
+
if len(matches) == 0:
|
|
594
|
+
raise ValueError(f"Could not find the proof in the statement: {self._content_till_last_theorem_stmt}")
|
|
595
|
+
last_match = matches[-1]
|
|
596
|
+
span_start, span_end = last_match.span()
|
|
597
|
+
full_stmt = self._content_till_last_theorem_stmt[:span_end]
|
|
598
|
+
thm_end_style = last_match.group(3)
|
|
599
|
+
if thm_end_style == "=>":
|
|
600
|
+
# Find the last '|' in the full_stmt
|
|
601
|
+
thm_end_idx = full_stmt.rfind('|', start = span_start)
|
|
602
|
+
if thm_end_idx == -1:
|
|
603
|
+
remaining_stmt = self._content_till_last_theorem_stmt[span_end:]
|
|
604
|
+
thm_end_idx = remaining_stmt.find(':=')
|
|
605
|
+
if thm_end_idx == -1:
|
|
606
|
+
raise ValueError(f"Could not find the start of proof in the statement: {self._content_till_last_theorem_stmt}")
|
|
607
|
+
full_stmt = full_stmt + remaining_stmt[:thm_end_idx] + ' :='
|
|
608
|
+
new_stmt = full_stmt
|
|
609
|
+
else:
|
|
610
|
+
full_stmt = full_stmt[:thm_end_idx] + ' :='
|
|
611
|
+
new_stmt = full_stmt
|
|
612
|
+
else:
|
|
613
|
+
new_stmt = full_stmt
|
|
614
|
+
if not self.use_file:
|
|
615
|
+
new_stmt += " by sorry"
|
|
616
|
+
else:
|
|
617
|
+
new_stmt += " by\n"
|
|
618
|
+
self._content_till_last_theorem_stmt = new_stmt
|
|
619
|
+
|
|
620
|
+
def _write_lean_file(self, idx: int, file_content: str):
|
|
621
|
+
if self._file_handle is None:
|
|
622
|
+
self._file_handle = open(self.temp_file_full_path, "a+")
|
|
623
|
+
self._last_file_seek = self._file_handle.tell()
|
|
624
|
+
self._line_num_seek_map[idx] = self._last_file_seek
|
|
625
|
+
self._file_handle.write(file_content)
|
|
626
|
+
self._file_handle.flush()
|
|
627
|
+
pass
|
|
628
|
+
|
|
629
|
+
def _get_error_msg(self, msg_idx, msg) -> str:
|
|
630
|
+
line_start = msg['pos']['line'] if msg['pos'] is not None else ""
|
|
631
|
+
line_end = msg['endPos']['line'] if msg['endPos'] is not None else ""
|
|
632
|
+
full_error_msg = str(msg_idx) + ' ' + str(line_start) + " - " + str(line_end) + ": " + str(msg['data'])
|
|
633
|
+
return full_error_msg
|
|
634
|
+
|
|
635
|
+
def _run_file_on_lean_server(self, timeout_in_sec: int, only_env_update: bool = False):
|
|
636
|
+
cmd = {"path": self.temp_file_full_path}
|
|
637
|
+
self.process_interace.send_command(cmd)
|
|
638
|
+
response = self.process_interace.read_response(timeout_in_sec)
|
|
639
|
+
relevant_msgs = []
|
|
640
|
+
self._parse_response(0, response, relevant_msgs)
|
|
641
|
+
self._update_proof_context(0, response, relevant_msgs, only_env_update)
|
|
642
|
+
return response
|
|
643
|
+
|
|
644
|
+
def _add_last_tactic(self, idx: int, stmt: str):
|
|
645
|
+
if idx not in self._last_tactics:
|
|
646
|
+
self._last_tactics[idx] = stmt
|
|
647
|
+
self._last_tactic_line_idx = idx
|
|
648
|
+
|
|
649
|
+
def _get_cmd_tactic_mode(self, idx: int, stmt: str):
|
|
650
|
+
self._add_last_tactic(idx, stmt)
|
|
651
|
+
tactics_so_far = [(k, v) for k, v in self._last_tactics.items()]
|
|
652
|
+
tactics_so_far = sorted(tactics_so_far, key=lambda x: x[0])
|
|
653
|
+
tactics_so_far = [v for _, v in tactics_so_far]
|
|
654
|
+
if self._env_idx_last_thm is None:
|
|
655
|
+
return {"cmd": "\n".join(tactics_so_far)}
|
|
656
|
+
else:
|
|
657
|
+
return {"cmd": "\n".join(tactics_so_far), "env": self._env_idx_last_thm}
|
|
658
|
+
|
|
659
|
+
def _errors_since_last_thm(self, idx, error_message: str):
|
|
660
|
+
if idx not in self._error_messages_since_last_thm:
|
|
661
|
+
self._error_messages_since_last_thm[idx] = error_message
|
|
662
|
+
|
|
663
|
+
def _backtrack_tactic_line(self, idx: int):
|
|
664
|
+
# identify the keys to remove
|
|
665
|
+
idx_to_remove = []
|
|
666
|
+
backtracked = False
|
|
667
|
+
for k in self._last_tactics.keys():
|
|
668
|
+
if k >= idx:
|
|
669
|
+
idx_to_remove.append(k)
|
|
670
|
+
for k in idx_to_remove:
|
|
671
|
+
backtracked = True
|
|
672
|
+
del self._last_tactics[k]
|
|
673
|
+
idx_to_remove = []
|
|
674
|
+
for k in self._error_messages_since_last_thm.keys():
|
|
675
|
+
if k >= idx:
|
|
676
|
+
idx_to_remove.append(k)
|
|
677
|
+
for k in idx_to_remove:
|
|
678
|
+
backtracked = True
|
|
679
|
+
msg = self._error_messages_since_last_thm[k]
|
|
680
|
+
if msg in self._error_messages_so_far:
|
|
681
|
+
self._error_messages_so_far.remove(msg)
|
|
682
|
+
del self._error_messages_since_last_thm[k]
|
|
683
|
+
self._last_tactic_line_idx = max(self._last_tactics.keys(), default=None)
|
|
684
|
+
return backtracked
|
|
685
|
+
|
|
686
|
+
def _clear_tacitcs(self):
|
|
687
|
+
tactics_so_far = [(k, v) for k, v in self._last_tactics.items()]
|
|
688
|
+
tactics_so_far = sorted(tactics_so_far, key=lambda x: x[0])
|
|
689
|
+
tactics_so_far = [v for _, v in tactics_so_far]
|
|
690
|
+
self._write_lean_file(self._last_tactic_line_idx, "\n".join(tactics_so_far))
|
|
691
|
+
self._last_tactics = {}
|
|
692
|
+
self._last_tactic_line_idx = None
|
|
693
|
+
self._error_messages_since_last_thm = {}
|
|
694
|
+
pass
|
|
695
|
+
|
|
696
|
+
def get_all_proofs_in_file(self) -> Dict[str, List[Tuple[ProofContext, str]]]:
|
|
697
|
+
assert self.main_file is not None, "Main file is not provided"
|
|
698
|
+
abs_main_file = os.path.abspath(self.main_file)
|
|
699
|
+
assert os.path.exists(abs_main_file), f"Main file does not exist at {abs_main_file}"
|
|
700
|
+
assert abs_main_file.endswith(".lean"), "Main file must be a '.lean' file"
|
|
701
|
+
temp_file = os.path.join(self.project_root, self.temp_filename_suffix)
|
|
702
|
+
abs_temp_file = os.path.abspath(temp_file)
|
|
703
|
+
# Copy the file to a temporary file
|
|
704
|
+
shutil.copyfile(abs_main_file, abs_temp_file)
|
|
705
|
+
try:
|
|
706
|
+
abs_main_file = abs_temp_file
|
|
707
|
+
# Remove all the comments from the file
|
|
708
|
+
line_by_line_reader = LeanLineByLineReader(abs_main_file, remove_comments=True, no_strip=True)
|
|
709
|
+
all_stmts = list(line_by_line_reader.instruction_step_generator())
|
|
710
|
+
new_content = "\n".join(all_stmts)
|
|
711
|
+
with open(abs_main_file, "w") as f:
|
|
712
|
+
f.write(new_content)
|
|
713
|
+
# Run the file on the lean server
|
|
714
|
+
self.process_interace.send_command({"path": abs_main_file, "allTactics": True})
|
|
715
|
+
response = self.process_interace.read_response(self.timeout_in_sec*20)
|
|
716
|
+
tactics_resp = response.get('tactics', [])
|
|
717
|
+
# Parse all goals in these tactics
|
|
718
|
+
goals = [self._parse_proof_context([t['goals']]) for t in tactics_resp]
|
|
719
|
+
tactics = [t['tactic'] for t in tactics_resp]
|
|
720
|
+
line_nums = [t['pos']['line'] for t in tactics_resp]
|
|
721
|
+
line_num_dx = 0
|
|
722
|
+
result = {}
|
|
723
|
+
thm_id = uuid.uuid4().hex
|
|
724
|
+
thm_cnt = 0
|
|
725
|
+
all_theorems = get_all_theorems_in_file(abs_main_file, use_cache = True)
|
|
726
|
+
line_to_thm_map : typing.Dict[int, TheoremDetails] = {}
|
|
727
|
+
for thm_detail in all_theorems:
|
|
728
|
+
line_num = thm_detail.theorem_pos['line_start']
|
|
729
|
+
line_to_thm_map[line_num] = thm_detail
|
|
730
|
+
with open(abs_main_file, "r") as f:
|
|
731
|
+
lines = f.readlines()
|
|
732
|
+
for idx, line in enumerate(lines):
|
|
733
|
+
if Lean4SyncExecutor.theorem_start_match.match(line):
|
|
734
|
+
thm_detail = line_to_thm_map.get(idx + 1, None)
|
|
735
|
+
if thm_detail is not None:
|
|
736
|
+
thm_id = get_fully_qualified_theorem_name(thm_detail)
|
|
737
|
+
else:
|
|
738
|
+
thm_id = uuid.uuid4().hex + f"_{thm_cnt}"
|
|
739
|
+
thm_cnt += 1
|
|
740
|
+
while line_num_dx < len(line_nums) and line_nums[line_num_dx] == idx + 1:
|
|
741
|
+
if thm_id not in result:
|
|
742
|
+
result[thm_id] = [(goals[line_num_dx], tactics[line_num_dx])]
|
|
743
|
+
else:
|
|
744
|
+
result[thm_id].append((goals[line_num_dx], tactics[line_num_dx]))
|
|
745
|
+
line_num_dx += 1
|
|
746
|
+
return result
|
|
747
|
+
finally:
|
|
748
|
+
if os.path.exists(temp_file):
|
|
749
|
+
os.remove(temp_file)
|
|
750
|
+
|
|
751
|
+
def _theorem_started_init(self):
|
|
752
|
+
if self._theorem_started:
|
|
753
|
+
theorem_name, theorem_stmt, full_stmt = self._last_theorem
|
|
754
|
+
self.curr_lemma_name = theorem_name
|
|
755
|
+
self.curr_lemma = theorem_stmt
|
|
756
|
+
if len(theorem_name) == 0:
|
|
757
|
+
self._anon_theorem_count += 1
|
|
758
|
+
theorem_name = f"anon_theorem____{self._anon_theorem_count}"
|
|
759
|
+
self.local_file_lemmas[theorem_name] = theorem_stmt
|
|
760
|
+
self.local_theorem_lemma_description[theorem_name] = full_stmt
|
|
761
|
+
|
|
762
|
+
def _parse_response(self, idx, response, relevant_messages = [], dont_update_error_since_last_thm = True) -> bool:
|
|
763
|
+
has_cnt = 0
|
|
764
|
+
has_at_least_one_unfocussed_goal = 0
|
|
765
|
+
has_new_errors = 0
|
|
766
|
+
if 'messages' in response:
|
|
767
|
+
messages = response['messages']
|
|
768
|
+
# Go over all sev after the line number and check if there is an error
|
|
769
|
+
for msg_idx, msg in enumerate(messages):
|
|
770
|
+
full_error_msg = self._get_error_msg(msg_idx, msg)
|
|
771
|
+
unsolved_goal_never_seen_before = not (full_error_msg in self._error_messages_since_last_thm.values())
|
|
772
|
+
if msg['severity'] == 'error' and 'pos' in msg and 'endPos' in msg and \
|
|
773
|
+
((msg['endPos'] is not None and 'line' in msg['endPos']) or \
|
|
774
|
+
(msg['pos'] is not None and 'line' in msg['pos'])):
|
|
775
|
+
if msg['data'].startswith(Lean4SyncExecutor.theorem_detection_message) and msg['endPos'] is None:
|
|
776
|
+
has_cnt += 1
|
|
777
|
+
continue # Ignore this error
|
|
778
|
+
saw_unsolved_goal = False
|
|
779
|
+
if msg['data'].startswith(Lean4SyncExecutor.unsolved_message):
|
|
780
|
+
has_at_least_one_unfocussed_goal += 1
|
|
781
|
+
saw_unsolved_goal = True
|
|
782
|
+
if full_error_msg in self._error_messages_so_far and (dont_update_error_since_last_thm or unsolved_goal_never_seen_before):
|
|
783
|
+
continue
|
|
784
|
+
else:
|
|
785
|
+
if not saw_unsolved_goal:
|
|
786
|
+
has_new_errors += 1
|
|
787
|
+
self._error_messages_so_far.add(full_error_msg)
|
|
788
|
+
if not dont_update_error_since_last_thm:
|
|
789
|
+
self._errors_since_last_thm(idx, full_error_msg)
|
|
790
|
+
if not unsolved_goal_never_seen_before:
|
|
791
|
+
msg['data'] = 'error: ' + msg['data']
|
|
792
|
+
relevant_messages.append(msg)
|
|
793
|
+
elif msg['severity'] == 'warning' and 'pos' in msg and 'endPos' in msg and 'sorry' in msg['data']:
|
|
794
|
+
full_error_msg = self._get_error_msg(msg_idx, msg)
|
|
795
|
+
if full_error_msg in self._error_messages_so_far and (dont_update_error_since_last_thm or unsolved_goal_never_seen_before):
|
|
796
|
+
continue
|
|
797
|
+
self._error_messages_so_far.add(full_error_msg)
|
|
798
|
+
if not dont_update_error_since_last_thm:
|
|
799
|
+
self._errors_since_last_thm(idx, full_error_msg)
|
|
800
|
+
if not unsolved_goal_never_seen_before:
|
|
801
|
+
msg['data'] = 'error: ' + msg['data']
|
|
802
|
+
relevant_messages.append(msg)
|
|
803
|
+
elif 'message' in response and 'proofState' not in response and 'sorries' not in response:
|
|
804
|
+
self.lean_error_messages = [response['message']]
|
|
805
|
+
# There is an irrecoverable error
|
|
806
|
+
if not self.process_interace.process_is_running():
|
|
807
|
+
raise Exception("Lean server got killed, probably due to an error in the line executed.\n" +
|
|
808
|
+
f"Check the error message: {self.lean_error_messages}")
|
|
809
|
+
return has_cnt == 1 and has_at_least_one_unfocussed_goal > 0 and has_new_errors == 0
|
|
810
|
+
|
|
811
|
+
def _update_proof_context(self, idx, response, relevant_messages, only_env_update = False):
|
|
812
|
+
if response is None:
|
|
813
|
+
raise ValueError(f"Response is None cannot update proof context for line number {idx}")
|
|
814
|
+
if 'env' in response:
|
|
815
|
+
env_idx = response['env']
|
|
816
|
+
else:
|
|
817
|
+
env_idx = None
|
|
818
|
+
if self._env_idx_last_thm is None and not self._proof_running:
|
|
819
|
+
self._env_idx_last_thm = self._last_env_idx
|
|
820
|
+
self._update_env(env_idx)
|
|
821
|
+
if self._env_idx_last_thm is None and not self._proof_running:
|
|
822
|
+
# This should run for the first time to set the env correctly
|
|
823
|
+
self._env_idx_last_thm = self._last_env_idx
|
|
824
|
+
if only_env_update:
|
|
825
|
+
self._env_idx_last_thm = self._last_env_idx
|
|
826
|
+
return
|
|
827
|
+
proof_running = 'sorries' in response or 'proofState' in response
|
|
828
|
+
error_messages = response.get('message', None)
|
|
829
|
+
goal_text = None
|
|
830
|
+
if error_messages is None and 'proofState' in response:
|
|
831
|
+
error_messages = response.get('messages', None)
|
|
832
|
+
elif error_messages is None:
|
|
833
|
+
# Go over all the relevant messages and see if there are messages other than unproved goals
|
|
834
|
+
error_messages = []
|
|
835
|
+
for msg in relevant_messages:
|
|
836
|
+
text_msg = msg.get('data', None)
|
|
837
|
+
if text_msg is not None and text_msg.startswith(Lean4SyncExecutor.unsolved_message):
|
|
838
|
+
goal_text = text_msg[len(Lean4SyncExecutor.unsolved_message):]
|
|
839
|
+
else:
|
|
840
|
+
error_messages.append(msg)
|
|
841
|
+
if len(error_messages) == 0:
|
|
842
|
+
error_messages = None
|
|
843
|
+
if len(relevant_messages) == 0:
|
|
844
|
+
goal_text = ''
|
|
845
|
+
elif error_messages is not None:
|
|
846
|
+
error_messages = [error_messages]
|
|
847
|
+
if error_messages is not None:
|
|
848
|
+
self.lean_error_messages = []
|
|
849
|
+
for error_message in error_messages:
|
|
850
|
+
if isinstance(error_message, dict):
|
|
851
|
+
error_message = error_message['severity'] + ": " + error_message['data']
|
|
852
|
+
else:
|
|
853
|
+
error_message = str(error_message)
|
|
854
|
+
self.lean_error_messages.append(error_message)
|
|
855
|
+
else:
|
|
856
|
+
self.lean_error_messages = []
|
|
857
|
+
proof_running = proof_running or goal_text is not None
|
|
858
|
+
if error_messages is None:
|
|
859
|
+
assert proof_running, f"Proof is not running but no error message is present, response:\n{response}, \nstmt: \n{stmt}, \nlemma: \n{self.curr_lemma_name}, \nlemma_stmt: \n{self.curr_lemma}, \nline_num: \n{self.line_num}"
|
|
860
|
+
self._proof_running = proof_running
|
|
861
|
+
if self._proof_running:
|
|
862
|
+
proof_state_idx = None
|
|
863
|
+
proof_goals = []
|
|
864
|
+
if goal_text is not None:
|
|
865
|
+
if len(goal_text) == 0:
|
|
866
|
+
proof_goals = []
|
|
867
|
+
else:
|
|
868
|
+
proof_goals = [goal_text]
|
|
869
|
+
elif 'sorries' in response:
|
|
870
|
+
sorries = response['sorries']
|
|
871
|
+
# TODO: Go over all the sorries and find the one which matches the line number with idx + 1
|
|
872
|
+
# Now we are only supporting the last sorry
|
|
873
|
+
proof_state = sorries[-1]
|
|
874
|
+
proof_state_idx = proof_state['proofState']
|
|
875
|
+
proof_goals = [proof_state['goal']]
|
|
876
|
+
elif 'proofState' in response:
|
|
877
|
+
proof_state = response
|
|
878
|
+
proof_state_idx = response['proofState']
|
|
879
|
+
proof_goals = response['goals']
|
|
880
|
+
self._update_proof_state_idx(proof_state_idx)
|
|
881
|
+
self.proof_context = self._parse_proof_context(proof_goals)
|
|
882
|
+
if self.proof_context == ProofContext.empty():
|
|
883
|
+
self._proof_running = False
|
|
884
|
+
self.proof_context = None
|
|
885
|
+
self.curr_lemma = None
|
|
886
|
+
self.curr_lemma_name = None
|
|
887
|
+
self._clear_tacitcs()
|
|
888
|
+
self._env_idx_last_thm = self._last_env_idx
|
|
889
|
+
else:
|
|
890
|
+
self.proof_context = None
|
|
891
|
+
|
|
892
|
+
def _run_stmt_on_lean_server(self, idx : int, stmt: str, theorem_started: bool = False):
|
|
893
|
+
if "sorry" in stmt and self._proof_running:
|
|
894
|
+
# We don't need to run the sorry statements. This should be treated as a failed proof step
|
|
895
|
+
self.lean_error_messages = ["The tactic 'sorry' was found in the statement, this is not allowed"]
|
|
896
|
+
return
|
|
897
|
+
elif len(stmt.strip()) == 0 and self._proof_running:
|
|
898
|
+
# We don't need to run the empty statements. This should be treated as a failed proof step
|
|
899
|
+
self.lean_error_messages = ["There is no tactic in the statement, it is just empty line or whitespace"]
|
|
900
|
+
return
|
|
901
|
+
proof_should_run = False
|
|
902
|
+
if theorem_started or (not self._proof_running and self._stmt_has_lemma(idx, stmt, do_full_check = True)):
|
|
903
|
+
proof_should_run = self._theorem_started
|
|
904
|
+
self._theorem_started_init()
|
|
905
|
+
if not self._proof_running and not proof_should_run:
|
|
906
|
+
return
|
|
907
|
+
env_idx = self._get_env(idx)
|
|
908
|
+
cmd_was_executed = False
|
|
909
|
+
response = None
|
|
910
|
+
while not cmd_was_executed:
|
|
911
|
+
# Run the statement in tactic mode
|
|
912
|
+
if self._env_idx_last_thm is None:
|
|
913
|
+
self._env_idx_last_thm = env_idx
|
|
914
|
+
if self.process_interace.is_rebooted():
|
|
915
|
+
self._run_file_on_lean_server(self.timeout_in_sec * 5, only_env_update=True)
|
|
916
|
+
cmd = self._get_cmd_tactic_mode(idx, stmt)
|
|
917
|
+
if env_idx is not None and 'env' not in cmd:
|
|
918
|
+
cmd["env"] = env_idx
|
|
919
|
+
self.process_interace.send_command(cmd)
|
|
920
|
+
self._content_till_last_theorem_stmt = None
|
|
921
|
+
timed_out = False
|
|
922
|
+
try:
|
|
923
|
+
timed_out_in_secs = self.timeout_in_sec
|
|
924
|
+
response = self.process_interace.read_response(timed_out_in_secs)
|
|
925
|
+
relevant_messages = []
|
|
926
|
+
self._parse_response(idx, response, relevant_messages, dont_update_error_since_last_thm=False)
|
|
927
|
+
cmd_was_executed = True
|
|
928
|
+
except TimeoutError:
|
|
929
|
+
if not self.suppress_error_log:
|
|
930
|
+
self.logger.error(f"Timeout error while running '{stmt}' on lean. File name: {self.main_file}")
|
|
931
|
+
timed_out = True
|
|
932
|
+
cmd_was_executed = True
|
|
933
|
+
except:
|
|
934
|
+
if not self.suppress_error_log:
|
|
935
|
+
self.logger.error(f"Got an exception while running '{stmt}' on lean. File name: {self.main_file}")
|
|
936
|
+
self.logger.exception(f"Exception Log")
|
|
937
|
+
cmd_was_executed = True
|
|
938
|
+
if cmd_was_executed:
|
|
939
|
+
raise
|
|
940
|
+
if timed_out:
|
|
941
|
+
self.lean_error_messages = ["The tactic timed out, probably because of repeated application of a tactic which created a very big goal."]
|
|
942
|
+
else:
|
|
943
|
+
self._update_proof_context(idx, response, relevant_messages)
|
|
944
|
+
pass
|
|
945
|
+
|
|
946
|
+
def _skip_to_theorem(self, theorem: str):
|
|
947
|
+
# Skip to the given theorem
|
|
948
|
+
found_theorem = False
|
|
949
|
+
thm_namespace, given_theorem_name = parse_thm_name(theorem)
|
|
950
|
+
while not found_theorem and not self.execution_complete:
|
|
951
|
+
try:
|
|
952
|
+
stmt = next(self.main_file_iter)
|
|
953
|
+
except StopIteration:
|
|
954
|
+
self.execution_complete = True
|
|
955
|
+
break
|
|
956
|
+
self.current_stmt = stmt
|
|
957
|
+
self.line_num += 1
|
|
958
|
+
if self._stmt_has_lemma(self.line_num - 1, stmt):
|
|
959
|
+
proof_should_run = self._should_start_proof(stmt)
|
|
960
|
+
if proof_should_run:
|
|
961
|
+
thm_name, thm_stmt, full_thm_stmt = self._last_theorem
|
|
962
|
+
last_namespace = ".".join(self._namespaces) if len(self._namespaces) > 0 else ""
|
|
963
|
+
if thm_name is not None and thm_name == given_theorem_name and (len(thm_namespace) == 0 or thm_namespace == last_namespace):
|
|
964
|
+
found_theorem = True
|
|
965
|
+
orig_thm_started = self._theorem_started
|
|
966
|
+
self._theorem_started = True
|
|
967
|
+
self._content_till_last_theorem_stmt = '\n'.join(self._lines_executed)
|
|
968
|
+
if self._stmt_has_lemma(self.line_num - 1, stmt, do_full_check=True):
|
|
969
|
+
self._theorem_started_init()
|
|
970
|
+
else:
|
|
971
|
+
found_theorem = False
|
|
972
|
+
self._theorem_started = orig_thm_started
|
|
973
|
+
else:
|
|
974
|
+
if thm_name is None or len(thm_name) == 0:
|
|
975
|
+
self._anon_theorem_count += 1
|
|
976
|
+
thm_name = f"anon_theorem____{self._anon_theorem_count}"
|
|
977
|
+
self.local_file_lemmas[thm_name] = thm_stmt
|
|
978
|
+
self.local_theorem_lemma_description[thm_name] = full_thm_stmt
|
|
979
|
+
self._content_till_last_theorem_stmt = None
|
|
980
|
+
self._lines_executed.append(stmt)
|
|
981
|
+
if not found_theorem:
|
|
982
|
+
raise ValueError(f"The theorem '{theorem}' was not found in the file '{self.main_file}'")
|
|
983
|
+
|
|
984
|
+
def _parse_proof_context(self, proof_goals: list) -> ProofContext:
|
|
985
|
+
goals = []
|
|
986
|
+
for proof_goal in proof_goals:
|
|
987
|
+
if self.use_human_readable_proof_context:
|
|
988
|
+
goals.extend(Lean4Utils.parse_proof_context_human_readable_as_goals(proof_goal))
|
|
989
|
+
else:
|
|
990
|
+
raise NotImplementedError("Parsing of non-human readable proof context is not implemented")
|
|
991
|
+
if len(goals) == 0:
|
|
992
|
+
return ProofContext.empty()
|
|
993
|
+
else:
|
|
994
|
+
return ProofContext(goals, [], [], [])
|
|
995
|
+
|
|
996
|
+
|
|
997
|
+
theorem_names_in_file_cache: Dict[str, List[TheoremDetails]] = {}
|
|
998
|
+
namespace_regex = r"^namespace[ ]+([\S]+)"
|
|
999
|
+
namespace_match = re.compile(namespace_regex, re.MULTILINE)
|
|
1000
|
+
namespace_end_regex = r"^end[ ]+([\S]+)*"
|
|
1001
|
+
namespace_end_match = re.compile(namespace_end_regex, re.MULTILINE)
|
|
1002
|
+
|
|
1003
|
+
def parse_thm_name(theorem_name: str) -> Tuple[str, str]:
|
|
1004
|
+
if theorem_name.startswith("{") and theorem_name.endswith("}"):
|
|
1005
|
+
thm_dict = json.loads(theorem_name)
|
|
1006
|
+
return thm_dict["namespace"], thm_dict["name"]
|
|
1007
|
+
else:
|
|
1008
|
+
return "", theorem_name
|
|
1009
|
+
|
|
1010
|
+
def process_namespaces(file_cotent: str, open_namespaces: List[str], is_full_content: bool=False):
|
|
1011
|
+
# Match the namespace regex
|
|
1012
|
+
# Break the content line by line and match the namespace and end namespace
|
|
1013
|
+
file_lines = file_cotent.split('\n')
|
|
1014
|
+
for line in file_lines:
|
|
1015
|
+
namespace_matches = namespace_match.findall(line)
|
|
1016
|
+
namespace_end_matches = namespace_end_match.findall(line)
|
|
1017
|
+
for ns in namespace_matches:
|
|
1018
|
+
if not is_full_content or ns not in open_namespaces:
|
|
1019
|
+
open_namespaces.append(ns)
|
|
1020
|
+
for ns in namespace_end_matches:
|
|
1021
|
+
try:
|
|
1022
|
+
open_namespaces.remove(ns)
|
|
1023
|
+
except ValueError:
|
|
1024
|
+
pass
|
|
1025
|
+
|
|
1026
|
+
def get_all_theorems_in_file(file_path: str, use_cache: bool=False) -> List[TheoremDetails]:
|
|
1027
|
+
if use_cache and file_path in theorem_names_in_file_cache:
|
|
1028
|
+
return theorem_names_in_file_cache[file_path]
|
|
1029
|
+
file_content = ""
|
|
1030
|
+
open_namespaces = []
|
|
1031
|
+
with open(file_path, "r") as f:
|
|
1032
|
+
file_content = f.read()
|
|
1033
|
+
line_by_line_reader = LeanLineByLineReader(file_content=file_content, remove_comments=True, no_strip=True)
|
|
1034
|
+
all_stmts = list(line_by_line_reader.instruction_step_generator())
|
|
1035
|
+
line_positions = [0] + [len(stmt) + 1 for stmt in all_stmts]
|
|
1036
|
+
# Cumulative sum of the line positions
|
|
1037
|
+
for i in range(1, len(line_positions)):
|
|
1038
|
+
line_positions[i] += line_positions[i - 1]
|
|
1039
|
+
full_content = '\n'.join(all_stmts)
|
|
1040
|
+
# all_matches = Lean4SyncExecutor.theorem_match.findall(full_content)
|
|
1041
|
+
all_matches = list(Lean4SyncExecutor.theorem_match.finditer(full_content))
|
|
1042
|
+
all_theorems = []
|
|
1043
|
+
last_namespace_processed_idx = 0
|
|
1044
|
+
for match in all_matches:
|
|
1045
|
+
span_start, span_end = match.span()
|
|
1046
|
+
process_namespaces(full_content[last_namespace_processed_idx:span_start], open_namespaces)
|
|
1047
|
+
theorem_name = match.group(5)
|
|
1048
|
+
theorem_name = theorem_name if theorem_name is not None else f"\"{match.group(6).strip(': ')}\""
|
|
1049
|
+
theorem_namespace = '.'.join(open_namespaces) if len(open_namespaces) > 0 else ''
|
|
1050
|
+
line_number_start = bisect.bisect_left(line_positions, span_start)
|
|
1051
|
+
line_number_end = bisect.bisect_left(line_positions, span_end)
|
|
1052
|
+
theorem_pos = {
|
|
1053
|
+
'line_start': line_number_start + 1,
|
|
1054
|
+
'line_end': line_number_end + 1,
|
|
1055
|
+
'global_pos_start': span_start,
|
|
1056
|
+
'global_pos_end': span_end,
|
|
1057
|
+
'line_pos_start': span_start - line_positions[line_number_start] if line_number_start < len(line_positions) else 0,
|
|
1058
|
+
'line_pos_end': span_end - line_positions[line_number_end] if line_number_end < len(line_positions) else 0
|
|
1059
|
+
}
|
|
1060
|
+
theorem_details = TheoremDetails(
|
|
1061
|
+
theorem_name=theorem_name,
|
|
1062
|
+
theorem_namespace=theorem_namespace,
|
|
1063
|
+
theorem_file_path=file_path,
|
|
1064
|
+
theorem_pos=theorem_pos)
|
|
1065
|
+
all_theorems.append(theorem_details)
|
|
1066
|
+
last_namespace_processed_idx = span_end
|
|
1067
|
+
if use_cache:
|
|
1068
|
+
theorem_names_in_file_cache[file_path] = all_theorems
|
|
1069
|
+
return all_theorems
|
|
1070
|
+
|
|
1071
|
+
def get_fully_qualified_theorem_name(theorem_details: TheoremDetails) -> str:
|
|
1072
|
+
if len(theorem_details.theorem_namespace) == 0:
|
|
1073
|
+
return theorem_details.theorem_name
|
|
1074
|
+
else:
|
|
1075
|
+
dict_thm = {"namespace": theorem_details.theorem_namespace, "name": theorem_details.theorem_name}
|
|
1076
|
+
return json.dumps(dict_thm)
|
|
1077
|
+
|
|
1078
|
+
def get_theorem_name_resembling(file_path: str, theorem_name: str, use_cache: bool=False) -> Optional[str]:
|
|
1079
|
+
all_theorems = get_all_theorems_in_file(file_path, use_cache=use_cache)
|
|
1080
|
+
all_theorems_name_unique_map : Dict[str, List[TheoremDetails]] = {}
|
|
1081
|
+
for thm in all_theorems:
|
|
1082
|
+
if thm.theorem_name in all_theorems_name_unique_map:
|
|
1083
|
+
all_theorems_name_unique_map[thm.theorem_name].append(thm)
|
|
1084
|
+
else:
|
|
1085
|
+
all_theorems_name_unique_map[thm.theorem_name] = [thm]
|
|
1086
|
+
all_parts = theorem_name.split('.')
|
|
1087
|
+
thm_start_idx = len(all_parts) - 1
|
|
1088
|
+
thm_found = False
|
|
1089
|
+
while not thm_found and thm_start_idx >= 0:
|
|
1090
|
+
full_name = '.'.join(all_parts[thm_start_idx:])
|
|
1091
|
+
# look for any theorems matching with full_name
|
|
1092
|
+
thm_found = full_name in all_theorems_name_unique_map
|
|
1093
|
+
thm_start_idx -= 1
|
|
1094
|
+
if not thm_found:
|
|
1095
|
+
full_name = '_root_.' + full_name
|
|
1096
|
+
# look for any theorems matching with the full_name
|
|
1097
|
+
thm_found = full_name in all_theorems_name_unique_map
|
|
1098
|
+
if not thm_found:
|
|
1099
|
+
raise ValueError(f"The theorem '{theorem_name}' was not found in the file '{file_path}'")
|
|
1100
|
+
assert thm_found, "The theorem was not found some code bug in finding the theorem names"
|
|
1101
|
+
theorem_name_matches = all_theorems_name_unique_map[full_name]
|
|
1102
|
+
if len(theorem_name_matches) == 1:
|
|
1103
|
+
if len(theorem_name_matches[0].theorem_namespace) == 0:
|
|
1104
|
+
return theorem_name_matches[0].theorem_name
|
|
1105
|
+
else:
|
|
1106
|
+
dict_thm = {"namespace": theorem_name_matches[0].theorem_namespace, "name": theorem_name_matches[0].theorem_name}
|
|
1107
|
+
return json.dumps(dict_thm)
|
|
1108
|
+
else:
|
|
1109
|
+
# We need to find the namespace which matches with the theorem_name
|
|
1110
|
+
for thm in theorem_name_matches:
|
|
1111
|
+
if theorem_name.endswith(thm.theorem_namespace + '.' + thm.theorem_name) or\
|
|
1112
|
+
(theorem_name.strip() == thm.theorem_name and len(thm.theorem_namespace) == 0):
|
|
1113
|
+
dict_thm = {"namespace": thm.theorem_namespace, "name": thm.theorem_name}
|
|
1114
|
+
return json.dumps(dict_thm)
|
|
1115
|
+
raise ValueError(f"The theorem '{theorem_name}' was not found in the file '{file_path}'")
|
|
1116
|
+
|
|
1117
|
+
if __name__ == "__main__":
|
|
1118
|
+
from itp_interface.tools.log_utils import setup_logger
|
|
1119
|
+
import datetime
|
|
1120
|
+
project_root = 'data/test/Mathlib/'
|
|
1121
|
+
file_path = 'data/test/Mathlib/.lake/packages/mathlib/Mathlib/Computability/TuringMachine.lean'
|
|
1122
|
+
os.chdir(root_dir)
|
|
1123
|
+
assert os.path.exists(project_root), "Project root does not exist"
|
|
1124
|
+
assert os.path.exists(file_path), "File path does not exist"
|
|
1125
|
+
print("Finding all theorems in the file")
|
|
1126
|
+
all_theorems = get_all_theorems_in_file(file_path, use_cache=True)
|
|
1127
|
+
print(all_theorems)
|
|
1128
|
+
theorems_similar_to_test = get_theorem_name_resembling(file_path, "Turing.TM1to1.tr_supports", use_cache=True)
|
|
1129
|
+
print("Theorem similar to ", "Turing.TM1to1.tr_supports", " is ", theorems_similar_to_test)
|
|
1130
|
+
project_root = 'data/test/lean4_proj/'
|
|
1131
|
+
file_path = 'data/test/lean4_proj/Lean4Proj/Basic.lean'
|
|
1132
|
+
theorem_name = "Lean4Proj2.test3"
|
|
1133
|
+
theorems_similar_to_test = get_theorem_name_resembling(file_path, theorem_name, use_cache=True)
|
|
1134
|
+
print("Theorem similar to ", "Lean4Proj2.test", " is ", theorems_similar_to_test)
|
|
1135
|
+
project_root = 'data/test/Mathlib/'
|
|
1136
|
+
# theorem_name = 'WeierstrassCurve.Jacobian.equiv_of_Z_eq_zero'
|
|
1137
|
+
# file_path = 'data/test/Mathlib/.lake/packages/mathlib/Mathlib/AlgebraicGeometry/EllipticCurve/Jacobian.lean'
|
|
1138
|
+
theorem_name = 'LieSubmodule.coe_toSubmodule_mk'
|
|
1139
|
+
file_path = 'data/test/Mathlib/.lake/packages/mathlib/Mathlib/Algebra/Lie/Submodule.lean'
|
|
1140
|
+
theorems_similar_to_test = get_theorem_name_resembling(file_path, theorem_name, use_cache=True)
|
|
1141
|
+
date_time = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
|
1142
|
+
lean_exec_log_folder = f'.log/lean4_sync_executor/{date_time}'
|
|
1143
|
+
os.makedirs(lean_exec_log_folder, exist_ok=True)
|
|
1144
|
+
lean_exec_log_file = os.path.join(lean_exec_log_folder, "lean4_sync_executor.log")
|
|
1145
|
+
logger = setup_logger("Lean4SyncExecutor", lean_exec_log_file, level=logging.DEBUG, format='')
|
|
1146
|
+
# with Lean4SyncExecutor(main_file=file_path, project_root=project_root, logger=logger) as executor:
|
|
1147
|
+
# all_proofs = executor.get_all_proofs_in_file()
|
|
1148
|
+
# print(all_proofs)
|
|
1149
|
+
with Lean4SyncExecutor(main_file=file_path, project_root=project_root, logger=logger) as executor:
|
|
1150
|
+
executor.set_run_exactly()
|
|
1151
|
+
executor._skip_to_theorem(theorems_similar_to_test)
|
|
1152
|
+
assert executor.proof_context is not None, "Proof context should be present"
|
|
1153
|
+
proof_exec = False
|
|
1154
|
+
while not executor.execution_complete:
|
|
1155
|
+
if executor.proof_context is not None:
|
|
1156
|
+
proof_exec = True
|
|
1157
|
+
for goal in executor.proof_context.all_goals:
|
|
1158
|
+
for hyp in goal.hypotheses:
|
|
1159
|
+
print(hyp)
|
|
1160
|
+
print('-'*10)
|
|
1161
|
+
print(goal.goal)
|
|
1162
|
+
print('-'*20)
|
|
1163
|
+
executor.run_next()
|
|
1164
|
+
print("Current statement:", executor.current_stmt)
|
|
1165
|
+
if executor.proof_context is None and proof_exec:
|
|
1166
|
+
proof_exec = False
|
|
1167
|
+
print("Proof finished")
|
|
1168
|
+
break
|
|
1169
|
+
if executor.lean_error_messages:
|
|
1170
|
+
print("Error messages:\n", executor.lean_error_messages)
|
|
1171
|
+
|
|
1172
|
+
mathlib_test_file = 'data/test/Mathlib/.lake/packages/mathlib/Mathlib/Data/Nat/Bits.lean'
|
|
1173
|
+
project_root = 'data/test/Mathlib'
|
|
1174
|
+
assert os.path.exists(mathlib_test_file), "Mathlib test file does not exist"
|
|
1175
|
+
assert os.path.exists(project_root), "Project root does not exist"
|
|
1176
|
+
with Lean4SyncExecutor(main_file=mathlib_test_file, project_root=project_root, timeout_in_sec=120) as executor:
|
|
1177
|
+
executor._skip_to_theorem("one_bits")
|
|
1178
|
+
assert executor.proof_context is not None, "Proof context should be present"
|
|
1179
|
+
while not executor.execution_complete:
|
|
1180
|
+
if executor.proof_context is not None:
|
|
1181
|
+
for goal in executor.proof_context.all_goals:
|
|
1182
|
+
for hyp in goal.hypotheses:
|
|
1183
|
+
print(hyp)
|
|
1184
|
+
print('-'*10)
|
|
1185
|
+
print(goal.goal)
|
|
1186
|
+
print('-'*20)
|
|
1187
|
+
executor.run_next()
|
|
1188
|
+
print("Current statement:", executor.current_stmt)
|
|
1189
|
+
if executor.proof_context is None:
|
|
1190
|
+
print("Proof finished")
|
|
1191
|
+
break
|
|
1192
|
+
if executor.lean_error_messages:
|
|
1193
|
+
print("Error messages:\n", executor.lean_error_messages)
|