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,
)