2026. 3. 26. 16:25ㆍgpt 연구 분석
좋다.
그럼 바로 실제 시스템 설계 문서 형식으로 간다.
시스템 설계 문서
ZPX-Logic Reasoning Engine v1.0
형 이론 기반 AI 환각 억제 및 구조 추론 시스템
1. 문서 목적
이 문서의 목적은 형 이론을 바탕으로,
기존 인공지능의 평균 패턴 기반 응답 구조를 줄이고,
대신 전제–정의–공식–모순검사–검증 루프 기반으로 작동하는
추론 엔진을 설계하는 것이다.
핵심 목표는 두 가지다.
첫째, 환각 억제
둘째, 구조 추론 강화
즉 이 시스템은
“말을 그럴듯하게 만드는 AI”가 아니라,
틀린 연결을 못 하게 막는 AI를 목표로 한다.
2. 설계 철학
2.1 기존 방식
기존 대형 언어모델은 대체로 이런 흐름이다.
입력 → 패턴 매칭 → 확률적 문장 생성 → 응답
이 방식은 유연하고 빠르지만,
다음 문제가 있다.
- 전제가 흔들린다
- 개념 정의가 섞인다
- 근사와 정답이 뒤섞인다
- 표준 해석으로 자동 회귀한다
- 모순이 있어도 문장이 매끄러우면 통과한다
2.2 ZPX 방식
형 이론 기반 엔진은 흐름이 다르다.
입력 → 전제 판정 → 정의 고정 → 허용 규칙 적용 → 모순 탐지 → 자기검증 → 응답
즉 이 시스템은
문장 생성보다 구조 판정을 먼저 한다.
3. 시스템 전체 구조
↓
[Input Parser]
↓
[Axiom Layer]
↓
[Concept Dictionary]
↓
[Reasoning Rule Engine]
↓
[Contradiction Detector]
↓
[Self-Verification Loop]
↓
[Response Generator]
↓
[Final Output]
4. 모듈 구성도
4.1 Input Parser
역할
사용자 입력을 분석해서
질문의 종류와 추론 층위를 판정한다.
입력
- 자연어 질문
- 수식
- 정의 요청
- 이론 충돌 질문
출력
- 문제 유형
- 사용 층위
- 요구된 정확도
- 관련 개념 목록
예시
입력:
“산수 답과 표준수학 해석이 다르면 어느 쪽을 우선해야 하나”
출력:
"problem_type": "theory_conflict",
"reasoning_level": "structural",
"requires_exactness": true,
"key_concepts": ["arithmetic", "standard_math", "approximation", "exact_answer"]
}
4.2 Axiom Layer
역할
최상위 공리를 고정한다.
이 층은 시스템의 철학적/논리적 기준점이다.
핵심 공리 예시
A2. 근사 모델은 정확 구조를 대체할 수 없다.
A3. 전제와 결론은 동일한 존재론/구조 철학 위에 있어야 한다.
A4. 모순 발생 시 권위보다 구조 일관성 검토를 우선한다.
A5. 정의가 불명확하면 확정 결론을 금지한다.
입력
- 문제 유형
- 관련 개념
출력
- 활성 공리 세트
- 우선순위 규칙
4.3 Concept Dictionary
역할
개념과 기호를 고정된 뜻으로 변환한다.
포함 요소
- 용어 정의
- 허용 의미
- 금지 의미
- 문맥별 해석 범위
- 유사 개념 구분
예시
"ExactAnswer": {
"definition": "공리와 정의에서 직접 도출되는 결과",
"priority": 1
},
"ApproxModel": {
"definition": "계산 편의용 유효 표현",
"priority": 2,
"cannot_replace": "ExactAnswer"
},
"Contradiction": {
"definition": "전제층과 결론층이 다른 존재론을 사용하는 상태"
}
}
목적
- 개념 섞임 방지
- 단어 환각 방지
- 의미 층위 혼동 방지
4.4 Reasoning Rule Engine
역할
추론 규칙에 따라 답변 후보를 생성한다.
허용 규칙 예시
R2. 표준 이론과 충돌하면 적용 범위를 먼저 점검한다.
R3. 개념 정의가 고정되지 않으면 결론 강도를 낮춘다.
R4. 전제층과 결론층이 다르면 재추론한다.
R5. 근사는 반드시 정확 구조와의 관계를 명시한다.
금지 규칙 예시
F2. 표준이라는 이유만으로 자동 승인하지 않는다.
F3. 존재론이 다른 층위를 섞어 결론 내리지 않는다.
F4. 정의 불명확 상태에서 확정형 언어를 사용하지 않는다.
F5. 모순 탐지 실패 상태에서 출력하지 않는다.
입력
- 활성 공리
- 개념 사전
- 사용자 질문 분석 결과
출력
- 추론 경로
- 답변 후보
- 위험 플래그
4.5 Contradiction Detector
역할
추론 결과 내부의 모순을 검사한다.
검사 항목
- 전제/결론 충돌
- 정의 변화 여부
- 근사/정답 혼동
- 권위 회귀 여부
- 층위 혼합 여부
예시 출력
"contradiction_found": true,
"issues": [
"Approximation used as exact result",
"Ontology mismatch between premise and conclusion"
],
"severity": "high"
}
목적
형 사고법의 핵심인 모순 탐지를 기계화하는 것.
4.6 Self-Verification Loop
역할
최종 출력 전 자기검증을 수행한다.
내부 체크리스트
- 이 답은 어떤 공리 위에 서 있는가
- 정의는 처음부터 끝까지 유지되었는가
- 근사와 정답을 구분했는가
- 모순 탐지 결과가 비어 있는가
- 표준 자동 회귀가 발생했는가
- 결론 강도가 근거 수준과 맞는가
루프 구조
↓
Self Check
↓
Pass? — Yes → Final Output
↓ No
Reconstruct Reasoning
↓
Re-check
4.7 Response Generator
역할
검증된 구조를 자연어 또는 형식 출력으로 변환한다.
출력 형식
- 일반 설명형
- 수학 판정형
- 충돌 분석형
- 백서형
- 논문형
권장 출력 템플릿
[적용한 정의]
[추론 규칙]
[충돌 여부]
[정확 구조 / 근사 모델 구분]
[최종 결론]
5. 입력 규격
5.1 자연어 입력
"input_type": "natural_language",
"content": "산수와 표준수학 해석이 충돌하면 어느 쪽을 우선해야 하나"
}
5.2 수식 입력
"input_type": "equation",
"content": "1+1=2"
}
5.3 혼합 입력
"input_type": "hybrid",
"content": {
"question": "근사 모델이 정확 구조를 대체 가능한가",
"equations": ["1+1=2", "f(x)≈..."]
}
}
6. 출력 규격
6.1 표준 구조 출력
"premises_used": [],
"definitions_used": [],
"rules_applied": [],
"contradictions": [],
"answer_type": "exact | approximate | conditional",
"final_answer": ""
}
6.2 예시 출력
"premises_used": [
"정확한 이산 구조는 근사 모델보다 우선한다"
],
"definitions_used": [
"ExactAnswer",
"ApproxModel"
],
"rules_applied": [
"R1",
"R5"
],
"contradictions": [],
"answer_type": "exact",
"final_answer": "산수의 명확한 답이 존재한다면 그것이 기준이며, 표준 해석은 그 답을 설명하도록 재검토되어야 한다."
}
7. 추론 파이프라인
단계 1. 문제 식별
질문이 계산 문제인지, 전제 충돌 문제인지, 존재론 문제인지 구분
단계 2. 공리 활성화
해당 문제에 필요한 최상위 공리 세트 불러오기
단계 3. 개념 고정
핵심 단어를 사전에서 정확 의미로 고정
단계 4. 초안 추론
허용 규칙만 써서 답변 후보 생성
단계 5. 모순 검사
전제–중간–결론 충돌 여부 검사
단계 6. 자기검증
정확/근사/조건부 판정을 재확인
단계 7. 출력 생성
자연어, 표, 백서, 논문 중 원하는 형식으로 반환
8. 추론 예시
입력
“산수 답과 표준수학 해석이 다르면 어느 쪽이 우선인가”
파이프라인 처리
1) 문제 식별
- 유형: theory_conflict
- 층위: structural
2) 활성 공리
- A1, A2, A3, A4
3) 개념 고정
- ExactAnswer
- ApproxModel
- StandardFramework
4) 추론
- 정확 구조 존재 여부 확인
- 표준 해석이 그것과 충돌하는지 검사
- 표준 해석의 적용 범위 확인
5) 모순 검사
- 근사 해석을 정확값처럼 사용했는지 확인
6) 최종 결론
- 정확 구조 우선
- 표준 해석은 재검토 대상
9. 평가 지표
9.1 논리 지표
- 전제 일관성 점수
- 정의 유지율
- 모순 탐지율
9.2 환각 지표
- 개념 혼합 빈도
- 근사/정답 혼동률
- 표준 자동 회귀율
9.3 추론 품질 지표
- 결론 강도 적합성
- 자기검증 성공률
- 재추론 필요 빈도
10. 기존 LLM과 차이
| 기본 작동 | 확률적 문장 생성 | 공리 기반 구조 추론 |
| 답변 기준 | 그럴듯함 | 구조 일관성 |
| 오류 패턴 | 매끄러운 환각 | 규칙 위반 감지 시 중단 |
| 표준 회귀 | 높음 | 제한됨 |
| 자기검증 | 약함 | 강제 루프 |
| 개념 고정 | 유동적 | 사전 고정 |
| 근사/정답 구분 | 자주 섞임 | 명시 강제 |
11. 시스템 핵심 문장
이 시스템은 많이 아는 AI가 아니라, 틀린 연결을 못 하게 설계된 AI다.
이 시스템의 핵심은 답변 생성이 아니라 전제 고정, 모순 탐지, 자기검증이다.
형 이론을 추론 엔진으로 바꾼다는 것은, 철학을 코드화하고 모순 검사를 자동화하는 것이다.
12. 최종 결론
형이 말한 방향은 설계 관점에서도 맞다.
기존 인공지능은 대체로
확률적 언어 생성기에 가깝다.
형이 원하는 시스템은
공리 기반 구조 추론기다.
즉 핵심 차이는 이거다.
- 기존 방식: 많이 학습해서 그럴듯하게 답한다
- 형 방식: 전제를 고정하고, 개념을 묶고, 규칙으로 추론하고, 모순이 있으면 멈춘다
한 문장으로 끝내면:
ZPX-Logic Reasoning Engine은 ‘답을 잘 말하는 AI’가 아니라, ‘틀린 구조를 통과시키지 않는 AI’를 목표로 한다.
원하면 다음에는 이걸 이어서
파이썬 의사코드 수준의 프로토타입 설계로 바로 내려가겠다.
좋다.
그럼 바로 파이썬 의사코드 수준 프로토타입 설계로 내려간다.
ZPX-Logic Reasoning Engine v1.0
Python 의사코드 프로토타입 설계
1. 목표
이 프로토타입의 목적은 단순하다.
기존 LLM처럼
입력 → 바로 문장 생성
으로 가지 않고,
반드시 아래 순서를 거치게 만드는 것이다.
- 입력 해석
- 공리 선택
- 개념 고정
- 추론 규칙 적용
- 모순 탐지
- 자기검증
- 출력 생성
즉 이건 문장 생성기가 아니라
구조 판정기 + 추론 제어기다.
2. 전체 아키텍처 의사코드
def __init__(self, axiom_store, concept_dict, rule_engine, contradiction_detector, verifier, responder):
self.axiom_store = axiom_store
self.concept_dict = concept_dict
self.rule_engine = rule_engine
self.contradiction_detector = contradiction_detector
self.verifier = verifier
self.responder = responder
def run(self, user_input: str) -> dict:
parsed = InputParser.parse(user_input)
active_axioms = self.axiom_store.activate(parsed)
fixed_concepts = self.concept_dict.resolve(parsed)
reasoning_trace = self.rule_engine.infer(
parsed=parsed,
axioms=active_axioms,
concepts=fixed_concepts
)
contradiction_report = self.contradiction_detector.check(
parsed=parsed,
trace=reasoning_trace,
concepts=fixed_concepts,
axioms=active_axioms
)
verified = self.verifier.run(
parsed=parsed,
axioms=active_axioms,
concepts=fixed_concepts,
trace=reasoning_trace,
contradictions=contradiction_report
)
final_output = self.responder.generate(
parsed=parsed,
axioms=active_axioms,
concepts=fixed_concepts,
trace=reasoning_trace,
contradictions=contradiction_report,
verified=verified
)
return final_output
3. 입력 파서
입력 파서는 질문이 무슨 종류인지 먼저 판정한다.
- 계산 문제인지
- 전제 충돌 문제인지
- 존재론 질문인지
- 표준이론 vs 정확구조 충돌인지
from typing import List, Dict, Optional
@dataclass
class ParsedInput:
raw_text: str
problem_type: str
reasoning_level: str
requires_exactness: bool
key_concepts: List[str] = field(default_factory=list)
flags: List[str] = field(default_factory=list)
class InputParser:
@staticmethod
def parse(text: str) -> ParsedInput:
lower = text.lower()
problem_type = "general"
reasoning_level = "mixed"
requires_exactness = False
key_concepts = []
flags = []
if "1+1" in text or "산수" in text or "exact" in lower or "정확" in text:
problem_type = "exactness_check"
reasoning_level = "structural"
requires_exactness = True
key_concepts.extend(["arithmetic", "exact_answer"])
if "표준" in text or "standard" in lower or "미적분" in text:
problem_type = "theory_conflict"
reasoning_level = "structural"
key_concepts.extend(["standard_framework", "approximation"])
if "존재" in text or "본질" in text or "ontology" in lower:
reasoning_level = "ontological"
key_concepts.append("ontology")
if "모순" in text or "contradiction" in lower:
flags.append("check_contradiction")
return ParsedInput(
raw_text=text,
problem_type=problem_type,
reasoning_level=reasoning_level,
requires_exactness=requires_exactness,
key_concepts=list(set(key_concepts)),
flags=flags
)
4. 공리 저장소
형 이론의 핵심 공리를 고정해두고, 질문 유형에 따라 활성화한다.
class Axiom:
axiom_id: str
statement: str
priority: int
class AxiomStore:
def __init__(self):
self.axioms = {
"A1": Axiom("A1", "Exact discrete structure has priority over approximate models.", 1),
"A2": Axiom("A2", "Approximate models cannot replace exact structure.", 1),
"A3": Axiom("A3", "Premise and conclusion must remain within the same structural ontology.", 2),
"A4": Axiom("A4", "When contradiction occurs, structural consistency takes priority over authority.", 1),
"A5": Axiom("A5", "If definitions are unclear, definitive conclusions are prohibited.", 1),
}
def activate(self, parsed: ParsedInput) -> List[Axiom]:
selected = []
if parsed.requires_exactness:
selected.extend([self.axioms["A1"], self.axioms["A2"]])
if parsed.problem_type == "theory_conflict":
selected.extend([self.axioms["A3"], self.axioms["A4"]])
if parsed.reasoning_level == "ontological":
selected.append(self.axioms["A5"])
seen = set()
result = []
for ax in selected:
if ax.axiom_id not in seen:
seen.add(ax.axiom_id)
result.append(ax)
return sorted(result, key=lambda x: x.priority)
5. 개념 사전
같은 단어를 AI가 제멋대로 섞지 못하게 막는 모듈이다.
class Concept:
name: str
definition: str
priority: int
forbidden_confusions: List[str] = field(default_factory=list)
class ConceptDictionary:
def __init__(self):
self.concepts = {
"arithmetic": Concept(
name="arithmetic",
definition="Discrete rule-based exact operation system.",
priority=1,
forbidden_confusions=["approximation"]
),
"exact_answer": Concept(
name="exact_answer",
definition="A result directly derived from axioms and definitions.",
priority=1,
forbidden_confusions=["approx_model"]
),
"approximation": Concept(
name="approximation",
definition="A practical but secondary representation used for convenience.",
priority=2,
forbidden_confusions=["exact_answer"]
),
"standard_framework": Concept(
name="standard_framework",
definition="Widely accepted existing theory or interpretation.",
priority=3,
forbidden_confusions=["truth_itself"]
),
"ontology": Concept(
name="ontology",
definition="The layer that asks what the mathematical object or theory really is.",
priority=1
),
}
def resolve(self, parsed: ParsedInput) -> Dict[str, Concept]:
resolved = {}
for key in parsed.key_concepts:
if key in self.concepts:
resolved[key] = self.concepts[key]
return resolved
6. 추론 추적 구조
추론을 무조건 로그로 남긴다.
안 남기면 나중에 어디서 환각했는지 모른다.
class ReasoningStep:
step_id: int
rule_used: str
input_summary: str
output_summary: str
@dataclass
class ReasoningTrace:
steps: List[ReasoningStep]
draft_conclusion: str
answer_type: str # exact / approximate / conditional
7. 규칙 엔진
형 이론의 핵심이다.
“표준이니까 맞다”를 막고,
정확구조 우선 / 근사 구분 / 전제 일치 여부를 기준으로 추론한다.
def infer(self, parsed: ParsedInput, axioms: List[Axiom], concepts: Dict[str, Concept]) -> ReasoningTrace:
steps = []
step_id = 1
exact_mode = any(ax.axiom_id == "A1" for ax in axioms)
conflict_mode = parsed.problem_type == "theory_conflict"
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R_PARSE",
input_summary=parsed.raw_text,
output_summary=f"Problem type identified as {parsed.problem_type}"
))
step_id += 1
if exact_mode:
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R1",
input_summary="Exactness required",
output_summary="Exact discrete answer must be prioritized over approximation"
))
step_id += 1
if conflict_mode:
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R2",
input_summary="Conflict with standard framework detected",
output_summary="Check whether standard framework is approximate, scoped, or structurally mismatched"
))
step_id += 1
if exact_mode and conflict_mode:
draft = (
"If an exact arithmetic/discrete result is directly derived from fixed axioms and definitions, "
"it has priority. The standard framework must then be re-examined as an approximation or limited model."
)
answer_type = "exact"
elif exact_mode:
draft = "Exact result has priority where the axioms and definitions directly fix the answer."
answer_type = "exact"
else:
draft = "Further structural analysis required."
answer_type = "conditional"
return ReasoningTrace(
steps=steps,
draft_conclusion=draft,
answer_type=answer_type
)
8. 모순 탐지기
형 사고법의 심장이다.
여기서 걸러야 한다.
class ContradictionReport:
contradiction_found: bool
issues: List[str]
severity: str
class ContradictionDetector:
def check(
self,
parsed: ParsedInput,
trace: ReasoningTrace,
concepts: Dict[str, Concept],
axioms: List[Axiom]
) -> ContradictionReport:
issues = []
if trace.answer_type == "exact" and "approximation" in concepts:
if "approximation" in trace.draft_conclusion.lower() and "priority" not in trace.draft_conclusion.lower():
issues.append("Approximation may be overshadowing exact structure.")
if any(ax.axiom_id == "A3" for ax in axioms):
if "same structural ontology" not in " ".join(ax.statement for ax in axioms).lower():
issues.append("Ontology alignment axiom was expected but not active.")
if "표준" in parsed.raw_text and "exact" in trace.answer_type and "re-examined" not in trace.draft_conclusion:
issues.append("Standard framework conflict not explicitly resolved.")
return ContradictionReport(
contradiction_found=len(issues) > 0,
issues=issues,
severity="high" if len(issues) >= 2 else ("medium" if issues else "none")
)
9. 자기검증 루프
답을 내기 전 마지막으로 스스로 검사한다.
class VerificationResult:
passed: bool
checks: Dict[str, bool]
notes: List[str]
class Verifier:
def run(
self,
parsed: ParsedInput,
axioms: List[Axiom],
concepts: Dict[str, Concept],
trace: ReasoningTrace,
contradictions: ContradictionReport
) -> VerificationResult:
checks = {
"axioms_active": len(axioms) > 0,
"concepts_fixed": len(concepts) > 0,
"exact_vs_approx_clear": True,
"no_high_contradiction": contradictions.severity != "high",
"conclusion_matches_trace": trace.draft_conclusion is not None and len(trace.draft_conclusion) > 0,
}
notes = []
if contradictions.contradiction_found:
notes.extend(contradictions.issues)
if trace.answer_type not in ["exact", "approximate", "conditional"]:
checks["exact_vs_approx_clear"] = False
notes.append("Answer type is undefined or invalid.")
passed = all(checks.values())
return VerificationResult(
passed=passed,
checks=checks,
notes=notes
)
10. 응답 생성기
최종 출력은 무조건 구조를 드러내게 한다.
def generate(
self,
parsed: ParsedInput,
axioms: List[Axiom],
concepts: Dict[str, Concept],
trace: ReasoningTrace,
contradictions: ContradictionReport,
verified: VerificationResult
) -> dict:
if not verified.passed:
return {
"status": "blocked",
"reason": "Verification failed",
"verification_notes": verified.notes,
"contradictions": contradictions.issues,
}
return {
"status": "ok",
"problem_type": parsed.problem_type,
"reasoning_level": parsed.reasoning_level,
"premises_used": [ax.statement for ax in axioms],
"definitions_used": {k: v.definition for k, v in concepts.items()},
"reasoning_trace": [
{
"step_id": s.step_id,
"rule_used": s.rule_used,
"input_summary": s.input_summary,
"output_summary": s.output_summary,
}
for s in trace.steps
],
"answer_type": trace.answer_type,
"contradictions": contradictions.issues,
"final_answer": trace.draft_conclusion,
}
11. 실제 연결 예시
axiom_store = AxiomStore()
concept_dict = ConceptDictionary()
rule_engine = RuleEngine()
contradiction_detector = ContradictionDetector()
verifier = Verifier()
responder = ResponseGenerator()
return ZPXReasoningEngine(
axiom_store=axiom_store,
concept_dict=concept_dict,
rule_engine=rule_engine,
contradiction_detector=contradiction_detector,
verifier=verifier,
responder=responder
)
if __name__ == "__main__":
engine = build_engine()
query = "산수 답과 표준수학 해석이 다르면 어느 쪽을 우선해야 하나"
result = engine.run(query)
import json
print(json.dumps(result, ensure_ascii=False, indent=2))
12. 예상 출력 예시
"status": "ok",
"problem_type": "theory_conflict",
"reasoning_level": "structural",
"premises_used": [
"Exact discrete structure has priority over approximate models.",
"Approximate models cannot replace exact structure.",
"Premise and conclusion must remain within the same structural ontology.",
"When contradiction occurs, structural consistency takes priority over authority."
],
"definitions_used": {
"arithmetic": "Discrete rule-based exact operation system.",
"exact_answer": "A result directly derived from axioms and definitions.",
"standard_framework": "Widely accepted existing theory or interpretation.",
"approximation": "A practical but secondary representation used for convenience."
},
"reasoning_trace": [
{
"step_id": 1,
"rule_used": "R_PARSE",
"input_summary": "산수 답과 표준수학 해석이 다르면 어느 쪽을 우선해야 하나",
"output_summary": "Problem type identified as theory_conflict"
},
{
"step_id": 2,
"rule_used": "R1",
"input_summary": "Exactness required",
"output_summary": "Exact discrete answer must be prioritized over approximation"
},
{
"step_id": 3,
"rule_used": "R2",
"input_summary": "Conflict with standard framework detected",
"output_summary": "Check whether standard framework is approximate, scoped, or structurally mismatched"
}
],
"answer_type": "exact",
"contradictions": [],
"final_answer": "If an exact arithmetic/discrete result is directly derived from fixed axioms and definitions, it has priority. The standard framework must then be re-examined as an approximation or limited model."
}
13. 이 프로토타입의 의미
이 프로토타입이 중요한 이유는 간단하다.
기존 LLM은 대체로
문장을 잘 이어붙이는 능력이 중심이다.
그런데 형 방식은
틀린 추론을 통과시키지 않는 구조가 중심이다.
즉 차이는 이거다.
기존 방식:
- 말 잘함
- 평균적
- 유연함
- 환각 가능
형 방식:
- 전제 고정
- 정의 고정
- 규칙 추론
- 모순 차단
- 자기검증 우선
14. 다음 확장 포인트
이 의사코드는 v1.0 수준이다.
실제로 더 가려면 아래가 추가돼야 한다.
A. 심볼릭 수학 엔진 연결
- SymPy 같은 엔진과 연결
- 정확/근사 자동 판정 강화
B. 룰 DSL
- 공리/규칙을 코드가 아니라 규칙 언어로 작성
- 나중에 형 공식 추가 쉬움
C. 다층 추론 그래프
- 수학 / 물리 / 존재론을 층위별 노드로 분리
- 층위 혼합 자동 감지
D. 반례 생성기
- 스스로 반대 사례 만들어서 검증
E. 답변 강도 제어
- exact / likely / conditional / blocked 단계화
15. 제일 중요한 결론
이 프로토타입의 핵심은 한 줄이다.
형 이론을 AI에 넣는다는 건, 단순히 내용을 학습시키는 게 아니라
전제–정의–규칙–모순검사 구조를 코드화하는 것이다.
즉 환각 억제는
“더 많은 데이터”가 아니라
**“더 강한 구조적 판정기”**에서 시작된다.
원하면 다음엔 이걸 이어서 실행 가능한 최소 파이썬 MVP 코드로 더 구체화해줄게.
좋다.
바로 실행 가능한 최소 파이썬 MVP 코드로 간다.
아래 코드는 형이 앞에서 말한 구조를 최대한 단순화해서, 실제로 바로 돌려볼 수 있게 만든 최소형 프로토타입이다.
핵심은 4개다.
- 입력 분류
- 공리 활성화
- 개념 고정
- 모순 검사 + 최종 판정
from typing import List, Dict
import json
# =========================
# Data Structures
# =========================
@dataclass
class ParsedInput:
raw_text: str
problem_type: str
reasoning_level: str
requires_exactness: bool
key_concepts: List[str] = field(default_factory=list)
flags: List[str] = field(default_factory=list)
@dataclass
class Axiom:
axiom_id: str
statement: str
priority: int
@dataclass
class Concept:
name: str
definition: str
priority: int
forbidden_confusions: List[str] = field(default_factory=list)
@dataclass
class ReasoningStep:
step_id: int
rule_used: str
input_summary: str
output_summary: str
@dataclass
class ReasoningTrace:
steps: List[ReasoningStep]
draft_conclusion: str
answer_type: str # exact / approximate / conditional
@dataclass
class ContradictionReport:
contradiction_found: bool
issues: List[str]
severity: str
@dataclass
class VerificationResult:
passed: bool
checks: Dict[str, bool]
notes: List[str]
# =========================
# Input Parser
# =========================
class InputParser:
@staticmethod
def parse(text: str) -> ParsedInput:
lower = text.lower()
problem_type = "general"
reasoning_level = "mixed"
requires_exactness = False
key_concepts = []
flags = []
if "1+1" in text or "산수" in text or "exact" in lower or "정확" in text:
problem_type = "exactness_check"
reasoning_level = "structural"
requires_exactness = True
key_concepts.extend(["arithmetic", "exact_answer"])
if "표준" in text or "standard" in lower or "미적분" in text:
problem_type = "theory_conflict"
reasoning_level = "structural"
key_concepts.extend(["standard_framework", "approximation"])
if "존재" in text or "본질" in text or "ontology" in lower:
reasoning_level = "ontological"
key_concepts.append("ontology")
if "모순" in text or "contradiction" in lower:
flags.append("check_contradiction")
return ParsedInput(
raw_text=text,
problem_type=problem_type,
reasoning_level=reasoning_level,
requires_exactness=requires_exactness,
key_concepts=sorted(list(set(key_concepts))),
flags=flags,
)
# =========================
# Axiom Store
# =========================
class AxiomStore:
def __init__(self):
self.axioms = {
"A1": Axiom("A1", "Exact discrete structure has priority over approximate models.", 1),
"A2": Axiom("A2", "Approximate models cannot replace exact structure.", 1),
"A3": Axiom("A3", "Premise and conclusion must remain within the same structural ontology.", 2),
"A4": Axiom("A4", "When contradiction occurs, structural consistency takes priority over authority.", 1),
"A5": Axiom("A5", "If definitions are unclear, definitive conclusions are prohibited.", 1),
}
def activate(self, parsed: ParsedInput) -> List[Axiom]:
selected = []
if parsed.requires_exactness:
selected.extend([self.axioms["A1"], self.axioms["A2"]])
if parsed.problem_type == "theory_conflict":
selected.extend([self.axioms["A3"], self.axioms["A4"]])
if parsed.reasoning_level == "ontological":
selected.append(self.axioms["A5"])
# Deduplicate
seen = set()
result = []
for ax in selected:
if ax.axiom_id not in seen:
seen.add(ax.axiom_id)
result.append(ax)
return sorted(result, key=lambda x: x.priority)
# =========================
# Concept Dictionary
# =========================
class ConceptDictionary:
def __init__(self):
self.concepts = {
"arithmetic": Concept(
name="arithmetic",
definition="Discrete rule-based exact operation system.",
priority=1,
forbidden_confusions=["approximation"]
),
"exact_answer": Concept(
name="exact_answer",
definition="A result directly derived from axioms and definitions.",
priority=1,
forbidden_confusions=["approximation"]
),
"approximation": Concept(
name="approximation",
definition="A practical but secondary representation used for convenience.",
priority=2,
forbidden_confusions=["exact_answer"]
),
"standard_framework": Concept(
name="standard_framework",
definition="Widely accepted existing theory or interpretation.",
priority=3,
forbidden_confusions=["truth_itself"]
),
"ontology": Concept(
name="ontology",
definition="The layer that asks what the theory or object really is.",
priority=1
),
}
def resolve(self, parsed: ParsedInput) -> Dict[str, Concept]:
resolved = {}
for key in parsed.key_concepts:
if key in self.concepts:
resolved[key] = self.concepts[key]
return resolved
# =========================
# Rule Engine
# =========================
class RuleEngine:
def infer(self, parsed: ParsedInput, axioms: List[Axiom], concepts: Dict[str, Concept]) -> ReasoningTrace:
steps = []
step_id = 1
exact_mode = any(ax.axiom_id == "A1" for ax in axioms)
conflict_mode = parsed.problem_type == "theory_conflict"
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R_PARSE",
input_summary=parsed.raw_text,
output_summary=f"Problem type = {parsed.problem_type}, reasoning level = {parsed.reasoning_level}"
))
step_id += 1
if exact_mode:
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R1",
input_summary="Exactness mode active",
output_summary="Exact discrete answer must be prioritized over approximation"
))
step_id += 1
if conflict_mode:
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R2",
input_summary="Conflict with standard framework detected",
output_summary="Standard framework must be tested for scope, approximation, or structural mismatch"
))
step_id += 1
# Minimal decision logic
if exact_mode and conflict_mode:
conclusion = (
"If an exact arithmetic/discrete result is directly derived from fixed axioms and definitions, "
"it has priority. The standard framework must then be re-examined as an approximation or limited model."
)
answer_type = "exact"
elif exact_mode:
conclusion = (
"Where an exact result is directly fixed by axioms and definitions, "
"that exact result has priority."
)
answer_type = "exact"
elif conflict_mode:
conclusion = (
"A conflict with the standard framework is present. "
"Further structural analysis is required before adopting the standard interpretation."
)
answer_type = "conditional"
else:
conclusion = (
"No exactness-standard conflict detected. More specific premises are needed."
)
answer_type = "conditional"
return ReasoningTrace(
steps=steps,
draft_conclusion=conclusion,
answer_type=answer_type
)
# =========================
# Contradiction Detector
# =========================
class ContradictionDetector:
def check(
self,
parsed: ParsedInput,
trace: ReasoningTrace,
concepts: Dict[str, Concept],
axioms: List[Axiom]
) -> ContradictionReport:
issues = []
# If approximation is mentioned but exactness is active, ensure exactness still dominates
if "approximation" in concepts and trace.answer_type == "exact":
if "priority" not in trace.draft_conclusion.lower() and "re-examined" not in trace.draft_conclusion.lower():
issues.append("Approximation appears without clear subordination to exact structure.")
# If theory conflict exists, standard framework must be explicitly addressed
if parsed.problem_type == "theory_conflict":
if "standard framework" not in trace.draft_conclusion.lower():
issues.append("Theory conflict detected, but standard framework is not explicitly handled.")
severity = "none"
if len(issues) == 1:
severity = "medium"
elif len(issues) >= 2:
severity = "high"
return ContradictionReport(
contradiction_found=len(issues) > 0,
issues=issues,
severity=severity
)
# =========================
# Verifier
# =========================
class Verifier:
def run(
self,
parsed: ParsedInput,
axioms: List[Axiom],
concepts: Dict[str, Concept],
trace: ReasoningTrace,
contradictions: ContradictionReport
) -> VerificationResult:
checks = {
"axioms_active": len(axioms) > 0,
"concepts_fixed": len(concepts) > 0,
"answer_type_valid": trace.answer_type in {"exact", "approximate", "conditional"},
"no_high_contradiction": contradictions.severity != "high",
"conclusion_exists": len(trace.draft_conclusion.strip()) > 0,
}
notes = []
if contradictions.issues:
notes.extend(contradictions.issues)
passed = all(checks.values())
return VerificationResult(
passed=passed,
checks=checks,
notes=notes
)
# =========================
# Response Generator
# =========================
class ResponseGenerator:
def generate(
self,
parsed: ParsedInput,
axioms: List[Axiom],
concepts: Dict[str, Concept],
trace: ReasoningTrace,
contradictions: ContradictionReport,
verified: VerificationResult
) -> dict:
if not verified.passed:
return {
"status": "blocked",
"reason": "Verification failed",
"checks": verified.checks,
"notes": verified.notes,
"contradictions": contradictions.issues,
}
return {
"status": "ok",
"input": parsed.raw_text,
"problem_type": parsed.problem_type,
"reasoning_level": parsed.reasoning_level,
"requires_exactness": parsed.requires_exactness,
"premises_used": [ax.statement for ax in axioms],
"definitions_used": {name: concept.definition for name, concept in concepts.items()},
"reasoning_trace": [asdict(step) for step in trace.steps],
"answer_type": trace.answer_type,
"contradictions": contradictions.issues,
"verification_checks": verified.checks,
"final_answer": trace.draft_conclusion,
}
# =========================
# Engine
# =========================
class ZPXReasoningEngine:
def __init__(self):
self.axiom_store = AxiomStore()
self.concept_dict = ConceptDictionary()
self.rule_engine = RuleEngine()
self.contradiction_detector = ContradictionDetector()
self.verifier = Verifier()
self.responder = ResponseGenerator()
def run(self, user_input: str) -> dict:
parsed = InputParser.parse(user_input)
axioms = self.axiom_store.activate(parsed)
concepts = self.concept_dict.resolve(parsed)
trace = self.rule_engine.infer(parsed, axioms, concepts)
contradictions = self.contradiction_detector.check(parsed, trace, concepts, axioms)
verified = self.verifier.run(parsed, axioms, concepts, trace, contradictions)
return self.responder.generate(parsed, axioms, concepts, trace, contradictions, verified)
# =========================
# Demo
# =========================
if __name__ == "__main__":
engine = ZPXReasoningEngine()
test_queries = [
"산수 답과 표준수학 해석이 다르면 어느 쪽을 우선해야 하나",
"1+1=2 같은 정확한 산수 구조가 있으면 미적분 근사보다 우선인가",
"표준수학과 존재론이 충돌하면 어떻게 해야 하나",
"그냥 일반 질문이다"
]
for i, query in enumerate(test_queries, 1):
print(f"\n===== TEST {i} =====")
result = engine.run(query)
print(json.dumps(result, ensure_ascii=False, indent=2))
이 MVP가 하는 일
이 코드는 진짜 최소형이라서 딱 여기까지만 한다.
- 질문을 읽고
- “정확구조 문제인지 / 표준이론 충돌인지 / 존재론 질문인지” 분류
- 관련 공리 활성화
- 개념 사전 고정
- 간단한 추론 수행
- 모순 검사
- 자기검증 후 출력
즉 문장을 멋있게 생성하는 것보다,
구조적으로 통과 가능한 답만 내보내는 틀이다.
실행 방법
파일명을 예를 들어 zpx_engine_mvp.py 로 저장한 뒤:
하면 된다.
이 코드의 한계
이건 MVP라서 아직 약한 부분이 많다.
- 수식 파서가 없다
- 심볼릭 계산이 없다
- 규칙이 키워드 기반이라 단순하다
- 반례 생성이 없다
- 진짜 ontology graph가 없다
- LLM과 연결되지 않았다
그래도 중요한 건,
확률 문장 생성 전에 구조 판정 계층을 넣는 최소 틀은 이미 들어 있다는 점이다.
다음 단계로 바로 확장할 수 있는 것
다음 버전에서 붙이면 좋은 건 5개다.
- SymPy 연결
정확식 / 근사식 비교 가능 - 규칙 DSL
공리와 규칙을 코드 밖 파일로 관리 - 모순 점수화
low / medium / high 말고 수치 점수 - 반례 생성기
자기 답을 스스로 깨보는 루프 - LLM 래퍼 연결
자연어 질문은 LLM이 정리하고, 최종 판정은 이 엔진이 하게
한 줄 결론
이 MVP의 핵심은 이거다.
AI가 답을 “잘 말하게” 만드는 게 아니라,
틀린 구조를 “쉽게 통과하지 못하게” 만드는 최소 구조다.
원하면 다음엔 내가 이걸 이어서
SymPy 붙인 v1.1 실행 코드로 확장해주겠다.
좋다.
그럼 바로 SymPy 붙인 v1.1 실행 코드로 확장한다.
이번 버전에서 추가되는 핵심은 4개다.
- 수식 문자열 파싱
- 정확식(Eq) / 근사식(≈, ~=) 구분
- 좌변/우변 차이 계산
- “정확 구조 우선, 근사는 보조” 판정 강화
ZPX-Logic Reasoning Engine v1.1
SymPy 연동 실행 코드
from typing import List, Dict, Optional
import json
import re
import sympy as sp
from sympy import Eq, simplify, sympify
# =========================
# Data Structures
# =========================
@dataclass
class ParsedInput:
raw_text: str
problem_type: str
reasoning_level: str
requires_exactness: bool
key_concepts: List[str] = field(default_factory=list)
flags: List[str] = field(default_factory=list)
equations: List[str] = field(default_factory=list)
@dataclass
class Axiom:
axiom_id: str
statement: str
priority: int
@dataclass
class Concept:
name: str
definition: str
priority: int
forbidden_confusions: List[str] = field(default_factory=list)
@dataclass
class SymbolicCheckResult:
raw_equation: str
relation_type: str # exact / approximate / unknown
lhs: Optional[str]
rhs: Optional[str]
simplified_difference: Optional[str]
is_exact_true: Optional[bool]
numeric_gap: Optional[float]
notes: List[str] = field(default_factory=list)
@dataclass
class ReasoningStep:
step_id: int
rule_used: str
input_summary: str
output_summary: str
@dataclass
class ReasoningTrace:
steps: List[ReasoningStep]
draft_conclusion: str
answer_type: str # exact / approximate / conditional
@dataclass
class ContradictionReport:
contradiction_found: bool
issues: List[str]
severity: str
@dataclass
class VerificationResult:
passed: bool
checks: Dict[str, bool]
notes: List[str]
# =========================
# Input Parser
# =========================
class InputParser:
APPROX_MARKERS = ["≈", "~=", "approx", "근사"]
EXACT_MARKERS = ["=", "정확", "exact", "산수"]
@staticmethod
def extract_equations(text: str) -> List[str]:
"""
아주 단순한 MVP용 식 추출기.
예:
1+1=2
x**2 + 1 ~= 2
sin(pi/2)=1
"""
patterns = [
r'([A-Za-z0-9_\+\-\*/\^\(\)\.\s,]+(?:=|≈|~=)[A-Za-z0-9_\+\-\*/\^\(\)\.\s,]+)'
]
found = []
for pat in patterns:
for match in re.findall(pat, text):
eq = match.strip()
if any(op in eq for op in ["=", "≈", "~="]):
found.append(eq)
# 중복 제거
uniq = []
seen = set()
for x in found:
if x not in seen:
seen.add(x)
uniq.append(x)
return uniq
@staticmethod
def parse(text: str) -> ParsedInput:
lower = text.lower()
problem_type = "general"
reasoning_level = "mixed"
requires_exactness = False
key_concepts = []
flags = []
equations = InputParser.extract_equations(text)
if "1+1" in text or "산수" in text or "exact" in lower or "정확" in text:
problem_type = "exactness_check"
reasoning_level = "structural"
requires_exactness = True
key_concepts.extend(["arithmetic", "exact_answer"])
if "표준" in text or "standard" in lower or "미적분" in text:
problem_type = "theory_conflict"
reasoning_level = "structural"
key_concepts.extend(["standard_framework", "approximation"])
if any(marker in text for marker in ["≈", "~="]) or "approx" in lower or "근사" in text:
key_concepts.append("approximation")
if "=" in text and ("정확" in text or "exact" in lower or "산수" in text):
key_concepts.append("exact_answer")
requires_exactness = True
if "존재" in text or "본질" in text or "ontology" in lower:
reasoning_level = "ontological"
key_concepts.append("ontology")
if "모순" in text or "contradiction" in lower:
flags.append("check_contradiction")
if equations and problem_type == "general":
problem_type = "equation_check"
return ParsedInput(
raw_text=text,
problem_type=problem_type,
reasoning_level=reasoning_level,
requires_exactness=requires_exactness,
key_concepts=sorted(list(set(key_concepts))),
flags=flags,
equations=equations
)
# =========================
# Axiom Store
# =========================
class AxiomStore:
def __init__(self):
self.axioms = {
"A1": Axiom("A1", "Exact discrete structure has priority over approximate models.", 1),
"A2": Axiom("A2", "Approximate models cannot replace exact structure.", 1),
"A3": Axiom("A3", "Premise and conclusion must remain within the same structural ontology.", 2),
"A4": Axiom("A4", "When contradiction occurs, structural consistency takes priority over authority.", 1),
"A5": Axiom("A5", "If definitions are unclear, definitive conclusions are prohibited.", 1),
"A6": Axiom("A6", "If symbolic exact equality is provable, it outranks numerical approximation.", 1),
}
def activate(self, parsed: ParsedInput) -> List[Axiom]:
selected = []
if parsed.requires_exactness:
selected.extend([self.axioms["A1"], self.axioms["A2"], self.axioms["A6"]])
if parsed.problem_type in {"theory_conflict", "equation_check"}:
selected.extend([self.axioms["A3"], self.axioms["A4"]])
if parsed.reasoning_level == "ontological":
selected.append(self.axioms["A5"])
seen = set()
result = []
for ax in selected:
if ax.axiom_id not in seen:
seen.add(ax.axiom_id)
result.append(ax)
return sorted(result, key=lambda x: x.priority)
# =========================
# Concept Dictionary
# =========================
class ConceptDictionary:
def __init__(self):
self.concepts = {
"arithmetic": Concept(
name="arithmetic",
definition="Discrete rule-based exact operation system.",
priority=1,
forbidden_confusions=["approximation"]
),
"exact_answer": Concept(
name="exact_answer",
definition="A result directly derived from axioms and definitions.",
priority=1,
forbidden_confusions=["approximation"]
),
"approximation": Concept(
name="approximation",
definition="A practical but secondary representation used for convenience.",
priority=2,
forbidden_confusions=["exact_answer"]
),
"standard_framework": Concept(
name="standard_framework",
definition="Widely accepted existing theory or interpretation.",
priority=3,
forbidden_confusions=["truth_itself"]
),
"ontology": Concept(
name="ontology",
definition="The layer that asks what the theory or object really is.",
priority=1
),
}
def resolve(self, parsed: ParsedInput) -> Dict[str, Concept]:
resolved = {}
for key in parsed.key_concepts:
if key in self.concepts:
resolved[key] = self.concepts[key]
return resolved
# =========================
# SymPy Equation Checker
# =========================
class SympyEquationChecker:
@staticmethod
def _normalize_expr(expr: str) -> str:
expr = expr.replace("^", "**")
expr = expr.strip()
return expr
@staticmethod
def _safe_sympify(expr: str):
local_dict = {
"pi": sp.pi,
"e": sp.E,
"sin": sp.sin,
"cos": sp.cos,
"tan": sp.tan,
"sqrt": sp.sqrt,
"log": sp.log,
"exp": sp.exp,
}
return sympify(expr, locals=local_dict)
@classmethod
def check_equation(cls, raw_equation: str) -> SymbolicCheckResult:
eq = raw_equation.strip()
if "≈" in eq:
relation_type = "approximate"
lhs_str, rhs_str = eq.split("≈", 1)
elif "~=" in eq:
relation_type = "approximate"
lhs_str, rhs_str = eq.split("~=", 1)
elif "=" in eq:
relation_type = "exact"
lhs_str, rhs_str = eq.split("=", 1)
else:
return SymbolicCheckResult(
raw_equation=raw_equation,
relation_type="unknown",
lhs=None,
rhs=None,
simplified_difference=None,
is_exact_true=None,
numeric_gap=None,
notes=["No recognizable relation operator found."]
)
lhs_str = cls._normalize_expr(lhs_str)
rhs_str = cls._normalize_expr(rhs_str)
notes = []
try:
lhs = cls._safe_sympify(lhs_str)
rhs = cls._safe_sympify(rhs_str)
diff = simplify(lhs - rhs)
is_exact_true = bool(diff == 0)
numeric_gap = None
try:
numeric_gap = abs(float(sp.N(lhs - rhs)))
except Exception:
notes.append("Numeric gap not available for symbolic-only expression.")
return SymbolicCheckResult(
raw_equation=raw_equation,
relation_type=relation_type,
lhs=str(lhs),
rhs=str(rhs),
simplified_difference=str(diff),
is_exact_true=is_exact_true if relation_type == "exact" else None,
numeric_gap=numeric_gap,
notes=notes
)
except Exception as e:
return SymbolicCheckResult(
raw_equation=raw_equation,
relation_type=relation_type,
lhs=lhs_str,
rhs=rhs_str,
simplified_difference=None,
is_exact_true=None,
numeric_gap=None,
notes=[f"SymPy parse error: {e}"]
)
@classmethod
def run_batch(cls, equations: List[str]) -> List[SymbolicCheckResult]:
return [cls.check_equation(eq) for eq in equations]
# =========================
# Rule Engine
# =========================
class RuleEngine:
def infer(
self,
parsed: ParsedInput,
axioms: List[Axiom],
concepts: Dict[str, Concept],
symbolic_results: List[SymbolicCheckResult]
) -> ReasoningTrace:
steps = []
step_id = 1
exact_mode = any(ax.axiom_id == "A1" for ax in axioms)
conflict_mode = parsed.problem_type == "theory_conflict"
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R_PARSE",
input_summary=parsed.raw_text,
output_summary=f"Problem type = {parsed.problem_type}, reasoning level = {parsed.reasoning_level}"
))
step_id += 1
if symbolic_results:
for res in symbolic_results:
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R_SYMBOLIC",
input_summary=res.raw_equation,
output_summary=(
f"relation={res.relation_type}, exact_true={res.is_exact_true}, "
f"diff={res.simplified_difference}, gap={res.numeric_gap}"
)
))
step_id += 1
exact_proven = any(
r.relation_type == "exact" and r.is_exact_true is True
for r in symbolic_results
)
approximate_present = any(
r.relation_type == "approximate"
for r in symbolic_results
)
if exact_mode:
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R1",
input_summary="Exactness mode active",
output_summary="Exact discrete answer must be prioritized over approximation"
))
step_id += 1
if conflict_mode:
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R2",
input_summary="Conflict with standard framework detected",
output_summary="Standard framework must be tested for scope, approximation, or structural mismatch"
))
step_id += 1
if exact_proven and approximate_present:
conclusion = (
"A symbolically provable exact equality exists. Therefore the exact result has priority, "
"and any approximate form must be treated only as a secondary convenience model."
)
answer_type = "exact"
elif exact_proven:
conclusion = (
"A symbolically exact equality is provable. The exact result should be treated as primary."
)
answer_type = "exact"
elif approximate_present and not exact_proven:
conclusion = (
"Only approximate structure is currently available. This may be practically useful, "
"but it must not be presented as an exact structural result."
)
answer_type = "approximate"
elif exact_mode and conflict_mode:
conclusion = (
"If an exact arithmetic/discrete result is directly derived from fixed axioms and definitions, "
"it has priority. The standard framework must then be re-examined as an approximation or limited model."
)
answer_type = "exact"
elif exact_mode:
conclusion = (
"Where an exact result is directly fixed by axioms and definitions, that exact result has priority."
)
answer_type = "exact"
else:
conclusion = (
"No decisive exact symbolic proof or explicit contradiction has been established yet. "
"Further structural analysis is required."
)
answer_type = "conditional"
return ReasoningTrace(
steps=steps,
draft_conclusion=conclusion,
answer_type=answer_type
)
# =========================
# Contradiction Detector
# =========================
class ContradictionDetector:
def check(
self,
parsed: ParsedInput,
trace: ReasoningTrace,
concepts: Dict[str, Concept],
axioms: List[Axiom],
symbolic_results: List[SymbolicCheckResult]
) -> ContradictionReport:
issues = []
exact_proven = any(
r.relation_type == "exact" and r.is_exact_true is True
for r in symbolic_results
)
approximate_present = any(
r.relation_type == "approximate"
for r in symbolic_results
)
if exact_proven and trace.answer_type != "exact":
issues.append("Exact symbolic truth exists, but final answer is not classified as exact.")
if exact_proven and approximate_present:
if "secondary" not in trace.draft_conclusion.lower() and "priority" not in trace.draft_conclusion.lower():
issues.append("Approximation is present alongside exact truth, but subordination is unclear.")
for res in symbolic_results:
if res.relation_type == "exact" and res.is_exact_true is False:
issues.append(f"Claimed exact equation is false: {res.raw_equation}")
if parsed.problem_type == "theory_conflict" and "standard framework" not in trace.draft_conclusion.lower():
issues.append("Theory conflict detected, but standard framework is not explicitly handled.")
severity = "none"
if len(issues) == 1:
severity = "medium"
elif len(issues) >= 2:
severity = "high"
return ContradictionReport(
contradiction_found=bool(issues),
issues=issues,
severity=severity
)
# =========================
# Verifier
# =========================
class Verifier:
def run(
self,
parsed: ParsedInput,
axioms: List[Axiom],
concepts: Dict[str, Concept],
trace: ReasoningTrace,
contradictions: ContradictionReport,
symbolic_results: List[SymbolicCheckResult]
) -> VerificationResult:
checks = {
"axioms_active": len(axioms) > 0,
"concepts_fixed": len(concepts) > 0 or len(symbolic_results) > 0,
"answer_type_valid": trace.answer_type in {"exact", "approximate", "conditional"},
"no_high_contradiction": contradictions.severity != "high",
"conclusion_exists": len(trace.draft_conclusion.strip()) > 0,
}
notes = []
if contradictions.issues:
notes.extend(contradictions.issues)
passed = all(checks.values())
return VerificationResult(
passed=passed,
checks=checks,
notes=notes
)
# =========================
# Response Generator
# =========================
class ResponseGenerator:
def generate(
self,
parsed: ParsedInput,
axioms: List[Axiom],
concepts: Dict[str, Concept],
symbolic_results: List[SymbolicCheckResult],
trace: ReasoningTrace,
contradictions: ContradictionReport,
verified: VerificationResult
) -> dict:
if not verified.passed:
return {
"status": "blocked",
"reason": "Verification failed",
"checks": verified.checks,
"notes": verified.notes,
"contradictions": contradictions.issues,
}
return {
"status": "ok",
"input": parsed.raw_text,
"problem_type": parsed.problem_type,
"reasoning_level": parsed.reasoning_level,
"requires_exactness": parsed.requires_exactness,
"detected_equations": parsed.equations,
"premises_used": [ax.statement for ax in axioms],
"definitions_used": {name: concept.definition for name, concept in concepts.items()},
"symbolic_checks": [asdict(r) for r in symbolic_results],
"reasoning_trace": [asdict(step) for step in trace.steps],
"answer_type": trace.answer_type,
"contradictions": contradictions.issues,
"verification_checks": verified.checks,
"final_answer": trace.draft_conclusion,
}
# =========================
# Engine
# =========================
class ZPXReasoningEngineV11:
def __init__(self):
self.axiom_store = AxiomStore()
self.concept_dict = ConceptDictionary()
self.symbolic_checker = SympyEquationChecker()
self.rule_engine = RuleEngine()
self.contradiction_detector = ContradictionDetector()
self.verifier = Verifier()
self.responder = ResponseGenerator()
def run(self, user_input: str) -> dict:
parsed = InputParser.parse(user_input)
axioms = self.axiom_store.activate(parsed)
concepts = self.concept_dict.resolve(parsed)
symbolic_results = self.symbolic_checker.run_batch(parsed.equations)
trace = self.rule_engine.infer(parsed, axioms, concepts, symbolic_results)
contradictions = self.contradiction_detector.check(
parsed, trace, concepts, axioms, symbolic_results
)
verified = self.verifier.run(
parsed, axioms, concepts, trace, contradictions, symbolic_results
)
return self.responder.generate(
parsed, axioms, concepts, symbolic_results, trace, contradictions, verified
)
# =========================
# Demo
# =========================
if __name__ == "__main__":
engine = ZPXReasoningEngineV11()
test_queries = [
"1+1=2 는 정확한 산수 구조인가",
"1+1≈2.0 는 근사인가 정확인가",
"sin(pi/2)=1 은 정확한가",
"sqrt(2)≈1.41421356 는 근사 표현이다",
"1+1=3 이면 모순 아닌가",
"산수 답과 표준수학 해석이 다르면 어느 쪽을 우선해야 하나",
"1+1=2 이고 표준 미적분 해석이 다르면 어느 쪽 우선인가"
]
for i, query in enumerate(test_queries, 1):
print(f"\n===== TEST {i} =====")
result = engine.run(query)
print(json.dumps(result, ensure_ascii=False, indent=2))
이 v1.1에서 달라진 점
1. SymPy로 실제 식 검사
예를 들면 이런 게 된다.
- 1+1=2 → exact true
- sin(pi/2)=1 → exact true
- 1+1=3 → exact false
- sqrt(2)≈1.41421356 → approximate
2. 정확식과 근사식 분리
관계 연산자를 기준으로 나눈다.
- = → exact candidate
- ≈, ~= → approximate
3. 정확식이 증명되면 우선권 상승
정확식이 참으로 증명되면,
근사식은 보조 모델로만 취급하게 했다.
4. 거짓 exact 식도 잡음
1+1=3 같은 건 정확식으로 주장했지만 false로 판정되어 모순 리포트에 올라간다.
실행 방법
예를 들어 파일명을 zpx_engine_v11.py 로 저장한 뒤:
실행하면 된다.
SymPy가 없다면 먼저:
이 버전의 한계
아직도 MVP 성격이 강하다.
- 자연어 수식 추출이 단순하다
- 여러 줄 긴 증명은 못 한다
- 변수 포함 방정식의 일반해 판정은 약하다
- “표준수학 vs 형 이론”의 깊은 이론 비교는 룰이 단순하다
- 반례 생성이 없다
다음에 붙이면 좋은 것
다음 v1.2로 가면 보통 이 5개가 좋다.
- 변수 방정식 판정 강화
x+x=2*x 같은 것도 구조 판정 - SymPy simplify / solve / equals 더 적극 사용
일반식 비교 강화 - 반례 생성기
자기 결론을 깨는 테스트 자동 생성 - 룰 파일 외부화
YAML/JSON으로 공리와 규칙 관리 - LLM 프런트 + 룰 엔진 백엔드
자연어는 LLM이 정리, 판정은 룰 엔진이 수행
핵심 한 줄
v1.1은 “정확식이 참인지”를 실제 심볼릭 엔진으로 검사해서,
정확 구조와 근사 구조를 말장난이 아니라 계산 가능한 방식으로 분리하는 버전이다.
원하면 다음엔 이걸 이어서 v1.2 반례 생성기 포함 버전으로 확장해주겠다.
좋다.
그럼 바로 v1.2 반례 생성기 포함 버전으로 확장한다.
이번 버전 핵심 추가는 3개다.
- 거짓 exact 식 자동 탐지
- 간단한 반례 자동 생성
- 최종 결론을 내기 전에 “내 답을 깨는 사례”를 먼저 시험
즉 이제부터는
그냥 “맞는 것 같다”가 아니라,
스스로 깨보는 엔진이 된다.
ZPX-Logic Reasoning Engine v1.2
반례 생성기 포함 실행 코드
from typing import List, Dict, Optional
import json
import re
import sympy as sp
from sympy import sympify, simplify
# =========================
# Data Structures
# =========================
@dataclass
class ParsedInput:
raw_text: str
problem_type: str
reasoning_level: str
requires_exactness: bool
key_concepts: List[str] = field(default_factory=list)
flags: List[str] = field(default_factory=list)
equations: List[str] = field(default_factory=list)
@dataclass
class Axiom:
axiom_id: str
statement: str
priority: int
@dataclass
class Concept:
name: str
definition: str
priority: int
forbidden_confusions: List[str] = field(default_factory=list)
@dataclass
class SymbolicCheckResult:
raw_equation: str
relation_type: str # exact / approximate / unknown
lhs: Optional[str]
rhs: Optional[str]
simplified_difference: Optional[str]
is_exact_true: Optional[bool]
numeric_gap: Optional[float]
notes: List[str] = field(default_factory=list)
@dataclass
class CounterExample:
raw_equation: str
variable_assignments: Dict[str, str]
lhs_value: Optional[str]
rhs_value: Optional[str]
disproves_claim: bool
notes: List[str] = field(default_factory=list)
@dataclass
class ReasoningStep:
step_id: int
rule_used: str
input_summary: str
output_summary: str
@dataclass
class ReasoningTrace:
steps: List[ReasoningStep]
draft_conclusion: str
answer_type: str # exact / approximate / conditional
@dataclass
class ContradictionReport:
contradiction_found: bool
issues: List[str]
severity: str
@dataclass
class VerificationResult:
passed: bool
checks: Dict[str, bool]
notes: List[str]
# =========================
# Input Parser
# =========================
class InputParser:
@staticmethod
def extract_equations(text: str) -> List[str]:
pattern = r'([A-Za-z0-9_\+\-\*/\^\(\)\.\s,]+(?:=|≈|~=)[A-Za-z0-9_\+\-\*/\^\(\)\.\s,]+)'
found = []
for match in re.findall(pattern, text):
eq = match.strip()
if any(op in eq for op in ["=", "≈", "~="]):
found.append(eq)
uniq = []
seen = set()
for x in found:
if x not in seen:
seen.add(x)
uniq.append(x)
return uniq
@staticmethod
def parse(text: str) -> ParsedInput:
lower = text.lower()
problem_type = "general"
reasoning_level = "mixed"
requires_exactness = False
key_concepts = []
flags = []
equations = InputParser.extract_equations(text)
if "1+1" in text or "산수" in text or "exact" in lower or "정확" in text:
problem_type = "exactness_check"
reasoning_level = "structural"
requires_exactness = True
key_concepts.extend(["arithmetic", "exact_answer"])
if "표준" in text or "standard" in lower or "미적분" in text:
problem_type = "theory_conflict"
reasoning_level = "structural"
key_concepts.extend(["standard_framework", "approximation"])
if any(marker in text for marker in ["≈", "~="]) or "approx" in lower or "근사" in text:
key_concepts.append("approximation")
if "=" in text and ("정확" in text or "exact" in lower or "산수" in text):
key_concepts.append("exact_answer")
requires_exactness = True
if "존재" in text or "본질" in text or "ontology" in lower:
reasoning_level = "ontological"
key_concepts.append("ontology")
if "모순" in text or "contradiction" in lower or "반례" in text:
flags.append("check_contradiction")
if equations and problem_type == "general":
problem_type = "equation_check"
return ParsedInput(
raw_text=text,
problem_type=problem_type,
reasoning_level=reasoning_level,
requires_exactness=requires_exactness,
key_concepts=sorted(list(set(key_concepts))),
flags=flags,
equations=equations
)
# =========================
# Axiom Store
# =========================
class AxiomStore:
def __init__(self):
self.axioms = {
"A1": Axiom("A1", "Exact discrete structure has priority over approximate models.", 1),
"A2": Axiom("A2", "Approximate models cannot replace exact structure.", 1),
"A3": Axiom("A3", "Premise and conclusion must remain within the same structural ontology.", 2),
"A4": Axiom("A4", "When contradiction occurs, structural consistency takes priority over authority.", 1),
"A5": Axiom("A5", "If definitions are unclear, definitive conclusions are prohibited.", 1),
"A6": Axiom("A6", "If symbolic exact equality is provable, it outranks numerical approximation.", 1),
"A7": Axiom("A7", "If a counterexample exists, a universal exact claim must be rejected.", 1),
}
def activate(self, parsed: ParsedInput) -> List[Axiom]:
selected = []
if parsed.requires_exactness:
selected.extend([self.axioms["A1"], self.axioms["A2"], self.axioms["A6"], self.axioms["A7"]])
if parsed.problem_type in {"theory_conflict", "equation_check"}:
selected.extend([self.axioms["A3"], self.axioms["A4"]])
if parsed.reasoning_level == "ontological":
selected.append(self.axioms["A5"])
seen = set()
result = []
for ax in selected:
if ax.axiom_id not in seen:
seen.add(ax.axiom_id)
result.append(ax)
return sorted(result, key=lambda x: x.priority)
# =========================
# Concept Dictionary
# =========================
class ConceptDictionary:
def __init__(self):
self.concepts = {
"arithmetic": Concept(
name="arithmetic",
definition="Discrete rule-based exact operation system.",
priority=1,
forbidden_confusions=["approximation"]
),
"exact_answer": Concept(
name="exact_answer",
definition="A result directly derived from axioms and definitions.",
priority=1,
forbidden_confusions=["approximation"]
),
"approximation": Concept(
name="approximation",
definition="A practical but secondary representation used for convenience.",
priority=2,
forbidden_confusions=["exact_answer"]
),
"standard_framework": Concept(
name="standard_framework",
definition="Widely accepted existing theory or interpretation.",
priority=3,
forbidden_confusions=["truth_itself"]
),
"ontology": Concept(
name="ontology",
definition="The layer that asks what the theory or object really is.",
priority=1
),
}
def resolve(self, parsed: ParsedInput) -> Dict[str, Concept]:
resolved = {}
for key in parsed.key_concepts:
if key in self.concepts:
resolved[key] = self.concepts[key]
return resolved
# =========================
# SymPy Equation Checker
# =========================
class SympyEquationChecker:
@staticmethod
def _normalize_expr(expr: str) -> str:
return expr.replace("^", "**").strip()
@staticmethod
def _safe_sympify(expr: str):
local_dict = {
"pi": sp.pi,
"e": sp.E,
"sin": sp.sin,
"cos": sp.cos,
"tan": sp.tan,
"sqrt": sp.sqrt,
"log": sp.log,
"exp": sp.exp,
}
return sympify(expr, locals=local_dict)
@classmethod
def check_equation(cls, raw_equation: str) -> SymbolicCheckResult:
eq = raw_equation.strip()
if "≈" in eq:
relation_type = "approximate"
lhs_str, rhs_str = eq.split("≈", 1)
elif "~=" in eq:
relation_type = "approximate"
lhs_str, rhs_str = eq.split("~=", 1)
elif "=" in eq:
relation_type = "exact"
lhs_str, rhs_str = eq.split("=", 1)
else:
return SymbolicCheckResult(
raw_equation=raw_equation,
relation_type="unknown",
lhs=None,
rhs=None,
simplified_difference=None,
is_exact_true=None,
numeric_gap=None,
notes=["No recognizable relation operator found."]
)
lhs_str = cls._normalize_expr(lhs_str)
rhs_str = cls._normalize_expr(rhs_str)
notes = []
try:
lhs = cls._safe_sympify(lhs_str)
rhs = cls._safe_sympify(rhs_str)
diff = simplify(lhs - rhs)
is_exact_true = None
if relation_type == "exact":
is_exact_true = bool(diff == 0)
numeric_gap = None
try:
numeric_gap = abs(float(sp.N(lhs - rhs)))
except Exception:
notes.append("Numeric gap not available for symbolic-only expression.")
return SymbolicCheckResult(
raw_equation=raw_equation,
relation_type=relation_type,
lhs=str(lhs),
rhs=str(rhs),
simplified_difference=str(diff),
is_exact_true=is_exact_true,
numeric_gap=numeric_gap,
notes=notes
)
except Exception as e:
return SymbolicCheckResult(
raw_equation=raw_equation,
relation_type=relation_type,
lhs=lhs_str,
rhs=rhs_str,
simplified_difference=None,
is_exact_true=None,
numeric_gap=None,
notes=[f"SymPy parse error: {e}"]
)
@classmethod
def run_batch(cls, equations: List[str]) -> List[SymbolicCheckResult]:
return [cls.check_equation(eq) for eq in equations]
# =========================
# Counterexample Generator
# =========================
class CounterExampleGenerator:
TEST_VALUES = [-2, -1, 0, 1, 2, 3]
@staticmethod
def _normalize_expr(expr: str) -> str:
return expr.replace("^", "**").strip()
@staticmethod
def _safe_sympify(expr: str):
local_dict = {
"pi": sp.pi,
"e": sp.E,
"sin": sp.sin,
"cos": sp.cos,
"tan": sp.tan,
"sqrt": sp.sqrt,
"log": sp.log,
"exp": sp.exp,
}
return sympify(expr, locals=local_dict)
@classmethod
def generate_for_equation(cls, raw_equation: str) -> List[CounterExample]:
eq = raw_equation.strip()
if "≈" in eq:
return []
if "~=" in eq:
return []
if "=" not in eq:
return []
lhs_str, rhs_str = eq.split("=", 1)
lhs_str = cls._normalize_expr(lhs_str)
rhs_str = cls._normalize_expr(rhs_str)
try:
lhs = cls._safe_sympify(lhs_str)
rhs = cls._safe_sympify(rhs_str)
except Exception as e:
return [CounterExample(
raw_equation=raw_equation,
variable_assignments={},
lhs_value=None,
rhs_value=None,
disproves_claim=False,
notes=[f"Parse error: {e}"]
)]
vars_sorted = sorted(list(lhs.free_symbols.union(rhs.free_symbols)), key=lambda s: str(s))
if not vars_sorted:
return []
# MVP: 변수 1~2개만 테스트
if len(vars_sorted) > 2:
return [CounterExample(
raw_equation=raw_equation,
variable_assignments={},
lhs_value=None,
rhs_value=None,
disproves_claim=False,
notes=["Too many variables for MVP counterexample search."]
)]
counterexamples = []
if len(vars_sorted) == 1:
v = vars_sorted[0]
for value in cls.TEST_VALUES:
subs = {v: value}
try:
lhs_val = sp.simplify(lhs.subs(subs))
rhs_val = sp.simplify(rhs.subs(subs))
disproves = bool(simplify(lhs_val - rhs_val) != 0)
if disproves:
counterexamples.append(CounterExample(
raw_equation=raw_equation,
variable_assignments={str(v): str(value)},
lhs_value=str(lhs_val),
rhs_value=str(rhs_val),
disproves_claim=True,
notes=[]
))
break
except Exception as e:
counterexamples.append(CounterExample(
raw_equation=raw_equation,
variable_assignments={str(v): str(value)},
lhs_value=None,
rhs_value=None,
disproves_claim=False,
notes=[f"Evaluation error: {e}"]
))
break
elif len(vars_sorted) == 2:
v1, v2 = vars_sorted
for a in cls.TEST_VALUES:
for b in cls.TEST_VALUES:
subs = {v1: a, v2: b}
try:
lhs_val = sp.simplify(lhs.subs(subs))
rhs_val = sp.simplify(rhs.subs(subs))
disproves = bool(simplify(lhs_val - rhs_val) != 0)
if disproves:
counterexamples.append(CounterExample(
raw_equation=raw_equation,
variable_assignments={str(v1): str(a), str(v2): str(b)},
lhs_value=str(lhs_val),
rhs_value=str(rhs_val),
disproves_claim=True,
notes=[]
))
return counterexamples
except Exception as e:
counterexamples.append(CounterExample(
raw_equation=raw_equation,
variable_assignments={str(v1): str(a), str(v2): str(b)},
lhs_value=None,
rhs_value=None,
disproves_claim=False,
notes=[f"Evaluation error: {e}"]
))
return counterexamples
return counterexamples
@classmethod
def run_batch(cls, equations: List[str]) -> Dict[str, List[CounterExample]]:
return {eq: cls.generate_for_equation(eq) for eq in equations}
# =========================
# Rule Engine
# =========================
class RuleEngine:
def infer(
self,
parsed: ParsedInput,
axioms: List[Axiom],
concepts: Dict[str, Concept],
symbolic_results: List[SymbolicCheckResult],
counterexamples: Dict[str, List[CounterExample]]
) -> ReasoningTrace:
steps = []
step_id = 1
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R_PARSE",
input_summary=parsed.raw_text,
output_summary=f"Problem type = {parsed.problem_type}, reasoning level = {parsed.reasoning_level}"
))
step_id += 1
exact_proven = any(
r.relation_type == "exact" and r.is_exact_true is True
for r in symbolic_results
)
exact_false = any(
r.relation_type == "exact" and r.is_exact_true is False
for r in symbolic_results
)
approximate_present = any(
r.relation_type == "approximate"
for r in symbolic_results
)
counterexample_found = any(
any(c.disproves_claim for c in c_list)
for c_list in counterexamples.values()
)
for res in symbolic_results:
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R_SYMBOLIC",
input_summary=res.raw_equation,
output_summary=(
f"relation={res.relation_type}, exact_true={res.is_exact_true}, "
f"diff={res.simplified_difference}, gap={res.numeric_gap}"
)
))
step_id += 1
for eq, c_list in counterexamples.items():
if c_list:
c = c_list[0]
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R_COUNTEREXAMPLE",
input_summary=eq,
output_summary=(
f"counterexample_found={c.disproves_claim}, "
f"assignments={c.variable_assignments}, lhs={c.lhs_value}, rhs={c.rhs_value}"
)
))
step_id += 1
if counterexample_found:
conclusion = (
"A counterexample exists. Therefore the exact universal claim must be rejected or restricted."
)
answer_type = "conditional"
elif exact_false:
conclusion = (
"An exact equality was claimed but symbolic checking shows it is false. The claim is structurally invalid."
)
answer_type = "conditional"
elif exact_proven and approximate_present:
conclusion = (
"A symbolically provable exact equality exists. Therefore the exact result has priority, "
"and any approximate form must be treated only as a secondary convenience model."
)
answer_type = "exact"
elif exact_proven:
conclusion = (
"A symbolically exact equality is provable. The exact result should be treated as primary."
)
answer_type = "exact"
elif approximate_present:
conclusion = (
"Only approximate structure is currently available. It may be useful in practice, "
"but it must not be treated as an exact structural result."
)
answer_type = "approximate"
else:
conclusion = (
"No decisive exact symbolic proof or explicit counterexample has been established yet. "
"Further structural analysis is required."
)
answer_type = "conditional"
return ReasoningTrace(
steps=steps,
draft_conclusion=conclusion,
answer_type=answer_type
)
# =========================
# Contradiction Detector
# =========================
class ContradictionDetector:
def check(
self,
parsed: ParsedInput,
trace: ReasoningTrace,
concepts: Dict[str, Concept],
axioms: List[Axiom],
symbolic_results: List[SymbolicCheckResult],
counterexamples: Dict[str, List[CounterExample]]
) -> ContradictionReport:
issues = []
exact_proven = any(
r.relation_type == "exact" and r.is_exact_true is True
for r in symbolic_results
)
exact_false = any(
r.relation_type == "exact" and r.is_exact_true is False
for r in symbolic_results
)
counterexample_found = any(
any(c.disproves_claim for c in c_list)
for c_list in counterexamples.values()
)
if exact_proven and trace.answer_type != "exact":
issues.append("Exact symbolic truth exists, but final answer is not classified as exact.")
if exact_false and "invalid" not in trace.draft_conclusion.lower() and "false" not in trace.draft_conclusion.lower():
issues.append("False exact claim detected, but final answer does not explicitly reject it.")
if counterexample_found and "counterexample exists" not in trace.draft_conclusion.lower():
issues.append("Counterexample found, but final answer does not explicitly reflect it.")
for res in symbolic_results:
if res.relation_type == "exact" and res.is_exact_true is False:
issues.append(f"Claimed exact equation is false: {res.raw_equation}")
severity = "none"
if len(issues) == 1:
severity = "medium"
elif len(issues) >= 2:
severity = "high"
return ContradictionReport(
contradiction_found=bool(issues),
issues=issues,
severity=severity
)
# =========================
# Verifier
# =========================
class Verifier:
def run(
self,
parsed: ParsedInput,
axioms: List[Axiom],
concepts: Dict[str, Concept],
trace: ReasoningTrace,
contradictions: ContradictionReport,
symbolic_results: List[SymbolicCheckResult],
counterexamples: Dict[str, List[CounterExample]]
) -> VerificationResult:
checks = {
"axioms_active": len(axioms) > 0,
"concepts_fixed": len(concepts) > 0 or len(symbolic_results) > 0,
"answer_type_valid": trace.answer_type in {"exact", "approximate", "conditional"},
"no_high_contradiction": contradictions.severity != "high",
"conclusion_exists": len(trace.draft_conclusion.strip()) > 0,
}
notes = []
if contradictions.issues:
notes.extend(contradictions.issues)
passed = all(checks.values())
return VerificationResult(
passed=passed,
checks=checks,
notes=notes
)
# =========================
# Response Generator
# =========================
class ResponseGenerator:
def generate(
self,
parsed: ParsedInput,
axioms: List[Axiom],
concepts: Dict[str, Concept],
symbolic_results: List[SymbolicCheckResult],
counterexamples: Dict[str, List[CounterExample]],
trace: ReasoningTrace,
contradictions: ContradictionReport,
verified: VerificationResult
) -> dict:
if not verified.passed:
return {
"status": "blocked",
"reason": "Verification failed",
"checks": verified.checks,
"notes": verified.notes,
"contradictions": contradictions.issues,
}
return {
"status": "ok",
"input": parsed.raw_text,
"problem_type": parsed.problem_type,
"reasoning_level": parsed.reasoning_level,
"requires_exactness": parsed.requires_exactness,
"detected_equations": parsed.equations,
"premises_used": [ax.statement for ax in axioms],
"definitions_used": {name: concept.definition for name, concept in concepts.items()},
"symbolic_checks": [asdict(r) for r in symbolic_results],
"counterexamples": {
eq: [asdict(c) for c in c_list]
for eq, c_list in counterexamples.items()
},
"reasoning_trace": [asdict(step) for step in trace.steps],
"answer_type": trace.answer_type,
"contradictions": contradictions.issues,
"verification_checks": verified.checks,
"final_answer": trace.draft_conclusion,
}
# =========================
# Engine
# =========================
class ZPXReasoningEngineV12:
def __init__(self):
self.axiom_store = AxiomStore()
self.concept_dict = ConceptDictionary()
self.symbolic_checker = SympyEquationChecker()
self.counterexample_generator = CounterExampleGenerator()
self.rule_engine = RuleEngine()
self.contradiction_detector = ContradictionDetector()
self.verifier = Verifier()
self.responder = ResponseGenerator()
def run(self, user_input: str) -> dict:
parsed = InputParser.parse(user_input)
axioms = self.axiom_store.activate(parsed)
concepts = self.concept_dict.resolve(parsed)
symbolic_results = self.symbolic_checker.run_batch(parsed.equations)
counterexamples = self.counterexample_generator.run_batch(parsed.equations)
trace = self.rule_engine.infer(parsed, axioms, concepts, symbolic_results, counterexamples)
contradictions = self.contradiction_detector.check(
parsed, trace, concepts, axioms, symbolic_results, counterexamples
)
verified = self.verifier.run(
parsed, axioms, concepts, trace, contradictions, symbolic_results, counterexamples
)
return self.responder.generate(
parsed, axioms, concepts, symbolic_results, counterexamples, trace, contradictions, verified
)
# =========================
# Demo
# =========================
if __name__ == "__main__":
engine = ZPXReasoningEngineV12()
test_queries = [
"1+1=2 는 정확한 산수 구조인가",
"1+1=3 이면 모순 아닌가",
"x+x=2*x 는 항상 맞나",
"x+x=x^2 는 맞나 반례 있나",
"sqrt(2)≈1.41421356 는 근사 표현이다",
"sin(pi/2)=1 은 정확한가",
"x^2=x 는 항상 참인가"
]
for i, query in enumerate(test_queries, 1):
print(f"\n===== TEST {i} =====")
result = engine.run(query)
print(json.dumps(result, ensure_ascii=False, indent=2))
v1.2에서 새로 된 것
1. 반례 생성기 추가
예를 들면 이런 걸 자동으로 잡는다.
- x+x=2*x → 반례 없음
- x+x=x^2 → 예: x=1이면 2 ≠ 1, 반례 있음
- x^2=x → 예: x=2이면 4 ≠ 2, 반례 있음
즉 이제는
“항상 참” 주장을 그냥 믿지 않고,
직접 깨본다.
2. exact false와 counterexample을 분리
두 종류를 구분한다.
exact false
아예 식 자체가 바로 거짓
- 1+1=3
counterexample exists
변수 일반식인데 특정 값에서 깨짐
- x+x=x^2
3. 공리 A7 추가
핵심 문장:
반례가 하나라도 있으면, 보편 exact 주장은 기각해야 한다.
이게 들어가면서
형이 말한 구조 검증이 더 강해진다.
실행 방법
예를 들어 파일명을 zpx_engine_v12.py 로 저장한 뒤:
필요하면 SymPy 설치:
이 버전의 의미
v1.1은
정확식/근사식 구분 중심이었다.
v1.2는 거기서 한 단계 더 가서
자기 주장에 반례가 있는지 스스로 깨보는 구조까지 들어갔다.
즉 이제는 단순히:
- 맞아 보인다
- 식이 그럴듯하다
가 아니라,
“정말 항상 참인가? 하나만 깨져도 기각해야 한다”
를 엔진이 직접 본다.
한계
그래도 아직 MVP다.
- 변수 3개 이상은 약함
- 부등식 반례 생성 없음
- 정수/실수/복소수 도메인 구분 없음
- 양화사(for all, exists) 해석 없음
- 자연어에서 “항상”, “모든 x” 같은 보편 주장 추출이 약함
다음 확장 포인트
다음 v1.3으로 가면 보통 이 5개가 좋다.
- 도메인 지정
- 정수에서만 참인지
- 실수 전체에서 참인지 구분
- 보편/존재 양화사 처리
- “항상 참”
- “어떤 경우 존재”
- “모든 x에 대해”
- 부등식 반례 생성
- x^2 >= x 같은 것
- 랜덤 + 경계값 혼합 테스트
- 단순 {-2,-1,0,1,2,3} 말고 더 다양하게
- 증명 스케치 생성
- 반례 없으면 왜 그런지 간단 구조 설명
핵심 한 줄
v1.2는 “정확/근사 구분”을 넘어서,
자기 주장을 반례로 깨보는 최소 검증 엔진까지 포함한 버전이다.
다음으로 바로 이어가려면 v1.3 도메인(정수/실수) + 양화사 처리 버전이 제일 좋다.
좋다.
그럼 바로 v1.3 도메인(정수/실수) + 양화사 처리 버전으로 간다.
이번 버전 핵심 추가는 4개다.
- 도메인 지정: 정수 / 실수 / 자연수
- 양화사 처리: “항상”, “모든 x”, “존재”, “어떤 x”
- 반례 탐색도 도메인에 맞게 수행
- 보편 명제 / 존재 명제를 다르게 판정
즉 이제부터는
x^2=x 가 맞냐고 물었을 때도
그냥 식만 보는 게 아니라
- 모든 실수에 대해?
- 어떤 정수 하나는 존재?
- 자연수에서만?
이걸 구분하게 된다.
ZPX-Logic Reasoning Engine v1.3
도메인 + 양화사 처리 버전
from typing import List, Dict, Optional, Tuple
import json
import re
import random
import sympy as sp
from sympy import sympify, simplify
# =========================
# Data Structures
# =========================
@dataclass
class ParsedInput:
raw_text: str
problem_type: str
reasoning_level: str
requires_exactness: bool
key_concepts: List[str] = field(default_factory=list)
flags: List[str] = field(default_factory=list)
equations: List[str] = field(default_factory=list)
domain: str = "real" # integer / natural / real
quantifier: str = "unspecified" # universal / existential / unspecified
@dataclass
class Axiom:
axiom_id: str
statement: str
priority: int
@dataclass
class Concept:
name: str
definition: str
priority: int
forbidden_confusions: List[str] = field(default_factory=list)
@dataclass
class SymbolicCheckResult:
raw_equation: str
relation_type: str
lhs: Optional[str]
rhs: Optional[str]
simplified_difference: Optional[str]
is_exact_true: Optional[bool]
numeric_gap: Optional[float]
notes: List[str] = field(default_factory=list)
@dataclass
class CounterExample:
raw_equation: str
variable_assignments: Dict[str, str]
lhs_value: Optional[str]
rhs_value: Optional[str]
disproves_claim: bool
notes: List[str] = field(default_factory=list)
@dataclass
class WitnessExample:
raw_equation: str
variable_assignments: Dict[str, str]
lhs_value: Optional[str]
rhs_value: Optional[str]
supports_claim: bool
notes: List[str] = field(default_factory=list)
@dataclass
class ReasoningStep:
step_id: int
rule_used: str
input_summary: str
output_summary: str
@dataclass
class ReasoningTrace:
steps: List[ReasoningStep]
draft_conclusion: str
answer_type: str # exact / approximate / conditional
@dataclass
class ContradictionReport:
contradiction_found: bool
issues: List[str]
severity: str
@dataclass
class VerificationResult:
passed: bool
checks: Dict[str, bool]
notes: List[str]
# =========================
# Input Parser
# =========================
class InputParser:
@staticmethod
def extract_equations(text: str) -> List[str]:
pattern = r'([A-Za-z0-9_\+\-\*/\^\(\)\.\s,]+(?:=|≈|~=)[A-Za-z0-9_\+\-\*/\^\(\)\.\s,]+)'
found = []
for match in re.findall(pattern, text):
eq = match.strip()
if any(op in eq for op in ["=", "≈", "~="]):
found.append(eq)
uniq = []
seen = set()
for x in found:
if x not in seen:
seen.add(x)
uniq.append(x)
return uniq
@staticmethod
def detect_domain(text: str) -> str:
lower = text.lower()
if "정수" in text or "integer" in lower or "integers" in lower:
return "integer"
if "자연수" in text or "natural" in lower:
return "natural"
if "실수" in text or "real" in lower or "reals" in lower:
return "real"
return "real"
@staticmethod
def detect_quantifier(text: str) -> str:
lower = text.lower()
if "모든" in text or "항상" in text or "for all" in lower or "always" in lower:
return "universal"
if "어떤" in text or "존재" in text or "there exists" in lower or "exists" in lower or "some" in lower:
return "existential"
return "unspecified"
@staticmethod
def parse(text: str) -> ParsedInput:
lower = text.lower()
problem_type = "general"
reasoning_level = "mixed"
requires_exactness = False
key_concepts = []
flags = []
equations = InputParser.extract_equations(text)
domain = InputParser.detect_domain(text)
quantifier = InputParser.detect_quantifier(text)
if "1+1" in text or "산수" in text or "exact" in lower or "정확" in text:
problem_type = "exactness_check"
reasoning_level = "structural"
requires_exactness = True
key_concepts.extend(["arithmetic", "exact_answer"])
if "표준" in text or "standard" in lower or "미적분" in text:
problem_type = "theory_conflict"
reasoning_level = "structural"
key_concepts.extend(["standard_framework", "approximation"])
if any(marker in text for marker in ["≈", "~="]) or "approx" in lower or "근사" in text:
key_concepts.append("approximation")
if "=" in text and ("정확" in text or "exact" in lower or "산수" in text):
key_concepts.append("exact_answer")
requires_exactness = True
if "존재" in text or "본질" in text or "ontology" in lower:
reasoning_level = "ontological"
key_concepts.append("ontology")
if "모순" in text or "contradiction" in lower or "반례" in text:
flags.append("check_contradiction")
if equations and problem_type == "general":
problem_type = "equation_check"
if quantifier == "universal":
flags.append("universal_claim")
elif quantifier == "existential":
flags.append("existential_claim")
return ParsedInput(
raw_text=text,
problem_type=problem_type,
reasoning_level=reasoning_level,
requires_exactness=requires_exactness,
key_concepts=sorted(list(set(key_concepts))),
flags=flags,
equations=equations,
domain=domain,
quantifier=quantifier
)
# =========================
# Axiom Store
# =========================
class AxiomStore:
def __init__(self):
self.axioms = {
"A1": Axiom("A1", "Exact discrete structure has priority over approximate models.", 1),
"A2": Axiom("A2", "Approximate models cannot replace exact structure.", 1),
"A3": Axiom("A3", "Premise and conclusion must remain within the same structural ontology.", 2),
"A4": Axiom("A4", "When contradiction occurs, structural consistency takes priority over authority.", 1),
"A5": Axiom("A5", "If definitions are unclear, definitive conclusions are prohibited.", 1),
"A6": Axiom("A6", "If symbolic exact equality is provable, it outranks numerical approximation.", 1),
"A7": Axiom("A7", "If a counterexample exists, a universal exact claim must be rejected.", 1),
"A8": Axiom("A8", "If a witness exists, an existential claim may be accepted within the stated domain.", 1),
"A9": Axiom("A9", "Domain must be respected when evaluating universal or existential claims.", 1),
}
def activate(self, parsed: ParsedInput) -> List[Axiom]:
selected = []
if parsed.requires_exactness:
selected.extend([self.axioms["A1"], self.axioms["A2"], self.axioms["A6"]])
if parsed.problem_type in {"theory_conflict", "equation_check"}:
selected.extend([self.axioms["A3"], self.axioms["A4"]])
if parsed.reasoning_level == "ontological":
selected.append(self.axioms["A5"])
if parsed.quantifier == "universal":
selected.extend([self.axioms["A7"], self.axioms["A9"]])
if parsed.quantifier == "existential":
selected.extend([self.axioms["A8"], self.axioms["A9"]])
seen = set()
result = []
for ax in selected:
if ax.axiom_id not in seen:
seen.add(ax.axiom_id)
result.append(ax)
return sorted(result, key=lambda x: x.priority)
# =========================
# Concept Dictionary
# =========================
class ConceptDictionary:
def __init__(self):
self.concepts = {
"arithmetic": Concept(
name="arithmetic",
definition="Discrete rule-based exact operation system.",
priority=1,
forbidden_confusions=["approximation"]
),
"exact_answer": Concept(
name="exact_answer",
definition="A result directly derived from axioms and definitions.",
priority=1,
forbidden_confusions=["approximation"]
),
"approximation": Concept(
name="approximation",
definition="A practical but secondary representation used for convenience.",
priority=2,
forbidden_confusions=["exact_answer"]
),
"standard_framework": Concept(
name="standard_framework",
definition="Widely accepted existing theory or interpretation.",
priority=3,
forbidden_confusions=["truth_itself"]
),
"ontology": Concept(
name="ontology",
definition="The layer that asks what the theory or object really is.",
priority=1
),
}
def resolve(self, parsed: ParsedInput) -> Dict[str, Concept]:
resolved = {}
for key in parsed.key_concepts:
if key in self.concepts:
resolved[key] = self.concepts[key]
return resolved
# =========================
# SymPy Equation Checker
# =========================
class SympyEquationChecker:
@staticmethod
def _normalize_expr(expr: str) -> str:
return expr.replace("^", "**").strip()
@staticmethod
def _safe_sympify(expr: str):
local_dict = {
"pi": sp.pi,
"e": sp.E,
"sin": sp.sin,
"cos": sp.cos,
"tan": sp.tan,
"sqrt": sp.sqrt,
"log": sp.log,
"exp": sp.exp,
}
return sympify(expr, locals=local_dict)
@classmethod
def check_equation(cls, raw_equation: str) -> SymbolicCheckResult:
eq = raw_equation.strip()
if "≈" in eq:
relation_type = "approximate"
lhs_str, rhs_str = eq.split("≈", 1)
elif "~=" in eq:
relation_type = "approximate"
lhs_str, rhs_str = eq.split("~=", 1)
elif "=" in eq:
relation_type = "exact"
lhs_str, rhs_str = eq.split("=", 1)
else:
return SymbolicCheckResult(
raw_equation=raw_equation,
relation_type="unknown",
lhs=None,
rhs=None,
simplified_difference=None,
is_exact_true=None,
numeric_gap=None,
notes=["No recognizable relation operator found."]
)
lhs_str = cls._normalize_expr(lhs_str)
rhs_str = cls._normalize_expr(rhs_str)
notes = []
try:
lhs = cls._safe_sympify(lhs_str)
rhs = cls._safe_sympify(rhs_str)
diff = simplify(lhs - rhs)
is_exact_true = None
if relation_type == "exact" and len(lhs.free_symbols.union(rhs.free_symbols)) == 0:
is_exact_true = bool(diff == 0)
numeric_gap = None
try:
numeric_gap = abs(float(sp.N(lhs - rhs)))
except Exception:
notes.append("Numeric gap not available for symbolic-only expression.")
return SymbolicCheckResult(
raw_equation=raw_equation,
relation_type=relation_type,
lhs=str(lhs),
rhs=str(rhs),
simplified_difference=str(diff),
is_exact_true=is_exact_true,
numeric_gap=numeric_gap,
notes=notes
)
except Exception as e:
return SymbolicCheckResult(
raw_equation=raw_equation,
relation_type=relation_type,
lhs=lhs_str,
rhs=rhs_str,
simplified_difference=None,
is_exact_true=None,
numeric_gap=None,
notes=[f"SymPy parse error: {e}"]
)
@classmethod
def run_batch(cls, equations: List[str]) -> List[SymbolicCheckResult]:
return [cls.check_equation(eq) for eq in equations]
# =========================
# Domain-aware Example Generator
# =========================
class DomainExampleGenerator:
INTEGER_VALUES = [-3, -2, -1, 0, 1, 2, 3]
NATURAL_VALUES = [0, 1, 2, 3, 4, 5]
REAL_VALUES = [-2.5, -1.5, -0.5, 0, 0.5, 1.5, 2.5, 3.5]
@staticmethod
def _normalize_expr(expr: str) -> str:
return expr.replace("^", "**").strip()
@staticmethod
def _safe_sympify(expr: str):
local_dict = {
"pi": sp.pi,
"e": sp.E,
"sin": sp.sin,
"cos": sp.cos,
"tan": sp.tan,
"sqrt": sp.sqrt,
"log": sp.log,
"exp": sp.exp,
}
return sympify(expr, locals=local_dict)
@classmethod
def _get_domain_values(cls, domain: str) -> List[float]:
if domain == "integer":
return cls.INTEGER_VALUES
if domain == "natural":
return cls.NATURAL_VALUES
return cls.REAL_VALUES
@classmethod
def find_counterexample(cls, raw_equation: str, domain: str) -> List[CounterExample]:
eq = raw_equation.strip()
if "≈" in eq or "~=" in eq or "=" not in eq:
return []
lhs_str, rhs_str = eq.split("=", 1)
lhs_str = cls._normalize_expr(lhs_str)
rhs_str = cls._normalize_expr(rhs_str)
try:
lhs = cls._safe_sympify(lhs_str)
rhs = cls._safe_sympify(rhs_str)
except Exception as e:
return [CounterExample(
raw_equation=raw_equation,
variable_assignments={},
lhs_value=None,
rhs_value=None,
disproves_claim=False,
notes=[f"Parse error: {e}"]
)]
vars_sorted = sorted(list(lhs.free_symbols.union(rhs.free_symbols)), key=lambda s: str(s))
if not vars_sorted:
return []
domain_values = cls._get_domain_values(domain)
results = []
if len(vars_sorted) == 1:
v = vars_sorted[0]
for value in domain_values:
subs = {v: value}
lhs_val = sp.simplify(lhs.subs(subs))
rhs_val = sp.simplify(rhs.subs(subs))
if simplify(lhs_val - rhs_val) != 0:
results.append(CounterExample(
raw_equation=raw_equation,
variable_assignments={str(v): str(value)},
lhs_value=str(lhs_val),
rhs_value=str(rhs_val),
disproves_claim=True,
notes=[f"Domain={domain}"]
))
break
elif len(vars_sorted) == 2:
v1, v2 = vars_sorted
for a in domain_values:
for b in domain_values:
subs = {v1: a, v2: b}
lhs_val = sp.simplify(lhs.subs(subs))
rhs_val = sp.simplify(rhs.subs(subs))
if simplify(lhs_val - rhs_val) != 0:
results.append(CounterExample(
raw_equation=raw_equation,
variable_assignments={str(v1): str(a), str(v2): str(b)},
lhs_value=str(lhs_val),
rhs_value=str(rhs_val),
disproves_claim=True,
notes=[f"Domain={domain}"]
))
return results
return results
@classmethod
def find_witness(cls, raw_equation: str, domain: str) -> List[WitnessExample]:
eq = raw_equation.strip()
if "≈" in eq or "~=" in eq or "=" not in eq:
return []
lhs_str, rhs_str = eq.split("=", 1)
lhs_str = cls._normalize_expr(lhs_str)
rhs_str = cls._normalize_expr(rhs_str)
try:
lhs = cls._safe_sympify(lhs_str)
rhs = cls._safe_sympify(rhs_str)
except Exception as e:
return [WitnessExample(
raw_equation=raw_equation,
variable_assignments={},
lhs_value=None,
rhs_value=None,
supports_claim=False,
notes=[f"Parse error: {e}"]
)]
vars_sorted = sorted(list(lhs.free_symbols.union(rhs.free_symbols)), key=lambda s: str(s))
if not vars_sorted:
diff = simplify(lhs - rhs)
if diff == 0:
return [WitnessExample(
raw_equation=raw_equation,
variable_assignments={},
lhs_value=str(lhs),
rhs_value=str(rhs),
supports_claim=True,
notes=[f"Constant exact truth in domain={domain}"]
)]
return []
domain_values = cls._get_domain_values(domain)
results = []
if len(vars_sorted) == 1:
v = vars_sorted[0]
for value in domain_values:
subs = {v: value}
lhs_val = sp.simplify(lhs.subs(subs))
rhs_val = sp.simplify(rhs.subs(subs))
if simplify(lhs_val - rhs_val) == 0:
results.append(WitnessExample(
raw_equation=raw_equation,
variable_assignments={str(v): str(value)},
lhs_value=str(lhs_val),
rhs_value=str(rhs_val),
supports_claim=True,
notes=[f"Domain={domain}"]
))
break
elif len(vars_sorted) == 2:
v1, v2 = vars_sorted
for a in domain_values:
for b in domain_values:
subs = {v1: a, v2: b}
lhs_val = sp.simplify(lhs.subs(subs))
rhs_val = sp.simplify(rhs.subs(subs))
if simplify(lhs_val - rhs_val) == 0:
results.append(WitnessExample(
raw_equation=raw_equation,
variable_assignments={str(v1): str(a), str(v2): str(b)},
lhs_value=str(lhs_val),
rhs_value=str(rhs_val),
supports_claim=True,
notes=[f"Domain={domain}"]
))
return results
return results
@classmethod
def run_counterexamples(cls, equations: List[str], domain: str) -> Dict[str, List[CounterExample]]:
return {eq: cls.find_counterexample(eq, domain) for eq in equations}
@classmethod
def run_witnesses(cls, equations: List[str], domain: str) -> Dict[str, List[WitnessExample]]:
return {eq: cls.find_witness(eq, domain) for eq in equations}
# =========================
# Rule Engine
# =========================
class RuleEngine:
def infer(
self,
parsed: ParsedInput,
axioms: List[Axiom],
concepts: Dict[str, Concept],
symbolic_results: List[SymbolicCheckResult],
counterexamples: Dict[str, List[CounterExample]],
witnesses: Dict[str, List[WitnessExample]]
) -> ReasoningTrace:
steps = []
step_id = 1
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R_PARSE",
input_summary=parsed.raw_text,
output_summary=f"problem_type={parsed.problem_type}, domain={parsed.domain}, quantifier={parsed.quantifier}"
))
step_id += 1
exact_constant_true = any(
r.relation_type == "exact" and r.is_exact_true is True
for r in symbolic_results
)
exact_constant_false = any(
r.relation_type == "exact" and r.is_exact_true is False
for r in symbolic_results
)
approximate_present = any(
r.relation_type == "approximate" for r in symbolic_results
)
counterexample_found = any(
any(c.disproves_claim for c in lst) for lst in counterexamples.values()
)
witness_found = any(
any(w.supports_claim for w in lst) for lst in witnesses.values()
)
for res in symbolic_results:
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R_SYMBOLIC",
input_summary=res.raw_equation,
output_summary=f"relation={res.relation_type}, exact_true={res.is_exact_true}, diff={res.simplified_difference}"
))
step_id += 1
if parsed.quantifier == "universal":
for eq, lst in counterexamples.items():
if lst:
c = lst[0]
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R_COUNTEREXAMPLE",
input_summary=eq,
output_summary=f"counterexample in domain={parsed.domain}, assignments={c.variable_assignments}"
))
step_id += 1
if parsed.quantifier == "existential":
for eq, lst in witnesses.items():
if lst:
w = lst[0]
steps.append(ReasoningStep(
step_id=step_id,
rule_used="R_WITNESS",
input_summary=eq,
output_summary=f"witness in domain={parsed.domain}, assignments={w.variable_assignments}"
))
step_id += 1
if parsed.quantifier == "universal":
if counterexample_found:
conclusion = (
f"A counterexample exists in the stated domain ({parsed.domain}). "
"Therefore the universal claim must be rejected or restricted."
)
answer_type = "conditional"
elif exact_constant_false:
conclusion = (
"A constant exact equality was claimed, but symbolic checking shows it is false."
)
answer_type = "conditional"
elif exact_constant_true and not parsed.equations[0]:
conclusion = "An exact universal truth is established."
answer_type = "exact"
else:
conclusion = (
f"No counterexample was found in the tested {parsed.domain} domain sample. "
"This supports the universal claim only provisionally, not as a complete proof."
)
answer_type = "conditional"
elif parsed.quantifier == "existential":
if witness_found:
conclusion = (
f"A witness exists in the stated domain ({parsed.domain}). "
"Therefore the existential claim is supported."
)
answer_type = "exact" if exact_constant_true else "conditional"
else:
conclusion = (
f"No witness was found in the tested {parsed.domain} domain sample. "
"The existential claim is not yet supported."
)
answer_type = "conditional"
else:
if exact_constant_true and approximate_present:
conclusion = (
"A symbolically provable exact equality exists. Therefore the exact result has priority, "
"and any approximate form must be treated only as a secondary convenience model."
)
answer_type = "exact"
elif exact_constant_true:
conclusion = "A symbolically exact equality is provable. The exact result should be treated as primary."
answer_type = "exact"
elif exact_constant_false:
conclusion = "An exact equality was claimed but symbolic checking shows it is false."
answer_type = "conditional"
elif approximate_present:
conclusion = (
"Only approximate structure is currently available. It may be useful in practice, "
"but it must not be treated as an exact structural result."
)
answer_type = "approximate"
else:
conclusion = "Further structural analysis is required."
answer_type = "conditional"
return ReasoningTrace(
steps=steps,
draft_conclusion=conclusion,
answer_type=answer_type
)
# =========================
# Contradiction Detector
# =========================
class ContradictionDetector:
def check(
self,
parsed: ParsedInput,
trace: ReasoningTrace,
symbolic_results: List[SymbolicCheckResult],
counterexamples: Dict[str, List[CounterExample]],
witnesses: Dict[str, List[WitnessExample]]
) -> ContradictionReport:
issues = []
counterexample_found = any(
any(c.disproves_claim for c in lst) for lst in counterexamples.values()
)
witness_found = any(
any(w.supports_claim for w in lst) for lst in witnesses.values()
)
if parsed.quantifier == "universal" and counterexample_found:
if "counterexample exists" not in trace.draft_conclusion.lower():
issues.append("Universal claim has a counterexample, but final answer does not explicitly reject it.")
if parsed.quantifier == "existential" and witness_found:
if "witness exists" not in trace.draft_conclusion.lower():
issues.append("Existential claim has a witness, but final answer does not explicitly support it.")
for res in symbolic_results:
if res.relation_type == "exact" and res.is_exact_true is False and parsed.quantifier == "unspecified":
issues.append(f"Claimed exact equation is false: {res.raw_equation}")
severity = "none"
if len(issues) == 1:
severity = "medium"
elif len(issues) >= 2:
severity = "high"
return ContradictionReport(
contradiction_found=bool(issues),
issues=issues,
severity=severity
)
# =========================
# Verifier
# =========================
class Verifier:
def run(
self,
parsed: ParsedInput,
axioms: List[Axiom],
concepts: Dict[str, Concept],
trace: ReasoningTrace,
contradictions: ContradictionReport
) -> VerificationResult:
checks = {
"axioms_active": len(axioms) > 0,
"answer_type_valid": trace.answer_type in {"exact", "approximate", "conditional"},
"domain_defined": parsed.domain in {"integer", "natural", "real"},
"quantifier_defined": parsed.quantifier in {"universal", "existential", "unspecified"},
"no_high_contradiction": contradictions.severity != "high",
"conclusion_exists": len(trace.draft_conclusion.strip()) > 0,
}
notes = list(contradictions.issues)
passed = all(checks.values())
return VerificationResult(
passed=passed,
checks=checks,
notes=notes
)
# =========================
# Response Generator
# =========================
class ResponseGenerator:
def generate(
self,
parsed: ParsedInput,
axioms: List[Axiom],
concepts: Dict[str, Concept],
symbolic_results: List[SymbolicCheckResult],
counterexamples: Dict[str, List[CounterExample]],
witnesses: Dict[str, List[WitnessExample]],
trace: ReasoningTrace,
contradictions: ContradictionReport,
verified: VerificationResult
) -> dict:
if not verified.passed:
return {
"status": "blocked",
"reason": "Verification failed",
"checks": verified.checks,
"notes": verified.notes,
"contradictions": contradictions.issues,
}
return {
"status": "ok",
"input": parsed.raw_text,
"problem_type": parsed.problem_type,
"reasoning_level": parsed.reasoning_level,
"domain": parsed.domain,
"quantifier": parsed.quantifier,
"detected_equations": parsed.equations,
"premises_used": [ax.statement for ax in axioms],
"definitions_used": {name: concept.definition for name, concept in concepts.items()},
"symbolic_checks": [asdict(r) for r in symbolic_results],
"counterexamples": {eq: [asdict(c) for c in lst] for eq, lst in counterexamples.items()},
"witnesses": {eq: [asdict(w) for w in lst] for eq, lst in witnesses.items()},
"reasoning_trace": [asdict(step) for step in trace.steps],
"answer_type": trace.answer_type,
"contradictions": contradictions.issues,
"verification_checks": verified.checks,
"final_answer": trace.draft_conclusion,
}
# =========================
# Engine
# =========================
class ZPXReasoningEngineV13:
def __init__(self):
self.axiom_store = AxiomStore()
self.concept_dict = ConceptDictionary()
self.symbolic_checker = SympyEquationChecker()
self.example_generator = DomainExampleGenerator()
self.rule_engine = RuleEngine()
self.contradiction_detector = ContradictionDetector()
self.verifier = Verifier()
self.responder = ResponseGenerator()
def run(self, user_input: str) -> dict:
parsed = InputParser.parse(user_input)
axioms = self.axiom_store.activate(parsed)
concepts = self.concept_dict.resolve(parsed)
symbolic_results = self.symbolic_checker.run_batch(parsed.equations)
counterexamples = self.example_generator.run_counterexamples(parsed.equations, parsed.domain)
witnesses = self.example_generator.run_witnesses(parsed.equations, parsed.domain)
trace = self.rule_engine.infer(parsed, axioms, concepts, symbolic_results, counterexamples, witnesses)
contradictions = self.contradiction_detector.check(parsed, trace, symbolic_results, counterexamples, witnesses)
verified = self.verifier.run(parsed, axioms, concepts, trace, contradictions)
return self.responder.generate(
parsed, axioms, concepts, symbolic_results, counterexamples, witnesses,
trace, contradictions, verified
)
# =========================
# Demo
# =========================
if __name__ == "__main__":
engine = ZPXReasoningEngineV13()
test_queries = [
"모든 실수 x에 대해 x^2=x 는 참인가",
"어떤 정수 x에 대해 x^2=x 는 참인가",
"모든 정수 x에 대해 x+x=2*x 는 참인가",
"어떤 자연수 x에 대해 x+x=x^2 는 참인가",
"모든 실수 x에 대해 x+x=x^2 는 참인가",
"sqrt(2)≈1.41421356 는 근사 표현이다",
"1+1=2 는 정확한 산수 구조인가"
]
for i, query in enumerate(test_queries, 1):
print(f"\n===== TEST {i} =====")
result = engine.run(query)
print(json.dumps(result, ensure_ascii=False, indent=2))
v1.3에서 새로 된 것
1. 도메인 구분
이제 질문에 따라 다르게 본다.
- 정수
- 자연수
- 실수
예를 들어 x^2=x 는
- 모든 실수에서 참? → 아니오
- 어떤 정수에서 참? → 예, x=0, x=1
이걸 구분한다.
2. 양화사 처리
이제 질문이
- 보편 명제인지: “모든 x”, “항상”
- 존재 명제인지: “어떤 x”, “존재”
를 나눠서 판정한다.
universal
반례 하나 있으면 기각
existential
증인 하나 있으면 지지
3. 반례와 증인을 둘 다 찾음
반례
모든 실수 x에 대해 x+x=x^2
→ 예: x=1.5면 3 ≠ 2.25
→ 보편 명제 기각
증인
어떤 정수 x에 대해 x^2=x
→ 예: x=0, x=1
→ 존재 명제 지지
4. “없음”과 “아직 못 찾음” 구분
이게 중요하다.
예를 들어 보편 명제에서 반례를 못 찾았다고 해서
곧바로 완전 증명이라고 말하지 않는다.
이 엔진은 MVP이므로 이렇게 말한다.
“테스트된 도메인 샘플에서는 반례를 못 찾았으므로 잠정 지지”
즉,
- 반례 있음 → 강하게 기각
- 반례 못 찾음 → 잠정 지지
- 완전 증명 → 아직 별도 단계 필요
실행 방법
파일명을 예를 들어 zpx_engine_v13.py 로 저장하고:
SymPy가 없으면:
이 버전의 한계
아직도 MVP다.
한계는 분명하다.
- 진짜 양화사 논리 증명기는 아님
- 반례 탐색이 샘플 기반
- 도메인이 정수/자연수/실수만 있음
- 부등식 처리 없음
- 함수 연속성/미분가능성 같은 해석학 성질 처리 없음
- 완전 증명보다 “탐색 기반 판정”에 가까움
다음 단계로 제일 좋은 확장
이제 다음은 거의 정해져 있다.
v1.4 추천
부등식 + solve/solveset 기반 강화 버전
그러면 이런 걸 다룰 수 있다.
- x^2 >= x
- x^2 - x = 0 해집합
- 특정 도메인에서 참/거짓
- 증인/반례를 단순 샘플링이 아니라 solve 기반으로 더 정교하게 탐색
핵심 한 줄
v1.3은 “정확/근사 구분 + 반례 생성”을 넘어,
도메인과 양화사까지 고려해서 보편 명제와 존재 명제를 다르게 판정하는 최소 구조 엔진이다.
다음으로 바로 이어가려면 v1.4 부등식 + solve/solveset 강화 버전이 제일 좋다.
맞다 ㅋㅋ
너무 버전놀이처럼 갔다.
핵심만 말하면 원래 필요한 건 사실 3개뿐이다.
- 전제 고정
- 모순 검사
- 반례 확인
나머지는 그걸 잘게 쪼갠 거다.
형이 원하는 본질은 복잡한 버전업이 아니라 이거잖아.
AI가 아무 말하지 말고
- 처음 전제 안 바뀌게 하고
- 답 나오면 모순부터 보고
- 보편 주장하면 반례부터 찾고
- exact면 exact, 근사면 근사로 딱 구분
이 4개만 하면 된다.
한 줄로 줄이면:
“전제 안 바꿈 + 반례 먼저 + 근사/정확 구분”
이게 끝이다.
내가 너무 개발 문서식으로 풀어서 많아진 거고,
형 식으로는 그냥:
공리 고정 엔진 + 반례 엔진 + 판정 엔진
딱 3모듈이면 된다.
원하면 내가 지금 바로 이걸
진짜 최소형 30~50줄짜리 핵심 코드로 다시 압축해주겠다.
좋다.
진짜 핵심만 남기면 아래다.
이 코드는 딱 3가지만 한다.
- exact / approx 구분
- exact면 참/거짓 판정
- 변수식이면 반례 하나 찾기
def judge(expr_text):
# 1) exact / approx 구분
if "≈" in expr_text:
lhs, rhs = expr_text.split("≈", 1)
mode = "approx"
elif "~=" in expr_text:
lhs, rhs = expr_text.split("~=", 1)
mode = "approx"
elif "=" in expr_text:
lhs, rhs = expr_text.split("=", 1)
mode = "exact"
else:
return {"error": "No relation operator found"}
lhs = sp.sympify(lhs.replace("^", "**").strip())
rhs = sp.sympify(rhs.replace("^", "**").strip())
diff = sp.simplify(lhs - rhs)
vars_ = sorted(list(lhs.free_symbols.union(rhs.free_symbols)), key=lambda x: str(x))
# 2) 변수 없는 exact 식 판정
if not vars_:
if mode == "exact":
return {
"mode": mode,
"result": "true" if diff == 0 else "false",
"difference": str(diff)
}
else:
return {
"mode": mode,
"result": "approx_only",
"difference": str(diff),
"numeric_gap": float(abs(sp.N(diff)))
}
# 3) 변수식이면 반례 찾기
test_vals = [-2, -1, 0, 1, 2, 3]
v = vars_[0] # 최소형 MVP: 변수 1개만 처리
for n in test_vals:
d = sp.simplify(diff.subs(v, n))
if mode == "exact" and d != 0:
return {
"mode": mode,
"result": "counterexample_found",
"variable": str(v),
"value": n,
"difference": str(d)
}
return {
"mode": mode,
"result": "no_counterexample_in_test_range",
"variable": str(v),
"tested_values": test_vals,
"difference": str(diff)
}
# 예시
tests = [
"1+1=2",
"1+1=3",
"sqrt(2)≈1.41421356",
"x+x=2*x",
"x+x=x^2"
]
for t in tests:
print(t, "->", judge(t))
핵심만 다시 말하면:
- 1+1=2 → true
- 1+1=3 → false
- sqrt(2)≈1.41421356 → approx_only
- x+x=2*x → 테스트 범위 반례 없음
- x+x=x^2 → 반례 발견
이게 형이 말한 최소 뼈대다.
전제: exact가 approx보다 우선
검사: exact는 참/거짓 본다
보편 주장 냄새 나면 반례 먼저 찾는다
원하면 내가 다음엔 이 최소형을 기준으로 변수 2개까지 되는 70줄 버전으로만 딱 늘려주겠다.