diff --git a/reasoning_gym/algorithmic/__init__.py b/reasoning_gym/algorithmic/__init__.py index 876ae8c6..b70a1e8d 100644 --- a/reasoning_gym/algorithmic/__init__.py +++ b/reasoning_gym/algorithmic/__init__.py @@ -42,7 +42,11 @@ from .string_manipulation import StringManipulationConfig, StringManipulationCur from .string_splitting import StringSplittingConfig, StringSplittingDataset from .string_synthesis import StringSynthesisConfig, StringSynthesisDataset from .word_ladder import WordLadderConfig, WordLadderDataset -from .word_sequence_reversal import WordSequenceReversalConfig, WordSequenceReversalDataset +from .word_sequence_reversal import ( + WordSequenceReversalConfig, + WordSequenceReversalCurriculum, + WordSequenceReversalDataset, +) from .word_sorting import TextTransformation, WordSortingConfig, WordSortingCurriculum, WordSortingDataset __all__ = [ @@ -72,6 +76,7 @@ __all__ = [ "SentenceReorderingDataset", "WordSequenceReversalConfig", "WordSequenceReversalDataset", + "WordSequenceReversalCurriculum", "WordSortingCurriculum", "WordSortingConfig", "WordSortingDataset", @@ -120,6 +125,7 @@ __all__ = [ "StringInsertionCurriculum", "StringManipulationConfig", "StringManipulationDataset", + "StringManipulationCurriculum", "StringSplittingConfig", "StringSplittingDataset", "StringSynthesisConfig", diff --git a/reasoning_gym/algorithmic/word_sequence_reversal.py b/reasoning_gym/algorithmic/word_sequence_reversal.py index 84e297aa..3f120af1 100644 --- a/reasoning_gym/algorithmic/word_sequence_reversal.py +++ b/reasoning_gym/algorithmic/word_sequence_reversal.py @@ -5,10 +5,16 @@ from dataclasses import dataclass from random import Random from typing import Optional +from ..coaching import AttributeType, BaseCurriculum, RangeAttributeDefinition from ..data import read_data_file from ..factory import ProceduralDataset, register_dataset -QUESTION_TEMPLATE = """Solve the following problem. Provide you answer as a comma-separated list of words with a space after the comma. Reverse this list of words: {question}""" +QUESTION_TEMPLATE = """Solve the following problem. + +Provide you answer as a comma-separated list of words with a space after the comma. + +Reverse this list of words: {words} +""" @dataclass @@ -42,19 +48,43 @@ class WordSequenceReversalDataset(ProceduralDataset): rng = Random(self.seed + idx) # Select random words - num_words = rng.randint(self.config.min_words, self.config.max_words) + num_words = min( + rng.randint(self.config.min_words, self.config.max_words), + len(self.words), + ) word_indices = rng.sample(range(len(self.words)), num_words) words = [self.words[i] for i in word_indices] # Create question and answer - question = ", ".join(words) + words_str = ", ".join(words) answer = ", ".join(reversed(words)) return { - "question": f"{QUESTION_TEMPLATE.format(question=question)}", + "question": f"{QUESTION_TEMPLATE.format(words=words_str)}", "answer": answer, - "metadata": {"num_words": num_words, "words": words}, + "metadata": {"num_words": num_words, "words": words, "difficulty": {"words": num_words}}, } -register_dataset("word_sequence_reversal", WordSequenceReversalDataset, WordSequenceReversalConfig) +class WordSequenceReversalCurriculum(BaseCurriculum): + def __init__(self): + super().__init__(WordSequenceReversalCurriculum.__name__, WordSequenceReversalConfig) + + # Define attributes + self._define_attributes( + RangeAttributeDefinition( + name="words", + levels=[10, 50, 100, 500], + default_level=1, + description="Number of words in the list", + attr_type=AttributeType.APPEND, + min_value=2, + lower_field_name="min_words", + upper_field_name="max_words", + ), + ) + + +register_dataset( + "word_sequence_reversal", WordSequenceReversalDataset, WordSequenceReversalConfig, WordSequenceReversalCurriculum +) diff --git a/tests/test_word_sequence_reversal.py b/tests/test_word_sequence_reversal.py index a117bfba..1a7571b6 100644 --- a/tests/test_word_sequence_reversal.py +++ b/tests/test_word_sequence_reversal.py @@ -1,6 +1,10 @@ import pytest -from reasoning_gym.algorithmic.word_sequence_reversal import WordSequenceReversalConfig, WordSequenceReversalDataset +from reasoning_gym.algorithmic.word_sequence_reversal import ( + WordSequenceReversalConfig, + WordSequenceReversalCurriculum, + WordSequenceReversalDataset, +) def test_word_sequence_reversal_config_validation(): @@ -73,3 +77,24 @@ def test_word_sequence_reversal_text_preprocessing(): assert len(dataset.words) > 0 # Verify words contain only alphanumeric characters assert all(word.isalnum() for word in dataset.words) + + +def test_word_sequence_reversal_curriculum(): + curriculum = WordSequenceReversalCurriculum() + + base_value = {"size": 150, "seed": 1} + + base_cfg: WordSequenceReversalConfig = curriculum.generate_configuration(base_value) + assert base_cfg.seed == 1 + assert base_cfg.size == 150 + assert base_cfg.min_words == 10 and base_cfg.max_words == 50 + + # test incrementing attribute levels + curriculum.increment_attr_level("words") + increased_cfg = curriculum.generate_configuration(base_value) + assert increased_cfg.min_words == 10 and increased_cfg.max_words == 100 + + # test decrementing attribute level for words again + curriculum.decrement_attr_level("words") + partially_decreased_cfg = curriculum.generate_configuration(base_value) + assert partially_decreased_cfg.min_words == 10 and partially_decreased_cfg.max_words == 50