siamese-py 2.0.0
A production-ready, asynchronous backward-chaining rule engine in Python.
Requires Python: >=3.8

# PyProlog Engine v2.0: Production-Ready Async Rule Engine

PyProlog is a high-performance, asynchronous backward-chaining rule engine in Python. It is designed for production environments where logic-based decisions may need to interact with external, non-blocking I/O resources like web APIs or databases.

## Key Features

-   **Fully Asynchronous**: Built on `asyncio` to handle I/O-bound tasks without blocking.
-   **Structured Logging**: Integrated with `loguru` for powerful and configurable tracing and debugging.
-   **External Configuration**: Load facts and rules from human-readable YAML files.
-   **Extensible Async Built-ins**: Easily write custom Python `async` functions to extend the engine's logic (e.g., for database access, API calls).
-   **Robust and Thread-Safe**: The query resolution process is stateless, allowing for safe concurrent querying from multiple async tasks.
-   **Control & Safety**: Prevents infinite loops with configurable search depth and limits the number of solutions.

## Installation

To install the library and its dependencies from the project root, run:
```bash
pip install .
```

## Quick Start

1.  **Define your knowledge in a YAML file (`knowledge.yaml`):**

    ```yaml
    facts:
      - [parent, david, john]
      - [parent, john, mary]

    rules:
      - head: [grandparent, '?GP', '?GC']
        body:
          - [parent, '?GP', '?P']
          - [parent, '?P', '?GC']
    ```

2.  **Write your async Python script:**

    ```python
    import asyncio
    from py_prolog import RuleEngine

    async def main():
        # Initialize the engine
        engine = RuleEngine()

        # Load knowledge from the file
        engine.load_from_file("knowledge.yaml")
        print("Knowledge base loaded.")

        # Asynchronously query the engine
        print("Query: Who is David's grandchild?")
        solutions = await engine.query("grandparent", "david", "?GC")
        
        async for sol in solutions:
            print(f"  - Solution: {sol}")

    if __name__ == "__main__":
        asyncio.run(main())
    ```

## Advanced Features

### Async Built-ins

The engine supports custom async built-in functions for external I/O operations:

```python
async def my_custom_builtin(goal, bindings):
    # Perform async operations like database queries or API calls
    result = await some_async_operation()
    if result:
        new_bindings = bindings.copy()
        new_bindings[goal.args[0]] = result
        yield new_bindings

# Register your custom built-in
engine = RuleEngine(builtins={"my_builtin": my_custom_builtin})
```

### Structured Logging

Configure detailed tracing of the engine's reasoning process:

```python
engine.configure_logging(level="TRACE")  # For detailed tracing
engine.configure_logging(level="INFO")   # For production use
```

### External Knowledge Bases

Load complex knowledge bases from YAML files:

```yaml
facts:
  - [person, alice]
  - [person, bob]
  - [parent, alice, bob]

rules:
  - head: [ancestor, '?A', '?D']
    body:
      - [parent, '?A', '?D']
  - head: [ancestor, '?A', '?D']
    body:
      - [parent, '?A', '?P']
      - [ancestor, '?P', '?D']
```

## API Reference

### RuleEngine

The main class for interacting with the rule engine.

#### Methods

- `__init__(builtins=None)`: Initialize the engine with optional custom built-ins
- `configure_logging(level="INFO", sink=sys.stderr)`: Configure logging output
- `load_from_file(filepath)`: Load knowledge base from YAML file
- `add_fact(name, *args)`: Add a fact to the knowledge base
- `add_rule(head_tuple, body_tuples)`: Add a rule to the knowledge base
- `query(name, *args, max_solutions=-1, max_depth=25)`: Query the knowledge base asynchronously
- `query_one(name, *args, **kwargs)`: Get the first solution or None
- `exists(name, *args, **kwargs)`: Check if at least one solution exists

### Core Types

- `Variable(name)`: Represents a Prolog variable (must start with '?')
- `Term(name, args)`: Represents a Prolog term
- `Rule(head, body)`: Represents a Prolog rule

## Examples

See the `examples/` directory for complete working examples:

- `knowledge.yaml`: Sample knowledge base
- `full_demo.py`: Comprehensive demonstration of all features

## License

MIT License - see LICENSE file for details.