#!/usr/bin/env python3 """psymap 검증 (5-7): HermiT 추론 → 분류·충족 불가능 확인 → CQ SPARQL 테스트.""" from owlready2 import * onto = get_ontology("file://psymap.owl").load() P = {c.name: c for c in onto.classes()} KO = {} for c in onto.classes(): ko = [l for l in c.prefLabel if getattr(l, "lang", "") == "ko"] KO[c.name] = str(ko[0]) if ko else c.name print("== 1. HermiT 추론 ==") with onto: sync_reasoner(infer_property_values=False, debug=0) bad = list(default_world.inconsistent_classes()) print("충족 불가능 클래스:", bad if bad else "0개 — 통과") wm_task = P["PSY_0000053"] members = sorted(KO[c.name] for c in onto.classes() if c is not wm_task and wm_task in c.is_a + c.equivalent_to) print("작업기억 과제(정의된 클래스)로 분류된 클래스:", members) print() print("== 2. CQ SPARQL 테스트 ==") import rdflib g = rdflib.Graph().parse("psymap.owl") NS = "https://example.org/psymap/" PRE = f"""PREFIX : <{NS}> PREFIX rdfs: PREFIX owl: PREFIX skos: PREFIX dct: """ def q(sparql): return list(g.query(PRE + sparql)) def ko_of(uri): r = q(f'SELECT ?l WHERE {{ <{uri}> skos:prefLabel ?l . FILTER(lang(?l)="ko") }}') return str(r[0][0]) if r else str(uri).split("/")[-1] results = {} # CQ1 작업기억의 상위 개념 경로 r = q(":PSY_0000018 rdfs:subClassOf* ?a . FILTER(isIRI(?a))".join( ["SELECT ?a WHERE { ", " }"])) results["CQ1"] = [ko_of(row[0]) for row in r] # CQ2 기억 능력의 하위 유형 전체 r = q("SELECT ?c WHERE { ?c rdfs:subClassOf+ :PSY_0000010 . FILTER(isIRI(?c)) }") results["CQ2"] = sorted(ko_of(row[0]) for row in r) # CQ3 작업기억을 측정하는 과제 (골드스탠더드: 숫자폭, N백) r = q("""SELECT ?t WHERE { ?t rdfs:subClassOf ?r . ?r owl:onProperty :measures ; owl:someValuesFrom :PSY_0000018 . FILTER(isIRI(?t)) }""") results["CQ3"] = sorted(ko_of(row[0]) for row in r) # CQ4 숫자폭 과제가 측정하는 구성개념들 r = q("""SELECT ?c WHERE { :PSY_0000051 rdfs:subClassOf ?r . ?r owl:onProperty :measures ; owl:someValuesFrom ?c . }""") results["CQ4"] = sorted(ko_of(row[0]) for row in r) # CQ5 일화·의미기억의 정의와 공통 상위 r = q("""SELECT ?c ?d ?p WHERE { VALUES ?c { :PSY_0000014 :PSY_0000015 } ?c skos:definition ?d ; rdfs:subClassOf ?p . FILTER(isIRI(?p)) }""") results["CQ5"] = [(ko_of(row[0]), str(row[1])[:26] + "…", ko_of(row[2])) for row in r] # CQ6 일화기억 정의의 근거 문헌 r = q("SELECT ?s WHERE { :PSY_0000014 dct:source ?s }") results["CQ6"] = [str(row[0]) for row in r] # CQ7 작업기억의 구성 요소 r = q("""SELECT ?c WHERE { ?c rdfs:subClassOf ?r . ?r owl:onProperty :component_of ; owl:someValuesFrom :PSY_0000018 . FILTER(isIRI(?c)) }""") results["CQ7"] = sorted(ko_of(row[0]) for row in r) # CQ8 해마가 관여하는 기억 과정 r = q("""SELECT ?p WHERE { ?p rdfs:subClassOf ?r . ?r owl:onProperty :depends_on ; owl:someValuesFrom :PSY_0000040 . FILTER(isIRI(?p)) }""") results["CQ8"] = sorted(ko_of(row[0]) for row in r) # CQ9 '작동기억' 검색이 작업기억에 닿는가 r = q("""SELECT ?c WHERE { ?c skos:altLabel ?a . FILTER(str(?a)="작동기억") }""") results["CQ9"] = [ko_of(row[0]) for row in r] # CQ10 Cognitive Atlas 대응물과 ID r = q("SELECT ?c ?m WHERE { ?c skos:exactMatch ?m } ORDER BY ?c") results["CQ10"] = [(ko_of(row[0]), str(row[1]).rsplit("/id/", 1)[-1].rstrip("/")) for row in r] GOLD = {"CQ3": ["N백 과제", "숫자폭 과제"]} for cq in [f"CQ{i}" for i in range(1, 11)]: v = results[cq] mark = "" if cq in GOLD: mark = " [골드스탠더드 " + ("일치 → PASS]" if sorted(v) == sorted(GOLD[cq]) else "불일치 → FAIL]") ok = "통과" if v else "실패(결과 없음)" print(f"{cq}: {v}{mark}") print() print("판정:", "전원 통과" if all(results[k] for k in results) else "실패 있음")