Skip to content

Data Flows

Overview

This document describes how data flows through Mistaber from user input to final reasoning results.

High-Level Flow

flowchart TB
    subgraph INPUT["USER INPUT"]
        hll["HLL Source Code<br/>@world, @rule, @makor, facts, rules"]
    end

    subgraph COMPILE["COMPILATION FLOW"]
        comp["HLL → AST → Normalized → Validated → ASP"]
    end

    subgraph REASON["REASONING FLOW"]
        reason["ASP + Ontology → Clingo → Answer Sets"]
    end

    subgraph OUTPUT["OUTPUT"]
        out["Forbidden/Permitted • Source traceability • Explanations"]
    end

    INPUT --> COMPILE --> REASON --> OUTPUT

1. Compilation Flow

Input: HLL Source Code

@world(base)
@rule(r_basar_bechalav)
@makor([sa("YD:87:1"), rambam("Maachalot Asurot 9:1")])
@madrega(d_oraita)

basar(chicken).
chalav(milk).
mixture(m1).
contains(m1, chicken).
contains(m1, milk).

forbidden(W, achiila, M, ctx_normal) :-
    mixture(M),
    mixture_is_basar_bechalav(M).

Stage 1: Parsing

Input: HLL source string Output: ParseResult dataclass

ParseResult(
    facts=[
        Fact(predicate="basar", args=["chicken"]),
        Fact(predicate="chalav", args=["milk"]),
        Fact(predicate="mixture", args=["m1"]),
        Fact(predicate="contains", args=["m1", "chicken"]),
        Fact(predicate="contains", args=["m1", "milk"]),
    ],
    rules=[
        Rule(
            head=Atom(predicate="forbidden", args=["W", "achiila", "M", "ctx_normal"]),
            body=[
                Atom(predicate="mixture", args=["M"]),
                Atom(predicate="mixture_is_basar_bechalav", args=["M"]),
            ]
        )
    ],
    world="base",
    rule_id="r_basar_bechalav",
    sources=[("sa", "YD:87:1"), ("rambam", "Maachalot Asurot 9:1")],
    madrega="d_oraita"
)

Stage 2: Normalization

Input: ParseResult with surface syntax Output: ParseResult with canonical predicates

Transformations: | Surface | Canonical | |---------|-----------| | basar(chicken) | food_type(chicken, basar) | | chalav(milk) | food_type(milk, chalav) |

ParseResult(
    facts=[
        Fact(predicate="food_type", args=["chicken", "basar"]),  # Normalized
        Fact(predicate="food_type", args=["milk", "chalav"]),    # Normalized
        Fact(predicate="mixture", args=["m1"]),
        Fact(predicate="contains", args=["m1", "chicken"]),
        Fact(predicate="contains", args=["m1", "milk"]),
    ],
    # ... rules unchanged, directives preserved
)

Stage 3: Type Checking

Input: Normalized ParseResult Output: List of TypeCheckError (errors and warnings)

Validations: 1. Predicate lookup: food_type exists in registry 2. Arity check: food_type has arity 2 3. Sort check: basar is valid for food_category sort 4. Makor check: normative rules have @makor directive 5. OWA negation: warn if negating open-world predicates

errors = []  # No errors in valid input

# If errors occurred:
errors = [
    TypeCheckError(
        message="Undeclared predicate: 'unknown_pred'",
        severity="error"
    ),
    TypeCheckError(
        message="Using negation on OWA predicate 'permitted'",
        severity="warning"
    )
]

Stage 4: Emission

Input: Validated ParseResult Output: ASP code string

% World: base
% Rule ID: r_basar_bechalav

rule(r_basar_bechalav).
scope(r_basar_bechalav, base).
makor(r_basar_bechalav, sa("YD:87:1")).
makor(r_basar_bechalav, rambam("Maachalot Asurot 9:1")).
madrega(r_basar_bechalav, d_oraita).

food_type(chicken, basar).
food_type(milk, chalav).
mixture(m1).
contains(m1, chicken).
contains(m1, milk).

%!trace_rule {"r_basar_bechalav: action on food is forbidden"}
forbidden(W, achiila, M, ctx_normal) :- mixture(M), mixture_is_basar_bechalav(M).

2. Reasoning Flow

Input Assembly

The solver receives multiple inputs combined:

flowchart LR
    subgraph CLINGO["CLINGO INPUT"]
        direction TB
        schema["1. Schema Files<br/>sorts.lp | constraints.lp | disjointness.lp"]
        base["2. Base Ontology<br/>substance.lp | madrega.lp | context.lp<br/>temporal.lp | status.lp | shiur.lp"]
        ext["3. Extensions (optional)<br/>ontology/extensions/*.lp"]
        user["4. User Program<br/>Compiled ASP from HLL"]
    end

    schema --> base --> ext --> user

Grounding Phase

Clingo grounds all rules with concrete values:

% User declared:
food_type(chicken, basar).

% Ontology rule (substance.lp):
food_type(F, Parent) :- food_type(F, Child), subcategory_of(Child, Parent).

% After grounding with subcategory(basar, maakhal):
food_type(chicken, maakhal).  % Derived

% User declared:
contains(m1, chicken).
contains(m1, milk).

% Ontology rule (substance.lp):
mixture_contains_basar(M) :- mixture(M), contains(M, F), food_type(F, basar).

% After grounding:
mixture_contains_basar(m1).  % Derived (chicken is basar)
mixture_contains_chalav(m1). % Derived (milk is chalav)
mixture_is_basar_bechalav(m1). % Derived

Solving Phase

Clingo computes stable models (answer sets):

Answer Set 1:
  food_type(chicken, basar)
  food_type(chicken, maakhal)
  food_type(milk, chalav)
  food_type(milk, maakhal)
  mixture(m1)
  contains(m1, chicken)
  contains(m1, milk)
  mixture_contains_basar(m1)
  mixture_contains_chalav(m1)
  mixture_is_basar_bechalav(m1)
  forbidden(base, achiila, m1, ctx_normal)  ← DERIVED

Output Extraction

with ctl.solve(yield_=True) as handle:
    for model in handle:
        atoms = model.symbols(shown=True)

        # Extract forbidden atoms
        forbidden = [a for a in atoms if a.name == "forbidden"]
        # → [forbidden(base, achiila, m1, ctx_normal)]

        # Extract permitted atoms
        permitted = [a for a in atoms if a.name == "permitted"]
        # → []

        # Extract safek atoms
        safek = [a for a in atoms if a.name == "safek"]
        # → []

3. Data Transformation Summary

HLL to AST

HLL Text               →    Python Dataclasses
─────────────────────       ───────────────────
"basar(chicken)."      →    Fact(predicate="basar", args=["chicken"])
"forbidden(W,A,M,C):-" →    Rule(head=Atom(...), body=[...])
"@world(base)"         →    ParseResult.world = "base"

AST to Normalized AST

Surface Syntax          →    Canonical Predicates
──────────────────────       ────────────────────
basar(chicken)          →    food_type(chicken, basar)
issur(achiila, X)       →    forbidden(W, achiila, X, ctx_normal)
chalav(Y)               →    food_type(Y, chalav)

Normalized AST to ASP

Python Dataclasses      →    ASP Text
──────────────────────       ─────────
Fact(food_type, [a,b])  →    "food_type(a, b)."
Rule(head, body)        →    "head :- body."
ParseResult.sources     →    "makor(rule_id, source)."

ASP + Ontology to Answer Sets

ASP Facts + Rules       →    Derived Atoms
─────────────────────        ────────────────────
food_type(chicken, of)  →    food_type(chicken, basar)
contains(m1, chicken)   →    mixture_contains_basar(m1)
contains(m1, milk)      →    mixture_is_basar_bechalav(m1)
mixture_is_basar...     →    forbidden(base, achiila, m1, ctx_normal)

4. Complete Example

Input HLL

@world(base)
@rule(r_example)
@makor([sa("YD:87:1")])
@madrega(d_oraita)

food(beef).
food_type(beef, beheima).
food(milk).
food_type(milk, chalav).
mixture(stew).
contains(stew, beef).
contains(stew, milk).

forbidden(W, achiila, M, ctx_normal) :-
    world(W),
    mixture(M),
    mixture_is_basar_bechalav(M).

Compilation

from mistaber.dsl.compiler import compile_hll

asp_code = compile_hll(hll_source)

Reasoning

import clingo

ctl = clingo.Control(["--warn=none"])

# Load ontology
ctl.load("mistaber/ontology/schema/sorts.lp")
ctl.load("mistaber/ontology/schema/disjointness.lp")
ctl.load("mistaber/ontology/base/substance.lp")

# Add compiled user program
ctl.add("user", [], asp_code)

# Ground
ctl.ground([("base", []), ("user", [])])

# Solve
results = []
with ctl.solve(yield_=True) as handle:
    for model in handle:
        results = [str(a) for a in model.symbols(shown=True)]

Output

# Derived atoms include:
"food_type(beef, beheima)"
"food_type(beef, basar)"       # Inherited
"food_type(beef, maakhal)"     # Inherited
"mixture_contains_basar(stew)"
"mixture_contains_chalav(stew)"
"mixture_is_basar_bechalav(stew)"
"forbidden(base, achiila, stew, ctx_normal)"  # Final ruling

5. Error Flows

Parse Error Flow

Invalid HLL → Parser → ParseError → CompileError → User
"Parse error at line 5: Unexpected token"

Type Error Flow

Valid syntax, invalid semantics → TypeChecker → TypeCheckError → CompileError
"Undeclared predicate: 'unknwon_pred'"

Unsatisfiable Flow

Contradictory facts → Clingo → UNSATISFIABLE → No answer sets
food_type(X, basar) AND food_type(X, chalav)  # Violates disjointness

6. Data Structures Reference

ParseResult

@dataclass
class ParseResult:
    facts: List[Fact]
    rules: List[Rule]
    world: Optional[str]
    rule_id: Optional[str]
    sources: Optional[List[Tuple[str, str]]]
    madrega: Optional[str]

TypeCheckError

@dataclass
class TypeCheckError:
    message: str
    severity: Literal["error", "warning"]
    predicate: str = ""
    line: int = 0

Clingo Symbols

# Clingo returns Symbol objects
symbol.name        # "forbidden"
symbol.arguments   # [Symbol("base"), Symbol("achiila"), ...]
str(symbol)        # "forbidden(base,achiila,m1,ctx_normal)"

7. Performance Considerations

Grounding Size

The number of ground atoms grows with: - Number of declared entities (foods, vessels, mixtures) - Number of rules with variables - Depth of inheritance hierarchies

Solving Complexity

Answer set computation is NP-complete. Factors affecting performance: - Number of choice rules - Depth of negation - Size of search space after constraints

Optimization Tips

  1. Minimize variables: Use concrete values where possible
  2. Add constraints early: Disjointness rules prune the search space
  3. Use #show directives: Limit output to relevant predicates
  4. Ground incrementally: For large programs, ground in stages