Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ The system consists of the following modules, implemented symmetrically in `ddss
- **Load** (`ddss/load.py`, `ddss/load.ts`): Batch import of facts from standard input
- **Dump** (`ddss/dump.py`, `ddss/dump.ts`): Export all facts and ideas to output
- **Search** (`ddss/search.py`, `ddss/search.ts`): Forward-chaining deductive search engine
- **Chain** (`ddss/chain.py`, `ddss/chain.ts`): Alternative forward-chaining engine using Chain API
- **Egg** (`ddss/egg.py`, `ddss/egg.ts`): E-graph based equality reasoning engine

## Installation
Expand Down Expand Up @@ -106,6 +107,7 @@ Available components:
- `input`: Interactive input interface
- `output`: Real-time display of facts and ideas
- `search`: Forward-chaining deductive search engine
- `chain`: Alternative forward-chaining engine using Chain API
- `egg`: E-graph based equality reasoning engine
- `load`: Batch import facts from standard input
- `dump`: Export all facts and ideas to output
Expand Down
34 changes: 34 additions & 0 deletions ddss/chain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import asyncio
from sqlalchemy import select
from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession
from apyds import Chain
from .orm import insert_or_ignore, Facts, Ideas
from .utility import str_rule_get_str_idea


async def main(session: async_sessionmaker[AsyncSession]) -> None:
try:
chain = Chain()
max_fact = -1

while True:
async with session() as sess:
for i in await sess.scalars(select(Facts).where(Facts.id > max_fact)):
max_fact = max(max_fact, i.id)
chain.add(i.data)
tasks = []

def handler(rule):
ds = str(rule)
tasks.append(asyncio.create_task(insert_or_ignore(sess, Facts, ds)))
if idea := str_rule_get_str_idea(ds):
tasks.append(asyncio.create_task(insert_or_ignore(sess, Ideas, idea)))
return False
Comment on lines +22 to +26

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ddss.chain.main creates Ideas rows when str_rule_get_str_idea(ds) returns a value, but the newly added Chain tests never assert that ideas are created. Add a test that triggers idea generation and verifies an Ideas record is inserted, mirroring the coverage that exists for the Search engine.

Copilot uses AI. Check for mistakes.

chain.execute(handler)
await asyncio.gather(*tasks)
await sess.commit()

await asyncio.sleep(0)
except asyncio.CancelledError:
pass
38 changes: 38 additions & 0 deletions ddss/chain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Op, type Sequelize } from "sequelize";
import { Chain } from "atsds";
import type { Rule } from "atsds";
import { Fact, Idea, insertOrIgnore } from "./orm.ts";
import { strRuleGetStrIdea } from "./utility.ts";

export async function main(sequelize: Sequelize): Promise<void> {
const chain = new Chain();
let maxFact = -1;

while (true) {
const newFacts = await Fact.findAll({
where: { id: { [Op.gt]: maxFact } },
});

for (const fact of newFacts) {
maxFact = Math.max(maxFact, fact.id);
chain.add(fact.data);
}

const tasks: Promise<void>[] = [];

const handler = (rule: Rule) => {
const ds = rule.toString();
tasks.push(insertOrIgnore(Fact, ds));
const idea = strRuleGetStrIdea(ds);
if (idea) {
tasks.push(insertOrIgnore(Idea, idea));
}
Comment on lines +24 to +29

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new code inserts derived ideas via strRuleGetStrIdea(ds) and insertOrIgnore(Idea, ...), but the added Chain tests only assert inferred facts. Add at least one test case that exercises and verifies idea creation (similar to the existing Search test that expects an Ideas row) so this behavior is protected for the Chain engine too.

Copilot uses AI. Check for mistakes.
return false;
};

chain.execute(handler);
await Promise.all(tasks);

await new Promise((resolve) => setTimeout(resolve, 0));
}
}
2 changes: 2 additions & 0 deletions ddss/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from .output import main as output
from .load import main as load
from .dump import main as dump
from .chain import main as chain

component_map: dict[str, callable[[async_sessionmaker[AsyncSession]], Awaitable[None]]] = {
"search": search,
Expand All @@ -19,6 +20,7 @@
"output": output,
"load": load,
"dump": dump,
"chain": chain,
}


Expand Down
2 changes: 2 additions & 0 deletions ddss/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { main as egg } from "./egg.ts";
import { main as input } from "./input.ts";
import { main as load } from "./load.ts";
import { main as output } from "./output.ts";
import { main as chain } from "./chain.ts";
import { initializeDatabase } from "./orm.ts";

type ComponentMain = (sequelize: Sequelize) => Promise<void>;
Expand All @@ -20,6 +21,7 @@ const componentMap: Record<string, ComponentMain> = {
output,
load,
dump,
chain,
};

async function run(addr: string, components: string[]): Promise<void> {
Expand Down
1 change: 1 addition & 0 deletions docs/en/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ The system consists of the following modules, implemented symmetrically in `ddss
- **Load** (`ddss/load.py`, `ddss/load.ts`): Batch import of facts from standard input
- **Dump** (`ddss/dump.py`, `ddss/dump.ts`): Export all facts and ideas to output
- **Search** (`ddss/search.py`, `ddss/search.ts`): Forward-chaining deductive search engine
- **Chain** (`ddss/chain.py`, `ddss/chain.ts`): Alternative forward-chaining engine using Chain API
- **Egg** (`ddss/egg.py`, `ddss/egg.ts`): E-graph based equality reasoning engine
1 change: 1 addition & 0 deletions docs/en/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Available components:
- `input`: Interactive input interface
- `output`: Real-time display of facts and ideas
- `search`: Forward-chaining deductive search engine
- `chain`: Alternative forward-chaining engine using Chain API
- `egg`: E-graph based equality reasoning engine
- `load`: Batch import facts from standard input
- `dump`: Export all facts and ideas to output
Expand Down
1 change: 1 addition & 0 deletions docs/zh/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
- **Load** (`ddss/load.py`, `ddss/load.ts`):从标准输入批量导入事实。
- **Dump** (`ddss/dump.py`, `ddss/dump.ts`):将所有事实和想法导出到输出。
- **Search** (`ddss/search.py`, `ddss/search.ts`):前向链接演绎搜索引擎。
- **Chain** (`ddss/chain.py`, `ddss/chain.ts`):使用 Chain API 的替代前向链接引擎。
- **Egg** (`ddss/egg.py`, `ddss/egg.ts`):基于 E-graph 的等式推理引擎。
1 change: 1 addition & 0 deletions docs/zh/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ ddss --component input output egg
- `input`: 交互式输入接口
- `output`: 实时显示事实和想法
- `search`: 前向链接演绎搜索引擎
- `chain`: 使用 Chain API 的替代前向链接引擎
- `egg`: 基于 E-graph 的等式推理引擎
- `load`: 批量导入事实
- `dump`: 导出所有事实和想法
Expand Down
24 changes: 12 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
"docs": "vitepress build"
},
"dependencies": {
"atsds": "^0.0.17",
"atsds-bnf": "^0.0.17",
"atsds-egg": "^0.0.17",
"atsds": "^0.0.18",
"atsds-bnf": "^0.0.18",
"atsds-egg": "^0.0.18",
"commander": "^14.0.3",
"mariadb": "^3.5.2",
"mysql2": "^3.19.1",
Expand Down
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ readme = "README.md"
authors = [{ email = "hzhangxyz@outlook.com", name = "Hao Zhang" }]
requires-python = ">=3.11"
dependencies = [
"apyds~=0.0.14",
"apyds-bnf~=0.0.14",
"apyds-egg~=0.0.14",
"apyds~=0.0.18",
"apyds-bnf~=0.0.18",
"apyds-egg~=0.0.18",
"prompt-toolkit~=3.0.52",
"sqlalchemy[aiosqlite,aiomysql,postgresql-asyncpg]~=2.0.45",
"tyro~=1.0.3",
Expand Down
Loading
Loading