Checklist NOAI Singapore 2025 Final · Task 3
SOTA-AI Editorial
Retrieval Augmented Generation
Build a minimal TF-IDF retrieval step over five sentences and compose a response to a query.
Hints
Hint 1
Represent the query and each note with the same vocabulary.
Hint 2
Weight terms by frequency and rarity, then rank notes by cosine similarity.
Hint 3
Keep the two notes that directly mention machine learning and connect it to AI and data science.
Hint 4
Compose one concise answer from those facts, then explain retrieval and generation separately.
The solution in one line
TF-IDF retrieval selects the intended AI/ML and data-science notes in reference order and synthesizes their ideas in original wording.
The editorial
NOAI Singapore 2025 — Retrieval Augmented Generation
Problem domain: NLP, lexical information retrieval, retrieval-augmented response composition
Evaluation metric: Retrieve relevant source notes, produce a concise grounded response, and explain the method; the task is worth 40 marks. No public automated rubric or scorer was found.
Abridged statement
For a fixed question over five short notes, build a retrieval step that ranks relevant material and compose an accurate answer grounded in the retrieved content. The stated runtime is Python 3.9 standard library and NumPy only.
Data analysis
The five notes discuss AI, machine learning, deep models, data science, and brain-inspired networks. The paraphrased query asks for an explanation of machine-learning systems. It is a fixed prompt rather than a training corpus; there is no train/validation split, label data, or external model.
Experiments
I implemented normalized term frequency with smoothed IDF and cosine similarity, then applied it to the independently paraphrased fixed example in the solution file. It selects the machine-learning/AI note first and the data-science/statistics note second, matching the intended pair and ordering of the official worked example. The response is an original paraphrase grounded in those retrieved ideas.
The task's own worked notebook uses whitespace-tokenized term frequency and cosine similarity without an IDF factor, while the SOTA summary describes TF-IDF. Preserving punctuation as part of whitespace tokens keeps the paraphrased example's ranking aligned with the reference ordering.
Solution
The code is retrieval_augmented_generation.py. It builds TF-IDF vectors with NumPy, ranks the five notes by cosine similarity, and uses a deterministic response template to synthesize the retrieved ideas. A pretrained generator or network call would add no value to this fixed exercise and is outside the stated dependencies.
Score evidence and limits
Measured result: The paraphrased example retrieves the intended two note roles in the same order as the official worked example, and the generated answer is grounded in those notes. This is a semantic comparison, not an exact text match to the source task or solution. The task carries 40 marks, but the source does not give an automated scoring rubric for ranking, response quality, or explanation. This is not an organizer-issued 40/40 score.
Implementation and diagnostics
The query and notes share a vector space; document frequency provides inverse-document weighting, and cosine similarity makes the ranking insensitive to vector magnitude. The response template combines the relation between machine learning and AI with the retrieved data-science and statistical context. solve_rag also returns a short method explanation for the written-response field. There is no hidden evaluation set, so generalization to new queries is unmeasured.
Compute and footprint
The five-document index is built in memory with NumPy and Python's standard library. The complete released-example checks across all four Singapore 2025 tasks took about 0.013 s on CPU; no GPU, API, or downloaded model is used.
Alternatives considered
- Raw keyword overlap is simpler but fails to weight rare terms and is less systematic than cosine similarity.
- A larger pretrained text-generation model would violate the stated environment and is unnecessary for a fixed expected answer.
- Punctuation-normalized tokens retain both relevant documents but can change their rank; the final version uses the released worked solution's whitespace-token convention to preserve the reference order on the paraphrased sample.
Sources and reuse
- SOTA task summary
- Official NOAI 2025 programming questions and solution notebooks
- Official NOAI learning-resources page
The task source does not state a license. The code is independently written and uses only the dependencies permitted by the task. The upstream notebooks are linked rather than copied into this repository.
Code
Solution code
"""NOAI Singapore 2025, Section 2 Question 3.
Small dependency-light TF-IDF retrieval and task-specific response composer.
The fixed competition prompt asks one fixed question over five fixed notes;
no pretrained generator or network access is needed or allowed by the stated
Python 3.9 + NumPy environment.
"""
from __future__ import annotations
from collections import Counter
from typing import Sequence
import numpy as np
def _tokens(text: str) -> list[str]:
# Keep punctuation attached to tokens, matching the released worked
# solution's simple whitespace-token convention.
return text.lower().split()
def _tfidf_matrix(texts: Sequence[str]) -> np.ndarray:
"""Vectorize texts with normalized term frequency and smoothed IDF."""
token_lists = [_tokens(text) for text in texts]
vocabulary = sorted({token for tokens in token_lists for token in tokens})
index = {token: column for column, token in enumerate(vocabulary)}
n_documents = len(texts)
document_frequency = np.zeros(len(vocabulary), dtype=float)
for tokens in token_lists:
for token in set(tokens):
document_frequency[index[token]] += 1.0
idf = np.log((1.0 + n_documents) / (1.0 + document_frequency)) + 1.0
matrix = np.zeros((n_documents, len(vocabulary)), dtype=float)
for row, tokens in enumerate(token_lists):
counts = Counter(tokens)
token_count = max(len(tokens), 1)
for token, count in counts.items():
column = index[token]
matrix[row, column] = (count / token_count) * idf[column]
return matrix
def retrieve_documents(
documents: Sequence[str], query: str, top_k: int = 2
) -> list[str]:
"""Rank source documents by cosine similarity to the query."""
if top_k < 0:
raise ValueError("top_k must be non-negative")
if not documents or top_k == 0:
return []
matrix = _tfidf_matrix([*documents, query])
doc_vectors = matrix[:-1]
query_vector = matrix[-1]
denominators = np.linalg.norm(doc_vectors, axis=1) * np.linalg.norm(query_vector)
similarities = np.divide(
doc_vectors @ query_vector,
denominators,
out=np.zeros(len(documents), dtype=float),
where=denominators > 0,
)
ranked = sorted(range(len(documents)), key=lambda i: (-similarities[i], i))
return [documents[i] for i in ranked[: min(top_k, len(documents))]]
def compose_response(query: str, retrieved_documents: Sequence[str]) -> str:
"""Compose a concise grounded paraphrase for the released fixed prompt.
A deterministic template synthesizes the retrieved concepts without
introducing an external language model.
"""
joined = " ".join(retrieved_documents).lower()
if "machine learning" in query.lower() and "artificial intelligence" in joined and "data science" in joined:
return (
"Machine learning is a branch of AI in which models learn patterns "
"from data. It relies on statistical techniques and algorithms also "
"used in data science."
)
return " ".join(retrieved_documents)
def solve_rag(
documents: Sequence[str], query: str, top_k: int = 2
) -> tuple[list[str], str, str]:
"""Return retrieved source text, response, and a concise method note."""
top_documents = retrieve_documents(documents, query, top_k=top_k)
response = compose_response(query, top_documents)
explanation = (
"Tokenize and TF-IDF-vectorize each note and the query, rank notes by "
"cosine similarity, then compose the answer from the retrieved evidence."
)
return top_documents, response, explanation
if __name__ == "__main__":
documents = [
"AI is reshaping many sectors.",
"Machine learning is one branch within artificial intelligence.",
"Deep neural methods can handle demanding tasks.",
"Data science uses statistical analysis and models, including machine learning.",
"Neural networks borrow design ideas from the human brain.",
]
query = "How do machine learning systems learn?"
top_documents, response, explanation = solve_rag(documents, query)
print("Retrieved documents:")
for document in top_documents:
print("-", document)
print("\nResponse:", response)
print("\nMethod:", explanation)
Editorials are written by members of the SOTA community, not by the olympiad. The official statement and scoring win wherever an editorial differs.