Skip to content

Tutorial 2: Your First Query

This tutorial introduces Mistaber's query system through a practical example: determining the halachic status of a meat and milk mixture.

Learning Objectives

  • Understand the basic query interface
  • Run queries using both the CLI and Python API
  • Interpret query results
  • Use the analyze command for scenario-based reasoning

Prerequisites

Estimated Time

15 minutes

Steps

Step 1: Understanding the Problem

Consider this scenario: You have a mixture containing beef and cow's milk. What is its halachic status according to the Shulchan Aruch?

This question involves: - Food classification: Beef is beheima (domesticated animal) - Mixture detection: The system must identify this as a basar bechalav (meat and milk) mixture - Ruling derivation: The system must derive the appropriate prohibition level

Step 2: Create a Scenario File

Create a file called beef_milk_scenario.lp with the following content:

% beef_milk_scenario.lp
% A simple basar bechalav scenario

% Declare the foods
food(beef_portion).
food(cow_milk).

% Classify the foods
food_type(beef_portion, beheima).   % Beef is from a domesticated animal
food_type(cow_milk, chalav).        % Cow's milk is dairy

% Create a mixture
mixture(beef_milk_mix).
contains(beef_milk_mix, beef_portion).
contains(beef_milk_mix, cow_milk).

This scenario declares two foods, classifies them, and creates a mixture containing both.

Step 3: Run the Analyze Command (CLI)

Use the CLI to analyze this scenario:

python -m core.cli.main --ontology ./mistaber/ontology analyze beef_milk_scenario.lp --world mechaber

You should see output showing the derived conclusions:

Analysis Results
================

[1]
  world: mechaber
  scenario: food(beef_portion). food(cow_milk)...

  atoms:
    - holds(issur(achiila,beef_milk_mix,d_oraita),mechaber)
    - holds(issur(bishul,beef_milk_mix,d_oraita),mechaber)
    - holds(issur(hanaah,beef_milk_mix,d_oraita),mechaber)
    - is_beheima_chalav_mixture(beef_milk_mix)
    ...

Step 4: Interpret the Results

The key derived atoms tell us:

Atom Meaning
holds(issur(achiila,beef_milk_mix,d_oraita),mechaber) Eating is forbidden at the Torah level
holds(issur(bishul,beef_milk_mix,d_oraita),mechaber) Cooking is forbidden at the Torah level
holds(issur(hanaah,beef_milk_mix,d_oraita),mechaber) Deriving benefit is forbidden at the Torah level
is_beheima_chalav_mixture(beef_milk_mix) System classified this as beheima + chalav

The d_oraita level indicates this is a Torah-level prohibition, reflecting Yoreh Deah 87:1.

Step 5: Query Using Python API

Now let's do the same thing using the Python API:

from pathlib import Path
from mistaber.engine import HsrsEngine

# Initialize engine
engine = HsrsEngine(Path("mistaber/ontology"))

# Define the scenario
scenario = """
food(beef_portion).
food(cow_milk).
food_type(beef_portion, beheima).
food_type(cow_milk, chalav).
mixture(beef_milk_mix).
contains(beef_milk_mix, beef_portion).
contains(beef_milk_mix, cow_milk).
"""

# Analyze the scenario
result = engine.analyze(scenario, world="mechaber")

# Print derived atoms
print("Derived conclusions:")
for atom in result["atoms"]:
    if "issur" in atom or "heter" in atom:
        print(f"  - {atom}")

Output:

Derived conclusions:
  - holds(issur(achiila,beef_milk_mix,d_oraita),mechaber)
  - holds(issur(bishul,beef_milk_mix,d_oraita),mechaber)
  - holds(issur(hanaah,beef_milk_mix,d_oraita),mechaber)

Step 6: Query for Specific Information

Use pattern queries to extract specific information:

from pathlib import Path
from mistaber.engine import HsrsEngine

engine = HsrsEngine(Path("mistaber/ontology"))

# Query: What types of issur exist for our mixture?
scenario = """
food(beef).
food(milk).
food_type(beef, beheima).
food_type(milk, chalav).
mixture(test_mix).
contains(test_mix, beef).
contains(test_mix, milk).
"""

result = engine.analyze(scenario, world="mechaber")

# Filter for issur atoms
issurim = [a for a in result["atoms"] if "issur(" in a]
print("Prohibitions found:")
for issur in issurim:
    print(f"  {issur}")

Step 7: Compare Across Worlds

See how different authorities rule on the same scenario:

from pathlib import Path
from mistaber.engine import HsrsEngine

engine = HsrsEngine(Path("mistaber/ontology"))

# Compare issur holdings across mechaber and rema
comparison = engine.compare(
    "holds(issur(achiila, M, D), W)",
    worlds=["mechaber", "rema"]
)

print("Comparison of issur(achiila) across worlds:")
for world, results in comparison.items():
    print(f"\n{world}:")
    for r in results[:5]:  # First 5 results
        print(f"  Mixture: {r.get('M', 'N/A')}, Level: {r.get('D', 'N/A')}")

Step 8: Ask Boolean Questions

Use ask() for simple yes/no questions:

from pathlib import Path
from mistaber.engine import HsrsEngine

engine = HsrsEngine(Path("mistaber/ontology"))

# Does the mechaber world exist?
print(f"Mechaber world exists: {engine.ask('world(mechaber)')}")

# Is mechaber accessible from base?
print(f"Mechaber inherits from base: {engine.ask('accessible(mechaber, base)')}")

Output:

Mechaber world exists: True
Mechaber inherits from base: True

Understanding Query Patterns

Variables vs Constants

In query patterns: - Uppercase letters are variables: X, World, Mixture - Lowercase words are constants: mechaber, base, achiila

# Variables (will match anything)
engine.query("world(X)")           # All worlds
engine.query("holds(P, W)")        # All properties in all worlds

# Constants (exact match)
engine.query("accessible(X, base)")  # Worlds accessible from 'base'

Common Query Patterns

# All worlds
engine.query("world(X)")

# Inheritance relationships
engine.query("accessible(Child, Parent)")

# All issur holdings
engine.query("holds(issur(Act, Item, Level), World)")

# Specific issur type
engine.query("holds(issur(achiila, Item, Level), World)")

# All makor (source) citations
engine.query("makor(Rule, Source)")

Exercises

Exercise 1: Poultry and Milk

Create a scenario with chicken and milk. What issur level do you expect?

Solution
scenario = """
food(chicken_breast).
food(goat_milk).
food_type(chicken_breast, of).  # Poultry
food_type(goat_milk, chalav).
mixture(chicken_milk_mix).
contains(chicken_milk_mix, chicken_breast).
contains(chicken_milk_mix, goat_milk).
"""

result = engine.analyze(scenario, world="mechaber")
# Expected: issur(achiila, chicken_milk_mix, d_rabanan)
# Note: Only eating is forbidden, and only at the rabbinic level

Exercise 2: Compare Mechaber and Rema

Create a fish and dairy scenario. How do the two authorities differ?

Solution
scenario = """
food(salmon).
food(cream).
food_type(salmon, dag).
food_type(cream, chalav).
mixture(fish_cream).
contains(fish_cream, salmon).
contains(fish_cream, cream).
"""

# Analyze in Mechaber's world
mechaber_result = engine.analyze(scenario, world="mechaber")
# Expected: sakana (health danger)

# Analyze in Rema's world
rema_result = engine.analyze(scenario, world="rema")
# Expected: heter (permitted)

What You've Learned

  • How to create scenario files in ASP format
  • How to use the analyze command to derive conclusions
  • How to query using the Python API
  • How to interpret issur and heter atoms
  • How to compare results across worlds

Next Steps

Continue to Tutorial 3: Understanding Worlds to learn about Mistaber's multi-world Kripke semantics.

Quick Reference

from pathlib import Path
from mistaber.engine import HsrsEngine

engine = HsrsEngine(Path("mistaber/ontology"))

# Boolean query
engine.ask("world(base)")  # True/False

# Pattern query
engine.query("world(X)")   # List of bindings

# Analyze scenario
engine.analyze("food(x). ...", world="mechaber")

# Compare worlds
engine.compare("pattern", worlds=["mechaber", "rema"])