Source code for knowledgespaces.query.pipeline

"""
Full QUERY pipeline: Block 1 → L1 → Block 2 → ... → Block N.

Orchestrates the complete derivation of a learning space from expert queries.
"""

from __future__ import annotations

from dataclasses import dataclass, field

from knowledgespaces.query.block1 import Block1Result, run_block1
from knowledgespaces.query.block2 import BlockNResult, run_block_n
from knowledgespaces.query.expert import Expert
from knowledgespaces.structures.knowledge_structure import KnowledgeStructure


[docs] @dataclass class QueryPipelineResult: """Result of the full QUERY pipeline.""" structure: KnowledgeStructure block1: Block1Result block_n_results: list[BlockNResult] = field(default_factory=list) @property def total_expert_queries(self) -> int: total = self.block1.stats.total_queries for bn in self.block_n_results: total += bn.stats.expert_queries return total @property def is_learning_space(self) -> bool: return self.structure.is_learning_space
[docs] def run_query( items: list[str], expert: Expert, *, use_qmax: bool = True, max_antecedent_size: int = 2, ) -> QueryPipelineResult: """Run the full QUERY algorithm. Parameters ---------- items : list[str] The domain of items. expert : Expert The expert to query. use_qmax : bool If True, use Qmax minimality test in Block 1. max_antecedent_size : int Maximum antecedent size for group queries. Default 2 (Block 2 only). Set to 3 for Block 3, etc. Returns ------- QueryPipelineResult The derived learning space with full traceability. """ # Block 1: discover surmise relation b1 = run_block1(items, expert, use_qmax=use_qmax) # Generate ordinal space L1 from the closure L1 = KnowledgeStructure.from_surmise_relation(b1.closure) # Build initial positive set from Block 1 closure prior_positive: set[tuple[frozenset[str], str]] = {(frozenset({a}), b) for a, b in b1.closure} # Block 2, 3, ..., N: refine to learning space current = L1 block_n_results: list[BlockNResult] = [] for size in range(2, max_antecedent_size + 1): bn = run_block_n( items, current, prior_positive, expert, antecedent_size=size, minimal_global=b1.minimal_global, ) block_n_results.append(bn) current = bn.structure prior_positive = bn.positive return QueryPipelineResult( structure=current, block1=b1, block_n_results=block_n_results, )