# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: percent
#       format_version: '1.3'
#       jupytext_version: 1.17.1
# ---

# %% [markdown]
"""
# Setup - TinyTorch Development Environment Configuration

Welcome to the Setup module! You'll configure your development environment and master the foundation of professional ML systems development.

## Learning Goals
- Systems understanding: How environment configuration affects ML system reproducibility and performance
- Core implementation skill: Build system configuration and introspection capabilities
- Pattern recognition: Understand how professional ML teams manage development environments
- Framework connection: See how PyTorch handles environment detection and hardware optimization
- Performance insight: Learn why proper environment setup is critical for ML system performance

## Build → Use → Reflect
1. **Build**: System configuration and environment detection functions
2. **Use**: Configure your personal TinyTorch installation with environment-aware settings
3. **Reflect**: Why do ML systems fail when environments differ between development and production?

## What You'll Achieve
By the end of this module, you'll understand:
- Deep technical understanding of how ML systems detect and adapt to their runtime environment
- Practical capability to build robust configuration systems that work across different platforms
- Systems insight into why environment reproducibility is critical for ML system reliability
- Performance consideration of how hardware detection enables automatic optimization choices
- Connection to production ML systems and how frameworks like PyTorch handle cross-platform deployment

## Systems Reality Check
💡 **Production Context**: PyTorch automatically detects CUDA availability and optimizes operations based on hardware - your configuration system enables similar adaptability
⚡ **Performance Note**: Environment detection happens once at startup, but configuration choices affect every operation - design for minimal runtime overhead

Let's build the foundation of your ML systems engineering skills!
"""

# %% nbgrader={"grade": false, "grade_id": "setup-imports", "locked": false, "schema_version": 3, "solution": false, "task": false}
#| default_exp core.setup

#| export
import sys
import platform
import psutil
from typing import Dict, Any

# %% nbgrader={"grade": false, "grade_id": "setup-verification", "locked": false, "schema_version": 3, "solution": false, "task": false}
print("🔥 TinyTorch Setup Module")
print(f"Python version: {sys.version_info.major}.{sys.version_info.minor}")
print(f"Platform: {platform.system()}")
print("Ready to configure your TinyTorch installation!")

# %% [markdown]
"""
## 🏗️ The Architecture of ML Systems Configuration

### Configuration Layers in Production ML
Real ML systems have multiple configuration layers:

```
┌─────────────────────────────────────┐
│        Application Config           │  ← Your personal info
├─────────────────────────────────────┤
│        System Environment           │  ← Hardware specs
├─────────────────────────────────────┤
│        Runtime Configuration        │  ← Python, libraries
├─────────────────────────────────────┤
│        Infrastructure Config        │  ← Cloud, containers
└─────────────────────────────────────┘
```

### Why Each Layer Matters
- **Application**: Identifies who built what and when
- **System**: Determines performance characteristics and limitations
- **Runtime**: Affects compatibility and feature availability
- **Infrastructure**: Enables scaling and deployment strategies

### Connection to Real ML Frameworks
Every major ML framework has configuration:
- **PyTorch**: `torch.cuda.is_available()`, `torch.get_num_threads()`
- **TensorFlow**: `tf.config.list_physical_devices()`, `tf.sysconfig.get_build_info()`
- **Hugging Face**: Model cards with system requirements and performance metrics
- **MLflow**: Experiment tracking with system context and reproducibility

### TinyTorch's Approach
We'll build configuration that's:
- **Educational**: Teaches system awareness
- **Practical**: Actually useful for debugging
- **Professional**: Follows industry standards
- **Extensible**: Ready for future ML systems features
"""

# %% [markdown]
"""
## Step 1: What is System Configuration?

### Definition
**System configuration** is the process of setting up your development environment with personalized information and system diagnostics. In TinyTorch, this means:

- **Personal Information**: Your name, email, institution for identification
- **System Information**: Hardware specs, Python version, platform details
- **Customization**: Making your TinyTorch installation uniquely yours

### Why Configuration Matters in ML Systems
Proper system configuration is crucial because:

#### 1. **Reproducibility** 
Your setup can be documented and shared:
```python
# Someone else can recreate your environment
config = {
    'developer': 'Your Name',
    'python_version': '3.9.7',
    'platform': 'Darwin',
    'memory_gb': 16.0
}
```

#### 2. **Debugging**
System info helps troubleshoot ML performance issues:
- **Memory errors**: "Do I have enough RAM for this model?"
- **Performance issues**: "How many CPU cores can I use?"
- **Compatibility problems**: "What Python version am I running?"

#### 3. **Professional Development**
Shows proper engineering practices:
- **Attribution**: Your work is properly credited
- **Collaboration**: Others can contact you about your code
- **Documentation**: System context is preserved

#### 4. **ML Systems Integration**
Connects to broader ML engineering:
- **Model cards**: Document system requirements
- **Experiment tracking**: Record hardware context
- **Deployment**: Match development to production environments

### Real-World Examples
- **Google Colab**: Shows GPU type, RAM, disk space
- **Kaggle**: Displays system specs for reproducibility
- **MLflow**: Tracks system context with experiments
- **Docker**: Containerizes entire system configuration

Let's start configuring your TinyTorch system!
"""


# %% [markdown]
"""
## Step 2: Personal Information Configuration

### The Concept: Identity in ML Systems
Your **personal information** identifies you as the developer and configures your TinyTorch installation. This isn't just administrative - it's foundational to professional ML development.

### Why Personal Info Matters in ML Engineering

#### 1. **Attribution and Accountability**
- **Model ownership**: Who built this model?
- **Responsibility**: Who should be contacted about issues?
- **Credit**: Proper recognition for your work

#### 2. **Collaboration and Communication**
- **Team coordination**: Multiple developers on ML projects
- **Knowledge sharing**: Others can learn from your work
- **Bug reports**: Contact info for issues and improvements

#### 3. **Professional Standards**
- **Industry practice**: All professional software has attribution
- **Open source**: Proper credit in shared code
- **Academic integrity**: Clear authorship in research

#### 4. **System Customization**
- **Personalized experience**: Your TinyTorch installation
- **Unique identification**: Distinguish your work from others
- **Development tracking**: Link code to developer

### Real-World Parallels
- **Git commits**: Author name and email in every commit
- **Docker images**: Maintainer information in container metadata
- **Python packages**: Author info in `setup.py` and `pyproject.toml`
- **Model cards**: Creator information for ML models

### Best Practices for Personal Configuration
- **Use real information**: Not placeholders or fake data
- **Professional email**: Accessible and appropriate
- **Descriptive system name**: Unique and meaningful
- **Consistent formatting**: Follow established conventions

Now let's implement your personal configuration!
"""

# %% [markdown]
"""
### Before We Code: The 5 C's

```python
# CONCEPT: What is Personal Information Configuration?
# Developer identity configuration that identifies you as the creator and
# configures your TinyTorch installation. Think Git commit attribution -
# every professional system needs to know who built it.

# CODE STRUCTURE: What We're Building  
def personal_info() -> Dict[str, str]:     # Returns developer identity
    return {                               # Dictionary with required fields
        'developer': 'Your Name',         # Your actual name
        'email': 'your@domain.com',       # Contact information
        'institution': 'Your Place',      # Affiliation
        'system_name': 'YourName-Dev',    # Unique system identifier
        'version': '1.0.0'                # Configuration version
    }

# CONNECTIONS: Real-World Equivalents
# Git commits - author name and email in every commit
# Docker images - maintainer information in container metadata
# Python packages - author info in setup.py and pyproject.toml
# Model cards - creator information for ML models

# CONSTRAINTS: Key Implementation Requirements
# - Use actual information (not placeholder text)
# - Email must be valid format (contains @ and domain)
# - System name should be unique and descriptive
# - All values must be strings, version stays '1.0.0'

# CONTEXT: Why This Matters in ML Systems
# Professional ML development requires attribution:
# - Model ownership: Who built this neural network?
# - Collaboration: Others can contact you about issues
# - Professional standards: Industry practice for all software
# - System customization: Makes your TinyTorch installation unique
```

**You're establishing your identity in the ML systems world.**
"""

# %% nbgrader={"grade": false, "grade_id": "personal-info", "locked": false, "schema_version": 3, "solution": true, "task": false}
#| export
def personal_info() -> Dict[str, str]:
    """
    Return personal information for this TinyTorch installation.
    
    This function configures your personal TinyTorch installation with your identity.
    It's the foundation of proper ML engineering practices - every system needs
    to know who built it and how to contact them.
    
    TODO: Implement personal information configuration.
    
    STEP-BY-STEP IMPLEMENTATION:
    1. Create a dictionary with your personal details
    2. Include all required keys: developer, email, institution, system_name, version
    3. Use your actual information (not placeholder text)
    4. Make system_name unique and descriptive
    5. Keep version as '1.0.0' for now
    
    EXAMPLE USAGE:
    ```python
    # Get your personal configuration
    info = personal_info()
    print(info['developer'])     # Expected: "Your Name" (not placeholder)
    print(info['email'])         # Expected: "you@domain.com" (valid email)
    print(info['system_name'])   # Expected: "YourName-Dev" (unique identifier)
    print(info)                  # Expected: Complete dict with 5 fields
    # Output: {
    #     'developer': 'Your Name',
    #     'email': 'you@domain.com',
    #     'institution': 'Your Institution',
    #     'system_name': 'YourName-TinyTorch-Dev',
    #     'version': '1.0.0'
    # }
    ```
    
    IMPLEMENTATION HINTS:
    - Replace the example with your real information
    - Use a descriptive system_name (e.g., 'YourName-TinyTorch-Dev')
    - Keep email format valid (contains @ and domain)
    - Make sure all values are strings
    - Consider how this info will be used in debugging and collaboration
    
    LEARNING CONNECTIONS:
    - This is like the 'author' field in Git commits
    - Similar to maintainer info in Docker images
    - Parallels author info in Python packages
    - Foundation for professional ML development
    """
    ### BEGIN SOLUTION
    return {
        'developer': 'Student Name',
        'email': 'student@university.edu',
        'institution': 'University Name',
        'system_name': 'StudentName-TinyTorch-Dev',
        'version': '1.0.0'
    }
    ### END SOLUTION

# %% [markdown]
"""
### 🧪 Unit Test: Personal Information Configuration

This test validates your `personal_info()` function implementation, ensuring it returns properly formatted developer information for system attribution and collaboration.
"""

# %% nbgrader={"grade": true, "grade_id": "test-personal-info-immediate", "locked": true, "points": 5, "schema_version": 3, "solution": false, "task": false}
def test_unit_personal_info_basic():
    """Test personal_info function implementation."""
    print("🔬 Unit Test: Personal Information...")
    
    # Test personal_info function
    personal = personal_info()
    
    # Test return type
    assert isinstance(personal, dict), "personal_info should return a dictionary"
    
    # Test required keys
    required_keys = ['developer', 'email', 'institution', 'system_name', 'version']
    for key in required_keys:
        assert key in personal, f"Dictionary should have '{key}' key"
    
    # Test non-empty values
    for key, value in personal.items():
        assert isinstance(value, str), f"Value for '{key}' should be a string"
        assert len(value) > 0, f"Value for '{key}' cannot be empty"
    
    # Test email format
    assert '@' in personal['email'], "Email should contain @ symbol"
    assert '.' in personal['email'], "Email should contain domain"
    
    # Test version format
    assert personal['version'] == '1.0.0', "Version should be '1.0.0'"
    
    # Test system name (should be unique/personalized)
    assert len(personal['system_name']) > 5, "System name should be descriptive"
    
    print("✅ Personal info function tests passed!")
    print(f"✅ TinyTorch configured for: {personal['developer']}")

# Test function defined (called in main block)

# %% [markdown]
"""
## Step 3: System Information Queries

### The Concept: Hardware-Aware ML Systems
**System information** provides details about your hardware and software environment. This is crucial for ML development because machine learning is fundamentally about computation, and computation depends on hardware.

### Why System Information Matters in ML Engineering

#### 1. **Performance Optimization**
- **CPU cores**: Determines parallelization strategies
- **Memory**: Limits batch size and model size
- **Architecture**: Affects numerical precision and optimization

#### 2. **Compatibility and Debugging**
- **Python version**: Determines available features and libraries
- **Platform**: Affects file paths, process management, and system calls
- **Architecture**: Influences numerical behavior and optimization

#### 3. **Resource Planning**
- **Training time estimation**: More cores = faster training
- **Memory requirements**: Avoid out-of-memory errors
- **Deployment matching**: Development should match production

#### 4. **Reproducibility**
- **Environment documentation**: Exact system specifications
- **Performance comparison**: Same code, different hardware
- **Bug reproduction**: System-specific issues

### The Python System Query Toolkit
You'll learn to use these essential Python modules:

#### `sys.version_info` - Python Version
```python
version_info = sys.version_info
python_version = f"{version_info.major}.{version_info.minor}.{version_info.micro}"
# Example: "3.9.7"
```

#### `platform.system()` - Operating System
```python
platform_name = platform.system()
# Examples: "Darwin" (macOS), "Linux", "Windows"
```

#### `platform.machine()` - CPU Architecture
```python
architecture = platform.machine()
# Examples: "x86_64", "arm64", "aarch64"
```

#### `psutil.cpu_count()` - CPU Cores
```python
cpu_count = psutil.cpu_count()
# Example: 8 (cores available for parallel processing)
```

#### `psutil.virtual_memory().total` - Total RAM
```python
memory_bytes = psutil.virtual_memory().total
memory_gb = round(memory_bytes / (1024**3), 1)
# Example: 16.0 GB
```

### Real-World Applications
- **PyTorch**: `torch.get_num_threads()` uses CPU count
- **TensorFlow**: `tf.config.list_physical_devices()` queries hardware
- **Scikit-learn**: `n_jobs=-1` uses all available cores
- **Dask**: Automatically configures workers based on CPU count

### ML Systems Performance Considerations
- **Memory-bound operations**: Matrix multiplication, large model loading
- **CPU-bound operations**: Data preprocessing, feature engineering
- **I/O-bound operations**: Data loading, model saving
- **Platform-specific optimizations**: SIMD instructions, memory management

Now let's implement system information queries!
"""

# %% [markdown]
"""
### Before We Code: The 5 C's

```python
# CONCEPT: What is System Information?
# Hardware and software environment detection for ML systems.
# Think computer specifications for gaming - ML needs to know what
# resources are available for optimal performance.

# CODE STRUCTURE: What We're Building  
def system_info() -> Dict[str, Any]:       # Queries system specs
    return {                               # Hardware/software details
        'python_version': '3.9.7',        # Python compatibility
        'platform': 'Darwin',             # Operating system
        'architecture': 'arm64',          # CPU architecture
        'cpu_count': 8,                   # Parallel processing cores
        'memory_gb': 16.0                 # Available RAM
    }

# CONNECTIONS: Real-World Equivalents
# torch.get_num_threads() (PyTorch) - uses CPU count for optimization
# tf.config.list_physical_devices() (TensorFlow) - queries hardware
# psutil.cpu_count() (System monitoring) - same underlying queries
# MLflow system tracking - documents environment for reproducibility

# CONSTRAINTS: Key Implementation Requirements
# - Use actual system queries (not hardcoded values)
# - Convert memory from bytes to GB for readability
# - Round memory to 1 decimal place for clean output
# - Return proper data types (strings, int, float)

# CONTEXT: Why This Matters in ML Systems
# Hardware awareness enables performance optimization:
# - Training: More CPU cores = faster data processing
# - Memory: Determines maximum model and batch sizes
# - Debugging: System specs help troubleshoot performance issues
# - Reproducibility: Document exact environment for experiment tracking
```

**You're building hardware-aware ML systems that adapt to their environment.**
"""

# %% nbgrader={"grade": false, "grade_id": "system-info", "locked": false, "schema_version": 3, "solution": true, "task": false}
#| export
def system_info() -> Dict[str, Any]:
    """
    Query and return system information for this TinyTorch installation.
    
    This function gathers crucial hardware and software information that affects
    ML performance, compatibility, and debugging. It's the foundation of 
    hardware-aware ML systems.
    
    TODO: Implement system information queries.
    
    STEP-BY-STEP IMPLEMENTATION:
    1. Get Python version using sys.version_info
    2. Get platform using platform.system()
    3. Get architecture using platform.machine()
    4. Get CPU count using psutil.cpu_count()
    5. Get memory using psutil.virtual_memory().total
    6. Convert memory from bytes to GB (divide by 1024^3)
    7. Return all information in a dictionary
    
    EXAMPLE USAGE:
    ```python
    # Query system information
    sys_info = system_info()
    print(f"Python: {sys_info['python_version']}")  # Expected: "3.x.x"
    print(f"Platform: {sys_info['platform']}")      # Expected: "Darwin"/"Linux"/"Windows"
    print(f"CPUs: {sys_info['cpu_count']}")         # Expected: 4, 8, 16, etc.
    print(f"Memory: {sys_info['memory_gb']} GB")    # Expected: 8.0, 16.0, 32.0, etc.
    
    # Full output example:
    print(sys_info)
    # Expected: {
    #     'python_version': '3.9.7',
    #     'platform': 'Darwin',
    #     'architecture': 'arm64', 
    #     'cpu_count': 8,
    #     'memory_gb': 16.0
    # }
    ```
    
    IMPLEMENTATION HINTS:
    - Use f-string formatting for Python version: f"{major}.{minor}.{micro}"
    - Memory conversion: bytes / (1024^3) = GB
    - Round memory to 1 decimal place for readability
    - Make sure data types are correct (strings for text, int for cpu_count, float for memory_gb)
    
    LEARNING CONNECTIONS:
    - This is like `torch.cuda.is_available()` in PyTorch
    - Similar to system info in MLflow experiment tracking
    - Parallels hardware detection in TensorFlow
    - Foundation for performance optimization in ML systems
    
    PERFORMANCE IMPLICATIONS:
    - cpu_count affects parallel processing capabilities
    - memory_gb determines maximum model and batch sizes
    - platform affects file system and process management
    - architecture influences numerical precision and optimization
    """
    ### BEGIN SOLUTION
    # Get Python version
    version_info = sys.version_info
    python_version = f"{version_info.major}.{version_info.minor}.{version_info.micro}"
    
    # Get platform information
    platform_name = platform.system()
    architecture = platform.machine()
    
    # Get CPU information
    cpu_count = psutil.cpu_count()
    
    # Get memory information (convert bytes to GB)
    memory_bytes = psutil.virtual_memory().total
    memory_gb = round(memory_bytes / (1024**3), 1)
    
    return {
        'python_version': python_version,
        'platform': platform_name,
        'architecture': architecture,
        'cpu_count': cpu_count,
        'memory_gb': memory_gb
    }
    ### END SOLUTION

# %% [markdown]
"""
### 🧪 Unit Test: System Information Query

This test validates your `system_info()` function implementation, ensuring it accurately detects and reports hardware and software specifications for performance optimization and debugging.
"""

# %% nbgrader={"grade": true, "grade_id": "test-system-info-immediate", "locked": true, "points": 5, "schema_version": 3, "solution": false, "task": false}
def test_unit_system_info_basic():
    """Test system_info function implementation."""
    print("🔬 Unit Test: System Information...")
    
    # Test system_info function
    sys_info = system_info()
    
    # Test return type
    assert isinstance(sys_info, dict), "system_info should return a dictionary"
    
    # Test required keys
    required_keys = ['python_version', 'platform', 'architecture', 'cpu_count', 'memory_gb']
    for key in required_keys:
        assert key in sys_info, f"Dictionary should have '{key}' key"
    
    # Test data types
    assert isinstance(sys_info['python_version'], str), "python_version should be string"
    assert isinstance(sys_info['platform'], str), "platform should be string"
    assert isinstance(sys_info['architecture'], str), "architecture should be string"
    assert isinstance(sys_info['cpu_count'], int), "cpu_count should be integer"
    assert isinstance(sys_info['memory_gb'], (int, float)), "memory_gb should be number"
    
    # Test reasonable values
    assert sys_info['cpu_count'] > 0, "CPU count should be positive"
    assert sys_info['memory_gb'] > 0, "Memory should be positive"
    assert len(sys_info['python_version']) > 0, "Python version should not be empty"
    
    # Test that values are actually queried (not hardcoded)
    actual_version = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
    assert sys_info['python_version'] == actual_version, "Python version should match actual system"
    
    print("✅ System info function tests passed!")
    print(f"✅ Python: {sys_info['python_version']} on {sys_info['platform']}")

# %% [markdown]
"""
### 🎯 Additional Comprehensive Tests

These comprehensive tests validate that your configuration functions work together and integrate properly with the TinyTorch system.
"""

# Test function defined (called in main block)

# %% [markdown]
"""
## 🧪 Testing Your Configuration Functions

### The Importance of Testing in ML Systems
Before we test your implementation, let's understand why testing is crucial in ML systems:

#### 1. **Reliability**
- **Function correctness**: Does your code do what it's supposed to?
- **Edge case handling**: What happens with unexpected inputs?
- **Error detection**: Catch bugs before they cause problems

#### 2. **Reproducibility**
- **Consistent behavior**: Same inputs always produce same outputs
- **Environment validation**: Ensure setup works across different systems
- **Regression prevention**: New changes don't break existing functionality

#### 3. **Professional Development**
- **Code quality**: Well-tested code is maintainable code
- **Collaboration**: Others can trust and extend your work
- **Documentation**: Tests serve as executable documentation

#### 4. **ML-Specific Concerns**
- **Data validation**: Ensure data types and shapes are correct
- **Performance verification**: Check that optimizations work
- **System compatibility**: Verify cross-platform behavior

### Testing Strategy
We'll use comprehensive testing that checks:
- **Return types**: Are outputs the correct data types?
- **Required fields**: Are all expected keys present?
- **Data validation**: Are values reasonable and properly formatted?
- **System accuracy**: Do queries match actual system state?

Now let's test your configuration functions!
"""

if __name__ == "__main__":
    # Run the unit tests
    test_unit_personal_info_basic()
    test_unit_system_info_basic()
    
    print("All tests passed!")
    print("Setup module complete!")


# %% [markdown]
"""
## 🤔 ML Systems Thinking: Interactive Questions

Now that you've built configuration management for your TinyTorch system, let's connect this foundational work to broader ML systems challenges. These questions help you think critically about how basic setup principles scale to production ML environments.

Take time to reflect thoughtfully on each question - your insights will help you understand how the configuration concepts you've implemented connect to real-world ML systems engineering.
"""

# %% [markdown]
"""
### Question 1: Team Development Configuration

**Context**: You've implemented personal configuration for individual TinyTorch development. In real ML teams, multiple developers, data scientists, and engineers collaborate on shared models and infrastructure.

**Reflection Question**: How would you design a configuration system that balances individual developer identity with team coordination needs in a production ML environment? Consider scenarios where teams share GPU clusters, model registries, and deployment pipelines while maintaining individual accountability and debugging capabilities.

Think about: individual vs shared resources, conflict resolution, attribution tracking, and environment standardization.

*Target length: 150-300 words*
"""

# %% nbgrader={"grade": true, "grade_id": "question-1-team-config", "locked": false, "points": 10, "schema_version": 3, "solution": true, "task": false}
"""
YOUR REFLECTION ON TEAM DEVELOPMENT CONFIGURATION:

TODO: Replace this text with your thoughtful response about designing configuration systems for team-based ML development.

Consider addressing:
- How would you maintain individual identity while enabling team coordination?
- What information would be shared vs. personal in a team configuration system?
- How would you handle resource conflicts when multiple developers need GPU access?
- What role would configuration play in debugging issues across team environments?
- How might team configuration differ from individual configuration?

Write a thoughtful analysis connecting your setup module experience to real team challenges.

GRADING RUBRIC (Instructor Use):
- Demonstrates understanding of individual vs team configuration needs (3 points)
- Addresses resource sharing and conflict resolution challenges (3 points)  
- Connects setup module concepts to real team scenarios (2 points)
- Shows systems thinking about scalability and coordination (2 points)
- Clear writing and practical insights (bonus points for exceptional responses)
"""

### BEGIN SOLUTION
# Student response area - instructor will replace this section during grading setup
# This is a manually graded question requiring thoughtful analysis of team configuration challenges
# Students should demonstrate understanding of balancing individual accountability with team coordination
### END SOLUTION

# %% [markdown]
"""
### Question 2: Hardware-Aware System Design

**Context**: Your system_info() function detects CPU cores, memory, and architecture. In production ML systems, this hardware awareness becomes critical for performance optimization and automated resource allocation.

**Reflection Question**: Design a hardware-aware configuration system that automatically adapts ML training strategies based on detected resources. How would your system handle the transition from development (8GB laptop) to training (64GB GPU server) to inference (edge device with 2GB)? What configuration decisions would be automated vs. manual?

Think about: automatic batch size scaling, parallelization strategies, memory management, and deployment target optimization.

*Target length: 150-300 words*
"""

# %% nbgrader={"grade": true, "grade_id": "question-2-hardware-aware", "locked": false, "points": 10, "schema_version": 3, "solution": true, "task": false}
"""
YOUR REFLECTION ON HARDWARE-AWARE SYSTEM DESIGN:

TODO: Replace this text with your thoughtful response about hardware-aware configuration systems.

Consider addressing:
- How would your system automatically adapt training parameters based on detected hardware?
- What would you do differently for development vs. training vs. inference environments?
- How would you handle memory constraints and batch size optimization automatically?
- What configuration decisions should be automated vs. left to manual tuning?
- How would your system gracefully handle resource limitations?

Write a practical design connecting your system_info() implementation to real performance challenges.

GRADING RUBRIC (Instructor Use):
- Shows understanding of hardware constraints impact on ML performance (3 points)
- Designs practical automated adaptation strategies (3 points)
- Addresses different deployment environments appropriately (2 points)
- Demonstrates systems thinking about resource optimization (2 points)
- Clear design reasoning and practical considerations (bonus points for innovative approaches)
"""

### BEGIN SOLUTION
# Student response area - instructor will replace this section during grading setup  
# This is a manually graded question requiring design thinking about hardware-aware systems
# Students should demonstrate understanding of automatic adaptation based on hardware detection
### END SOLUTION

# %% [markdown]
"""
### Question 3: Configuration in Production ML Pipelines

**Context**: Your configuration functions provide system information and personal attribution. In production ML pipelines, configuration becomes part of model lineage, experiment tracking, and compliance requirements.

**Reflection Question**: How would configuration management integrate with modern ML operations (MLOps) tools for model deployment and monitoring? Consider a scenario where your model needs to be deployed across multiple environments with different compliance requirements, monitoring needs, and performance targets. What configuration information becomes part of the model artifact vs. environment-specific?

Think about: model lineage tracking, compliance auditing, A/B testing configuration, and production monitoring requirements.

*Target length: 150-300 words*
"""

# %% nbgrader={"grade": true, "grade_id": "question-3-production-config", "locked": false, "points": 10, "schema_version": 3, "solution": true, "task": false}
"""
YOUR REFLECTION ON PRODUCTION ML PIPELINE CONFIGURATION:

TODO: Replace this text with your thoughtful response about configuration in production ML systems.

Consider addressing:
- How would configuration information become part of model lineage and audit trails?
- What configuration would be bundled with the model vs. environment-specific?
- How would your configuration system support A/B testing and deployment strategies?
- What role would configuration play in monitoring and debugging production issues?
- How would compliance requirements (data governance, model validation) affect configuration design?

Write an analysis connecting your setup module concepts to MLOps and production deployment challenges.

GRADING RUBRIC (Instructor Use):
- Understands configuration role in model lineage and compliance (3 points)
- Addresses model artifact vs. environment configuration separation (3 points)
- Shows awareness of MLOps integration challenges (2 points)
- Demonstrates production systems thinking (2 points)
- Clear analysis with practical MLOps insights (bonus points for deep understanding)
"""

### BEGIN SOLUTION
# Student response area - instructor will replace this section during grading setup
# This is a manually graded question requiring understanding of production ML configuration challenges  
# Students should demonstrate understanding of configuration in MLOps and production deployment contexts
### END SOLUTION

# %% [markdown]
"""
## 🎯 MODULE SUMMARY: Setup Configuration

You've successfully configured your TinyTorch installation and learned the foundations of ML systems engineering:

### What You've Accomplished
✅ **Personal Configuration**: Set up your identity and custom system name  
✅ **System Queries**: Learned to gather hardware and software information  
✅ **NBGrader Workflow**: Mastered solution blocks and automated testing  
✅ **Code Export**: Created functions that become part of your tinytorch package  
✅ **Professional Setup**: Established proper development practices  

### Key Concepts You've Learned

#### 1. **System Awareness**
- **Hardware constraints**: Understanding CPU, memory, and architecture limitations
- **Software dependencies**: Python version and platform compatibility
- **Performance implications**: How system specs affect ML workloads

#### 2. **Configuration Management**
- **Personal identification**: Professional attribution and contact information
- **Environment documentation**: Reproducible system specifications
- **Professional standards**: Industry-standard development practices

#### 3. **ML Systems Foundations**
- **Reproducibility**: System context for experiment tracking
- **Debugging**: Hardware info for performance troubleshooting
- **Collaboration**: Proper attribution and contact information

#### 4. **Development Workflow**
- **NBGrader integration**: Automated testing and grading
- **Code export**: Functions become part of production package
- **Testing practices**: Comprehensive validation of functionality

### Next Steps in Your ML Systems Journey

#### **Immediate Actions**
1. **Export your code**: `tito module export 01_setup`
2. **Test your installation**: 
   ```python
   from tinytorch.core.setup import personal_info, system_info
   print(personal_info())  # Your personal details
   print(system_info())    # System information
   ```
3. **Verify package integration**: Ensure your functions work in the tinytorch package

#### **Looking Ahead**
- **Module 1 (Tensor)**: Build the fundamental data structure for ML
- **Module 2 (Activations)**: Add nonlinearity for complex learning
- **Module 3 (Layers)**: Create the building blocks of neural networks
- **Module 4 (Networks)**: Compose layers into powerful architectures

#### **Course Progression**
You're now ready to build a complete ML system from scratch:
```
Setup → Tensor → Activations → Layers → Networks → CNN → DataLoader → 
Autograd → Optimizers → Training → Compression → Kernels → Benchmarking → MLOps
```

### Professional Development Milestone

You've taken your first step in ML systems engineering! This module taught you:
- **System thinking**: Understanding hardware and software constraints
- **Professional practices**: Proper attribution, testing, and documentation
- **Tool mastery**: NBGrader workflow and package development
- **Foundation building**: Creating reusable, tested, documented code

**Ready for the next challenge?** Let's build the foundation of ML systems with tensors!
"""
