Skip to content

⚡ Bolt: [performance improvement] Optimize solution lookup to O(N) hash map#132

Open
glacy wants to merge 1 commit into
mainfrom
bolt/optimize-solution-lookup-12094407777118020402
Open

⚡ Bolt: [performance improvement] Optimize solution lookup to O(N) hash map#132
glacy wants to merge 1 commit into
mainfrom
bolt/optimize-solution-lookup-12094407777118020402

Conversation

@glacy

@glacy glacy commented Jun 13, 2026

Copy link
Copy Markdown
Owner

💡 What: The O(NM) inner loop used to find solutions for exercises was replaced by building an O(N) lookup dictionary first.
🎯 Why: Iterating over solutions for every single exercise was scaling poorly when extracting large files or large volumes of material. By pre-building a dictionary grouped by the target label, we get amortized O(1) matching per exercise.
📊 Impact: Reduces computational complexity from O(N
M) to O(N+M) during both indexing and extraction operations, leading to notably faster execution for large materials directories.
🔬 Measurement: Verify changes in Evolutia test suite executions involving MaterialExtractor and RAGIndexer, where parsing time should demonstrably scale better. Tests continue to pass confirming behavioral equivalence.


PR created automatically by Jules for task 12094407777118020402 started by @glacy

…utions to exercises

Co-authored-by: glacy <1131951+glacy@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

Copilot AI review requested due to automatic review settings June 13, 2026 17:41

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR optimizes solution lookup during indexing/extraction by replacing per-exercise linear scans over solutions with a precomputed dictionary keyed by exercise_label, reducing the hot path from O(N*M) to O(N+M) per material.

Changes:

  • Build solutions_by_label dict once per material to speed up matching in RAGIndexer.index_materials().
  • Apply the same dict-based solution lookup optimization in MaterialExtractor.get_all_exercises().
  • Formatting/consistency updates (quotes, wrapping) across the touched modules.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
evolutia/rag/rag_indexer.py Adds per-material solutions_by_label lookup and includes broad reformatting of the module.
evolutia/material_extractor.py Uses per-material solutions_by_label in get_all_exercises() and applies formatting/consistency updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +159 to 160
elif self.embedding_provider == "sentence-transformers":
return self.embedding_model.encode(text, show_progress_bar=False).tolist()
Comment on lines +197 to +200
elif self.embedding_provider == "sentence-transformers":
return self.embedding_model.encode(
texts, show_progress_bar=True, batch_size=32
).tolist()
Comment on lines +288 to +300
# Generar embeddings
embeddings = self._generate_embeddings_batch(chunks)

# Sincronizar chunks con embeddings (por si se filtraron vacíos en _generate_embeddings_batch)
# Aunque aquí preferimos filtrar antes para mantener consistencia
valid_indices = [i for i, chunk in enumerate(chunks) if chunk and chunk.strip()]
chunks = [chunks[i] for i in valid_indices]

if not chunks:
logger.warning(
f"Ejercicio {exercise.get('label', 'unknown')} no tiene contenido válido para indexar"
)
return []
Comment on lines +343 to +359
chunks = self._chunk_text(content, chunk_size, chunk_overlap)

# Preparar metadatos
chunk_metadata = {"type": "reading", **metadata}

# Generar embeddings
embeddings = self._generate_embeddings_batch(chunks)

# Sincronizar chunks con embeddings
valid_indices = [i for i, chunk in enumerate(chunks) if chunk and chunk.strip()]
chunks = [chunks[i] for i in valid_indices]

if not chunks:
logger.warning(
f"Lectura {metadata.get('title', 'unknown')} no tiene contenido válido para indexar"
)
return []
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants