Checklist Bulgaria selection 2026 National Competition in AI, final (in-person) round · Task 2
Nahuatl–Spanish Sentence Retrieval
Bulgarian title: Извличане на изречения Науатл-Испански
For each Nahuatl sentence, pick its Spanish translation from 10 candidates.
The task
A linguistics team studying Nahuatl, an agglutinative language of Mexico, needs a system that finds matching translations in bilingual collections. Given a Nahuatl sentence and 10 Spanish candidates (exactly one correct), the system must return the index of the correct translation. The statement explains Nahuatl morphology with examples and suggests hand-crafted morphological features, fine-tuning semantic models, ensembling or re-ranking.
The baseline encodes the query and the candidates with paraphrase-multilingual-MiniLM-L12-v2 and chooses the highest cosine similarity (about 33%). Contestants implement predict(nahuatl, candidates) -> int.
Abridged and translated by SOTA from the official Bulgarian materials. The official statement has the exact rules, and it wins wherever this summary differs.
In English
This task was published in Bulgarian. SOTA translated it into English on 17 September 2026. Only the words changed in the notebooks: markdown, code comments, messages and printed output. The code, file names and paths are the original's, so a translated notebook runs with the original data.
Read the task notebook in English
Nahuatl–Spanish Sentence Retrieval
1. Task description
Your task is to work with a linguistic research team that studies Nahuatl - an indigenous language spoken in Mexico by more than 1.5 million people. The team has collected a parallel corpus of sentence pairs in Nahuatl and Spanish, but it needs an efficient system for finding matching translations in large bilingual collections.
Your task is to build a cross-language representation system (cross-language): given a sentence in Nahuatl, the goal is to find its correct Spanish translation among a set of 10 candidates.
This is a fundamental problem in natural language processing, with applications in:
- Machine translation quality evaluation
- Parallel corpus extraction from web data
- Cross-language information representation
About the Nahuatl language
Nahuatl is an agglutinative language, which means that words are formed by joining morphemes (small units of meaning). This is very different from Spanish or English, where words are more isolated.
Examples of Nahuatl morphology:
| Nahuatl | Breakdown | Meaning |
|---|---|---|
nocal |
no-cal = my-house |
"my house" |
nimitztlazohtla |
ni-mitz-tlazohtla = I-you-love |
"I love you" |
tlacualli |
tla-cua-lli = something-eat-something |
"food" |
cihuaconetl |
cihua-conetl = woman-child |
"girl" |
tlenamacac |
tle-nama-cac = fire-sell-person |
"fire seller" |
Why this matters for NLP:
- Standard tokenisers (designed for Spanish/English) may not split Nahuatl words correctly
- A single Nahuatl word may correspond to a whole phrase in Spanish
- Morpheme patterns can help to identify translations (e.g. shared roots, loanwords)
2. Data
Data structure
Training set: 10,000 parallel sentence pairs
- Format: CSV with columns
nahuatl, spanish - Each row is a verified translation pair
- Use it to learn cross-language semantic similarity
Validation set: 500 retrieval queries
- Use it to check your solution
- Each query contains:
- 1 sentence in Nahuatl
- 10 Spanish candidate sentences (labelled
spanish_0tospanish_9) - Exactly 1 candidate is the correct translation (the ground truth is provided)
Test set: 500 retrieval queries
- The same structure as the validation set
3. Task
For each query in the test set:
- Input: 1 sentence in Nahuatl + 10 Spanish candidate sentences
- Output: One integer (0-9) indicating which Spanish candidate is the correct translation
Submission format
Generate Task_2_USER_ID_submission.csv, containing:
- 500 rows (one for each test query)
- Each row: one integer 0-9
- No header row
- Replace
USER_IDwith your identification number.
4. Scoring
Main metric: Accuracy@1 (accuracy on the first attempt)
Accuracy@1 = (Number of queries with a correctly predicted position) / (Total number of queries)
The ranking will be determined on the basis of Accuracy@1 on a hidden test set (held-out test set). The provided validation set (with ground-truth values) is for local evaluation of your solution — use it to check and improve your approach before submitting.
5. Baseline approach
This notebook implements a simple baseline approach, using pre-trained multilingual embeddings (semantic embeddings):
- Model:
paraphrase-multilingual-MiniLM-L12-v2 - Method: Encoding the Nahuatl query and all Spanish candidates, and choosing the candidate with the highest cosine similarity
- Expected score: about 33%
How can you improve the score?
This problem can be approached in many different ways: constructing hand-crafted features that exploit the morphology of the language, fine-tuning models for semantic comparison or ensembling several such models, secondary models for re-ranking the result.
Experiment boldly and find out what works best!
Submitting the solution:
Replace USER_ID with your identification number.
Task_2_USER_ID_submission.csvwith the predictions of your best model- the executed Jupyter notebook, named
Task_2_USER_ID.ipynb
Setup
import pandas as pd
import numpy as np
from typing import List
Loading the data
Loading the training, validation and test sets from the provided CSV files.
# Loading the data
DATA_DIR = "."
print("Loading data...")
train_df = pd.read_csv(f"{DATA_DIR}/training_set.csv")
val_df = pd.read_csv(f"{DATA_DIR}/validation_set.csv")
test_df = pd.read_csv(f"{DATA_DIR}/test_set.csv")
val_ground_truth = pd.read_csv(f"{DATA_DIR}/ground_truth_validation.csv")['correct_position'].tolist()
print(f"Training set: {len(train_df)} pairs")
print(f"Validation set: {len(val_df)} queries (with ground-truth values for local evaluation)")
print(f"Test set: {len(test_df)} queries")
# Overview of the training set
print("Overview of the training set:")
print(train_df.head())
print(f"\nColumns: {list(train_df.columns)}")
# Overview of the structure of the validation set
print("Overview of the validation set:")
print(f"Columns: {list(val_df.columns)}")
print(f"\nExample query:")
print(f" Nahuatl: {val_df.iloc[0]['nahuatl'][:80]}...")
print(f"\n Candidates:")
for i in range(10):
print(f" spanish_{i}: {val_df.iloc[0][f'spanish_{i}'][:60]}...")
YOUR SOLUTION
Edit this section to implement your approach.
You have access to:
train_df: 10,000 training pairs with columns['nahuatl', 'spanish']val_df: 500 validation queries with columns['nahuatl', 'spanish_0', ..., 'spanish_9']test_df: 500 test queries (the same structure as val_df)
Requirement: Implement the predict function below. It will be called once for each query.
def predict(nahuatl: str, candidates: List[str]) -> int:
"""
Arguments:
nahuatl: The Nahuatl sentence to translate
candidates: A list of 10 Spanish candidate sentences
Returns:
Index (0-9) of the predicted correct translation
"""
You may add any code above the predict function (model loading, training, helper functions, etc.).
# ============================================================================
# YOUR SOLUTION - START
# ============================================================================
# Add your imports, model loading, training code and helper
# functions here. The only requirement is that you implement the predict() function.
# ============================================================================
!pip install -q sentence-transformers
from sentence_transformers import SentenceTransformer, util
import torch
# Loading a pre-trained multilingual model
print("Loading model...")
model = SentenceTransformer('sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2')
print("The model is loaded!")
def predict(nahuatl: str, candidates: List[str]) -> int:
"""
Predicts which Spanish candidate is the correct translation.
Arguments:
nahuatl: The Nahuatl sentence
candidates: A list of 10 Spanish candidate sentences
Returns:
Index (0-9) of the predicted correct translation
"""
# Encoding the query and the candidates
query_embedding = model.encode(nahuatl, convert_to_tensor=True)
candidate_embeddings = model.encode(candidates, convert_to_tensor=True)
# Computing the cosine similarity
similarities = util.cos_sim(query_embedding, candidate_embeddings)[0]
# Returning the index with the highest similarity
return torch.argmax(similarities).item()
# ============================================================================
# YOUR SOLUTION - END
# ============================================================================
Evaluation and submission (do not edit below)
The code below:
- Runs your
predictfunction on the validation set and shows your score - Runs predictions on the test set and generates
submission.csv
def run_predictions(df: pd.DataFrame) -> List[int]:
"""Runs predict() on all queries in the dataframe."""
predictions = []
for idx, row in df.iterrows():
nahuatl = row['nahuatl']
candidates = [row[f'spanish_{i}'] for i in range(10)]
pred = predict(nahuatl, candidates)
assert pred in list(range(0,10)), f"Your prediction {pred} is not an integer between 0 and 9"
predictions.append(pred)
if (idx + 1) % 100 == 0:
print(f" Processed {idx + 1}/{len(df)} queries...")
return predictions
# Evaluation on the validation set
print("Evaluating on the validation set...")
val_predictions = run_predictions(val_df)
correct = sum(1 for pred, gt in zip(val_predictions, val_ground_truth) if pred == gt)
accuracy = correct / len(val_ground_truth)
print("\n" + "="*50)
print(f"VALIDATION SCORE: {accuracy:.4f} ({accuracy*100:.2f}%)")
print(f"Correct: {correct}/{len(val_ground_truth)}")
print("="*50)
USER_ID = ''
assert USER_ID != '', "Please enter your ID"
# Generating the test predictions
print("\nGenerating test predictions...")
test_predictions = run_predictions(test_df)
# Saving to submission.csv
submission_filename = f'Task_2_{USER_ID}_submission.csv'
pd.DataFrame(test_predictions).to_csv(submission_filename, index=False, header=False)
print("\n" + "="*50)
print("READY FOR SUBMISSION")
print("="*50)
print(f" {submission_filename}.csv: {len(test_predictions)} predictions")
print(f" {submission_filename}.csv: ready for upload")
print("="*50)
Translated by SOTA. The Bulgarian original is the official version and wins wherever the two differ. The notebook reads training_set.csv, validation_set.csv, test_set.csv and ground_truth_validation.csv, which are next to it in the original folder. The Nahuatl and Spanish sentences in the printed output are data and stay untranslated. If you organise this olympiad and would like the translation removed, email [email protected] and we will take it down.
At a glance
- You get
training_set.csv(10,000 pairs, columns nahuatl, spanish);validation_set.csvandtest_set.csv(500 queries each, columns nahuatl,spanish_0...spanish_9); validation ground truth.- You submit
Task_2_USER_ID_submission.csvwith 500 rows, one integer 0-9 per row, no header, plus the executed notebookTask_2_USER_ID.ipynb.- Scoring
- Accuracy@1 on the hidden test set.
- Rules
- Only the predict function section may be edited; the evaluation cells must not be changed.
- Format
- Final (in-person) round of Bulgaria's first National Competition in AI (school year 2025/2026), held on 28 February 2026 in Plovdiv (the organisers announced 28 Feb - 1 Mar 2026); the top 120 of the online first round (31 Jan 2026) were invited. Task 2.