Discord

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.

  • NLP
  • Cross-lingual retrieval
  • Bulgarian original · English translation

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 748 words and 8 code cells

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_0 to spanish_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_ID with 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.csv with 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:

  1. Runs your predict function on the validation set and shows your score
  2. 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.csv and test_set.csv (500 queries each, columns nahuatl, spanish_0 ... spanish_9); validation ground truth.
You submit
Task_2_USER_ID_submission.csv with 500 rows, one integer 0-9 per row, no header, plus the executed notebook Task_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.

Details

Year
2026, Mathematics High School 'Akad. Kiril Popov', Plovdiv, Bulgaria
Round
National Competition in AI, final (in-person) round · Task 2
Language
Bulgarian; English translation by SOTA
License
Not stated by the source