atsds 0.0.1-alpha32 → 0.0.1-alpha33
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/README.md +358 -1
- package/dist/ds.wasm.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,2 +1,359 @@
|
|
|
1
|
-
# A Deductive System
|
|
1
|
+
# DS - A Deductive System
|
|
2
|
+
|
|
3
|
+
A deductive system for logical inference, implemented in C++. The library provides bindings for Python (via pybind11) and TypeScript/JavaScript (via Emscripten/WebAssembly).
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
- **C++ Core**: The core implementation in `src/` and `include/ds/` provides the fundamental data structures and algorithms
|
|
8
|
+
- **Python Bindings**: Built with pybind11, wrapping the C++ core (see `pyds/`)
|
|
9
|
+
- **TypeScript/JavaScript Bindings**: Built with Emscripten, compiling C++ to WebAssembly (see `tsds/`)
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Multi-Language Support**: Use the same deductive system in C++, Python, or TypeScript/JavaScript
|
|
14
|
+
- **Logical Terms**: Work with variables, items (constants/functors), and lists
|
|
15
|
+
- **Rule-Based Inference**: Define rules and facts, perform logical deduction
|
|
16
|
+
- **Unification and Matching**: Unify terms and match rules
|
|
17
|
+
- **Search Engine**: Built-in search mechanism for iterative inference
|
|
18
|
+
- **WebAssembly**: Run inference in the browser or Node.js environments
|
|
19
|
+
- **Type-Safe**: Strong typing support in TypeScript and Python
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
### TypeScript/JavaScript (npm)
|
|
24
|
+
|
|
25
|
+
The TypeScript/JavaScript package wraps the C++ core via WebAssembly.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install atsds
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The package includes WebAssembly binaries and TypeScript type definitions.
|
|
32
|
+
|
|
33
|
+
### Python (pip)
|
|
34
|
+
|
|
35
|
+
The Python package wraps the C++ core via pybind11.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install apyds
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Then import as `pyds`:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
import pyds
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Requires Python 3.10-3.14.
|
|
48
|
+
|
|
49
|
+
### C++ (Core Library)
|
|
50
|
+
|
|
51
|
+
The C++ library is the core implementation. Both Python and TypeScript bindings are built on top of it.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
git clone https://github.com/USTC-KnowledgeComputingLab/ds.git
|
|
55
|
+
cd ds
|
|
56
|
+
cmake -B build
|
|
57
|
+
cmake --build build
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Include the headers from `include/ds/` in your C++ project.
|
|
61
|
+
|
|
62
|
+
## Quick Start
|
|
63
|
+
|
|
64
|
+
### TypeScript/JavaScript Example
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { rule_t, search_t } from "atsds";
|
|
68
|
+
|
|
69
|
+
// Create a search engine
|
|
70
|
+
const search = new search_t(1000, 10000);
|
|
71
|
+
|
|
72
|
+
// Modus ponens: P -> Q, P |- Q
|
|
73
|
+
search.add("(`P -> `Q) `P `Q");
|
|
74
|
+
// Axiom schema 1: p -> (q -> p)
|
|
75
|
+
search.add("(`p -> (`q -> `p))");
|
|
76
|
+
// Axiom schema 2: (p -> (q -> r)) -> ((p -> q) -> (p -> r))
|
|
77
|
+
search.add("((`p -> (`q -> `r)) -> ((`p -> `q) -> (`p -> `r)))");
|
|
78
|
+
// Axiom schema 3: (!p -> !q) -> (q -> p)
|
|
79
|
+
search.add("(((! `p) -> (! `q)) -> (`q -> `p))");
|
|
80
|
+
|
|
81
|
+
// Premise: !!X
|
|
82
|
+
search.add("(! (! X))");
|
|
83
|
+
|
|
84
|
+
// Target: X (double negation elimination)
|
|
85
|
+
const target = new rule_t("X");
|
|
86
|
+
|
|
87
|
+
// Execute search until target is found
|
|
88
|
+
while (true) {
|
|
89
|
+
let found = false;
|
|
90
|
+
search.execute((candidate) => {
|
|
91
|
+
if (candidate.key() === target.key()) {
|
|
92
|
+
console.log("Found:", candidate.toString());
|
|
93
|
+
found = true;
|
|
94
|
+
return true; // Stop search
|
|
95
|
+
}
|
|
96
|
+
return false; // Continue searching
|
|
97
|
+
});
|
|
98
|
+
if (found) break;
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Python Example
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
import pyds
|
|
106
|
+
|
|
107
|
+
# Create a search engine
|
|
108
|
+
search = pyds.Search(1000, 10000)
|
|
109
|
+
|
|
110
|
+
# Modus ponens: P -> Q, P |- Q
|
|
111
|
+
search.add("(`P -> `Q) `P `Q")
|
|
112
|
+
# Axiom schema 1: p -> (q -> p)
|
|
113
|
+
search.add("(`p -> (`q -> `p))")
|
|
114
|
+
# Axiom schema 2: (p -> (q -> r)) -> ((p -> q) -> (p -> r))
|
|
115
|
+
search.add("((`p -> (`q -> `r)) -> ((`p -> `q) -> (`p -> `r)))")
|
|
116
|
+
# Axiom schema 3: (!p -> !q) -> (q -> p)
|
|
117
|
+
search.add("(((! `p) -> (! `q)) -> (`q -> `p))")
|
|
118
|
+
|
|
119
|
+
# Premise: !!X
|
|
120
|
+
search.add("(! (! X))")
|
|
121
|
+
|
|
122
|
+
# Target: X (double negation elimination)
|
|
123
|
+
target = pyds.Rule("X")
|
|
124
|
+
|
|
125
|
+
# Execute search until target is found
|
|
126
|
+
while True:
|
|
127
|
+
found = False
|
|
128
|
+
def callback(candidate):
|
|
129
|
+
global found
|
|
130
|
+
if candidate == target:
|
|
131
|
+
print("Found:", candidate)
|
|
132
|
+
found = True
|
|
133
|
+
return True # Stop search
|
|
134
|
+
return False # Continue searching
|
|
135
|
+
search.execute(callback)
|
|
136
|
+
if found:
|
|
137
|
+
break
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### C++ Example
|
|
141
|
+
|
|
142
|
+
```cpp
|
|
143
|
+
#include <cstdio>
|
|
144
|
+
#include <cstring>
|
|
145
|
+
#include <ds/ds.hh>
|
|
146
|
+
#include <ds/search.hh>
|
|
147
|
+
#include <ds/utility.hh>
|
|
148
|
+
|
|
149
|
+
int main() {
|
|
150
|
+
ds::search_t search(1000, 10000);
|
|
151
|
+
|
|
152
|
+
// Modus ponens: P -> Q, P |- Q
|
|
153
|
+
search.add("(`P -> `Q) `P `Q");
|
|
154
|
+
// Axiom schema 1: p -> (q -> p)
|
|
155
|
+
search.add("(`p -> (`q -> `p))");
|
|
156
|
+
// Axiom schema 2: (p -> (q -> r)) -> ((p -> q) -> (p -> r))
|
|
157
|
+
search.add("((`p -> (`q -> `r)) -> ((`p -> `q) -> (`p -> `r)))");
|
|
158
|
+
// Axiom schema 3: (!p -> !q) -> (q -> p)
|
|
159
|
+
search.add("(((! `p) -> (! `q)) -> (`q -> `p))");
|
|
160
|
+
|
|
161
|
+
// Premise: !!X
|
|
162
|
+
search.add("(! (! X))");
|
|
163
|
+
|
|
164
|
+
// Target: X (double negation elimination)
|
|
165
|
+
auto target = ds::text_to_rule("X", 1000);
|
|
166
|
+
|
|
167
|
+
// Execute search until target is found
|
|
168
|
+
while (true) {
|
|
169
|
+
bool found = false;
|
|
170
|
+
search.execute([&](ds::rule_t* candidate) {
|
|
171
|
+
if (candidate->data_size() == target->data_size() &&
|
|
172
|
+
memcmp(candidate->head(), target->head(), candidate->data_size()) == 0) {
|
|
173
|
+
printf("Found: %s", ds::rule_to_text(candidate, 1000).get());
|
|
174
|
+
found = true;
|
|
175
|
+
return true; // Stop search
|
|
176
|
+
}
|
|
177
|
+
return false; // Continue searching
|
|
178
|
+
});
|
|
179
|
+
if (found) break;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Core Concepts
|
|
187
|
+
|
|
188
|
+
### Terms
|
|
189
|
+
|
|
190
|
+
Terms are the basic building blocks of the deductive system:
|
|
191
|
+
|
|
192
|
+
- **Variables**: Prefixed with backtick, e.g., `` `X``, `` `P``, `` `Q``
|
|
193
|
+
- **Items**: Constants or functors, e.g., `a`, `father`, `!`
|
|
194
|
+
- **Lists**: Ordered sequences enclosed in parentheses, e.g., `(a b c)`, `(father john mary)`
|
|
195
|
+
|
|
196
|
+
### Rules
|
|
197
|
+
|
|
198
|
+
Rules consist of zero or more premises (above the line) and a conclusion (below the line):
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
premise1
|
|
202
|
+
premise2
|
|
203
|
+
----------
|
|
204
|
+
conclusion
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
A fact is a rule without premises:
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
----------
|
|
211
|
+
(parent john mary)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Grounding
|
|
215
|
+
|
|
216
|
+
Grounding substitutes variables with values using a dictionary:
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
const a = new term_t("`a");
|
|
220
|
+
const dict = new term_t("((`a b))"); // Substitute `a with b
|
|
221
|
+
const result = a.ground(dict);
|
|
222
|
+
console.log(result.toString()); // "b"
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Matching
|
|
226
|
+
|
|
227
|
+
Matching unifies the first premise of a rule with a fact to produce a new rule. For example, applying modus ponens to double negation elimination:
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
// Modus ponens rule: (p -> q), p |- q
|
|
231
|
+
const mp = new rule_t("(`p -> `q)\n`p\n`q\n");
|
|
232
|
+
// Double negation elimination axiom: !!x -> x
|
|
233
|
+
const pq = new rule_t("((! (! `x)) -> `x)");
|
|
234
|
+
// Match produces: !!x |- x
|
|
235
|
+
console.log(mp.match(pq).toString()); // "(! (! `x))\n----------\n`x\n"
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## API Overview
|
|
239
|
+
|
|
240
|
+
### TypeScript/JavaScript
|
|
241
|
+
|
|
242
|
+
- `buffer_size(size?: number)`: Get/set buffer size for internal operations
|
|
243
|
+
- `string_t`: String wrapper class
|
|
244
|
+
- `variable_t`: Logical variable class
|
|
245
|
+
- `item_t`: Item (constant/functor) class
|
|
246
|
+
- `list_t`: List class
|
|
247
|
+
- `term_t`: General term class (variable, item, or list)
|
|
248
|
+
- `rule_t`: Logical rule class
|
|
249
|
+
- `search_t`: Search engine for inference
|
|
250
|
+
|
|
251
|
+
### Python
|
|
252
|
+
|
|
253
|
+
- `buffer_size(size: int)`: Set buffer size
|
|
254
|
+
- `scoped_buffer_size(size: int)`: Context manager for temporary buffer size
|
|
255
|
+
- `String`: String wrapper class
|
|
256
|
+
- `Variable`: Logical variable class
|
|
257
|
+
- `Item`: Item (constant/functor) class
|
|
258
|
+
- `List`: List class
|
|
259
|
+
- `Term`: General term class
|
|
260
|
+
- `Rule`: Logical rule class
|
|
261
|
+
- `Search`: Search engine for inference
|
|
262
|
+
|
|
263
|
+
### C++ (Core)
|
|
264
|
+
|
|
265
|
+
All classes are in the `ds` namespace:
|
|
266
|
+
|
|
267
|
+
- `string_t`: String handling
|
|
268
|
+
- `variable_t`: Logical variables
|
|
269
|
+
- `item_t`: Items (constants/functors)
|
|
270
|
+
- `list_t`: Lists
|
|
271
|
+
- `term_t`: General terms
|
|
272
|
+
- `rule_t`: Logical rules
|
|
273
|
+
- `search_t`: Search engine (in `<ds/search.hh>`)
|
|
274
|
+
|
|
275
|
+
See header files in `include/ds/` for detailed API documentation.
|
|
276
|
+
|
|
277
|
+
## Building from Source
|
|
278
|
+
|
|
279
|
+
### Prerequisites
|
|
280
|
+
|
|
281
|
+
- C++20 compatible compiler
|
|
282
|
+
- CMake 3.15+
|
|
283
|
+
- For TypeScript: Emscripten SDK
|
|
284
|
+
- For Python: Python 3.10-3.14, scikit-build-core, pybind11
|
|
285
|
+
|
|
286
|
+
### Build All Components
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
# Clone repository
|
|
290
|
+
git clone https://github.com/USTC-KnowledgeComputingLab/ds.git
|
|
291
|
+
cd ds
|
|
292
|
+
|
|
293
|
+
# Build C++ library
|
|
294
|
+
cmake -B build
|
|
295
|
+
cmake --build build
|
|
296
|
+
|
|
297
|
+
# Build TypeScript/JavaScript (requires Emscripten)
|
|
298
|
+
npm install
|
|
299
|
+
npm run build
|
|
300
|
+
|
|
301
|
+
# Build Python package
|
|
302
|
+
pip install -e ".[dev]"
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Running Tests
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
# TypeScript/JavaScript tests
|
|
309
|
+
npm test
|
|
310
|
+
|
|
311
|
+
# Python tests
|
|
312
|
+
pytest
|
|
313
|
+
|
|
314
|
+
# C++ tests (if available)
|
|
315
|
+
cd build && ctest
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Examples
|
|
319
|
+
|
|
320
|
+
Example programs are provided in the `examples/` directory:
|
|
321
|
+
|
|
322
|
+
- `examples/main.mjs`: TypeScript/JavaScript example
|
|
323
|
+
- `examples/main.py`: Python example
|
|
324
|
+
- `examples/main.cc`: C++ example
|
|
325
|
+
|
|
326
|
+
Each example demonstrates logical inference using propositional logic axioms.
|
|
327
|
+
|
|
328
|
+
## Development
|
|
329
|
+
|
|
330
|
+
### Code Formatting
|
|
331
|
+
|
|
332
|
+
The project uses code formatting tools for consistency:
|
|
333
|
+
|
|
334
|
+
- C++: clang-format (`.clang-format` config provided)
|
|
335
|
+
- Python: ruff (configured in `pyproject.toml`)
|
|
336
|
+
- TypeScript: Biome (configured in `biome.json`)
|
|
337
|
+
|
|
338
|
+
### Pre-commit Hooks
|
|
339
|
+
|
|
340
|
+
Pre-commit hooks are configured in `.pre-commit-config.yaml`.
|
|
341
|
+
|
|
342
|
+
## License
|
|
343
|
+
|
|
344
|
+
This project is licensed under the GNU General Public License v3.0 or later. See [LICENSE.md](LICENSE.md) for details.
|
|
345
|
+
|
|
346
|
+
## Repository
|
|
347
|
+
|
|
348
|
+
- **GitHub**: [USTC-KnowledgeComputingLab/ds](https://github.com/USTC-KnowledgeComputingLab/ds)
|
|
349
|
+
- **npm package**: [atsds](https://www.npmjs.com/package/atsds)
|
|
350
|
+
- **PyPI package**: [apyds](https://pypi.org/project/apyds/)
|
|
351
|
+
|
|
352
|
+
## Author
|
|
353
|
+
|
|
354
|
+
Hao Zhang <hzhangxyz@outlook.com>
|
|
355
|
+
|
|
356
|
+
## Contributing
|
|
357
|
+
|
|
358
|
+
Contributions are welcome! Please feel free to submit issues or pull requests.
|
|
2
359
|
|