#! /usr/bin/python3 # Last edited on 2026-10-30 19:59:15 by stolfi import os, sys, re from sys import stderr as err from math import inf, isfinite import bimatching_eval_funcs as bef # import bitemplate_funcs as btf import bimatching_funcs as bmf import write_parsing_funcs as wpf import test_bipatterns as tb def all_tests(match_test_func, debug_level): # The {match_test_func} must take arguments {text0, text1, bitemp, un1_per_un0, debug_level} and # return {bimatch,score}. test_match_0(match_test_func, debug_level) test_match_3(match_test_func, debug_level, with_dain = False, with_AMENO = False) test_match_3(match_test_func, debug_level, with_dain = True, with_AMENO = False) test_match_3(match_test_func, debug_level, with_dain = False, with_AMENO = True ) test_match_1(match_test_func, debug_level, with_dain = False) test_match_1(match_test_func, debug_level, with_dain = True) test_match_2(match_test_func, debug_level) return # ---------------------------------------------------------------------- def test_match \ ( match_test_func, text0, pad0, text1, pad1, bitemp, un1_per_un0, bimatch_exp, score_exp, debug_level ): err.write("=== testing {match_bitemplate} ===\n") debug = False nh = len(bimatch_exp); ng = nh + 1; ns = ng + nh; nr = nh; # Find {bimatch_cmp[0..nr]}, the best matching of {bitemp}: err.write("matching ...\n") bimatch_cmp, score_cmp = match_test_func(text0, text1, bitemp, un1_per_un0, debug_level) assert (bimatch_cmp is None) == (bimatch_exp is None) assert isfinite(score_cmp) == isfinite(score_exp) if bimatch_cmp is not None: err.write(f"{score_cmp = :.8f}\n") nh = len(bimatch_exp) assert len(bimatch_cmp) == nh, f"wrong bimatch length {len(bimatch_cmp) = } {nh = }" err.write("bimatching:\n") bmf.write_bimatching(err, '', bimatch_cmp, text0, pad0, text1, pad1) err.write("extracting the segments ...\n") segs0, segs1, hit_penalties = bmf.extract_segments(text0, text1, bimatch_cmp) hit_str = [ f"{hp:5.3f}" for hp in hit_penalties ] err.write(f"hit penalties = {hit_str!r}\n") mpars = ((segs0, '?', pad0,), (segs1, '?', ' ',),) err.write("matching result:\n") wpf.write_parsings(err, "", True, mpars) bugs = 0 for ih in range(nh): ri_cmp = bimatch_cmp[ih][0:4] ri_exp = bimatch_exp[ih][0:4] if ri_cmp != ri_exp: err.write(f"** rung {ih} {ri_cmp = !r} {ri_exp = !r}\n") bugs += 1 assert bugs == 0, f"bimatch_cmp does not match expected" # Checking the score computation: err.write(f"checking computed score with expected score ...\n") if abs(score_cmp - score_exp) > 0.0005: err.write(f"** don't match: {score_cmp = :.8f} {score_exp = :.8f}\n") err.write(f"checking computed score with compute_full_score_from_macro_parsings ...\n") score_mac = bef.compute_full_score_from_macro_parsings \ ( segs0, segs1, un1_per_un0, hit_penalties ) if abs(score_cmp - score_mac) > 0.0005: err.write(f"** don't match: {score_cmp = :.8f} {score_mac = :.8f}\n") err.write("=================================\n") return # ---------------------------------------------------------------------- def test_match_0(match_test_func, debug_level): err.write(f"=== test_match_0() ===========\n") text0 = "...XX........XaX..." text1 = "...ZZ..ZaZ...ZaZ..." bipatA = ( ( 0.000, 'XX', 'YY', ), ( 0.020, 'XX', 'ZZ', ), ( 0.040, 'Xa?X', 'Za?Z', ), ) bitemp = ( bipatA, bipatA ) un1_per_un0 = 1.000 bimatch_exp = ( ( 3, 5, 3, 5 ), ( 13, 16, 13, 16 ), ) score_exp = 0.060 test_match \ ( match_test_func, text0, ' ', text1, ' ', bitemp, un1_per_un0, bimatch_exp, score_exp, debug_level ) return # ---------------------------------------------------------------------- def test_match_1(match_test_func, debug_level, with_dain): err.write("\n\n\n") err.write(f"=== test_match_1({with_dain=!r}) ===========\n") text0 = \ "主杀鬼肪主耳聋肠主遗溺肶胵裹黄皮" text1 = \ "daiinchsdqokeeeydaiinokaiinotaiindaiincheolkallkldaindoeeokcheeoltaiinotcheedychoraiino" if not with_dain: text1 = re.sub(r"dain", "xxxx", text1) bipat_USES = tb.test_bipattern('USES') bitemp = ( bipat_USES, bipat_USES, bipat_USES, ) un1_per_un0 = 5.000 score_exp = None bimatch_exp = None if with_dain: score_exp = 1.688 bimatch_exp = ( ( 0, 1, 0, 5 ), # 'daiin' ( 4, 5, 22, 27 ), # 'kaiin' ( 8, 9, 49, 53 ), # 'dain' ) else: score_exp = 2.309 bimatch_exp = ( ( 0, 1, 0, 5 ), # 'daiin' ( 4, 5, 16, 21 ), # 'daiin' ( 8, 9, 33, 38 ), # 'daiin' ) test_match \ ( match_test_func, text0, ' ', text1, ' ', bitemp, un1_per_un0, bimatch_exp, score_exp, debug_level ) return # ---------------------------------------------------------------------- def test_match_2(match_test_func, debug_level): err.write("\n\n\n") err.write(f"=== test_match_2() ===========\n") text0 = \ "蜂子主治风头除蛊毒补虚羸伤中久服令人光泽好颜色不老大黄蜂子主心腹胀满痛轻" + \ "身益气土蜂子主治痈肿" text1 = \ "deechdyopchedaiinypchedyodalychedyqopcheokaiinshedypodairochedalloiinchedy" + \ "qokaiinchdydaiindchdoseedolchdolkchedychokaiinchdyqoeedyokchedydaiiinchedy" + \ "daiinykeedyokeeedychedolchdaiinykardarycheold" + \ "chedydkchsaiinchdedyqodaiinokchedaiinchain" bipat_USES = tb.test_bipattern('USES') bipat_QI = tb.test_bipattern('QI') bipat_LONG = tb.test_bipattern('LONG') bitemp = ( bipat_USES, bipat_LONG, bipat_USES, bipat_QI, bipat_USES, ) un1_per_un0 = 5.000 score_exp = 2.053 bimatch_exp = ( ( 2, 3, 12, 17, ), # 'daiin' ( 14, 16, 85, 95, ), # 'daiind?chdos?' ( 29, 30, 148, 153, ), # 'daiin' ( 38, 39, 193, 198, ), # 'chedy' ( 42, 43, 215, 220, ), # 'daiin' ) test_match \ ( match_test_func, text0, ' ', text1, ' ', bitemp, un1_per_un0, bimatch_exp, score_exp, debug_level ) return # ---------------------------------------------------------------------- def test_match_3(match_test_func, debug_level, with_dain, with_AMENO): err.write("\n\n\n") err.write(f"=== test_match_3({with_dain=!r},{with_AMENO=!r}) ===========\n") # (w1a1d0g0) 74 hanzi text0 = \ "丹雄鸡主女人崩中漏下赤白沃补虚温中止血通神杀毒辟不祥头主杀鬼肪主耳聋肠主遗溺肶胵" + \ "裹黄皮主泄利屎白主消渴伤寒寒热翮羽主下血闭鸡子主除热火疮痫痉可作虎魄" assert len(text0) == 74 # 371 eva text1 = \ "poarkeeodaiinqoaiinaracpheeyqoeedeodyqokaiinqoteda" + \ "iinaporaiinapylsheodytaiinoteeyoteeoolotaiinokeeyq" + \ "okaiinoraiiinaldalsheeodaiinchsdqokeeeydaiinokaiin" + \ "otaiinchedaiinolkallkldaindoeeokcheeoltaiinotcheed" + \ "ychoraiinodaiinchedyotaiinalkaishdlaiinsheodokeeod" + \ "yqoaiinytaiinotaiinchdaldydaiiinchdaiinockheyyshey" + \ "ckhysheoqoeeolkaiinchsokoltchdysheeeyokaiinaraildy" + \ "cheodyoaiiinainokshey" assert len(text1) == 371 if not with_dain: text1 = re.sub(r"dain", "xxxx", text1) bipat_USES = tb.test_bipattern('USES') bipat_AMENO = tb.test_bipattern('AMENO') if with_AMENO: bitemp = ( bipat_USES, ) * 7 + ( bipat_AMENO, bipat_USES, ) else: bitemp = ( bipat_USES, ) * 8 un1_per_un0 = 5.000 score_exp = None bimatch_exp = None if with_AMENO: score_exp = 1.398 bimatch_exp = ( ( 3, 4, 8, 13), # 'daiin' ( 27, 28, 123, 128), # 'daiin' ( 31, 32, 139, 144), # 'daiin' ( 35, 36, 159, 164), # 'daiin' ( 43, 44, 204, 209), # 'raiin' ( 48, 49, 234, 239), # 'laiin' ( 57, 58, 284, 289), # 'daiin' ( 59, 61, 295, 304), # 'ysheyckhy' ( 63, 64, 314, 319), # 'laiin' ) elif with_dain: score_exp = 1.417 bimatch_exp = ( ( 3, 4, 8, 13), # 'daiin' ( 27, 28, 123, 128), # 'daiin' ( 31, 32, 145, 150), # 'kaiin' ( 35, 36, 172, 176), # 'dain' ( 43, 44, 210, 215), # 'raiin' ( 48, 49, 234, 239), # 'laiin' ( 57, 58, 284, 289), # 'daiin' ( 63, 64, 314, 319), # 'kaiin' ) else: score_exp = 1.457 bimatch_exp = ( ( 3, 4, 8, 13), # 'daiin' ( 27, 28, 123, 128), # 'daiin' ( 31, 32, 139, 144), # 'daiin' ( 35, 36, 159, 164), # 'daiin' ( 43, 44, 204, 209), # 'raiin' ( 48, 49, 234, 239), # 'laiin' ( 57, 58, 284, 289), # 'daiin' ( 63, 64, 314, 319), # 'kaiin' ) test_match \ ( match_test_func, text0, ' ', text1, ' ', bitemp, un1_per_un0, bimatch_exp, score_exp, debug_level ) return # ----------------------------------------------------------------------