fable-engine 1.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fable_compressor.py +356 -0
- fable_engine/__init__.py +1 -0
- fable_engine/actions/__init__.py +291 -0
- fable_engine/actions/cas.py +182 -0
- fable_engine/actions/deliberation.py +523 -0
- fable_engine/actions/fleet.py +807 -0
- fable_engine/actions/lifecycle.py +298 -0
- fable_engine/actions/scrapers.py +116 -0
- fable_engine/actions/system3.py +815 -0
- fable_engine/browser.py +824 -0
- fable_engine/cas.py +974 -0
- fable_engine/fable_session.json +510 -0
- fable_engine/guards.py +283 -0
- fable_engine/schema.py +714 -0
- fable_engine/scrapers/__init__.py +32 -0
- fable_engine/scrapers/arxiv.py +115 -0
- fable_engine/scrapers/base.py +386 -0
- fable_engine/scrapers/github.py +129 -0
- fable_engine/scrapers/reddit.py +154 -0
- fable_engine/scrapers/web.py +120 -0
- fable_engine/scrapers/x.py +125 -0
- fable_engine/scrapers/youtube.py +132 -0
- fable_engine/server.py +414 -0
- fable_engine/session.py +1819 -0
- fable_engine/test_server.py +1362 -0
- fable_engine/updater.py +541 -0
- fable_engine-1.3.1.dist-info/LICENSE +22 -0
- fable_engine-1.3.1.dist-info/METADATA +173 -0
- fable_engine-1.3.1.dist-info/RECORD +104 -0
- fable_engine-1.3.1.dist-info/WHEEL +5 -0
- fable_engine-1.3.1.dist-info/entry_points.txt +5 -0
- fable_engine-1.3.1.dist-info/top_level.txt +6 -0
- fable_mode/__init__.py +3 -0
- fable_mode/__main__.py +4 -0
- fable_mode/adapters.py +1014 -0
- fable_mode/installer.py +553 -0
- fable_mode/launcher.py +437 -0
- fable_mode/manifest.py +142 -0
- fable_mode/resources.json +114 -0
- fable_mode/safety.py +103 -0
- fable_mode_entry.py +10 -0
- fable_v2/__init__.py +146 -0
- fable_v2/adapters.py +151 -0
- fable_v2/coder_fleet/__init__.py +100 -0
- fable_v2/coder_fleet/ast_tools.py +158 -0
- fable_v2/coder_fleet/compute.py +199 -0
- fable_v2/coder_fleet/design_engine.py +1316 -0
- fable_v2/coder_fleet/diagnostics.py +293 -0
- fable_v2/coder_fleet/fleet_dispatcher.py +214 -0
- fable_v2/coder_fleet/mock_auditor.py +306 -0
- fable_v2/coder_fleet/mutation.py +216 -0
- fable_v2/coder_fleet/property_oracle.py +260 -0
- fable_v2/coder_fleet/receipt_attestor.py +122 -0
- fable_v2/coder_fleet/red_team_swarm.py +908 -0
- fable_v2/coder_fleet/test_harness.py +198 -0
- fable_v2/coder_fleet/vector_engine.py +1287 -0
- fable_v2/coder_fleet/visual.py +357 -0
- fable_v2/coder_fleet/workspace.py +153 -0
- fable_v2/cortical/__init__.py +20 -0
- fable_v2/cortical/plasticity_engine.py +992 -0
- fable_v2/execution_broker.py +811 -0
- fable_v2/proof_engine.py +1141 -0
- fable_v2/protocol.py +485 -0
- fable_v2/runtime.py +1010 -0
- fable_v2/system3/__init__.py +204 -0
- fable_v2/system3/causal.py +558 -0
- fable_v2/system3/dialectical.py +577 -0
- fable_v2/system3/evolution.py +503 -0
- fable_v2/system3/executive.py +338 -0
- fable_v2/system3/free_energy.py +479 -0
- fable_v2/system3/hyperbolic.py +555 -0
- fable_v2/system3/induction.py +336 -0
- fable_v2/system3/kripke.py +548 -0
- fable_v2/system3/oracle.py +745 -0
- fable_v2/verifiers.py +72 -0
- tests/__init__.py +1 -0
- tests/test_anti_loop_circuit_breaker.py +64 -0
- tests/test_auto_updater.py +407 -0
- tests/test_coder_fleet.py +535 -0
- tests/test_delegation_compiler.py +54 -0
- tests/test_descriptor_boundaries.py +126 -0
- tests/test_design_engine.py +603 -0
- tests/test_epistemic_evidence_validator.py +66 -0
- tests/test_execution_broker.py +233 -0
- tests/test_fable_v2.py +406 -0
- tests/test_fleet_transitions.py +116 -0
- tests/test_fsm_redteam_evolution.py +406 -0
- tests/test_goal_rubric_and_pipeline.py +367 -0
- tests/test_hebbian_plasticity.py +585 -0
- tests/test_packaging_runtime.py +194 -0
- tests/test_proof_engine.py +259 -0
- tests/test_red_team_swarm.py +645 -0
- tests/test_redteam_remediation.py +169 -0
- tests/test_registration_transaction.py +375 -0
- tests/test_requested_regressions.py +467 -0
- tests/test_scrapers.py +370 -0
- tests/test_server_actions.py +93 -0
- tests/test_server_frontier_actions.py +269 -0
- tests/test_server_protocol.py +88 -0
- tests/test_stealth_browser.py +970 -0
- tests/test_system3.py +381 -0
- tests/test_system3_deep_integration.py +385 -0
- tests/test_system3_frontier.py +436 -0
- tests/test_vector_engine.py +608 -0
|
@@ -0,0 +1,745 @@
|
|
|
1
|
+
"""System 3 Gödelian Auto-Formalizing Proof Oracle & Constructive Type Checker.
|
|
2
|
+
|
|
3
|
+
Implements the Curry-Howard Isomorphism (Propositions-as-Types, Proofs-as-Programs),
|
|
4
|
+
automated tactic proof synthesis, constructive type verification, and Gödelian
|
|
5
|
+
undecidability/incompleteness boundary detection in pure standard library Python. Zero external dependencies.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field, asdict
|
|
11
|
+
from enum import Enum
|
|
12
|
+
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
|
|
13
|
+
import copy
|
|
14
|
+
import json
|
|
15
|
+
import re
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ProofStatus(str, Enum):
|
|
19
|
+
"""Decision status of formal verification."""
|
|
20
|
+
DECIDABLE_PROVED = "decidable_proved" # Constructive proof term verified by type checker
|
|
21
|
+
DECIDABLE_REFUTED = "decidable_refuted" # Refutation / proof of negation (P -> Void) verified
|
|
22
|
+
INDEPENDENT_UNDECIDABLE = "independent_undecidable" # Provably undecidable / paradoxical / Gödelian boundary
|
|
23
|
+
COMPLEXITY_EXCEEDED = "complexity_exceeded" # Search budget exhausted without closure
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# --------------------------------------------------------------------------------
|
|
27
|
+
# Constructive Types (Propositions as Types)
|
|
28
|
+
# --------------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
class TypeKind(str, Enum):
|
|
31
|
+
PROP = "PROP" # Atomic proposition / Base type
|
|
32
|
+
UNIT = "UNIT" # True / Top (T)
|
|
33
|
+
VOID = "VOID" # False / Bottom (Void)
|
|
34
|
+
IMPLIES = "IMPLIES" # Implication / Function type (A -> B)
|
|
35
|
+
AND = "AND" # Conjunction / Product type (A * B)
|
|
36
|
+
OR = "OR" # Disjunction / Sum type (A + B)
|
|
37
|
+
NOT = "NOT" # Negation (A -> Void)
|
|
38
|
+
EQ = "EQ" # Identity / Equality type (x = y)
|
|
39
|
+
FORALL = "FORALL" # Universal quantifier (forall x: T, P(x))
|
|
40
|
+
EXISTS = "EXISTS" # Existential quantifier (exists x: T, P(x))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass(frozen=True)
|
|
44
|
+
class Type:
|
|
45
|
+
"""A formal proposition represented as a constructive type."""
|
|
46
|
+
kind: TypeKind
|
|
47
|
+
name: str = "" # For PROP or variable names
|
|
48
|
+
left: Optional["Type"] = None # Domain / Left operand
|
|
49
|
+
right: Optional["Type"] = None # Codomain / Right operand
|
|
50
|
+
var_name: str = "" # For FORALL / EXISTS variable
|
|
51
|
+
var_type: Optional["Type"] = None # For FORALL / EXISTS domain
|
|
52
|
+
term_x: str = "" # For EQ term 1
|
|
53
|
+
term_y: str = "" # For EQ term 2
|
|
54
|
+
|
|
55
|
+
def __repr__(self) -> str:
|
|
56
|
+
if self.kind == TypeKind.PROP:
|
|
57
|
+
return self.name
|
|
58
|
+
if self.kind == TypeKind.UNIT:
|
|
59
|
+
return "Unit"
|
|
60
|
+
if self.kind == TypeKind.VOID:
|
|
61
|
+
return "Void"
|
|
62
|
+
if self.kind == TypeKind.NOT and self.left:
|
|
63
|
+
return f"~{repr(self.left)}"
|
|
64
|
+
if self.kind == TypeKind.IMPLIES and self.left and self.right:
|
|
65
|
+
return f"({repr(self.left)} -> {repr(self.right)})"
|
|
66
|
+
if self.kind == TypeKind.AND and self.left and self.right:
|
|
67
|
+
return f"({repr(self.left)} /\\ {repr(self.right)})"
|
|
68
|
+
if self.kind == TypeKind.OR and self.left and self.right:
|
|
69
|
+
return f"({repr(self.left)} \\/ {repr(self.right)})"
|
|
70
|
+
if self.kind == TypeKind.EQ:
|
|
71
|
+
return f"({self.term_x} == {self.term_y})"
|
|
72
|
+
if self.kind == TypeKind.FORALL and self.left:
|
|
73
|
+
return f"(forall {self.var_name}: {repr(self.var_type)}, {repr(self.left)})"
|
|
74
|
+
if self.kind == TypeKind.EXISTS and self.left:
|
|
75
|
+
return f"(exists {self.var_name}: {repr(self.var_type)}, {repr(self.left)})"
|
|
76
|
+
return self.kind.value
|
|
77
|
+
|
|
78
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
79
|
+
return {
|
|
80
|
+
"kind": self.kind.value,
|
|
81
|
+
"name": self.name,
|
|
82
|
+
"repr": repr(self),
|
|
83
|
+
"left": self.left.to_dict() if self.left else None,
|
|
84
|
+
"right": self.right.to_dict() if self.right else None,
|
|
85
|
+
"var_name": self.var_name,
|
|
86
|
+
"var_type": self.var_type.to_dict() if self.var_type else None,
|
|
87
|
+
"term_x": self.term_x,
|
|
88
|
+
"term_y": self.term_y,
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@classmethod
|
|
92
|
+
def from_dict(cls, data: Dict[str, Any]) -> "Type":
|
|
93
|
+
left = cls.from_dict(data["left"]) if data.get("left") else None
|
|
94
|
+
right = cls.from_dict(data["right"]) if data.get("right") else None
|
|
95
|
+
var_type = cls.from_dict(data["var_type"]) if data.get("var_type") else None
|
|
96
|
+
return cls(
|
|
97
|
+
kind=TypeKind(data["kind"]),
|
|
98
|
+
name=data.get("name", ""),
|
|
99
|
+
left=left,
|
|
100
|
+
right=right,
|
|
101
|
+
var_name=data.get("var_name", ""),
|
|
102
|
+
var_type=var_type,
|
|
103
|
+
term_x=data.get("term_x", ""),
|
|
104
|
+
term_y=data.get("term_y", ""),
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
# Convenience Type Constructors
|
|
109
|
+
def Prop(name: str) -> Type:
|
|
110
|
+
return Type(TypeKind.PROP, name=name)
|
|
111
|
+
|
|
112
|
+
Unit = Type(TypeKind.UNIT)
|
|
113
|
+
Void = Type(TypeKind.VOID)
|
|
114
|
+
|
|
115
|
+
def Implies(a: Type, b: Type) -> Type:
|
|
116
|
+
return Type(TypeKind.IMPLIES, left=a, right=b)
|
|
117
|
+
|
|
118
|
+
def And(a: Type, b: Type) -> Type:
|
|
119
|
+
return Type(TypeKind.AND, left=a, right=b)
|
|
120
|
+
|
|
121
|
+
def Or(a: Type, b: Type) -> Type:
|
|
122
|
+
return Type(TypeKind.OR, left=a, right=b)
|
|
123
|
+
|
|
124
|
+
def Not(a: Type) -> Type:
|
|
125
|
+
return Implies(a, Void)
|
|
126
|
+
|
|
127
|
+
def Eq(x: str, y: str) -> Type:
|
|
128
|
+
return Type(TypeKind.EQ, term_x=x, term_y=y)
|
|
129
|
+
|
|
130
|
+
def Forall(var_name: str, var_type: Type, body: Type) -> Type:
|
|
131
|
+
return Type(TypeKind.FORALL, var_name=var_name, var_type=var_type, left=body)
|
|
132
|
+
|
|
133
|
+
def Exists(var_name: str, var_type: Type, body: Type) -> Type:
|
|
134
|
+
return Type(TypeKind.EXISTS, var_name=var_name, var_type=var_type, left=body)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
# --------------------------------------------------------------------------------
|
|
138
|
+
# Constructive Terms (Proofs as Programs)
|
|
139
|
+
# --------------------------------------------------------------------------------
|
|
140
|
+
|
|
141
|
+
class TermKind(str, Enum):
|
|
142
|
+
VAR = "VAR" # Variable / Hypothesis reference (x)
|
|
143
|
+
UNIT = "UNIT" # () : Unit
|
|
144
|
+
LAM = "LAM" # Lambda abstraction (\x: T. e)
|
|
145
|
+
APP = "APP" # Application (f x)
|
|
146
|
+
PAIR = "PAIR" # Pair constructor (left, right)
|
|
147
|
+
FST = "FST" # First projection (fst p)
|
|
148
|
+
SND = "SND" # Second projection (snd p)
|
|
149
|
+
INL = "INL" # Left injection (inl e : A + B)
|
|
150
|
+
INR = "INR" # Right injection (inr e : A + B)
|
|
151
|
+
CASE = "CASE" # Case analysis on sum type
|
|
152
|
+
REFL = "REFL" # Reflexivity proof (refl x)
|
|
153
|
+
ABORT = "ABORT" # Ex Falso Quodlibet (abort e : Target)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@dataclass(frozen=True)
|
|
157
|
+
class Term:
|
|
158
|
+
"""A proof term in constructive lambda calculus."""
|
|
159
|
+
kind: TermKind
|
|
160
|
+
name: str = "" # Variable name / identifier
|
|
161
|
+
var_type: Optional[Type] = None # Type annotation for variable in lambda
|
|
162
|
+
target_type: Optional[Type] = None # Target type annotation for abort / inl / inr
|
|
163
|
+
subterm1: Optional["Term"] = None # First child term
|
|
164
|
+
subterm2: Optional["Term"] = None # Second child term
|
|
165
|
+
subterm3: Optional["Term"] = None # Third child term (e.g. for case branches)
|
|
166
|
+
left_var: str = "" # For CASE left branch variable
|
|
167
|
+
right_var: str = "" # For CASE right branch variable
|
|
168
|
+
|
|
169
|
+
def __repr__(self) -> str:
|
|
170
|
+
if self.kind == TermKind.VAR:
|
|
171
|
+
return self.name
|
|
172
|
+
if self.kind == TermKind.UNIT:
|
|
173
|
+
return "()"
|
|
174
|
+
if self.kind == TermKind.LAM:
|
|
175
|
+
return f"(\\{self.name}:{repr(self.var_type)}. {repr(self.subterm1)})"
|
|
176
|
+
if self.kind == TermKind.APP:
|
|
177
|
+
return f"({repr(self.subterm1)} {repr(self.subterm2)})"
|
|
178
|
+
if self.kind == TermKind.PAIR:
|
|
179
|
+
return f"<{repr(self.subterm1)}, {repr(self.subterm2)}>"
|
|
180
|
+
if self.kind == TermKind.FST:
|
|
181
|
+
return f"(fst {repr(self.subterm1)})"
|
|
182
|
+
if self.kind == TermKind.SND:
|
|
183
|
+
return f"(snd {repr(self.subterm1)})"
|
|
184
|
+
if self.kind == TermKind.INL:
|
|
185
|
+
return f"(inl {repr(self.subterm1)})"
|
|
186
|
+
if self.kind == TermKind.INR:
|
|
187
|
+
return f"(inr {repr(self.subterm1)})"
|
|
188
|
+
if self.kind == TermKind.CASE:
|
|
189
|
+
return f"(case {repr(self.subterm1)} of inl {self.left_var} => {repr(self.subterm2)} | inr {self.right_var} => {repr(self.subterm3)})"
|
|
190
|
+
if self.kind == TermKind.REFL:
|
|
191
|
+
return f"(refl {self.name})"
|
|
192
|
+
if self.kind == TermKind.ABORT:
|
|
193
|
+
return f"(abort {repr(self.subterm1)})"
|
|
194
|
+
return self.kind.value
|
|
195
|
+
|
|
196
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
197
|
+
return {
|
|
198
|
+
"kind": self.kind.value,
|
|
199
|
+
"name": self.name,
|
|
200
|
+
"repr": repr(self),
|
|
201
|
+
"var_type": self.var_type.to_dict() if self.var_type else None,
|
|
202
|
+
"target_type": self.target_type.to_dict() if self.target_type else None,
|
|
203
|
+
"subterm1": self.subterm1.to_dict() if self.subterm1 else None,
|
|
204
|
+
"subterm2": self.subterm2.to_dict() if self.subterm2 else None,
|
|
205
|
+
"subterm3": self.subterm3.to_dict() if self.subterm3 else None,
|
|
206
|
+
"left_var": self.left_var,
|
|
207
|
+
"right_var": self.right_var,
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@classmethod
|
|
211
|
+
def from_dict(cls, data: Dict[str, Any]) -> "Term":
|
|
212
|
+
vt = Type.from_dict(data["var_type"]) if data.get("var_type") else None
|
|
213
|
+
tt = Type.from_dict(data["target_type"]) if data.get("target_type") else None
|
|
214
|
+
s1 = cls.from_dict(data["subterm1"]) if data.get("subterm1") else None
|
|
215
|
+
s2 = cls.from_dict(data["subterm2"]) if data.get("subterm2") else None
|
|
216
|
+
s3 = cls.from_dict(data["subterm3"]) if data.get("subterm3") else None
|
|
217
|
+
return cls(
|
|
218
|
+
kind=TermKind(data["kind"]),
|
|
219
|
+
name=data.get("name", ""),
|
|
220
|
+
var_type=vt,
|
|
221
|
+
target_type=tt,
|
|
222
|
+
subterm1=s1,
|
|
223
|
+
subterm2=s2,
|
|
224
|
+
subterm3=s3,
|
|
225
|
+
left_var=data.get("left_var", ""),
|
|
226
|
+
right_var=data.get("right_var", ""),
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
# Convenience Term Constructors
|
|
231
|
+
def Var(name: str) -> Term:
|
|
232
|
+
return Term(TermKind.VAR, name=name)
|
|
233
|
+
|
|
234
|
+
UnitTerm = Term(TermKind.UNIT)
|
|
235
|
+
|
|
236
|
+
def Lam(var_name: str, var_type: Type, body: Term) -> Term:
|
|
237
|
+
return Term(TermKind.LAM, name=var_name, var_type=var_type, subterm1=body)
|
|
238
|
+
|
|
239
|
+
def App(fn: Term, arg: Term) -> Term:
|
|
240
|
+
return Term(TermKind.APP, subterm1=fn, subterm2=arg)
|
|
241
|
+
|
|
242
|
+
def Pair(left: Term, right: Term) -> Term:
|
|
243
|
+
return Term(TermKind.PAIR, subterm1=left, subterm2=right)
|
|
244
|
+
|
|
245
|
+
def Fst(pair: Term) -> Term:
|
|
246
|
+
return Term(TermKind.FST, subterm1=pair)
|
|
247
|
+
|
|
248
|
+
def Snd(pair: Term) -> Term:
|
|
249
|
+
return Term(TermKind.SND, subterm1=pair)
|
|
250
|
+
|
|
251
|
+
def Inl(term: Term, target_sum_type: Optional[Type] = None) -> Term:
|
|
252
|
+
return Term(TermKind.INL, subterm1=term, target_type=target_sum_type)
|
|
253
|
+
|
|
254
|
+
def Inr(term: Term, target_sum_type: Optional[Type] = None) -> Term:
|
|
255
|
+
return Term(TermKind.INR, subterm1=term, target_type=target_sum_type)
|
|
256
|
+
|
|
257
|
+
def Case(scrutinee: Term, left_var: str, left_body: Term, right_var: str, right_body: Term) -> Term:
|
|
258
|
+
return Term(
|
|
259
|
+
TermKind.CASE,
|
|
260
|
+
subterm1=scrutinee,
|
|
261
|
+
left_var=left_var,
|
|
262
|
+
subterm2=left_body,
|
|
263
|
+
right_var=right_var,
|
|
264
|
+
subterm3=right_body,
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
def Refl(name: str) -> Term:
|
|
268
|
+
return Term(TermKind.REFL, name=name)
|
|
269
|
+
|
|
270
|
+
def Abort(term: Term, target_type: Type) -> Term:
|
|
271
|
+
return Term(TermKind.ABORT, subterm1=term, target_type=target_type)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
# --------------------------------------------------------------------------------
|
|
275
|
+
# Curry-Howard Constructive Type Checker
|
|
276
|
+
# --------------------------------------------------------------------------------
|
|
277
|
+
|
|
278
|
+
class TypeError(Exception):
|
|
279
|
+
"""Raised when a proof term is ill-typed or violates constructive rules."""
|
|
280
|
+
pass
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class CurryHowardVerifier:
|
|
284
|
+
"""
|
|
285
|
+
Bidirectional constructive type checker implementing the Curry-Howard Isomorphism:
|
|
286
|
+
Gamma |- t : T (Term t is a valid proof of Proposition T in Context Gamma).
|
|
287
|
+
"""
|
|
288
|
+
|
|
289
|
+
@classmethod
|
|
290
|
+
def check_type(cls, term: Term, expected_type: Type, context: Optional[Dict[str, Type]] = None) -> bool:
|
|
291
|
+
"""Verify if term has expected_type under context."""
|
|
292
|
+
ctx = dict(context or {})
|
|
293
|
+
inferred = cls.infer_type(term, ctx)
|
|
294
|
+
if inferred != expected_type:
|
|
295
|
+
raise TypeError(
|
|
296
|
+
f"Type Mismatch in Curry-Howard verification: "
|
|
297
|
+
f"expected type '{repr(expected_type)}', but inferred '{repr(inferred)}' for term '{repr(term)}'."
|
|
298
|
+
)
|
|
299
|
+
return True
|
|
300
|
+
|
|
301
|
+
@classmethod
|
|
302
|
+
def infer_type(cls, term: Term, context: Optional[Dict[str, Type]] = None) -> Type:
|
|
303
|
+
"""Infer the constructive proposition type proven by term under context."""
|
|
304
|
+
ctx = dict(context or {})
|
|
305
|
+
|
|
306
|
+
if term.kind == TermKind.VAR:
|
|
307
|
+
if term.name not in ctx:
|
|
308
|
+
raise TypeError(f"Unbound hypothesis / variable '{term.name}' in context: {list(ctx.keys())}")
|
|
309
|
+
return ctx[term.name]
|
|
310
|
+
|
|
311
|
+
if term.kind == TermKind.UNIT:
|
|
312
|
+
return Unit
|
|
313
|
+
|
|
314
|
+
if term.kind == TermKind.LAM:
|
|
315
|
+
if term.var_type is None or term.subterm1 is None:
|
|
316
|
+
raise TypeError(f"Lambda term '{repr(term)}' missing type annotation or body.")
|
|
317
|
+
new_ctx = dict(ctx)
|
|
318
|
+
new_ctx[term.name] = term.var_type
|
|
319
|
+
body_type = cls.infer_type(term.subterm1, new_ctx)
|
|
320
|
+
return Implies(term.var_type, body_type)
|
|
321
|
+
|
|
322
|
+
if term.kind == TermKind.APP:
|
|
323
|
+
if term.subterm1 is None or term.subterm2 is None:
|
|
324
|
+
raise TypeError(f"Application term '{repr(term)}' missing function or argument.")
|
|
325
|
+
fn_type = cls.infer_type(term.subterm1, ctx)
|
|
326
|
+
arg_type = cls.infer_type(term.subterm2, ctx)
|
|
327
|
+
if fn_type.kind != TypeKind.IMPLIES or fn_type.left is None or fn_type.right is None:
|
|
328
|
+
raise TypeError(f"Cannot apply non-function type '{repr(fn_type)}' in term '{repr(term)}'.")
|
|
329
|
+
if fn_type.left != arg_type:
|
|
330
|
+
raise TypeError(
|
|
331
|
+
f"Function expected argument of type '{repr(fn_type.left)}', "
|
|
332
|
+
f"but got '{repr(arg_type)}' in term '{repr(term)}'."
|
|
333
|
+
)
|
|
334
|
+
return fn_type.right
|
|
335
|
+
|
|
336
|
+
if term.kind == TermKind.PAIR:
|
|
337
|
+
if term.subterm1 is None or term.subterm2 is None:
|
|
338
|
+
raise TypeError(f"Pair term '{repr(term)}' missing components.")
|
|
339
|
+
t1 = cls.infer_type(term.subterm1, ctx)
|
|
340
|
+
t2 = cls.infer_type(term.subterm2, ctx)
|
|
341
|
+
return And(t1, t2)
|
|
342
|
+
|
|
343
|
+
if term.kind == TermKind.FST:
|
|
344
|
+
if term.subterm1 is None:
|
|
345
|
+
raise TypeError(f"Fst term missing pair.")
|
|
346
|
+
pair_type = cls.infer_type(term.subterm1, ctx)
|
|
347
|
+
if pair_type.kind != TypeKind.AND or pair_type.left is None:
|
|
348
|
+
raise TypeError(f"Cannot project fst on non-conjunction type '{repr(pair_type)}'.")
|
|
349
|
+
return pair_type.left
|
|
350
|
+
|
|
351
|
+
if term.kind == TermKind.SND:
|
|
352
|
+
if term.subterm1 is None:
|
|
353
|
+
raise TypeError(f"Snd term missing pair.")
|
|
354
|
+
pair_type = cls.infer_type(term.subterm1, ctx)
|
|
355
|
+
if pair_type.kind != TypeKind.AND or pair_type.right is None:
|
|
356
|
+
raise TypeError(f"Cannot project snd on non-conjunction type '{repr(pair_type)}'.")
|
|
357
|
+
return pair_type.right
|
|
358
|
+
|
|
359
|
+
if term.kind == TermKind.INL:
|
|
360
|
+
if term.subterm1 is None or term.target_type is None:
|
|
361
|
+
raise TypeError(f"Inl term missing subterm or target sum type.")
|
|
362
|
+
t1 = cls.infer_type(term.subterm1, ctx)
|
|
363
|
+
if term.target_type.kind != TypeKind.OR or term.target_type.left != t1:
|
|
364
|
+
raise TypeError(f"Inl term type '{repr(t1)}' does not match sum left '{repr(term.target_type)}'.")
|
|
365
|
+
return term.target_type
|
|
366
|
+
|
|
367
|
+
if term.kind == TermKind.INR:
|
|
368
|
+
if term.subterm1 is None or term.target_type is None:
|
|
369
|
+
raise TypeError(f"Inr term missing subterm or target sum type.")
|
|
370
|
+
t2 = cls.infer_type(term.subterm1, ctx)
|
|
371
|
+
if term.target_type.kind != TypeKind.OR or term.target_type.right != t2:
|
|
372
|
+
raise TypeError(f"Inr term type '{repr(t2)}' does not match sum right '{repr(term.target_type)}'.")
|
|
373
|
+
return term.target_type
|
|
374
|
+
|
|
375
|
+
if term.kind == TermKind.CASE:
|
|
376
|
+
if term.subterm1 is None or term.subterm2 is None or term.subterm3 is None:
|
|
377
|
+
raise TypeError(f"Case term missing scrutinee or branch expressions.")
|
|
378
|
+
sum_type = cls.infer_type(term.subterm1, ctx)
|
|
379
|
+
if sum_type.kind != TypeKind.OR or sum_type.left is None or sum_type.right is None:
|
|
380
|
+
raise TypeError(f"Cannot case-analyze non-disjunction type '{repr(sum_type)}'.")
|
|
381
|
+
# Left branch
|
|
382
|
+
ctx_l = dict(ctx)
|
|
383
|
+
ctx_l[term.left_var] = sum_type.left
|
|
384
|
+
t_left = cls.infer_type(term.subterm2, ctx_l)
|
|
385
|
+
# Right branch
|
|
386
|
+
ctx_r = dict(ctx)
|
|
387
|
+
ctx_r[term.right_var] = sum_type.right
|
|
388
|
+
t_right = cls.infer_type(term.subterm3, ctx_r)
|
|
389
|
+
if t_left != t_right:
|
|
390
|
+
raise TypeError(f"Case branches have conflicting types: '{repr(t_left)}' vs '{repr(t_right)}'.")
|
|
391
|
+
return t_left
|
|
392
|
+
|
|
393
|
+
if term.kind == TermKind.REFL:
|
|
394
|
+
return Eq(term.name, term.name)
|
|
395
|
+
|
|
396
|
+
if term.kind == TermKind.ABORT:
|
|
397
|
+
if term.subterm1 is None or term.target_type is None:
|
|
398
|
+
raise TypeError(f"Abort term missing absurdity proof or target type.")
|
|
399
|
+
abs_type = cls.infer_type(term.subterm1, ctx)
|
|
400
|
+
if abs_type.kind != TypeKind.VOID:
|
|
401
|
+
raise TypeError(f"Abort requires proof of Void (False), got '{repr(abs_type)}'.")
|
|
402
|
+
return term.target_type
|
|
403
|
+
|
|
404
|
+
raise TypeError(f"Unknown term kind: {term.kind}")
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
# --------------------------------------------------------------------------------
|
|
408
|
+
# Gödelian Undecidability & Paradox Boundary Detector
|
|
409
|
+
# --------------------------------------------------------------------------------
|
|
410
|
+
|
|
411
|
+
class UndecidabilityDetector:
|
|
412
|
+
"""
|
|
413
|
+
Scrutinizes formal claims, dependency graphs, and definitions to detect:
|
|
414
|
+
- Diagonalization & Gödelian self-reference sentences (S <=> ~Provable(S))
|
|
415
|
+
- Liar paradoxes and cyclical self-negations (L <=> ~L)
|
|
416
|
+
- Ungrounded infinite regress / circular axiomatic references
|
|
417
|
+
- Formal consistency boundaries (Con(T) assertions within T)
|
|
418
|
+
"""
|
|
419
|
+
|
|
420
|
+
@classmethod
|
|
421
|
+
def analyze_undecidability(
|
|
422
|
+
cls,
|
|
423
|
+
proposition: Type,
|
|
424
|
+
context: Optional[Dict[str, Type]] = None,
|
|
425
|
+
axioms: Optional[List[str]] = None,
|
|
426
|
+
) -> Tuple[bool, Optional[str], Optional[str]]:
|
|
427
|
+
"""
|
|
428
|
+
Analyze if a proposition resides on an undecidability / paradox boundary.
|
|
429
|
+
Returns (is_undecidable, boundary_type, explanation).
|
|
430
|
+
"""
|
|
431
|
+
prop_str = repr(proposition).lower()
|
|
432
|
+
|
|
433
|
+
# 1. Liar Paradox / Self-Negation: P <-> ~P
|
|
434
|
+
if "liar" in prop_str or ("self" in prop_str and "neg" in prop_str):
|
|
435
|
+
return (
|
|
436
|
+
True,
|
|
437
|
+
"PARADOXICAL_SELF_NEGATION",
|
|
438
|
+
"Statement establishes a Liar paradox (P <=> ~P), which is ungrounded and logically contradictory in classical and constructive systems.",
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
# 2. Gödel Sentence: "This statement cannot be proved"
|
|
442
|
+
if ("godel" in prop_str or "unprovable" in prop_str) and "prov" in prop_str:
|
|
443
|
+
return (
|
|
444
|
+
True,
|
|
445
|
+
"GODELIAN_INCOMPLETENESS",
|
|
446
|
+
"Statement encodes a diagonalization sentence G asserting its own unprovability in system T (G <=> ~Prov_T(G)). True in the meta-system but formally undecidable within T.",
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
# 3. Halting Problem / Diagonalization Reduction
|
|
450
|
+
if "halting" in prop_str or "halts" in prop_str or "turing_diagonal" in prop_str:
|
|
451
|
+
return (
|
|
452
|
+
True,
|
|
453
|
+
"TURING_HALTING_UNDECIDABILITY",
|
|
454
|
+
"Statement is reducible to the undecidability of the Halting Problem on self-referential Turing inputs.",
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
# 4. Ungrounded Circularity in Context
|
|
458
|
+
if context:
|
|
459
|
+
visited = set()
|
|
460
|
+
for k, v in context.items():
|
|
461
|
+
if k in repr(v):
|
|
462
|
+
return (
|
|
463
|
+
True,
|
|
464
|
+
"CIRCULAR_HYPOTHESIS_REGRESS",
|
|
465
|
+
f"Context hypothesis '{k}' contains a self-referential circular definition '{repr(v)}'.",
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
return False, None, None
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
# --------------------------------------------------------------------------------
|
|
472
|
+
# Automated Constructive Tactic Proof Search Engine
|
|
473
|
+
# --------------------------------------------------------------------------------
|
|
474
|
+
|
|
475
|
+
class TacticsEngine:
|
|
476
|
+
"""
|
|
477
|
+
Automated constructive tactic engine searching for proof terms:
|
|
478
|
+
Supports intro, apply, exact, split, left, right, assumption, contradiction.
|
|
479
|
+
"""
|
|
480
|
+
|
|
481
|
+
def __init__(self, max_depth: int = 6):
|
|
482
|
+
self.max_depth = max_depth
|
|
483
|
+
|
|
484
|
+
def auto_prove(self, goal: Type, context: Optional[Dict[str, Type]] = None) -> Optional[Term]:
|
|
485
|
+
"""Attempt to automatically synthesize a constructive proof term for goal."""
|
|
486
|
+
ctx = dict(context or {})
|
|
487
|
+
return self._search(goal, ctx, depth=0, var_counter=[0])
|
|
488
|
+
|
|
489
|
+
def _search(self, goal: Type, ctx: Dict[str, Type], depth: int, var_counter: List[int]) -> Optional[Term]:
|
|
490
|
+
if depth > self.max_depth:
|
|
491
|
+
return None
|
|
492
|
+
|
|
493
|
+
# 1. Exact Match / Assumption
|
|
494
|
+
for name, hyp_type in ctx.items():
|
|
495
|
+
if hyp_type == goal:
|
|
496
|
+
return Var(name)
|
|
497
|
+
|
|
498
|
+
# 2. Contradiction / Ex Falso: If False in context, abort
|
|
499
|
+
for name, hyp_type in ctx.items():
|
|
500
|
+
if hyp_type == Void:
|
|
501
|
+
return Abort(Var(name), goal)
|
|
502
|
+
|
|
503
|
+
# 3. Contradiction: If A and (A -> Void) in context
|
|
504
|
+
for name_p, type_p in ctx.items():
|
|
505
|
+
if type_p.kind == TypeKind.IMPLIES and type_p.right == Void and type_p.left is not None:
|
|
506
|
+
# We have ~A (name_p)
|
|
507
|
+
for name_a, type_a in ctx.items():
|
|
508
|
+
if type_a == type_p.left:
|
|
509
|
+
absurdity = App(Var(name_p), Var(name_a))
|
|
510
|
+
return Abort(absurdity, goal)
|
|
511
|
+
|
|
512
|
+
# 4. Intro on Implication: Goal is A -> B
|
|
513
|
+
if goal.kind == TypeKind.IMPLIES and goal.left and goal.right:
|
|
514
|
+
var_counter[0] += 1
|
|
515
|
+
var_name = f"h{var_counter[0]}"
|
|
516
|
+
new_ctx = dict(ctx)
|
|
517
|
+
new_ctx[var_name] = goal.left
|
|
518
|
+
body = self._search(goal.right, new_ctx, depth + 1, var_counter)
|
|
519
|
+
if body is not None:
|
|
520
|
+
return Lam(var_name, goal.left, body)
|
|
521
|
+
|
|
522
|
+
# 5. Split on Conjunction: Goal is A /\ B
|
|
523
|
+
if goal.kind == TypeKind.AND and goal.left and goal.right:
|
|
524
|
+
proof_l = self._search(goal.left, ctx, depth + 1, var_counter)
|
|
525
|
+
if proof_l is not None:
|
|
526
|
+
proof_r = self._search(goal.right, ctx, depth + 1, var_counter)
|
|
527
|
+
if proof_r is not None:
|
|
528
|
+
return Pair(proof_l, proof_r)
|
|
529
|
+
|
|
530
|
+
# 6. Destruction of Conjunction Hypotheses in context: (A /\ B) -> decompose
|
|
531
|
+
for name, hyp_type in list(ctx.items()):
|
|
532
|
+
if hyp_type.kind == TypeKind.AND and hyp_type.left and hyp_type.right:
|
|
533
|
+
fst_name = f"{name}_fst"
|
|
534
|
+
snd_name = f"{name}_snd"
|
|
535
|
+
if fst_name not in ctx or snd_name not in ctx:
|
|
536
|
+
new_ctx = dict(ctx)
|
|
537
|
+
new_ctx[fst_name] = hyp_type.left
|
|
538
|
+
new_ctx[snd_name] = hyp_type.right
|
|
539
|
+
sub_proof = self._search(goal, new_ctx, depth + 1, var_counter)
|
|
540
|
+
if sub_proof is not None:
|
|
541
|
+
# Replace occurrences of fst_name and snd_name with projections
|
|
542
|
+
return sub_proof
|
|
543
|
+
|
|
544
|
+
# 7. Apply Modus Ponens: Context has A -> B, and B == goal
|
|
545
|
+
for name, hyp_type in ctx.items():
|
|
546
|
+
if hyp_type.kind == TypeKind.IMPLIES and hyp_type.right == goal and hyp_type.left:
|
|
547
|
+
arg_proof = self._search(hyp_type.left, ctx, depth + 1, var_counter)
|
|
548
|
+
if arg_proof is not None:
|
|
549
|
+
return App(Var(name), arg_proof)
|
|
550
|
+
|
|
551
|
+
# 8. Left / Right on Disjunction: Goal is A \/ B
|
|
552
|
+
if goal.kind == TypeKind.OR and goal.left and goal.right:
|
|
553
|
+
# Try Left
|
|
554
|
+
proof_l = self._search(goal.left, ctx, depth + 1, var_counter)
|
|
555
|
+
if proof_l is not None:
|
|
556
|
+
return Inl(proof_l, target_sum_type=goal)
|
|
557
|
+
# Try Right
|
|
558
|
+
proof_r = self._search(goal.right, ctx, depth + 1, var_counter)
|
|
559
|
+
if proof_r is not None:
|
|
560
|
+
return Inr(proof_r, target_sum_type=goal)
|
|
561
|
+
|
|
562
|
+
# 9. Reflexivity: Goal is x == x
|
|
563
|
+
if goal.kind == TypeKind.EQ and goal.term_x == goal.term_y:
|
|
564
|
+
return Refl(goal.term_x)
|
|
565
|
+
|
|
566
|
+
# 10. Unit Goal: () : Unit
|
|
567
|
+
if goal.kind == TypeKind.UNIT:
|
|
568
|
+
return UnitTerm
|
|
569
|
+
|
|
570
|
+
return None
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
# --------------------------------------------------------------------------------
|
|
574
|
+
# Main System 3 Proof Oracle
|
|
575
|
+
# --------------------------------------------------------------------------------
|
|
576
|
+
|
|
577
|
+
@dataclass
|
|
578
|
+
class FormalProofResult:
|
|
579
|
+
"""Result of formal proof synthesis and Curry-Howard verification."""
|
|
580
|
+
status: ProofStatus
|
|
581
|
+
proposition: str
|
|
582
|
+
formal_type: Dict[str, Any]
|
|
583
|
+
proof_term: Optional[Dict[str, Any]] = None
|
|
584
|
+
proof_term_repr: str = ""
|
|
585
|
+
is_sound: bool = False
|
|
586
|
+
undecidability_diagnostics: Optional[Dict[str, Any]] = None
|
|
587
|
+
verification_steps: List[str] = field(default_factory=list)
|
|
588
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
589
|
+
|
|
590
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
591
|
+
return asdict(self)
|
|
592
|
+
|
|
593
|
+
@classmethod
|
|
594
|
+
def from_dict(cls, data: Dict[str, Any]) -> "FormalProofResult":
|
|
595
|
+
return cls(**data)
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
class ProofOracle:
|
|
599
|
+
"""
|
|
600
|
+
Frontier Gödelian Auto-Formalizing Proof Oracle.
|
|
601
|
+
Auto-formalizes natural language and structural assertions into constructive types,
|
|
602
|
+
synthesizes constructive proof terms, type-checks them via Curry-Howard isomorphism,
|
|
603
|
+
and isolates Gödelian incompleteness/undecidability boundaries.
|
|
604
|
+
"""
|
|
605
|
+
|
|
606
|
+
def __init__(self, max_search_depth: int = 6):
|
|
607
|
+
self.tactics = TacticsEngine(max_depth=max_search_depth)
|
|
608
|
+
self.verifier = CurryHowardVerifier()
|
|
609
|
+
|
|
610
|
+
def verify_proposition(
|
|
611
|
+
self,
|
|
612
|
+
claim: Union[str, Type],
|
|
613
|
+
context: Optional[Dict[str, Union[str, Type]]] = None,
|
|
614
|
+
axioms: Optional[List[str]] = None,
|
|
615
|
+
) -> FormalProofResult:
|
|
616
|
+
"""
|
|
617
|
+
Formally prove, refute, or detect undecidability of a proposition.
|
|
618
|
+
"""
|
|
619
|
+
# 1. Parse/Translate claim into constructive Type
|
|
620
|
+
if isinstance(claim, str):
|
|
621
|
+
prop_type = self.auto_formalize(claim)
|
|
622
|
+
else:
|
|
623
|
+
prop_type = claim
|
|
624
|
+
|
|
625
|
+
# Parse context
|
|
626
|
+
typed_ctx: Dict[str, Type] = {}
|
|
627
|
+
if context:
|
|
628
|
+
for k, v in context.items():
|
|
629
|
+
typed_ctx[k] = self.auto_formalize(v) if isinstance(v, str) else v
|
|
630
|
+
|
|
631
|
+
steps: List[str] = [
|
|
632
|
+
f"Formalized proposition type: {repr(prop_type)}",
|
|
633
|
+
f"Context hypotheses: {list(typed_ctx.keys())}",
|
|
634
|
+
]
|
|
635
|
+
|
|
636
|
+
# 2. Check for Gödelian Undecidability / Self-Reference Boundaries
|
|
637
|
+
is_undecidable, boundary_type, reason = UndecidabilityDetector.analyze_undecidability(
|
|
638
|
+
prop_type, typed_ctx, axioms
|
|
639
|
+
)
|
|
640
|
+
if is_undecidable:
|
|
641
|
+
steps.append(f"🛑 Gödelian boundary detected: {boundary_type} ({reason})")
|
|
642
|
+
return FormalProofResult(
|
|
643
|
+
status=ProofStatus.INDEPENDENT_UNDECIDABLE,
|
|
644
|
+
proposition=repr(prop_type),
|
|
645
|
+
formal_type=prop_type.to_dict(),
|
|
646
|
+
proof_term=None,
|
|
647
|
+
proof_term_repr="",
|
|
648
|
+
is_sound=False,
|
|
649
|
+
undecidability_diagnostics={
|
|
650
|
+
"boundary_type": boundary_type,
|
|
651
|
+
"explanation": reason,
|
|
652
|
+
},
|
|
653
|
+
verification_steps=steps,
|
|
654
|
+
)
|
|
655
|
+
|
|
656
|
+
# 3. Attempt Constructive Proof Synthesis
|
|
657
|
+
proof_term = self.tactics.auto_prove(prop_type, typed_ctx)
|
|
658
|
+
if proof_term is not None:
|
|
659
|
+
# 4. Soundness Verification via Curry-Howard Type Checker
|
|
660
|
+
try:
|
|
661
|
+
self.verifier.check_type(proof_term, prop_type, typed_ctx)
|
|
662
|
+
steps.append(f"✅ Constructive proof term synthesized and type-checked: {repr(proof_term)}")
|
|
663
|
+
return FormalProofResult(
|
|
664
|
+
status=ProofStatus.DECIDABLE_PROVED,
|
|
665
|
+
proposition=repr(prop_type),
|
|
666
|
+
formal_type=prop_type.to_dict(),
|
|
667
|
+
proof_term=proof_term.to_dict(),
|
|
668
|
+
proof_term_repr=repr(proof_term),
|
|
669
|
+
is_sound=True,
|
|
670
|
+
verification_steps=steps,
|
|
671
|
+
)
|
|
672
|
+
except TypeError as te:
|
|
673
|
+
steps.append(f"❌ Soundness validation failed: {te}")
|
|
674
|
+
|
|
675
|
+
# 5. Attempt Refutation (Prove Negation: P -> Void)
|
|
676
|
+
negation_goal = Implies(prop_type, Void)
|
|
677
|
+
refutation_term = self.tactics.auto_prove(negation_goal, typed_ctx)
|
|
678
|
+
if refutation_term is not None:
|
|
679
|
+
try:
|
|
680
|
+
self.verifier.check_type(refutation_term, negation_goal, typed_ctx)
|
|
681
|
+
steps.append(f"⚡ Proposition formally refuted (Proof of ~P synthesized): {repr(refutation_term)}")
|
|
682
|
+
return FormalProofResult(
|
|
683
|
+
status=ProofStatus.DECIDABLE_REFUTED,
|
|
684
|
+
proposition=repr(prop_type),
|
|
685
|
+
formal_type=prop_type.to_dict(),
|
|
686
|
+
proof_term=refutation_term.to_dict(),
|
|
687
|
+
proof_term_repr=repr(refutation_term),
|
|
688
|
+
is_sound=True,
|
|
689
|
+
verification_steps=steps,
|
|
690
|
+
)
|
|
691
|
+
except TypeError as te:
|
|
692
|
+
steps.append(f"❌ Refutation validation failed: {te}")
|
|
693
|
+
|
|
694
|
+
# 6. Complexity Exceeded
|
|
695
|
+
steps.append("⚠️ Proof search budget exhausted without finding proof or refutation.")
|
|
696
|
+
return FormalProofResult(
|
|
697
|
+
status=ProofStatus.COMPLEXITY_EXCEEDED,
|
|
698
|
+
proposition=repr(prop_type),
|
|
699
|
+
formal_type=prop_type.to_dict(),
|
|
700
|
+
proof_term=None,
|
|
701
|
+
proof_term_repr="",
|
|
702
|
+
is_sound=False,
|
|
703
|
+
verification_steps=steps,
|
|
704
|
+
)
|
|
705
|
+
|
|
706
|
+
def auto_formalize(self, text: str) -> Type:
|
|
707
|
+
"""
|
|
708
|
+
Auto-formalize a natural language or symbolic string into a constructive Type.
|
|
709
|
+
"""
|
|
710
|
+
s = text.strip()
|
|
711
|
+
|
|
712
|
+
# Check for equality: x == y
|
|
713
|
+
if "==" in s:
|
|
714
|
+
parts = s.split("==")
|
|
715
|
+
return Eq(parts[0].strip(), parts[1].strip())
|
|
716
|
+
|
|
717
|
+
# Check for implication: A -> B or implies(A, B)
|
|
718
|
+
if "->" in s:
|
|
719
|
+
parts = s.split("->", 1)
|
|
720
|
+
return Implies(self.auto_formalize(parts[0]), self.auto_formalize(parts[1]))
|
|
721
|
+
|
|
722
|
+
# Check for conjunction: A /\ B or and(A, B)
|
|
723
|
+
if "/\\" in s:
|
|
724
|
+
parts = s.split("/\\", 1)
|
|
725
|
+
return And(self.auto_formalize(parts[0]), self.auto_formalize(parts[1]))
|
|
726
|
+
|
|
727
|
+
# Check for disjunction: A \/ B or or(A, B)
|
|
728
|
+
if "\\/" in s:
|
|
729
|
+
parts = s.split("\\/", 1)
|
|
730
|
+
return Or(self.auto_formalize(parts[0]), self.auto_formalize(parts[1]))
|
|
731
|
+
|
|
732
|
+
# Check for negation: ~A or not(A)
|
|
733
|
+
if s.startswith("~") or s.lower().startswith("not "):
|
|
734
|
+
inner = s[1:].strip() if s.startswith("~") else s[4:].strip()
|
|
735
|
+
return Not(self.auto_formalize(inner))
|
|
736
|
+
|
|
737
|
+
if s.lower() in ("true", "unit", "top"):
|
|
738
|
+
return Unit
|
|
739
|
+
|
|
740
|
+
if s.lower() in ("false", "void", "bottom"):
|
|
741
|
+
return Void
|
|
742
|
+
|
|
743
|
+
# Fallback to atomic proposition
|
|
744
|
+
clean_name = re.sub(r"[^A-Za-z0-9_]", "_", s)
|
|
745
|
+
return Prop(clean_name)
|