"""anchor_cases.tsv 정답 열 재생성 — 입력 200개는 그대로, 답만 Python select_supine_anchor 로 다시 뽑는다. 사용: python gen_anchor_cases.py 행 형식: bestcm,nch,ch3,hit,tot,cap|... (best='-' 는 재부착) """ import io, sys, math, os, types # library/__init__.py 가 이 체크아웃에 없는 analysis 패키지를 import 해 깨진다 — 패키지 껍데기만 등록하고 # 필요한 모듈만 상대 import 로 읽는다(runners 등은 실제 파일에서 로드). _root = r"C:\Projects\piezophantomtest\piezo-phantom-test" for _name, _path in (("vesiscan_test", os.path.join(_root, "vesiscan_test")), ("vesiscan_test.library", os.path.join(_root, "vesiscan_test", "library"))): _m = types.ModuleType(_name); _m.__path__ = [_path]; _m.__package__ = _name; sys.modules[_name] = _m import vesiscan_test.library.alignment.alignment_selection as sel src, dst = sys.argv[1], sys.argv[2] raw = io.open(src, encoding="utf-8", newline="").read() nl = "\r\n" if "\r\n" in raw else "\n" # 원본 줄바꿈 유지 — diff 가 답 열만 보이게 lines = raw.splitlines() out, changed, null_before, null_after, fallback = [], 0, 0, 0, 0 for line in lines: if not line.strip() or line.startswith("#"): out.append(line) continue best_old, recs_raw = line.split("\t", 1) recs = [] for f in recs_raw.split("|"): cm, nch, ch3, hit, tot, cap = f.split(",") capv = float(cap) if cap not in ("nan", "") else math.nan recs.append(dict(align_cm=int(cm), nch=int(nch), ch3=ch3, ch3_hit=int(hit), ch3_tot=int(tot), cap_frac=capv)) d = sel.select_supine_anchor(recs, tie="cap", offset_cm=0) best_new = "-" if d.align_cm is None else str(d.align_cm) if best_old == "-": null_before += 1 if best_new == "-": null_after += 1 if d.reasons and d.reasons[0] == sel.NO_CH3_FALLBACK_TAG: fallback += 1 if best_new != best_old: changed += 1 assert best_old == "-", f"non-reattach answer changed: {line}" out.append(best_new + "\t" + recs_raw) io.open(dst, "w", encoding="utf-8", newline="").write(nl.join(out) + nl) print(f"cases={sum(1 for l in lines if l.strip() and not l.startswith('#'))} reattach before={null_before} after={null_after} " f"fallback={fallback} changed={changed} -> {dst}")