import json from functools import lru_cache from pathlib import Path CATALOG = Path(__file__).resolve().parent / "public/topics/methods.json" FIELDS = { "credit_granularity": "credit_granularity", "required_supervision": "required_supervision", "learned_value_critic": "learned_value_critic", "evaluation_setting": "evaluation_settings", } @lru_cache(maxsize=1) def method_catalog(): return json.loads(CATALOG.read_text()) def values(method, facet): entries = method[FIELDS[facet]] if facet == "learned_value_critic": return {entries["value"]} return {entry["value"] for entry in entries} def list_method_facets() -> dict: """List exact filter values for agent RL credit granularity, supervision, value critics and evaluation settings. Each value reports its source-supported method count.""" catalog = method_catalog() return { "scope": catalog["scope"], "method_count": len(catalog["methods"]), "facets": { name: { **definition, "counts": { value: sum(value in values(method, name) for method in catalog["methods"]) for value in definition["values"] }, } for name, definition in catalog["facet_definitions"].items() }, "matching": "Exact membership within each facet; AND across supplied facets. Empty filters are unrestricted. Unknown is distinct from yes and no.", } def filter_methods( credit_granularity: str = "", required_supervision: str = "", learned_value_critic: str = "", evaluation_setting: str = "", ) -> dict: """Filter agent RL credit-assignment methods by research conditions and return original section evidence and BibTeX. Discover accepted values with list_method_facets. Filters combine with AND; empty strings leave a facet unrestricted. Unknown critic status never matches no. Results use publication order without a relevance or quality ranking.""" catalog = method_catalog() filters = { "credit_granularity": credit_granularity, "required_supervision": required_supervision, "learned_value_critic": learned_value_critic, "evaluation_setting": evaluation_setting, } selected = {name: value for name, value in filters.items() if value} for name, value in selected.items(): accepted = catalog["facet_definitions"][name]["values"] if value not in accepted: raise ValueError(f"Unsupported {name}: {value}. Accepted values: {accepted}") results = [ method for method in catalog["methods"] if all(value in values(method, name) for name, value in selected.items()) ] return {"scope": catalog["scope"], "filters": selected, "catalog_size": len(catalog["methods"]), "count": len(results), "results": results}