forked from QWED-AI/qwed-verification
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvalidator.py
More file actions
138 lines (118 loc) · 4.8 KB
/
Copy pathvalidator.py
File metadata and controls
138 lines (118 loc) · 4.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
"""
Semantic Validation Layer: Pre-validates LLM outputs before symbolic verification.
This layer catches garbage outputs (like "banana * unicorn") BEFORE they reach SymPy.
It's the second line of defense after structured extraction.
Validation Checks:
1. Syntax: Can SymPy parse the expression?
2. Symbols: Only mathematical symbols allowed (no random variables)
3. Evaluable: Can we calculate a numerical result?
"""
from qwed_new.core.safe_parser import safe_parse_expr
from typing import Dict
class SemanticValidator:
"""
Validates that an expression is mathematically sound before verification.
This prevents the verification engine from crashing on invalid inputs.
"""
# Allowed mathematical symbols and functions
ALLOWED_SYMBOLS = {
'pi', 'e', # Constants
'sin', 'cos', 'tan', 'cot', 'sec', 'csc', # Trig functions
'asin', 'acos', 'atan', # Inverse trig
'sinh', 'cosh', 'tanh', # Hyperbolic
'log', 'ln', 'exp', # Logarithmic/exponential
'sqrt', 'cbrt', # Roots
'abs', 'factorial', # Other functions
}
def validate(self, expression: str) -> Dict[str, any]:
"""
Validate an expression against all checks.
Args:
expression: The mathematical expression to validate
Returns:
Dict with:
- is_valid: bool (True if all checks pass)
- checks_passed: List of check names that passed
- checks_failed: List of check names that failed
- error: Optional error message
Example:
validator = SemanticValidator()
result = validator.validate("2 + 2")
# Returns: {
# "is_valid": True,
# "checks_passed": ["syntax", "symbols", "evaluable"],
# "checks_failed": []
# }
"""
checks_passed = []
checks_failed = []
error = None
# Check 1: Syntax validation
try:
expr = safe_parse_expr(expression)
checks_passed.append("syntax")
except Exception as e:
checks_failed.append("syntax")
error = f"Syntax error: {str(e)}"
return {
"is_valid": False,
"checks_passed": checks_passed,
"checks_failed": checks_failed,
"error": error
}
# Check 2: Symbol validation (no undefined variables)
try:
# Get all free symbols (variables) in the expression
free_symbols = {str(s) for s in expr.free_symbols}
# Check if any symbols are not in our allowed list
invalid_symbols = free_symbols - self.ALLOWED_SYMBOLS
if invalid_symbols:
checks_failed.append("symbols")
error = f"Invalid symbols found: {invalid_symbols}. Only mathematical constants and functions are allowed."
return {
"is_valid": False,
"checks_passed": checks_passed,
"checks_failed": checks_failed,
"error": error
}
checks_passed.append("symbols")
except Exception as e:
checks_failed.append("symbols")
error = f"Symbol validation error: {str(e)}"
return {
"is_valid": False,
"checks_passed": checks_passed,
"checks_failed": checks_failed,
"error": error
}
# Check 3: Evaluability (can we get a numerical result?)
try:
# Try to evaluate the expression to a float
result = float(expr.evalf())
# Check for NaN or Infinity
if not (-1e308 < result < 1e308): # Rough bounds for valid floats
checks_failed.append("evaluable")
error = "Expression evaluates to infinity or invalid number"
return {
"is_valid": False,
"checks_passed": checks_passed,
"checks_failed": checks_failed,
"error": error
}
checks_passed.append("evaluable")
except Exception as e:
checks_failed.append("evaluable")
error = f"Cannot evaluate expression: {str(e)}"
return {
"is_valid": False,
"checks_passed": checks_passed,
"checks_failed": checks_failed,
"error": error
}
# All checks passed!
return {
"is_valid": True,
"checks_passed": checks_passed,
"checks_failed": checks_failed,
"error": None
}