Knowledge Concept Graph (KCG) wrapper. The paper uses the KCG/RCD-derived relation graph to judge whether two concepts are related when reinforcing memory. The graph can be built with ``Code/tools/rcd_graph/build_kcg.py``, which refactors the RCD ``data/ASSIST/graph`` concept-map ut
| 5 | |
| 6 | |
| 7 | class RelationGraph: |
| 8 | """Knowledge Concept Graph (KCG) wrapper. |
| 9 | |
| 10 | The paper uses the KCG/RCD-derived relation graph to judge whether two |
| 11 | concepts are related when reinforcing memory. The graph can be built with |
| 12 | ``Code/tools/rcd_graph/build_kcg.py``, which refactors the RCD |
| 13 | ``data/ASSIST/graph`` concept-map utility into an Agent4Edu tool. |
| 14 | """ |
| 15 | |
| 16 | def __init__(self, data_path: str | Path): |
| 17 | data_path = Path(data_path) |
| 18 | self.kcg_pairs = {tuple(pair) for pair in load_json(data_path / "kcg.json")} |
| 19 | self.know_name = {normalize_concept(k): int(v) for k, v in load_json(data_path / "know_name_list.json").items()} |
| 20 | self.know_course = {normalize_concept(k): str(v) for k, v in load_json(data_path / "know_course_list.json").items()} |
| 21 | self.concepts = list(self.know_name.keys()) |
| 22 | |
| 23 | def concept_id(self, concept: str) -> int | None: |
| 24 | return self.know_name.get(normalize_concept(concept)) |
| 25 | |
| 26 | def course(self, concept: str) -> str | None: |
| 27 | return self.know_course.get(normalize_concept(concept)) |
| 28 | |
| 29 | def is_related(self, left: str, right: str) -> bool: |
| 30 | left_id = self.concept_id(left) |
| 31 | right_id = self.concept_id(right) |
| 32 | if left_id is None or right_id is None: |
| 33 | return False |
| 34 | return (left_id, right_id) in self.kcg_pairs or (right_id, left_id) in self.kcg_pairs |
| 35 | |
| 36 | def same_course(self, left: str, right: str) -> bool: |
| 37 | return self.course(left) is not None and self.course(left) == self.course(right) |
| 38 | |
| 39 | def sample_distractors(self, true_concept: str, k: int = 2, seed: int | None = None) -> list[str]: |
| 40 | return pick_distractors(true_concept, self.concepts, k=k, seed=seed) |
| 41 | |
| 42 | |
| 43 | def normalize_kcg_pairs(raw_pairs: Iterable[Sequence[Any]]) -> list[list[int]]: |