diff --git a/reasoning_gym/core/attributes.py b/reasoning_gym/core/attributes.py new file mode 100644 index 00000000..658bcaf9 --- /dev/null +++ b/reasoning_gym/core/attributes.py @@ -0,0 +1,42 @@ +""" +Core definitions for curriculum attributes and types. +""" + +from typing import Dict, List, Union, Any, Set, Optional +from dataclasses import dataclass +from enum import Enum + +class AttributeType(Enum): + """Defines how attribute levels should be interpreted""" + STATIC = "static" # Each level is independent + UBOUND = "ubound" # Each level is an upper bound + APPEND = "append" # Each level includes all previous levels + +@dataclass +class AttributeDefinition: + """Defines a difficulty attribute with its possible levels and properties""" + levels: List[Any] + current_level: int + description: str + attr_type: AttributeType = AttributeType.STATIC # Default to static + + @classmethod + def validate_attributes(cls, attributes: Dict[str, 'AttributeDefinition'], valid_types: Set[AttributeType], curriculum: Optional[str] = None) -> None: + """ + Validates that all attributes use types from the valid_types set. + + Args: + attributes: Dictionary of attribute definitions + valid_types: Set of allowed AttributeTypes for this curriculum + curriculum: A string identifier for the curriculum or class that owns these attributes + + Raises: + ValueError: If any attribute uses an invalid type + """ + for name, attr in attributes.items(): + if attr.attr_type not in valid_types: + curriculum_class = f"{curriculum}." if curriculum else "" + raise ValueError( + f"Attribute '{curriculum_class}{name}' uses type {attr.attr_type.value} " + f"which is not in the curriculum's valid types: {[t.value for t in valid_types]}" + ) \ No newline at end of file diff --git a/reasoning_gym/curricula/arithmetic/chain_sum_curriculum.py b/reasoning_gym/curricula/arithmetic/chain_sum_curriculum.py new file mode 100644 index 00000000..3298733b --- /dev/null +++ b/reasoning_gym/curricula/arithmetic/chain_sum_curriculum.py @@ -0,0 +1,105 @@ +""" +Curriculum definition for the ChainSum exercise. +This file defines the templates, attributes, and difficulty levels for generating chain sum problems. +""" + +from typing import Dict, List, Union, Any +from reasoning_gym.core.attributes import AttributeDefinition, AttributeType + +# Define which attribute types are valid for this curriculum +ATTRIBUTE_TYPES = { + AttributeType.STATIC, # For base numbers + AttributeType.UBOUND, # For ranges like digits and terms + AttributeType.APPEND # For operators and notations +} + +# Curriculum definition +CURRICULUM_NAME = "ChainSumCurriculum" + +ATTRIBUTES = { + "num_digits": AttributeDefinition( + levels=[1, 2, 3, 4], + current_level=0, # Start with 1-digit numbers + description="Number of digits in each operand", + attr_type=AttributeType.UBOUND + ), + + "num_decimals": AttributeDefinition( + levels=[0, 1, 2], + current_level=0, # Start with integers + description="Number of decimal places in operands", + attr_type=AttributeType.UBOUND + ), + + "operators": AttributeDefinition( + levels=['+', '-', '*', '/', '**'], + current_level=0, # Start with basic operators + description="Set of operators that can be used, each level includes all previous operators", + attr_type=AttributeType.APPEND + ), + + "max_terms": AttributeDefinition( + levels=[2, 3, 4, 5], + current_level=0, # Start with 2 terms + description="Maximum number of terms in the expression", + attr_type=AttributeType.UBOUND + ), + + "sign": AttributeDefinition( + levels=['', '+', '-'], + current_level=0, # Start without negatives + description="Whether negative numbers are allowed", + attr_type=AttributeType.APPEND + ), + + "notation": AttributeDefinition( + levels=["regular", "scientific"], + current_level=0, + description="The notation to use for the expression", + attr_type=AttributeType.APPEND + ), + + "base": AttributeDefinition( + levels=[10, 2, 16], + current_level=0, + description="The base to use for the expression", + attr_type=AttributeType.STATIC + ) +} + +# Validate attributes use allowed types (and include the curriculum name in error messages) +AttributeDefinition.validate_attributes(ATTRIBUTES, ATTRIBUTE_TYPES, curriculum=CURRICULUM_NAME) + +# Template definitions +TEMPLATES = [ + { + "question": "What is {expression}?", + "answer": "{result}", + "metadata": {"type": "direct"} + }, + { + "question": "Calculate the following: {expression}", + "answer": "{result}", + "metadata": {"type": "direct"} + }, + { + "question": "Solve {expression}", + "answer": "{result}", + "metadata": {"type": "direct"} + } +] + +# Generator functions for placeholders +def generate_expression(attributes: Dict[str, Any]) -> Dict[str, str]: + """ + Generates an expression and its result based on current attribute levels. + This is a placeholder - actual implementation will be in the Exercise class. + + Args: + attributes: Dictionary of current attribute levels + + Returns: + Dict containing the expression and result as strings + """ + # This will be implemented in the Exercise class + pass \ No newline at end of file