### Negation: Find Nodes NOT Reachable from Node 1 Source: https://context7.com/pcarbonn/pydatalog/llms.txt Demonstrates using negation-as-failure (~ operator) to find nodes that are not reachable from a specific starting node in a graph. Requires edge facts and a reachable rule. ```python from pyDatalog import pyDatalog @pyDatalog.program() def _(): + edge(1, 2); + edge(2, 3); + edge(3, 4); + edge(5, 6) # Reachability reachable(X, Y) <= edge(X, Y) reachable(X, Y) <= reachable(X, Z) & edge(Z, Y) pyDatalog.create_terms('X, Y, P') # Nodes NOT reachable from 1 print(edge(X, Y) & ~reachable(1, X) & (X != 1)) # [(5, 6)] ``` -------------------------------- ### SQLAlchemy Integration with pyDatalog.sqlMetaMixin Source: https://context7.com/pcarbonn/pydatalog/llms.txt Combines `pyDatalog.Mixin` with SQLAlchemy's `DeclarativeMeta` for Datalog rules to query relational database rows transparently via the SQLAlchemy ORM. Requires SQLAlchemy to be installed. ```python from pyDatalog import pyDatalog from sqlalchemy import create_engine, Column, Integer, String, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base(cls=pyDatalog.Mixin, metaclass=pyDatalog.sqlMetaMixin) engine = create_engine('sqlite:///:memory:', echo=False) Session = sessionmaker(bind=engine) session = Session() Base.session = session class Employee(Base): __tablename__ = 'employee' name = Column(String, primary_key=True) manager_name = Column(String, ForeignKey('employee.name')) salary = Column(Integer) def __init__(self, name, manager_name, salary): super().__init__() self.name = name self.manager_name = manager_name self.salary = salary def __repr__(self): return "Employee: %s" % self.name @pyDatalog.program() def Employee(self): (Employee.manager[X] == Y) <= (Employee.manager_name[X] == Z) & (Z == Employee.name[Y]) Employee.salary_class[X] = Employee.salary[X] // 1000 Employee.indirect_manager(X, Y) <= (Employee.manager[X] == Y) & (Y != None) Employee.indirect_manager(X, Y) <= (Employee.manager[X] == Z) & Employee.indirect_manager(Z, Y) & (Y != None) (Employee.report_count[X] == len_(Y)) <= Employee.indirect_manager(Y, X) Base.metadata.create_all(engine) John = Employee('John', None, 6800); session.add(John) Mary = Employee('Mary', 'John', 6300); session.add(Mary) Sam = Employee('Sam', 'Mary', 5900); session.add(Sam) session.commit() pyDatalog.create_terms('X, N') print(John.salary_class) # 6 Employee.indirect_manager(Mary, X) print(X) # [Employee: John] result = (Employee.salary[X] < 6000) & Employee.indirect_manager(X, John) print(result) # [(Employee: Sam,)] ``` -------------------------------- ### Graph Algorithms: Shortest Path with min_ Source: https://context7.com/pcarbonn/pydatalog/llms.txt Implements a shortest path algorithm for a graph using recursive rules and the min_ aggregate function. Requires link facts and path_cost rules. ```python from pyDatalog import pyDatalog @pyDatalog.program() def _(): + link(1, 2); + link(2, 3); + link(2, 4) + link(4, 5); + link(5, 6) link(X, Y) <= link(Y, X) # bidirectional # All paths with accumulated cost path_cost(X, Y, P, C) <= link(X, Y) & (P == []) & (C == 0) path_cost(X, Y, P, C) <= ( path_cost(X, Z, P2, C2) & link(Z, Y) & (X != Y) & (X._not_in(P2)) & (Y._not_in(P2)) & (P == P2 + [Z]) & (C == C2 + 1) ) # Shortest path = minimum cost path (shortest_path[X, Y] == min_(P, order_by=C)) <= path_cost(X, Y, P, C) pyDatalog.create_terms('X, Y, P, C') print(shortest_path[1, 6] == P) # shortest path from node 1 to node 6 ``` -------------------------------- ### Aggregate: Calculate Employee Budget Source: https://context7.com/pcarbonn/pydatalog/llms.txt Calculates the total budget for an employee by summing the salaries of their indirect reports. Requires Employee.indirect_manager and Employee.salary facts. ```python from pyDatalog import pyDatalog # Facts: (employee, indirect_manager) + Employee.indirect_manager('Mary', 'John') + Employee.indirect_manager('Peter', 'John') + Employee.indirect_manager('John', 'CEO') # Facts: (employee, salary) + Employee.salary['Mary'] == 1200 + Employee.salary['Peter'] == 1000 + Employee.salary['John'] == 10000 + Employee.salary['CEO'] == 12000 # Rule: Calculate budget based on indirect managers' salaries (Employee.budget[X] == sum_(N, for_each=Y)) <= Employee.indirect_manager(Y, X) & (Employee.salary[Y] == N) # Query: Get John's budget Employee.budget[John] == X print(X) # [12200] (or 12300 after updating Mary's salary) ``` -------------------------------- ### Query Knowledge Base via String with pyDatalog.ask() Source: https://context7.com/pcarbonn/pydatalog/llms.txt Query the Datalog knowledge base using a string with `pyDatalog.ask()`. This method is required for querying unprefixed predicates that cannot be expressed as inline Python expressions. It returns an `Answer` object. ```python from pyDatalog import pyDatalog pyDatalog.create_terms('salary, lowest, X, N') + (salary['John'] == 6800) + (salary['Mary'] == 6300) + (salary['Sam'] == 5900) ``` -------------------------------- ### Load Datalog Clauses from a String with pyDatalog.load() Source: https://context7.com/pcarbonn/pydatalog/llms.txt Load Datalog rules and facts dynamically from a Python string using `pyDatalog.load()`. This is useful for constructing rules at runtime or loading them from external sources. Variables from the calling scope are accessible. ```python from pyDatalog import pyDatalog pyDatalog.create_terms('salary, indirect_manager, budget, X, Y, N') + (salary['John'] == 6800) + (salary['Mary'] == 6300) + (salary['Sam'] == 5900) + (indirect_manager('Mary', 'John') == True) + (indirect_manager('Sam', 'Mary') == True) + (indirect_manager('Sam', 'John') == True) # Load an aggregate rule from a string pyDatalog.load(""" (budget[X] == sum_(N, for_each=Y)) <= indirect_manager(Y, X) & (salary[Y] == N) """) print(budget['John'] == N) # total salary of John's reports: [(12200,)] ``` -------------------------------- ### Aggregate: Find Minimum Salary Overall Source: https://context7.com/pcarbonn/pydatalog/llms.txt Finds the minimum salary across all employees using the min_ aggregate function. Requires salary facts. ```python from pyDatalog import pyDatalog pyDatalog.create_terms( 'salary, department, emp_count, total_salary, min_salary, max_salary, ' 'sorted_names, ranked, X, Y, N, D, R' ) # Facts: (name, department, salary) + (salary['Alice'] == 9000); + (department['Alice'] == 'Eng') + (salary['Bob'] == 7500); + (department['Bob'] == 'Eng') + (salary['Carol'] == 8200); + (department['Carol'] == 'HR') + (salary['Dan'] == 6800); + (department['Dan'] == 'HR') pyDatalog.create_terms('global_min') (global_min[1] == min_(X, order_by=N)) <= (salary[X] == N) print(global_min[1] == X) # [('Dan',)] ``` -------------------------------- ### Object-Oriented Datalog with pyDatalog.Mixin Source: https://context7.com/pcarbonn/pydatalog/llms.txt Enables Datalog capabilities for Python objects by subclassing `pyDatalog.Mixin`. Attributes can be queried, and rules defined as class-level clauses using `@pyDatalog.program()`. ```python from pyDatalog import pyDatalog class Employee(pyDatalog.Mixin): def __init__(self, name, manager, salary): super().__init__() self.name = name self.manager = manager # another Employee or None self.salary = salary def __repr__(self): return self.name @pyDatalog.program() def Employee(self): # Derived attribute: salary class Employee.salary_class[X] = Employee.salary[X] // 1000 # Recursive rule: all indirect managers Employee.indirect_manager(X, Y) <= (Employee.manager[X] == Y) & (Y != None) Employee.indirect_manager(X, Y) <= (Employee.manager[X] == Z) & Employee.indirect_manager(Z, Y) & (Y != None) # Aggregate: count reports (Employee.report_count[X] == len_(Y)) <= Employee.indirect_manager(Y, X) John = Employee('John', None, 6800) Mary = Employee('Mary', John, 6300) Sam = Employee('Sam', Mary, 5900) pyDatalog.create_terms('X') print(John.salary_class) # 6 print(Employee.salary[X] == 6300) # [(Mary,)] print(X.v()) # Mary Employee.indirect_manager(Mary, X) print(X) # [John] print(Employee.report_count[John] == X)# [(2,)] # Compound query: employees of John with salary below 6000 result = (Employee.salary[X] < 6000) & Employee.indirect_manager(X, John) print(result) # [(Sam,)] ``` -------------------------------- ### Aggregate: Calculate Total Salary Per Department Source: https://context7.com/pcarbonn/pydatalog/llms.txt Calculates the total salary for each department using the sum_ aggregate function. Requires salary and department facts. ```python from pyDatalog import pyDatalog pyDatalog.create_terms( 'salary, department, emp_count, total_salary, min_salary, max_salary, ' 'sorted_names, ranked, X, Y, N, D, R' ) # Facts: (name, department, salary) + (salary['Alice'] == 9000); + (department['Alice'] == 'Eng') + (salary['Bob'] == 7500); + (department['Bob'] == 'Eng') + (salary['Carol'] == 8200); + (department['Carol'] == 'HR') + (salary['Dan'] == 6800); + (department['Dan'] == 'HR') # Total salary per department (total_salary[D] == sum_(N, for_each=X)) <= (department[X] == D) & (salary[X] == N) print(total_salary[D] == N) # [('Eng', 16500), ('HR', 15000)] ``` -------------------------------- ### pyDatalog.load Source: https://context7.com/pcarbonn/pydatalog/llms.txt Parses and loads Datalog rules and facts given as a Python string. This is useful for dynamic rule construction or loading rules from external sources. Referenced variables from the calling scope are accessible. ```APIDOC ## `pyDatalog.load(code)` — Load Datalog Clauses from a String Parses and loads Datalog rules and facts given as a Python string. Useful for dynamic rule construction or loading rules from external sources. Referenced variables from the calling scope are accessible. ### Example ```python from pyDatalog import pyDatalog pyDatalog.create_terms('salary, indirect_manager, budget, X, Y, N') + (salary['John'] == 6800) + (salary['Mary'] == 6300) + (salary['Sam'] == 5900) + (indirect_manager('Mary', 'John') == True) + (indirect_manager('Sam', 'Mary') == True) + (indirect_manager('Sam', 'John') == True) # Load an aggregate rule from a string pyDatalog.load(""" (budget[X] == sum_(N, for_each=Y)) <= indirect_manager(Y, X) & (salary[Y] == N) """) print(budget['John'] == N) # total salary of John's reports: [(12200,)] ``` ``` -------------------------------- ### Programmatic Fact Management with assert_fact and retract_fact Source: https://context7.com/pcarbonn/pydatalog/llms.txt Manage facts in the Datalog knowledge base programmatically using `assert_fact` and `retract_fact`. This is useful when predicate names or arguments are determined dynamically at runtime. ```python from pyDatalog import pyDatalog # Assert facts programmatically pyDatalog.assert_fact('salary', 'John', 6800) pyDatalog.assert_fact('salary', 'Mary', 6300) pyDatalog.assert_fact('salary', 'Sam', 5900) pyDatalog.create_terms('salary, X, Y') # Query print(salary[X] == 6300) # [('Mary',)] # Retract a fact pyDatalog.retract_fact('salary', 'Mary', 6300) print(salary[X] == 6300) # [] ``` -------------------------------- ### pyDatalog.ask Source: https://context7.com/pcarbonn/pydatalog/llms.txt Evaluates a Datalog query given as a string and returns an `Answer` object. This is required when querying unprefixed predicates that cannot be expressed as inline Python expressions. ```APIDOC ## `pyDatalog.ask(code)` — Query the Knowledge Base via String Evaluates a Datalog query given as a string and returns an `Answer` object. Required when querying unprefixed predicates that cannot be expressed as inline Python expressions. ### Example ```python from pyDatalog import pyDatalog pyDatalog.create_terms('salary, lowest, X, N') + (salary['John'] == 6800) + (salary['Mary'] == 6300) + (salary['Sam'] == 5900) ``` ``` -------------------------------- ### Define Datalog Program Blocks with @pyDatalog.program() Source: https://context7.com/pcarbonn/pydatalog/llms.txt Use the `@pyDatalog.program()` decorator to define a function body as a block of Datalog clauses. Undefined capitalized names within the function are automatically treated as Datalog variables, simplifying syntax. ```python from pyDatalog import pyDatalog @pyDatalog.program() def _(): # Facts + link(1, 2) + link(2, 3) + link(2, 4) + link(5, 6) # Make links bi-directional link(X, Y) <= link(Y, X) # Recursive reachability can_reach(X, Y) <= link(X, Y) can_reach(X, Y) <= can_reach(X, Z) & link(Z, Y) & (X != Y) pyDatalog.create_terms('X, Y') print(can_reach(1, Y)) # all nodes reachable from node 1 ``` -------------------------------- ### Create Anonymous Variables with pyDatalog Source: https://context7.com/pcarbonn/pydatalog/llms.txt Generates a list of anonymous Datalog variables, useful for programmatic query construction. Anonymous variables avoid the need to name each variable individually. ```python from pyDatalog import pyDatalog pyDatalog.create_terms('score, player') + (score['Alice'] == 95) + (score['Bob'] == 87) X, Y = pyDatalog.variables(2) # Use anonymous variables in a query result = score[X] == Y print(result) # [('Alice', 95), ('Bob', 87)] ``` -------------------------------- ### Declare Variables and Predicates with create_terms Source: https://context7.com/pcarbonn/pydatalog/llms.txt Use `create_terms` to define Datalog variables and predicate symbols in the caller's scope. This must be done before using inline Datalog expressions. Results from queries are lazy lists. ```python from pyDatalog import pyDatalog pyDatalog.create_terms('parent, ancestor, manager, salary_class, X, Y, Z, N') # Assert facts using the + operator + parent('John', 'Adams') + parent('Mary', 'John') # Define recursive rules with <= ancestor(X, Y) <= parent(X, Y) ancestor(X, Y) <= parent(X, Z) & ancestor(Z, Y) # Query inline — results are lazy lists of tuples print(ancestor('Mary', X)) # [('John',), ('Adams',)] # Get the first value with .v() ancestor('Mary', X) print(X.v()) # 'John' # One-liner: query and get first result with >= ``` ```python print(ancestor('Mary', X) >= X) # 'John' ``` -------------------------------- ### Aggregate: Count Employees Per Department Source: https://context7.com/pcarbonn/pydatalog/llms.txt Counts the number of employees in each department using the len_ aggregate function. Requires salary and department facts. ```python from pyDatalog import pyDatalog pyDatalog.create_terms( 'salary, department, emp_count, total_salary, min_salary, max_salary, ' 'sorted_names, ranked, X, Y, N, D, R' ) # Facts: (name, department, salary) + (salary['Alice'] == 9000); + (department['Alice'] == 'Eng') + (salary['Bob'] == 7500); + (department['Bob'] == 'Eng') + (salary['Carol'] == 8200); + (department['Carol'] == 'HR') + (salary['Dan'] == 6800); + (department['Dan'] == 'HR') # Count employees per department (emp_count[D] == len_(X)) <= (department[X] == D) print(emp_count[D] == N) # [('Eng', 2), ('HR', 2)] ``` -------------------------------- ### pyDatalog.create_terms Source: https://context7.com/pcarbonn/pydatalog/llms.txt Declares Datalog variables (capitalized names) and predicate symbols (lowercase names) in the caller's local scope. This must be called before any inline Datalog expressions. ```APIDOC ## `pyDatalog.create_terms(*names)` — Declare Variables and Predicates Creates Datalog variables (capitalized names) and predicate symbols (lowercase names) in the caller's local scope. Must be called before any inline Datalog expressions. Also available as `create_atoms()` for backward compatibility. ### Example ```python from pyDatalog import pyDatalog pyDatalog.create_terms('parent, ancestor, manager, salary_class, X, Y, Z, N') # Assert facts using the + operator + parent('John', 'Adams') + parent('Mary', 'John') # Define recursive rules with <= ancestor(X, Y) <= parent(X, Y) ancestor(X, Y) <= parent(X, Z) & ancestor(Z, Y) # Query inline — results are lazy lists of tuples print(ancestor('Mary', X)) # [('John',), ('Adams',)] # Get the first value with .v() ancestor('Mary', X) print(X.v()) # 'John' # One-liner: query and get first result with >= print(ancestor('Mary', X) >= X) # 'John' ``` ``` -------------------------------- ### @pyDatalog.program() Source: https://context7.com/pcarbonn/pydatalog/llms.txt A decorator that marks a function body as a block of Datalog clauses. Undefined capitalized names inside the function are automatically treated as Datalog variables, eliminating the need for `create_terms()` within the block. ```APIDOC ## `@pyDatalog.program()` — Decorator for Datalog Program Blocks A decorator that marks a function body as a block of Datalog clauses. Undefined capitalized names inside the function are automatically treated as Datalog variables, eliminating the need for `create_terms()` within the block. ### Example ```python from pyDatalog import pyDatalog @pyDatalog.program() def _(): # Facts + link(1, 2) + link(2, 3) + link(2, 4) + link(5, 6) # Make links bi-directional link(X, Y) <= link(Y, X) # Recursive reachability can_reach(X, Y) <= link(X, Y) can_reach(X, Y) <= can_reach(X, Z) & link(Z, Y) & (X != Y) pyDatalog.create_terms('X, Y') print(can_reach(1, Y)) # all nodes reachable from node 1 ``` ``` -------------------------------- ### Define a rule for lowest salary Source: https://context7.com/pcarbonn/pydatalog/llms.txt Defines a Datalog rule to find the person with the lowest salary. The result is a set of tuples. ```python pyDatalog.load("(lowest[1] == min_(X, order_by=N)) <= (salary[X] == N)") result = pyDatalog.ask("lowest[1] == X") print(result) # {(1, 'Sam')} print(type(result)) # ``` -------------------------------- ### Register Custom Python Function as Datalog Predicate Source: https://context7.com/pcarbonn/pydatalog/llms.txt Uses the @pyDatalog.predicate() decorator to register a Python function as a Datalog predicate. This allows Datalog queries to execute arbitrary Python logic, such as calculating Fibonacci numbers. ```python from pyDatalog import pyDatalog # Register a Python function as a Datalog predicate named 'fibonacci' @pyDatalog.predicate() def fibonacci2(X, Y): """Resolve fibonacci(X, Y) where Y = fib(X) for a known X.""" if X.is_const(): n = X.id a, b = 0, 1 for _ in range(n): a, b = b, a + b yield (X, a) else: raise StopIteration pyDatalog.create_terms('X, Y') print(pyDatalog.ask('fibonacci(5, Y)')) # {(5, 5)} print(pyDatalog.ask('fibonacci(10, Y)')) # {(10, 55)} ``` -------------------------------- ### Clear pyDatalog Knowledge Base Source: https://context7.com/pcarbonn/pydatalog/llms.txt Resets the Datalog database to an empty state by clearing all facts and rules. This is useful for testing or reinitializing between independent scenarios. ```python from pyDatalog import pyDatalog pyDatalog.create_terms('color, X') + color('red') + color('blue') print(color(X)) # [('red',), ('blue',)] pyDatalog.clear() print(color(X)) # [] ``` -------------------------------- ### Set Membership: Query Nodes Within a Set Source: https://context7.com/pcarbonn/pydatalog/llms.txt Uses the ._in() method to filter query results, returning only nodes that are present in a specified list. Requires node facts. ```python from pyDatalog import pyDatalog @pyDatalog.program() def _(): + edge(1, 2); + edge(2, 3); + edge(3, 4); + edge(5, 6) # Reachability reachable(X, Y) <= edge(X, Y) reachable(X, Y) <= reachable(X, Z) & edge(Z, Y) pyDatalog.create_terms('X, Y, P') # Nodes NOT reachable from 1 print(edge(X, Y) & ~reachable(1, X) & (X != 1)) # [(5, 6)] # Membership: only query nodes in a given set pyDatalog.create_terms('node') + node(1); + node(3); + node(5) print(node(X) & X._in([1, 3])) # [(1,), (3,)] ``` -------------------------------- ### Aggregate: Concatenate Names Per Department Source: https://context7.com/pcarbonn/pydatalog/llms.txt Concatenates employee names within each department, sorted alphabetically, using the concat_ aggregate function. Requires department and salary facts. ```python from pyDatalog import pyDatalog pyDatalog.create_terms( 'salary, department, emp_count, total_salary, min_salary, max_salary, ' 'sorted_names, ranked, X, Y, N, D, R' ) # Facts: (name, department, salary) + (salary['Alice'] == 9000); + (department['Alice'] == 'Eng') + (salary['Bob'] == 7500); + (department['Bob'] == 'Eng') + (salary['Carol'] == 8200); + (department['Carol'] == 'HR') + (salary['Dan'] == 6800); + (department['Dan'] == 'HR') # Concatenate names per department, sorted alphabetically (sorted_names[D] == concat_(X, order_by=X, sep=', ')) <= (department[X] == D) print(sorted_names[D] == N) # [('Eng', 'Alice, Bob'), ('HR', 'Carol, Dan')] ``` -------------------------------- ### Set Membership: Query Nodes NOT Within a Set Source: https://context7.com/pcarbonn/pydatalog/llms.txt Uses the ._not_in() method to exclude query results, returning only nodes that are not present in a specified list. Requires node facts. ```python from pyDatalog import pyDatalog @pyDatalog.program() def _(): + edge(1, 2); + edge(2, 3); + edge(3, 4); + edge(5, 6) # Reachability reachable(X, Y) <= edge(X, Y) reachable(X, Y) <= reachable(X, Z) & edge(Z, Y) pyDatalog.create_terms('X, Y, P') # Nodes NOT reachable from 1 print(edge(X, Y) & ~reachable(1, X) & (X != 1)) # [(5, 6)] # Membership: only query nodes in a given set pyDatalog.create_terms('node') + node(1); + node(3); + node(5) print(node(X) & X._in([1, 3])) # [(1,), (3,)] print(node(X) & X._not_in([1])) # [(3,), (5,)] ``` -------------------------------- ### pyDatalog.assert_fact / pyDatalog.retract_fact Source: https://context7.com/pcarbonn/pydatalog/llms.txt Asserts or retracts a fact from the Datalog knowledge base at runtime without using the `+`/`-` operator syntax. This is useful when predicate names or arguments are determined dynamically. ```APIDOC ## `pyDatalog.assert_fact(predicate_name, *args)` / `pyDatalog.retract_fact(predicate_name, *args)` — Programmatic Fact Management Asserts or retracts a fact from the Datalog knowledge base at runtime without using the `+`/`-` operator syntax. Useful when predicate names or arguments are determined dynamically. ### Example ```python from pyDatalog import pyDatalog # Assert facts programmatically pyDatalog.assert_fact('salary', 'John', 6800) pyDatalog.assert_fact('salary', 'Mary', 6300) pyDatalog.assert_fact('salary', 'Sam', 5900) pyDatalog.create_terms('salary, X, Y') # Query print(salary[X] == 6300) # [('Mary',)] # Retract a fact pyDatalog.retract_fact('salary', 'Mary', 6300) print(salary[X] == 6300) # [] ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.