Querying Experts

The QUERY algorithm (Koppen & Doignon, 1990) derives a knowledge structure by asking an expert prerequisite questions.

How it works

The algorithm asks questions of the form:

If a student fails all items in set \(A\), will they also fail item \(q\)?

It proceeds in phases:

  1. Block 1: Pair queries (\(|A| = 1\)) to discover the surmise relation.

  2. Block 2+: Group queries (\(|A| \geq 2\)) to refine the structure into a learning space.

Three inference mechanisms reduce the number of questions:

  • Negative monotonicity: If \(q\) is minimal, no set implies \(q\).

  • Positive monotonicity: If a subset of \(A\) already implies \(q\), so does \(A\).

  • Structural test (Theorem 43): If answering YES would create a hanging state, the answer must be NO.

Basic usage

from knowledgespaces import run_query
from knowledgespaces.query import CallbackExpert

def my_expert(antecedent, consequent):
    # Your logic: human input, LLM call, database lookup, etc.
    known = {("add", "sub"), ("sub", "mul"), ("mul", "div")}
    return any((a, consequent) in known for a in antecedent)

expert = CallbackExpert(my_expert)
result = run_query(["add", "sub", "mul", "div"], expert)

print(result.is_learning_space)
print(result.total_expert_queries)

Controlling the algorithm

# Without Qmax minimality test (fewer group queries, more pair queries)
result = run_query(items, expert, use_qmax=False)

# With Block 3 (group queries of size 3)
result = run_query(items, expert, max_antecedent_size=3)

Inspecting results

# The derived structure
for state in result.structure:
    print(set(state))

# Block 1 details
print(result.block1.relation)       # direct prerequisites found
print(result.block1.minimal_global)  # items certified minimal by Qmax
print(result.block1.stats)           # query counts

# Full query log
for entry in result.block1.log:
    print(f"{entry.query}{entry.answer} ({entry.source.name})")