Skip to content

Commit 2fd1669

Browse files
Copilothzhangxyz
andauthored
Enhance documentation with detailed examples and explanations (#39)
* Initial plan * Enhance documentation with detailed examples and explanations Co-authored-by: hzhangxyz <[email protected]> * Address code review feedback for documentation Co-authored-by: hzhangxyz <[email protected]> * Remove a unproper paragraph. * Fix an example. * Remove unproper paragraphs. * Reorder python and ts. * Remove unproper paragraphs. * Add supported language paragraph. * Fix exmaples. * Remove unproper paragraph. * Fix. * Fix. * Fix. * Remove useless paragraph. * Remove useless paragraph. * Fix wording. * Fix. * Remove useless code. * Remove unproper paragraph. * Remove useless paragraph. * Update package.json. * Remove useless paragraph. --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: hzhangxyz <[email protected]> Co-authored-by: Hao Zhang <[email protected]>
1 parent c9385b9 commit 2fd1669

File tree

11 files changed

+364
-70
lines changed

11 files changed

+364
-70
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,9 +336,16 @@ Pre-commit hooks are configured in `.pre-commit-config.yaml`.
336336

337337
This project is licensed under the GNU General Public License v3.0 or later. See [LICENSE.md](LICENSE.md) for details.
338338

339+
## Documentation
340+
341+
For comprehensive documentation including tutorials, API reference, and examples, visit:
342+
343+
- **[DS Documentation](https://ustc-knowledgecomputinglab.github.io/ds)**
344+
339345
## Repository
340346

341347
- **GitHub**: [USTC-KnowledgeComputingLab/ds](https://github.com/USTC-KnowledgeComputingLab/ds)
348+
- **Documentation**: [ustc-knowledgecomputinglab.github.io/ds](https://ustc-knowledgecomputinglab.github.io/ds)
342349
- **npm package**: [atsds](https://www.npmjs.com/package/atsds)
343350
- **PyPI package**: [apyds](https://pypi.org/project/apyds/)
344351

docs/api/cpp.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,3 +550,73 @@ std::unique_ptr<char> rule_to_text(rule_t* rule, length_t length);
550550
- `length`: Maximum size for the resulting text
551551

552552
**Returns:** A unique_ptr to the text, or nullptr if length exceeded.
553+
554+
---
555+
556+
## Complete Example
557+
558+
Here's a complete example demonstrating the C++ API:
559+
560+
```cpp
561+
#include <ds/ds.hh>
562+
#include <ds/search.hh>
563+
#include <ds/utility.hh>
564+
#include <cstring>
565+
#include <iostream>
566+
567+
int main() {
568+
const int buffer_size = 1000;
569+
570+
// Create terms using utility functions
571+
auto term = ds::text_to_term("(f `x `y)", buffer_size);
572+
573+
std::cout << "Term: " << ds::term_to_text(term.get(), buffer_size).get() << std::endl;
574+
575+
// Work with rules
576+
auto fact = ds::text_to_rule("(parent john mary)", buffer_size);
577+
auto rule = ds::text_to_rule("(father `X `Y)\n----------\n(parent `X `Y)\n", buffer_size);
578+
579+
std::cout << "\nFact:\n" << ds::rule_to_text(fact.get(), buffer_size).get();
580+
std::cout << "Rule premises: " << rule->premises_count() << std::endl;
581+
std::cout << "Rule conclusion: " << ds::term_to_text(rule->conclusion(), buffer_size).get() << std::endl;
582+
583+
// Search engine
584+
ds::search_t search(1000, 10000);
585+
586+
// Add rules and facts
587+
search.add("p q"); // p implies q
588+
search.add("q r"); // q implies r
589+
search.add("p"); // fact: p
590+
591+
std::cout << "\nRunning inference:" << std::endl;
592+
593+
// Execute search
594+
auto target = ds::text_to_rule("r", buffer_size);
595+
bool found = false;
596+
597+
while (!found) {
598+
auto count = search.execute([&](ds::rule_t* candidate) {
599+
std::cout << " Derived: " << ds::rule_to_text(candidate, buffer_size).get();
600+
601+
// Check if this is our target
602+
if (candidate->data_size() == target->data_size() &&
603+
memcmp(candidate->head(), target->head(), candidate->data_size()) == 0) {
604+
found = true;
605+
return true; // Stop
606+
}
607+
return false; // Continue
608+
});
609+
610+
if (count == 0) {
611+
std::cout << " (no more inferences)" << std::endl;
612+
break;
613+
}
614+
}
615+
616+
if (found) {
617+
std::cout << "Target found!" << std::endl;
618+
}
619+
620+
return 0;
621+
}
622+
```

docs/api/python.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,3 +452,63 @@ def callback(candidate):
452452

453453
search.execute(callback)
454454
```
455+
456+
---
457+
458+
## Complete Example
459+
460+
Here's a complete example demonstrating most of the API:
461+
462+
```python
463+
import apyds
464+
465+
# Configure buffer size for operations
466+
apyds.buffer_size(2048)
467+
468+
# Create terms
469+
var = apyds.Variable("`X")
470+
item = apyds.Item("hello")
471+
lst = apyds.List("(a b c)")
472+
term = apyds.Term("(f `x `y)")
473+
474+
print(f"Variable: {var}, name: {var.name}")
475+
print(f"Item: {item}, name: {item.name}")
476+
print(f"List: {lst}, length: {len(lst)}")
477+
print(f"Term: {term}, type: {type(term.term)}")
478+
479+
# Work with rules
480+
fact = apyds.Rule("(parent john mary)")
481+
rule = apyds.Rule("(father `X `Y)\n----------\n(parent `X `Y)\n")
482+
483+
print(f"\nFact: {fact}")
484+
print(f"Rule premises: {len(rule)}, conclusion: {rule.conclusion}")
485+
486+
# Grounding
487+
term_a = apyds.Term("`a")
488+
dictionary = apyds.Term("((`a hello))")
489+
grounded = term_a // dictionary
490+
print(f"\nGrounding `a with ((` hello)): {grounded}")
491+
492+
# Matching
493+
mp = apyds.Rule("(`p -> `q)\n`p\n`q\n")
494+
axiom = apyds.Rule("((A) -> B)")
495+
matched = mp @ axiom
496+
print(f"\nMatching modus ponens with (A -> B):\n{matched}")
497+
498+
# Search engine
499+
search = apyds.Search(1000, 10000)
500+
search.add("p q") # p implies q
501+
search.add("q r") # q implies r
502+
search.add("p") # fact: p
503+
504+
print("\nRunning inference:")
505+
for i in range(3):
506+
count = search.execute(lambda r: print(f" Derived: {r}") or False)
507+
if count == 0:
508+
break
509+
510+
# Using context manager for buffer size
511+
with apyds.scoped_buffer_size(4096):
512+
big_term = apyds.Term("(a b c d e f g h i j)")
513+
print(f"\nBig term: {big_term}")
514+
```

docs/api/typescript.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,3 +447,79 @@ search.execute((candidate) => {
447447
return false; // Continue searching
448448
});
449449
```
450+
451+
---
452+
453+
## Complete Example
454+
455+
Here's a complete example demonstrating most of the TypeScript API:
456+
457+
```typescript
458+
import {
459+
buffer_size,
460+
string_t,
461+
variable_t,
462+
item_t,
463+
list_t,
464+
term_t,
465+
rule_t,
466+
search_t
467+
} from "atsds";
468+
469+
// Configure buffer size
470+
buffer_size(2048);
471+
472+
// Create terms
473+
const varX = new variable_t("`X");
474+
const item = new item_t("hello");
475+
const lst = new list_t("(a b c)");
476+
const term = new term_t("(f `x `y)");
477+
478+
console.log(`Variable: ${varX.toString()}, name: ${varX.name().toString()}`);
479+
console.log(`Item: ${item.toString()}, name: ${item.name().toString()}`);
480+
console.log(`List: ${lst.toString()}, length: ${lst.length()}`);
481+
console.log(`Term: ${term.toString()}`);
482+
483+
// Work with rules
484+
const fact = new rule_t("(parent john mary)");
485+
const rule = new rule_t("(father `X `Y)\n----------\n(parent `X `Y)\n");
486+
487+
console.log(`\nFact: ${fact.toString()}`);
488+
console.log(`Rule premises: ${rule.length()}, conclusion: ${rule.conclusion().toString()}`);
489+
490+
// Grounding
491+
const termA = new term_t("`a");
492+
const dictionary = new term_t("((`a hello))");
493+
const grounded = termA.ground(dictionary);
494+
if (grounded) {
495+
console.log(`\nGrounding \`a with ((\`a hello)): ${grounded.toString()}`);
496+
}
497+
498+
// Matching
499+
const mp = new rule_t("(`p -> `q)\n`p\n`q\n");
500+
const axiom = new rule_t("((A) -> B)");
501+
const matched = mp.match(axiom);
502+
if (matched) {
503+
console.log(`\nMatching modus ponens with (A -> B):\n${matched.toString()}`);
504+
}
505+
506+
// Search engine
507+
const search = new search_t(1000, 10000);
508+
search.add("p q"); // p implies q
509+
search.add("q r"); // q implies r
510+
search.add("p"); // fact: p
511+
512+
console.log("\nRunning inference:");
513+
for (let i = 0; i < 3; i++) {
514+
const count = search.execute((r) => {
515+
console.log(` Derived: ${r.toString()}`);
516+
return false;
517+
});
518+
if (count === 0) break;
519+
}
520+
521+
// Copying and comparison
522+
const rule1 = new rule_t("(a b c)");
523+
const rule2 = rule1.copy();
524+
console.log(`\nRule comparison: ${rule1.key() === rule2.key()}`); // true
525+
```

docs/concepts/rules.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ A rule consists of:
1111

1212
### Text Representation
1313

14-
Rules are written with premises and conclusion separated by dashes:
14+
Rules are written with premises and conclusion separated by dashes (at least four dashes):
1515

1616
```
1717
premise1
@@ -33,6 +33,31 @@ Or explicitly:
3333
(parent john mary)
3434
```
3535

36+
!!! info "Rule Format Details"
37+
- Premises are separated by newlines
38+
- The separator line must contain at least 4 dashes (`----`) between premises and conclusion
39+
- Whitespace around premises and conclusion is trimmed
40+
- A rule without an premises is a fact
41+
42+
### Compact Rule Format
43+
44+
For rules with multiple premises, you can use space-separated terms on a single line:
45+
46+
```
47+
(`P -> `Q) `P `Q
48+
```
49+
50+
This is equivalent to:
51+
52+
```
53+
(`P -> `Q)
54+
`P
55+
----------
56+
`Q
57+
```
58+
59+
The last term is the conclusion, and all preceding terms are premises.
60+
3661
### Examples
3762

3863
**Modus Ponens** (if P implies Q and P is true, then Q is true):

docs/concepts/search.md

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ The search engine:
99
1. Maintains a collection of rules and facts
1010
2. Iteratively applies rules to generate new facts
1111
3. Notifies you of each new inference via a callback
12+
4. Automatically prevents duplicate inferences
13+
14+
!!! info "How It Works"
15+
The search engine uses a forward-chaining inference approach:
16+
17+
1. When you call `execute()`, the engine tries to match the first premise of each rule with existing facts
18+
2. When a match is found, variables in the rule are substituted and a new rule (with one fewer premise) is created
19+
3. If the new rule has no premises, it becomes a new fact
20+
4. The callback is invoked for each newly derived rule
21+
5. Duplicate rules are automatically filtered out
1222

1323
## Creating a Search Engine
1424

@@ -21,7 +31,7 @@ The search engine:
2131
search = apyds.Search()
2232

2333
# Create with custom sizes
24-
search = apyds.Search(limit_size=2000, buffer_size=20000)
34+
search = apyds.Search(limit_size=1000, buffer_size=10000)
2535
```
2636

2737
=== "TypeScript"
@@ -33,7 +43,7 @@ The search engine:
3343
const search = new search_t();
3444

3545
// Create with custom sizes
36-
const search2 = new search_t(2000, 20000);
46+
const search2 = new search_t(1000, 10000);
3747
```
3848

3949
=== "C++"
@@ -47,8 +57,8 @@ The search engine:
4757

4858
### Parameters
4959

50-
- **limit_size**: Maximum size (in bytes) for each stored rule/fact (default: 1000)
51-
- **buffer_size**: Size of the internal buffer for intermediate operations (default: 10000)
60+
- **limit_size**: Maximum size (in bytes) for each stored rule/fact (default: 1000). Rules or facts larger than this are rejected.
61+
- **buffer_size**: Size of the internal buffer for intermediate operations (default: 10000). Increase this if you work with complex rules.
5262

5363
## Adding Rules and Facts
5464

@@ -66,11 +76,6 @@ Use the `add()` method to add rules and facts to the knowledge base.
6676

6777
# Add a rule with premises
6878
search.add("(father `X `Y)\n----------\n(parent `X `Y)\n")
69-
70-
# Add multiple facts and rules
71-
search.add("(father john mary)")
72-
search.add("(father john bob)")
73-
search.add("(mother mary alice)")
7479
```
7580

7681
=== "TypeScript"
@@ -298,6 +303,7 @@ Clears all rules and facts:
298303
2. **Limit Size**: Restricts maximum rule/fact complexity - too small may reject valid rules
299304
3. **Iterative Execution**: Call `execute()` in a loop to continue inference until convergence
300305
4. **Early Termination**: Return `true` from callback to stop as soon as target is found
306+
5. **Deduplication**: The engine automatically deduplicates facts, avoiding redundant computation
301307

302308
## See Also
303309

0 commit comments

Comments
 (0)