fix: restore frequency_filter at 0.2, add dual 0.8 BEX coverage
- frequency_filter(min_coverage=0.2) strips rare symbols before clustering/inference - DEFAULT_COVERAGE=0.8 passed to infer_ensemble for sequence-level core/outlier detection - Both filters active: symbol-level (0.2) then BEX sequence-level (0.8) - Fix seq_of_file tracking broken by filter creating new list objects
This commit is contained in:
parent
55d21af48e
commit
eb2173442b
1 changed files with 16 additions and 10 deletions
|
|
@ -155,6 +155,9 @@ def scan_directory(dir_path, gitignore_spec=None):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_COVERAGE = 0.8
|
||||||
|
|
||||||
|
|
||||||
def frequency_filter(sequences, min_coverage=0.2):
|
def frequency_filter(sequences, min_coverage=0.2):
|
||||||
"""Remove symbols appearing in fewer than min_coverage fraction of files.
|
"""Remove symbols appearing in fewer than min_coverage fraction of files.
|
||||||
|
|
||||||
|
|
@ -257,9 +260,12 @@ def cluster_methods_adaptive(sequences, min_cluster_size=3, ngram_size=3, other_
|
||||||
return clusters
|
return clusters
|
||||||
|
|
||||||
|
|
||||||
def analyze_clusters(file_paths, extension, project_root="", min_coverage=0.2, prefer=None, kmax=2, N=3):
|
def analyze_clusters(file_paths, extension, project_root="", min_coverage=DEFAULT_COVERAGE, prefer=None, kmax=2, N=3):
|
||||||
"""Run full pipeline with clustering: preprocess → cluster → per-cluster infer.
|
"""Run full pipeline with clustering: preprocess → cluster → per-cluster infer.
|
||||||
|
|
||||||
|
Each cluster gets its own ensemble inference with BEX core/outlier
|
||||||
|
detection at the given min_coverage threshold.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list of (label, ensemble_result_dict, method_count, meta) tuples.
|
list of (label, ensemble_result_dict, method_count, meta) tuples.
|
||||||
meta = {"files": set(paths), "imports": [lines], "arg_patterns": {...}, "packages": [...]}.
|
meta = {"files": set(paths), "imports": [lines], "arg_patterns": {...}, "packages": [...]}.
|
||||||
|
|
@ -277,7 +283,7 @@ def analyze_clusters(file_paths, extension, project_root="", min_coverage=0.2, p
|
||||||
if not sequences:
|
if not sequences:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
sequences = frequency_filter(sequences, min_coverage)
|
sequences = frequency_filter(sequences, min_coverage=0.2)
|
||||||
clusters = cluster_methods_adaptive(sequences)
|
clusters = cluster_methods_adaptive(sequences)
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
|
|
@ -289,7 +295,7 @@ def analyze_clusters(file_paths, extension, project_root="", min_coverage=0.2, p
|
||||||
imports = _extract_imports(cluster_fps)
|
imports = _extract_imports(cluster_fps)
|
||||||
arg_patterns = _build_arg_patterns(cluster_fps)
|
arg_patterns = _build_arg_patterns(cluster_fps)
|
||||||
symbol_seqs = [[text for _, text, _ in seq] for seq in cluster_seqs]
|
symbol_seqs = [[text for _, text, _ in seq] for seq in cluster_seqs]
|
||||||
result = infer_ensemble(symbol_seqs, kmax=kmax, N=N, prefer=prefer)
|
result = infer_ensemble(symbol_seqs, kmax=kmax, N=N, prefer=prefer, min_coverage=min_coverage)
|
||||||
packages = _top_packages(cluster_fps, project_root)
|
packages = _top_packages(cluster_fps, project_root)
|
||||||
meta = {"files": cluster_fps, "imports": imports, "arg_patterns": arg_patterns, "packages": packages}
|
meta = {"files": cluster_fps, "imports": imports, "arg_patterns": arg_patterns, "packages": packages}
|
||||||
results.append((label, result, len(cluster_seqs), meta))
|
results.append((label, result, len(cluster_seqs), meta))
|
||||||
|
|
@ -297,13 +303,13 @@ def analyze_clusters(file_paths, extension, project_root="", min_coverage=0.2, p
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
def infer(file_paths, extension, min_coverage=0.2, prefer=None, kmax=2, N=3):
|
def infer(file_paths, extension, min_coverage=DEFAULT_COVERAGE, prefer=None, kmax=2, N=3):
|
||||||
"""Run full pipeline: preprocess → frequency filter → ensemble infer.
|
"""Run full pipeline: preprocess → frequency filter → ensemble infer.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
file_paths: list of source file paths (same language).
|
file_paths: list of source file paths (same language).
|
||||||
extension: language extension (e.g. '.py').
|
extension: language extension (e.g. '.py').
|
||||||
min_coverage: minimum file fraction for a symbol to be kept.
|
min_coverage: BEX core coverage threshold for outlier removal.
|
||||||
prefer: inference algorithm preference ('crx', 'idregex', or None).
|
prefer: inference algorithm preference ('crx', 'idregex', or None).
|
||||||
kmax: max k for k-ORE algorithms.
|
kmax: max k for k-ORE algorithms.
|
||||||
N: number of random trials.
|
N: number of random trials.
|
||||||
|
|
@ -319,16 +325,16 @@ def infer(file_paths, extension, min_coverage=0.2, prefer=None, kmax=2, N=3):
|
||||||
if method_seq:
|
if method_seq:
|
||||||
sequences.append(method_seq)
|
sequences.append(method_seq)
|
||||||
|
|
||||||
sequences = frequency_filter(sequences, min_coverage)
|
sequences = frequency_filter(sequences, min_coverage=0.2)
|
||||||
|
|
||||||
symbol_seqs = [[text for _, text, _ in seq] for seq in sequences]
|
symbol_seqs = [[text for _, text, _ in seq] for seq in sequences]
|
||||||
|
|
||||||
return infer_ensemble(symbol_seqs, kmax=kmax, N=N, prefer=prefer)
|
return infer_ensemble(symbol_seqs, kmax=kmax, N=N, prefer=prefer, min_coverage=min_coverage)
|
||||||
|
|
||||||
|
|
||||||
def analyze_directory(
|
def analyze_directory(
|
||||||
dir_path,
|
dir_path,
|
||||||
min_coverage=0.2,
|
min_coverage=DEFAULT_COVERAGE,
|
||||||
prefer=None,
|
prefer=None,
|
||||||
kmax=2,
|
kmax=2,
|
||||||
include=None,
|
include=None,
|
||||||
|
|
@ -410,8 +416,8 @@ def _parse_args(argv=None):
|
||||||
help="Maximum k for k-ORE algorithms (default: 2)",
|
help="Maximum k for k-ORE algorithms (default: 2)",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--min-coverage", type=float, default=0.2,
|
"--min-coverage", type=float, default=DEFAULT_COVERAGE,
|
||||||
help="Minimum file fraction for a symbol to survive frequency filter (default: 0.2)",
|
help="BEX core coverage threshold — outlier methods are removed until this fraction remains (default: 0.8)",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--include",
|
"--include",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue