DreamLog is a logic programming system that learns by alternating between wake and sleep phases. During wake, it uses LLMs to generate missing knowledge. During sleep, it compresses what it knows into more general principles. Like biological brains, roughly.
Compression is learning
The theoretical basis comes from algorithmic information theory: the system that explains your data with the shortest program is the one most likely to generalize. This is Solomonoff induction, the mathematical formalization of Occam’s razor.
For logic programming, the sleep phase searches for minimal representations that preserve deductive closure:
Find the shortest knowledge base that still derives all the same facts.
Wake phase: generate knowledge
During wake, DreamLog operates as a logic programming engine with LLM-based knowledge generation:
from dreamlog.pythonic import dreamlog
kb = dreamlog(llm_provider="openai")
# Add some facts
kb.fact("parent", "john", "mary")
kb.fact("parent", "mary", "alice")
# Add a rule
kb.rule("grandparent", ["X", "Z"]) \
.when("parent", ["X", "Y"]) \
.and_("parent", ["Y", "Z"])
# Query
for result in kb.query("grandparent", "X", "alice"):
print(f"{result.bindings['X']} is Alice's grandparent") # john
The interesting part is what happens with undefined predicates:
# Query a predicate we never defined
for result in kb.query("sibling", "X", "Y"):
# LLM generates knowledge about siblings on-the-fly
print(result)
When the evaluator encounters an undefined predicate, it triggers the LLM hook to generate both facts and rules. The system infers primitive properties (like gender from names) and derives rules compositionally.
Sleep phase: compress knowledge
During sleep, DreamLog reorganizes through compression operators:
from dreamlog.kb_dreamer import KnowledgeBaseDreamer
dreamer = KnowledgeBaseDreamer(kb.provider)
session = dreamer.dream(
kb,
dream_cycles=3, # Multiple REM cycles
exploration_samples=10, # Try different optimizations
verify=True # Ensure behavior preservation
)
print(f"Compression: {session.compression_ratio:.1%}")
print(f"Generalization: {session.generalization_score:.2f}")
The compression operators:
- Anti-unification: find general patterns from specific instances
- Predicate invention: discover intermediate concepts that simplify rules
- Subsumption elimination: remove specific rules subsumed by general ones
This is where the real learning happens. The wake phase accumulates facts and rules. The sleep phase finds the structure in them.
KB-aware RAG
A key design choice: the retrieval-augmented generation is knowledge-base-aware. The system uses weighted embeddings combining query similarity (70%) with knowledge base context (30%), so example selection considers both the query structure and current reasoning state.
A success-based learning mechanism tracks which examples lead to successful inference, progressively improving retrieval quality through experience.
Validation
Generated rules and facts undergo:
- Structural validation: syntax, variable safety
- Semantic validation: preventing circular rules while allowing undefined predicates
- LLM-as-judge verification: fact-checking consistency with common-sense knowledge
Error-tolerant parsing handles common LLM formatting errors with correction-based retry.
Interactive TUI
python -m dreamlog.tui
Commands:
fact parent john maryto add factsrule grandparent X Z :- parent X Y, parent Y Zto add rulesquery grandparent X aliceto run queriesdream 3to run sleep cyclesshowto display the knowledge base
The idea
Intelligence emerges from the interplay of exploration and exploitation. Wake accumulates. Sleep consolidates. The cycle repeats:
- Consolidation: strengthen important patterns
- Abstraction: find general principles
- Compression: achieve more with less
- Creativity: explore novel reorganizations
This isn’t logic programming with LLMs bolted on. It’s a system where knowledge representation evolves through use.
Getting started
pip install dreamlog
from dreamlog.pythonic import dreamlog
kb = dreamlog(llm_provider="ollama")
kb.parse("""
(parent john mary)
(parent mary alice)
(grandparent X Z) :- (parent X Y), (parent Y Z)
""")
for result in kb.query("grandparent", "john", "X"):
print(result.bindings['X']) # alice
Links
- Repository: github.com/queelius/dreamlog
- Technical report: DreamLog paper
- Project page: /projects/dreamlog/
Discussion