proofery 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +247 -0
- package/dist/block.d.ts +19 -0
- package/dist/block.d.ts.map +1 -0
- package/dist/block.js +24 -0
- package/dist/block.js.map +1 -0
- package/dist/calculateVerifier.d.ts +10 -0
- package/dist/calculateVerifier.d.ts.map +1 -0
- package/dist/calculateVerifier.js +184 -0
- package/dist/calculateVerifier.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +94 -0
- package/dist/cli.js.map +1 -0
- package/dist/context.d.ts +33 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +50 -0
- package/dist/context.js.map +1 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +16 -0
- package/dist/errors.js.map +1 -0
- package/dist/expression.d.ts +32 -0
- package/dist/expression.d.ts.map +1 -0
- package/dist/expression.js +123 -0
- package/dist/expression.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/nodeParser.d.ts +16 -0
- package/dist/nodeParser.d.ts.map +1 -0
- package/dist/nodeParser.js +23 -0
- package/dist/nodeParser.js.map +1 -0
- package/dist/parser.d.ts +10 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +161 -0
- package/dist/parser.js.map +1 -0
- package/dist/simplifier.d.ts +10 -0
- package/dist/simplifier.d.ts.map +1 -0
- package/dist/simplifier.js +52 -0
- package/dist/simplifier.js.map +1 -0
- package/dist/verifier.d.ts +9 -0
- package/dist/verifier.d.ts.map +1 -0
- package/dist/verifier.js +547 -0
- package/dist/verifier.js.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# proofery
|
|
2
|
+
|
|
3
|
+
A mathematical proof verifier.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
proofery is both a **command-line tool** and a **JavaScript/TypeScript library** that verifies mathematical proofs written in the `.prf` format. It parses proof content, checks the logical validity of theorem proofs, and reports any errors with helpful line numbers.
|
|
8
|
+
|
|
9
|
+
Use it as a CLI tool to verify `.prf` files, or import it as a library to integrate proof verification into your web applications or Node.js projects.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Full proof verification** - Supports all proof step types including:
|
|
14
|
+
- `unpack-and`, `cases`, `witness`, `exact`
|
|
15
|
+
- `calculate` with equational reasoning
|
|
16
|
+
- `consider`, `forall-apply`, `deconstruct-exists`
|
|
17
|
+
- `we-have`, `focus-or`, `define`, `assert`, `assert-goal`
|
|
18
|
+
- **Axiom and theorem management** - Collect and verify theorems based on axioms
|
|
19
|
+
- **Clear error messages** - Reports errors with line numbers
|
|
20
|
+
- **Verbose mode** - Optional detailed output during verification
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
### From source
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cd proofery
|
|
28
|
+
npm install
|
|
29
|
+
npm run build
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Global installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install -g .
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
### As a Command-Line Tool
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Basic usage
|
|
44
|
+
node dist/cli.js example.prf
|
|
45
|
+
|
|
46
|
+
# With verbose output
|
|
47
|
+
node dist/cli.js --verbose example.prf
|
|
48
|
+
|
|
49
|
+
# If installed globally
|
|
50
|
+
proofery --verbose example.prf
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Command-line options:**
|
|
54
|
+
- `--verbose`, `-v` - Enable verbose output showing verification progress
|
|
55
|
+
- `--help`, `-h` - Display help message
|
|
56
|
+
|
|
57
|
+
### As a Library
|
|
58
|
+
|
|
59
|
+
#### In Node.js
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { parseContent, verifyFile } from 'proofery';
|
|
63
|
+
|
|
64
|
+
const prfContent = `
|
|
65
|
+
axiom my_axiom
|
|
66
|
+
suppose a : Nat
|
|
67
|
+
conclude eq(a, a)
|
|
68
|
+
|
|
69
|
+
theorem reflexivity
|
|
70
|
+
suppose x : Nat
|
|
71
|
+
conclude eq(x, x)
|
|
72
|
+
proof
|
|
73
|
+
exact my_axiom
|
|
74
|
+
`;
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const blocks = parseContent(prfContent);
|
|
78
|
+
verifyFile(blocks, false);
|
|
79
|
+
console.log('✓ Proof verified successfully!');
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error('Verification failed:', error.message);
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
#### In the Browser
|
|
86
|
+
|
|
87
|
+
```html
|
|
88
|
+
<!DOCTYPE html>
|
|
89
|
+
<html>
|
|
90
|
+
<head>
|
|
91
|
+
<title>Proofery Demo</title>
|
|
92
|
+
</head>
|
|
93
|
+
<body>
|
|
94
|
+
<textarea id="proof-input" rows="10" cols="50">
|
|
95
|
+
axiom test
|
|
96
|
+
conclude eq(1, 1)
|
|
97
|
+
</textarea>
|
|
98
|
+
<button onclick="verifyProof()">Verify Proof</button>
|
|
99
|
+
<div id="result"></div>
|
|
100
|
+
|
|
101
|
+
<script type="module">
|
|
102
|
+
import { parseContent, verifyFile } from './dist/index.js';
|
|
103
|
+
|
|
104
|
+
window.verifyProof = function() {
|
|
105
|
+
const content = document.getElementById('proof-input').value;
|
|
106
|
+
const resultDiv = document.getElementById('result');
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
const blocks = parseContent(content);
|
|
110
|
+
verifyFile(blocks, false);
|
|
111
|
+
resultDiv.textContent = '✓ Proof verified successfully!';
|
|
112
|
+
resultDiv.style.color = 'green';
|
|
113
|
+
} catch (error) {
|
|
114
|
+
resultDiv.textContent = '✗ Error: ' + error.message;
|
|
115
|
+
resultDiv.style.color = 'red';
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
</script>
|
|
119
|
+
</body>
|
|
120
|
+
</html>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### Available Exports
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
// Functions
|
|
127
|
+
import { parseContent, parseFile, verifyFile } from 'proofery';
|
|
128
|
+
|
|
129
|
+
// Types
|
|
130
|
+
import { Block, Expression, Context } from 'proofery';
|
|
131
|
+
|
|
132
|
+
// Error classes
|
|
133
|
+
import { VerificationError, ParseError } from 'proofery';
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## File Format
|
|
137
|
+
|
|
138
|
+
Proof files use the `.prf` extension and consist of:
|
|
139
|
+
|
|
140
|
+
- **Axioms** - Statements assumed to be true
|
|
141
|
+
- **Theorems** - Statements that must be proven
|
|
142
|
+
|
|
143
|
+
Each theorem includes:
|
|
144
|
+
- `suppose` blocks - Hypotheses and variable declarations
|
|
145
|
+
- `conclude` block - The goal to prove
|
|
146
|
+
- `proof` block - The proof steps
|
|
147
|
+
|
|
148
|
+
Example:
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
axiom associativity_of_addition
|
|
152
|
+
suppose a : Nat
|
|
153
|
+
suppose b : Nat
|
|
154
|
+
suppose c : Nat
|
|
155
|
+
conclude eq(add(add(a, b), c), add(a, add(b, c)))
|
|
156
|
+
|
|
157
|
+
theorem test1
|
|
158
|
+
suppose a : Prop
|
|
159
|
+
suppose b : Prop
|
|
160
|
+
suppose h1 : a
|
|
161
|
+
suppose h2 : b
|
|
162
|
+
conclude and(a, b)
|
|
163
|
+
proof
|
|
164
|
+
unpack-and
|
|
165
|
+
goal a
|
|
166
|
+
proof
|
|
167
|
+
exact h1
|
|
168
|
+
goal b
|
|
169
|
+
proof
|
|
170
|
+
exact h2
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
For complete language reference, see the original `LANGUAGE_REFERENCE.md`.
|
|
174
|
+
|
|
175
|
+
## Development
|
|
176
|
+
|
|
177
|
+
### Project Structure
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
proofery/
|
|
181
|
+
├── src/
|
|
182
|
+
│ ├── index.ts # Library entry point (exports)
|
|
183
|
+
│ ├── cli.ts # CLI entry point
|
|
184
|
+
│ ├── parser.ts # .prf file parser
|
|
185
|
+
│ ├── verifier.ts # Main proof verifier
|
|
186
|
+
│ ├── expression.ts # Expression tree representation
|
|
187
|
+
│ ├── block.ts # Block structure
|
|
188
|
+
│ ├── context.ts # Context tracking
|
|
189
|
+
│ ├── simplifier.ts # Expression simplification
|
|
190
|
+
│ ├── calculateVerifier.ts # Calculate step verifier
|
|
191
|
+
│ └── errors.ts # Custom error classes
|
|
192
|
+
├── examples/
|
|
193
|
+
│ └── example.prf # Example proof file
|
|
194
|
+
├── package.json
|
|
195
|
+
├── tsconfig.json
|
|
196
|
+
└── README.md
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Building
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
npm run build
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
This compiles TypeScript to JavaScript in the `dist/` directory.
|
|
206
|
+
|
|
207
|
+
### Testing
|
|
208
|
+
|
|
209
|
+
Test the CLI with the example file:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
npm run build
|
|
213
|
+
node dist/cli.js --verbose examples/example.prf
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Test the library API:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
npm run build
|
|
220
|
+
node -e "
|
|
221
|
+
const { parseContent, verifyFile } = require('./dist/index.js');
|
|
222
|
+
const fs = require('fs');
|
|
223
|
+
const content = fs.readFileSync('examples/example.prf', 'utf-8');
|
|
224
|
+
const blocks = parseContent(content);
|
|
225
|
+
verifyFile(blocks, true);
|
|
226
|
+
console.log('\n✓ Library API test passed!');
|
|
227
|
+
"
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Differences from Python Version
|
|
231
|
+
|
|
232
|
+
This TypeScript implementation is a faithful port of the Python version with the following technical differences:
|
|
233
|
+
|
|
234
|
+
- Uses TypeScript's type system for enhanced type safety
|
|
235
|
+
- Uses `Map` instead of Python dictionaries for axiom/theorem storage
|
|
236
|
+
- Console output uses Node.js conventions
|
|
237
|
+
- File I/O uses Node.js `fs` module
|
|
238
|
+
|
|
239
|
+
The verification logic and proof language remain identical to the Python version.
|
|
240
|
+
|
|
241
|
+
## License
|
|
242
|
+
|
|
243
|
+
MIT
|
|
244
|
+
|
|
245
|
+
## Author
|
|
246
|
+
|
|
247
|
+
Port by Jeremy Magland (original Python version also by Jeremy Magland)
|
package/dist/block.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Block representation for proof structure.
|
|
3
|
+
*/
|
|
4
|
+
import { Expression } from './expression.js';
|
|
5
|
+
/**
|
|
6
|
+
* Represents a block in the proof tree.
|
|
7
|
+
*/
|
|
8
|
+
export declare class Block {
|
|
9
|
+
readonly lineNum: number;
|
|
10
|
+
readonly blockType: string;
|
|
11
|
+
readonly args: Expression[];
|
|
12
|
+
children: Block[];
|
|
13
|
+
constructor(lineNum: number, blockType: string, args?: Expression[], children?: Block[]);
|
|
14
|
+
/**
|
|
15
|
+
* String representation of the block.
|
|
16
|
+
*/
|
|
17
|
+
toString(): string;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=block.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../src/block.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C;;GAEG;AACH,qBAAa,KAAK;aAEM,OAAO,EAAE,MAAM;aACf,SAAS,EAAE,MAAM;aACjB,IAAI,EAAE,UAAU,EAAE;IAC3B,QAAQ,EAAE,KAAK,EAAE;gBAHR,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,UAAU,EAAO,EAChC,QAAQ,GAAE,KAAK,EAAO;IAGjC;;OAEG;IACH,QAAQ,IAAI,MAAM;CAMrB"}
|
package/dist/block.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Block representation for proof structure.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Represents a block in the proof tree.
|
|
6
|
+
*/
|
|
7
|
+
export class Block {
|
|
8
|
+
constructor(lineNum, blockType, args = [], children = []) {
|
|
9
|
+
this.lineNum = lineNum;
|
|
10
|
+
this.blockType = blockType;
|
|
11
|
+
this.args = args;
|
|
12
|
+
this.children = children;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* String representation of the block.
|
|
16
|
+
*/
|
|
17
|
+
toString() {
|
|
18
|
+
const argsStr = this.args.length > 0
|
|
19
|
+
? ` ${this.args.map(a => a.toString()).join(' ')}`
|
|
20
|
+
: '';
|
|
21
|
+
return `${this.blockType}${argsStr}`;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=block.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block.js","sourceRoot":"","sources":["../src/block.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,MAAM,OAAO,KAAK;IACd,YACoB,OAAe,EACf,SAAiB,EACjB,OAAqB,EAAE,EAChC,WAAoB,EAAE;QAHb,YAAO,GAAP,OAAO,CAAQ;QACf,cAAS,GAAT,SAAS,CAAQ;QACjB,SAAI,GAAJ,IAAI,CAAmB;QAChC,aAAQ,GAAR,QAAQ,CAAc;IAC9B,CAAC;IAEJ;;OAEG;IACH,QAAQ;QACJ,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;YAChC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;YAClD,CAAC,CAAC,EAAE,CAAC;QACT,OAAO,GAAG,IAAI,CAAC,SAAS,GAAG,OAAO,EAAE,CAAC;IACzC,CAAC;CACJ"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verification logic for calculate blocks.
|
|
3
|
+
*/
|
|
4
|
+
import { Block } from './block.js';
|
|
5
|
+
import { Context } from './context.js';
|
|
6
|
+
/**
|
|
7
|
+
* Verify a calculate block and return true if goal is resolved.
|
|
8
|
+
*/
|
|
9
|
+
export declare function verifyCalculate(step: Block, context: Context, axiomsAndTheorems: Map<string, Block>): boolean;
|
|
10
|
+
//# sourceMappingURL=calculateVerifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculateVerifier.d.ts","sourceRoot":"","sources":["../src/calculateVerifier.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAIvC;;GAEG;AACH,wBAAgB,eAAe,CAC3B,IAAI,EAAE,KAAK,EACX,OAAO,EAAE,OAAO,EAChB,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,GACtC,OAAO,CAwDT"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verification logic for calculate blocks.
|
|
3
|
+
*/
|
|
4
|
+
import { VerificationError } from './errors.js';
|
|
5
|
+
/**
|
|
6
|
+
* Verify a calculate block and return true if goal is resolved.
|
|
7
|
+
*/
|
|
8
|
+
export function verifyCalculate(step, context, axiomsAndTheorems) {
|
|
9
|
+
// 1. Validate that the goal is an equality
|
|
10
|
+
if (context.goal === null) {
|
|
11
|
+
throw new VerificationError(`Line ${step.lineNum}: No goal for calculate`);
|
|
12
|
+
}
|
|
13
|
+
if (context.goal.name !== 'eq' || context.goal.children.length !== 2) {
|
|
14
|
+
throw new VerificationError(`Line ${step.lineNum}: Goal must be eq(a, b), got ${context.goal}`);
|
|
15
|
+
}
|
|
16
|
+
const initialExpr = context.goal.children[0];
|
|
17
|
+
const finalExpr = context.goal.children[1];
|
|
18
|
+
// 2. Validate calculate structure
|
|
19
|
+
if (step.args.length !== 1) {
|
|
20
|
+
throw new VerificationError(`Line ${step.lineNum}: 'calculate' must have exactly one argument (initial expression)`);
|
|
21
|
+
}
|
|
22
|
+
const calcInitial = step.args[0];
|
|
23
|
+
if (!calcInitial.equals(initialExpr)) {
|
|
24
|
+
throw new VerificationError(`Line ${step.lineNum}: Calculate initial expression ${calcInitial} does not match goal LHS ${initialExpr}`);
|
|
25
|
+
}
|
|
26
|
+
if (step.children.length === 0) {
|
|
27
|
+
throw new VerificationError(`Line ${step.lineNum}: Calculate block must have at least one step`);
|
|
28
|
+
}
|
|
29
|
+
// 3. Process each calculation step
|
|
30
|
+
let currentExpr = initialExpr;
|
|
31
|
+
for (const child of step.children) {
|
|
32
|
+
if (child.blockType !== '=') {
|
|
33
|
+
throw new VerificationError(`Line ${child.lineNum}: Calculate children must be '=' blocks, got '${child.blockType}'`);
|
|
34
|
+
}
|
|
35
|
+
currentExpr = verifyCalcStep(child, currentExpr, context, axiomsAndTheorems);
|
|
36
|
+
}
|
|
37
|
+
// 4. Final check: current expression should equal goal's RHS
|
|
38
|
+
if (!currentExpr.equals(finalExpr)) {
|
|
39
|
+
throw new VerificationError(`Line ${step.lineNum}: Calculate final expression ${currentExpr} does not match goal RHS ${finalExpr}`);
|
|
40
|
+
}
|
|
41
|
+
return true; // Goal resolved
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Verify a single calculation step and return the new expression.
|
|
45
|
+
*/
|
|
46
|
+
function verifyCalcStep(step, prevExpr, context, axiomsAndTheorems) {
|
|
47
|
+
if (step.args.length < 2) {
|
|
48
|
+
throw new VerificationError(`Line ${step.lineNum}: '=' must have at least 2 arguments (new_expr and justification)`);
|
|
49
|
+
}
|
|
50
|
+
const newExpr = step.args[0];
|
|
51
|
+
const justificationType = step.args[1].name;
|
|
52
|
+
if (step.args[1].children.length > 0) {
|
|
53
|
+
throw new VerificationError(`Line ${step.lineNum}: Justification type must be a simple identifier (by-lhs or by-rhs)`);
|
|
54
|
+
}
|
|
55
|
+
// Get the equation (lhs, rhs) based on justification
|
|
56
|
+
const remainingArgs = step.args.slice(2);
|
|
57
|
+
let lhs, rhs;
|
|
58
|
+
if (justificationType === 'by-lhs') {
|
|
59
|
+
[lhs, rhs] = getEquationForJustification(step, context, axiomsAndTheorems, remainingArgs);
|
|
60
|
+
// by-lhs: verify that prevExpr can be transformed to newExpr by replacing lhs with rhs where needed
|
|
61
|
+
if (!verifyTransformation(prevExpr, newExpr, lhs, rhs)) {
|
|
62
|
+
throw new VerificationError(`Line ${step.lineNum}: Cannot transform ${prevExpr} to ${newExpr} using by-lhs ${lhs} = ${rhs}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else if (justificationType === 'by-rhs') {
|
|
66
|
+
[lhs, rhs] = getEquationForJustification(step, context, axiomsAndTheorems, remainingArgs);
|
|
67
|
+
// by-rhs: verify that prevExpr can be transformed to newExpr by replacing rhs with lhs where needed
|
|
68
|
+
if (!verifyTransformation(prevExpr, newExpr, rhs, lhs)) {
|
|
69
|
+
throw new VerificationError(`Line ${step.lineNum}: Cannot transform ${prevExpr} to ${newExpr} using by-rhs ${lhs} = ${rhs}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
throw new VerificationError(`Line ${step.lineNum}: Unknown justification type '${justificationType}', expected 'by-lhs' or 'by-rhs'`);
|
|
74
|
+
}
|
|
75
|
+
return newExpr;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get the (lhs, rhs) equation from either a variable or axiom/theorem.
|
|
79
|
+
*/
|
|
80
|
+
function getEquationForJustification(step, context, axiomsAndTheorems, args) {
|
|
81
|
+
if (args.length === 0) {
|
|
82
|
+
throw new VerificationError(`Line ${step.lineNum}: Justification requires at least one argument`);
|
|
83
|
+
}
|
|
84
|
+
const firstArg = args[0];
|
|
85
|
+
// First argument must be a simple identifier
|
|
86
|
+
if (firstArg.children.length > 0) {
|
|
87
|
+
throw new VerificationError(`Line ${step.lineNum}: First justification argument must be a simple identifier (variable or axiom name)`);
|
|
88
|
+
}
|
|
89
|
+
const name = firstArg.name;
|
|
90
|
+
// Check if it's a variable in context (with only one arg total)
|
|
91
|
+
if (args.length === 1 && context.hasVariable(name)) {
|
|
92
|
+
// This is a variable reference
|
|
93
|
+
return getEquationFromVariable(step, name, context);
|
|
94
|
+
}
|
|
95
|
+
// Otherwise, treat it as an axiom/theorem
|
|
96
|
+
const axiomArgs = args.slice(1); // Remaining args are the axiom arguments
|
|
97
|
+
return getEquationFromAxiom(step, name, axiomArgs, context, axiomsAndTheorems);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Extract (lhs, rhs) from a variable with type eq(lhs, rhs).
|
|
101
|
+
*/
|
|
102
|
+
function getEquationFromVariable(step, varName, context) {
|
|
103
|
+
if (!context.hasVariable(varName)) {
|
|
104
|
+
throw new VerificationError(`Line ${step.lineNum}: Variable '${varName}' not in context`);
|
|
105
|
+
}
|
|
106
|
+
const varType = context.getVariableType(varName);
|
|
107
|
+
if (varType.name !== 'eq' || varType.children.length !== 2) {
|
|
108
|
+
throw new VerificationError(`Line ${step.lineNum}: Variable '${varName}' must have type eq(a, b), got ${varType}`);
|
|
109
|
+
}
|
|
110
|
+
return [varType.children[0], varType.children[1]];
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Extract (lhs, rhs) from an axiom/theorem after substituting arguments.
|
|
114
|
+
*/
|
|
115
|
+
function getEquationFromAxiom(step, axiomName, args, context, axiomsAndTheorems) {
|
|
116
|
+
if (!axiomsAndTheorems.has(axiomName)) {
|
|
117
|
+
throw new VerificationError(`Line ${step.lineNum}: Axiom or theorem '${axiomName}' not found`);
|
|
118
|
+
}
|
|
119
|
+
const axiomBlock = axiomsAndTheorems.get(axiomName);
|
|
120
|
+
// Extract suppose blocks
|
|
121
|
+
const supposeBlocks = [];
|
|
122
|
+
let concludeBlock = null;
|
|
123
|
+
for (const child of axiomBlock.children) {
|
|
124
|
+
if (child.blockType === 'suppose') {
|
|
125
|
+
supposeBlocks.push(child);
|
|
126
|
+
}
|
|
127
|
+
else if (child.blockType === 'conclude') {
|
|
128
|
+
concludeBlock = child;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (concludeBlock === null) {
|
|
132
|
+
throw new VerificationError(`Line ${step.lineNum}: Axiom '${axiomName}' has no conclude block`);
|
|
133
|
+
}
|
|
134
|
+
// Verify number of arguments matches
|
|
135
|
+
if (args.length !== supposeBlocks.length) {
|
|
136
|
+
throw new VerificationError(`Line ${step.lineNum}: Axiom '${axiomName}' expects ${supposeBlocks.length} arguments, got ${args.length}`);
|
|
137
|
+
}
|
|
138
|
+
// Build substitution map
|
|
139
|
+
const substitutions = new Map();
|
|
140
|
+
for (let i = 0; i < supposeBlocks.length; i++) {
|
|
141
|
+
const suppose = supposeBlocks[i];
|
|
142
|
+
const arg = args[i];
|
|
143
|
+
// Parse suppose: suppose name : type
|
|
144
|
+
if (suppose.args.length !== 1) {
|
|
145
|
+
throw new VerificationError(`Line ${step.lineNum}: Invalid suppose block in axiom '${axiomName}'`);
|
|
146
|
+
}
|
|
147
|
+
const supposeArg = suppose.args[0];
|
|
148
|
+
if (supposeArg.name !== 'var' || supposeArg.children.length !== 2) {
|
|
149
|
+
throw new VerificationError(`Line ${step.lineNum}: Invalid suppose format in axiom '${axiomName}'`);
|
|
150
|
+
}
|
|
151
|
+
const varName = supposeArg.children[0].name;
|
|
152
|
+
substitutions.set(varName, arg);
|
|
153
|
+
}
|
|
154
|
+
// Get the conclusion and verify it's an equation
|
|
155
|
+
let conclusion = concludeBlock.args[0];
|
|
156
|
+
// Apply substitutions to the conclusion
|
|
157
|
+
for (const [varName, argExpr] of substitutions) {
|
|
158
|
+
conclusion = conclusion.substitute(varName, argExpr);
|
|
159
|
+
}
|
|
160
|
+
if (conclusion.name !== 'eq' || conclusion.children.length !== 2) {
|
|
161
|
+
throw new VerificationError(`Line ${step.lineNum}: Axiom '${axiomName}' conclusion must be eq(a, b), got ${conclusion}`);
|
|
162
|
+
}
|
|
163
|
+
return [conclusion.children[0], conclusion.children[1]];
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Verify that prevExpr can be transformed to targetExpr by replacing fromExpr with toExpr where needed.
|
|
167
|
+
*/
|
|
168
|
+
function verifyTransformation(prevExpr, targetExpr, fromExpr, toExpr) {
|
|
169
|
+
// If they're already equal, no substitution needed
|
|
170
|
+
if (prevExpr.equals(targetExpr)) {
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
// Try substituting at the root level
|
|
174
|
+
if (prevExpr.equals(fromExpr)) {
|
|
175
|
+
return toExpr.equals(targetExpr);
|
|
176
|
+
}
|
|
177
|
+
// If names don't match or different number of children, can't transform
|
|
178
|
+
if (prevExpr.name !== targetExpr.name || prevExpr.children.length !== targetExpr.children.length) {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
// Recursively check all children
|
|
182
|
+
return prevExpr.children.every((pc, i) => verifyTransformation(pc, targetExpr.children[i], fromExpr, toExpr));
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=calculateVerifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculateVerifier.js","sourceRoot":"","sources":["../src/calculateVerifier.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;GAEG"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Command-line interface for proofery.
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import { parseFileSync } from './nodeParser.js';
|
|
7
|
+
import { verifyFile } from './verifier.js';
|
|
8
|
+
import { VerificationError, ParseError } from './errors.js';
|
|
9
|
+
function main() {
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
// Parse command line arguments
|
|
12
|
+
let verbose = false;
|
|
13
|
+
let filepath = null;
|
|
14
|
+
for (let i = 0; i < args.length; i++) {
|
|
15
|
+
const arg = args[i];
|
|
16
|
+
if (arg === '--verbose' || arg === '-v') {
|
|
17
|
+
verbose = true;
|
|
18
|
+
}
|
|
19
|
+
else if (arg === '--help' || arg === '-h') {
|
|
20
|
+
printHelp();
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}
|
|
23
|
+
else if (!arg.startsWith('-')) {
|
|
24
|
+
filepath = arg;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
console.error(`Unknown option: ${arg}`);
|
|
28
|
+
printHelp();
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (!filepath) {
|
|
33
|
+
console.error('Error: No file specified');
|
|
34
|
+
printHelp();
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
// Check if file exists
|
|
39
|
+
if (!fs.existsSync(filepath)) {
|
|
40
|
+
console.error(`Error: File '${filepath}' not found`);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
// Parse the file
|
|
44
|
+
if (verbose) {
|
|
45
|
+
console.log(`Parsing ${filepath}...`);
|
|
46
|
+
}
|
|
47
|
+
const blocks = parseFileSync(filepath);
|
|
48
|
+
if (verbose) {
|
|
49
|
+
console.log(`Parsed ${blocks.length} top-level blocks\n`);
|
|
50
|
+
}
|
|
51
|
+
// Verify the proofs
|
|
52
|
+
verifyFile(blocks, verbose);
|
|
53
|
+
if (verbose) {
|
|
54
|
+
console.log('\n✓ All proofs verified successfully!');
|
|
55
|
+
}
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
if (error instanceof VerificationError || error instanceof ParseError || error instanceof SyntaxError) {
|
|
60
|
+
console.error(`Error: ${error.message}`);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
else if (error instanceof Error) {
|
|
64
|
+
console.error(`Unexpected error: ${error.message}`);
|
|
65
|
+
if (verbose && error.stack) {
|
|
66
|
+
console.error(error.stack);
|
|
67
|
+
}
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
console.error(`Unexpected error: ${error}`);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function printHelp() {
|
|
77
|
+
console.log(`
|
|
78
|
+
proofery - A mathematical proof verifier
|
|
79
|
+
|
|
80
|
+
Usage: proofery [options] <file>
|
|
81
|
+
|
|
82
|
+
Arguments:
|
|
83
|
+
<file> Path to the .prf file to verify
|
|
84
|
+
|
|
85
|
+
Options:
|
|
86
|
+
-v, --verbose Enable verbose output
|
|
87
|
+
-h, --help Show this help message
|
|
88
|
+
|
|
89
|
+
Example:
|
|
90
|
+
proofery --verbose example.prf
|
|
91
|
+
`);
|
|
92
|
+
}
|
|
93
|
+
main();
|
|
94
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context tracking for proof verification.
|
|
3
|
+
*/
|
|
4
|
+
import { Expression } from './expression.js';
|
|
5
|
+
/**
|
|
6
|
+
* Context holds variables and their types, plus the current goal.
|
|
7
|
+
*/
|
|
8
|
+
export declare class Context {
|
|
9
|
+
private variables;
|
|
10
|
+
goal: Expression | null;
|
|
11
|
+
constructor();
|
|
12
|
+
/**
|
|
13
|
+
* Add a variable with its type to the context.
|
|
14
|
+
*/
|
|
15
|
+
addVariable(name: string, varType: Expression): void;
|
|
16
|
+
/**
|
|
17
|
+
* Check if a variable exists in the context.
|
|
18
|
+
*/
|
|
19
|
+
hasVariable(name: string): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Get the type of a variable.
|
|
22
|
+
*/
|
|
23
|
+
getVariableType(name: string): Expression | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Create a deep copy of this context.
|
|
26
|
+
*/
|
|
27
|
+
copy(): Context;
|
|
28
|
+
/**
|
|
29
|
+
* String representation of the context.
|
|
30
|
+
*/
|
|
31
|
+
toString(): string;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=context.d.ts.map
|