Unverified Commit c08c45ee authored by Utorque's avatar Utorque Committed by GitHub
Browse files

Merge pull request #7 from Utorque/claude/align-sim-data-generator-01HUQacsiojn3J1Kan2yE7Nw

Add sim_data_gen.py to forecast_app with generated JSON files
parents e3db5895 aee1bb0d
Loading
Loading
Loading
Loading
+7843 −0

File added.

Preview size limit exceeded, changes collapsed.

+710 −0
Original line number Diff line number Diff line
[
  {
    "month_index": 120,
    "year": 11,
    "month": 1,
    "date": "2023-11",
    "watches": [
      {
        "watch_id": 1,
        "watch_name": "Watch_0",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 773.58,
        "stockout_cost": 0.0,
        "total_costs": 773.58,
        "profit": -773.58
      },
      {
        "watch_id": 2,
        "watch_name": "Watch_1",
        "demand": 0,
        "production": 0,
        "inventory_start": 106,
        "inventory_end": 106,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 779.25,
        "stockout_cost": 0.0,
        "total_costs": 779.25,
        "profit": -779.25
      },
      {
        "watch_id": 3,
        "watch_name": "Watch_2",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 980.62,
        "stockout_cost": 0.0,
        "total_costs": 980.62,
        "profit": -980.62
      }
    ]
  },
  {
    "month_index": 121,
    "year": 11,
    "month": 2,
    "date": "2023-12",
    "watches": [
      {
        "watch_id": 1,
        "watch_name": "Watch_0",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 773.58,
        "stockout_cost": 0.0,
        "total_costs": 773.58,
        "profit": -773.58
      },
      {
        "watch_id": 2,
        "watch_name": "Watch_1",
        "demand": 0,
        "production": 0,
        "inventory_start": 106,
        "inventory_end": 106,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 779.25,
        "stockout_cost": 0.0,
        "total_costs": 779.25,
        "profit": -779.25
      },
      {
        "watch_id": 3,
        "watch_name": "Watch_2",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 980.62,
        "stockout_cost": 0.0,
        "total_costs": 980.62,
        "profit": -980.62
      }
    ]
  },
  {
    "month_index": 122,
    "year": 11,
    "month": 3,
    "date": "2024-01",
    "watches": [
      {
        "watch_id": 1,
        "watch_name": "Watch_0",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 773.58,
        "stockout_cost": 0.0,
        "total_costs": 773.58,
        "profit": -773.58
      },
      {
        "watch_id": 2,
        "watch_name": "Watch_1",
        "demand": 0,
        "production": 0,
        "inventory_start": 106,
        "inventory_end": 106,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 779.25,
        "stockout_cost": 0.0,
        "total_costs": 779.25,
        "profit": -779.25
      },
      {
        "watch_id": 3,
        "watch_name": "Watch_2",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 980.62,
        "stockout_cost": 0.0,
        "total_costs": 980.62,
        "profit": -980.62
      }
    ]
  },
  {
    "month_index": 123,
    "year": 11,
    "month": 4,
    "date": "2024-02",
    "watches": [
      {
        "watch_id": 1,
        "watch_name": "Watch_0",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 773.58,
        "stockout_cost": 0.0,
        "total_costs": 773.58,
        "profit": -773.58
      },
      {
        "watch_id": 2,
        "watch_name": "Watch_1",
        "demand": 0,
        "production": 0,
        "inventory_start": 106,
        "inventory_end": 106,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 779.25,
        "stockout_cost": 0.0,
        "total_costs": 779.25,
        "profit": -779.25
      },
      {
        "watch_id": 3,
        "watch_name": "Watch_2",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 980.62,
        "stockout_cost": 0.0,
        "total_costs": 980.62,
        "profit": -980.62
      }
    ]
  },
  {
    "month_index": 124,
    "year": 11,
    "month": 5,
    "date": "2024-03",
    "watches": [
      {
        "watch_id": 1,
        "watch_name": "Watch_0",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 773.58,
        "stockout_cost": 0.0,
        "total_costs": 773.58,
        "profit": -773.58
      },
      {
        "watch_id": 2,
        "watch_name": "Watch_1",
        "demand": 0,
        "production": 0,
        "inventory_start": 106,
        "inventory_end": 106,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 779.25,
        "stockout_cost": 0.0,
        "total_costs": 779.25,
        "profit": -779.25
      },
      {
        "watch_id": 3,
        "watch_name": "Watch_2",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 980.62,
        "stockout_cost": 0.0,
        "total_costs": 980.62,
        "profit": -980.62
      }
    ]
  },
  {
    "month_index": 125,
    "year": 11,
    "month": 6,
    "date": "2024-04",
    "watches": [
      {
        "watch_id": 1,
        "watch_name": "Watch_0",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 773.58,
        "stockout_cost": 0.0,
        "total_costs": 773.58,
        "profit": -773.58
      },
      {
        "watch_id": 2,
        "watch_name": "Watch_1",
        "demand": 0,
        "production": 0,
        "inventory_start": 106,
        "inventory_end": 106,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 779.25,
        "stockout_cost": 0.0,
        "total_costs": 779.25,
        "profit": -779.25
      },
      {
        "watch_id": 3,
        "watch_name": "Watch_2",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 980.62,
        "stockout_cost": 0.0,
        "total_costs": 980.62,
        "profit": -980.62
      }
    ]
  },
  {
    "month_index": 126,
    "year": 11,
    "month": 7,
    "date": "2024-05",
    "watches": [
      {
        "watch_id": 1,
        "watch_name": "Watch_0",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 773.58,
        "stockout_cost": 0.0,
        "total_costs": 773.58,
        "profit": -773.58
      },
      {
        "watch_id": 2,
        "watch_name": "Watch_1",
        "demand": 0,
        "production": 0,
        "inventory_start": 106,
        "inventory_end": 106,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 779.25,
        "stockout_cost": 0.0,
        "total_costs": 779.25,
        "profit": -779.25
      },
      {
        "watch_id": 3,
        "watch_name": "Watch_2",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 980.62,
        "stockout_cost": 0.0,
        "total_costs": 980.62,
        "profit": -980.62
      }
    ]
  },
  {
    "month_index": 127,
    "year": 11,
    "month": 8,
    "date": "2024-06",
    "watches": [
      {
        "watch_id": 1,
        "watch_name": "Watch_0",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 773.58,
        "stockout_cost": 0.0,
        "total_costs": 773.58,
        "profit": -773.58
      },
      {
        "watch_id": 2,
        "watch_name": "Watch_1",
        "demand": 0,
        "production": 0,
        "inventory_start": 106,
        "inventory_end": 106,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 779.25,
        "stockout_cost": 0.0,
        "total_costs": 779.25,
        "profit": -779.25
      },
      {
        "watch_id": 3,
        "watch_name": "Watch_2",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 980.62,
        "stockout_cost": 0.0,
        "total_costs": 980.62,
        "profit": -980.62
      }
    ]
  },
  {
    "month_index": 128,
    "year": 11,
    "month": 9,
    "date": "2024-07",
    "watches": [
      {
        "watch_id": 1,
        "watch_name": "Watch_0",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 773.58,
        "stockout_cost": 0.0,
        "total_costs": 773.58,
        "profit": -773.58
      },
      {
        "watch_id": 2,
        "watch_name": "Watch_1",
        "demand": 0,
        "production": 0,
        "inventory_start": 106,
        "inventory_end": 106,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 779.25,
        "stockout_cost": 0.0,
        "total_costs": 779.25,
        "profit": -779.25
      },
      {
        "watch_id": 3,
        "watch_name": "Watch_2",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 980.62,
        "stockout_cost": 0.0,
        "total_costs": 980.62,
        "profit": -980.62
      }
    ]
  },
  {
    "month_index": 129,
    "year": 11,
    "month": 10,
    "date": "2024-08",
    "watches": [
      {
        "watch_id": 1,
        "watch_name": "Watch_0",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 773.58,
        "stockout_cost": 0.0,
        "total_costs": 773.58,
        "profit": -773.58
      },
      {
        "watch_id": 2,
        "watch_name": "Watch_1",
        "demand": 0,
        "production": 0,
        "inventory_start": 106,
        "inventory_end": 106,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 779.25,
        "stockout_cost": 0.0,
        "total_costs": 779.25,
        "profit": -779.25
      },
      {
        "watch_id": 3,
        "watch_name": "Watch_2",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 980.62,
        "stockout_cost": 0.0,
        "total_costs": 980.62,
        "profit": -980.62
      }
    ]
  },
  {
    "month_index": 130,
    "year": 11,
    "month": 11,
    "date": "2024-09",
    "watches": [
      {
        "watch_id": 1,
        "watch_name": "Watch_0",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 773.58,
        "stockout_cost": 0.0,
        "total_costs": 773.58,
        "profit": -773.58
      },
      {
        "watch_id": 2,
        "watch_name": "Watch_1",
        "demand": 0,
        "production": 0,
        "inventory_start": 106,
        "inventory_end": 106,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 779.25,
        "stockout_cost": 0.0,
        "total_costs": 779.25,
        "profit": -779.25
      },
      {
        "watch_id": 3,
        "watch_name": "Watch_2",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 980.62,
        "stockout_cost": 0.0,
        "total_costs": 980.62,
        "profit": -980.62
      }
    ]
  },
  {
    "month_index": 131,
    "year": 11,
    "month": 12,
    "date": "2024-10",
    "watches": [
      {
        "watch_id": 1,
        "watch_name": "Watch_0",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 773.58,
        "stockout_cost": 0.0,
        "total_costs": 773.58,
        "profit": -773.58
      },
      {
        "watch_id": 2,
        "watch_name": "Watch_1",
        "demand": 0,
        "production": 0,
        "inventory_start": 106,
        "inventory_end": 106,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 779.25,
        "stockout_cost": 0.0,
        "total_costs": 779.25,
        "profit": -779.25
      },
      {
        "watch_id": 3,
        "watch_name": "Watch_2",
        "demand": 0,
        "production": 0,
        "inventory_start": 108,
        "inventory_end": 108,
        "units_sold": 0,
        "stockout_units": 0,
        "revenue": 0,
        "production_cost": 0.0,
        "labor_cost": 0.0,
        "holding_cost": 980.62,
        "stockout_cost": 0.0,
        "total_costs": 980.62,
        "profit": -980.62
      }
    ]
  }
]
 No newline at end of file
+7136 −0

File added.

Preview size limit exceeded, changes collapsed.

+155 −0
Original line number Diff line number Diff line
"""
Simulation-based Data Generator for Supply Chain Forecasting Educational App

Uses the full supply chain simulation to generate realistic data for 3 watch models.
This generates more realistic data compared to the simple data_generator.py as it
uses the complete simulation with all supply chain entities and dynamics.
"""

import sys
import os
import json
import numpy as np
from typing import Dict, List

# Add parent directory to path to import supply_chain_sim
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from supply_chain_sim import gen_data


def get_training_data(dataset: Dict, training_years: int = 10) -> Dict:
    """
    Extract training data (first N years) from full dataset

    Args:
        dataset: Full dataset
        training_years: Number of years to include in training set

    Returns:
        Dictionary with training data only
    """
    training_months = training_years * 12

    training_data = {
        'metadata': dataset['metadata'].copy(),
        'historical_data': dataset['historical_data'][:training_months]
    }
    training_data['metadata']['years'] = training_years
    training_data['metadata']['total_months'] = training_months
    training_data['metadata']['note'] = f"Training data: first {training_years} years"

    return training_data


def get_test_data(dataset: Dict, test_year: int = 11) -> List[Dict]:
    """
    Extract test data (year to predict)

    Args:
        dataset: Full dataset
        test_year: Year number to extract (1-based)

    Returns:
        List of monthly data for the test year
    """
    start_idx = (test_year - 1) * 12
    end_idx = test_year * 12

    return dataset['historical_data'][start_idx:end_idx]


def save_dataset(dataset: Dict, filepath: str):
    """Save dataset to JSON file"""
    # Create directory if it doesn't exist
    os.makedirs(os.path.dirname(filepath), exist_ok=True)

    with open(filepath, 'w') as f:
        json.dump(dataset, f, indent=2)
    print(f"✓ Dataset saved to {filepath}")


def main():
    """Generate and save the simulation-based dataset"""
    print("=" * 60)
    print("SIMULATION-BASED DATA GENERATOR FOR FORECAST APP")
    print("=" * 60)
    print("\nGenerating Supply Chain Dataset using full simulation...")
    print("-" * 60)

    # Configure the simulation
    config = {
        'seed': 42,
        'years': 11,
        'scenario': 'basic',
        'n_customers': 500,
        'n_retailers': 6,
        'n_suppliers': 5,
        'n_warehouses': 2
    }

    print(f"\nConfiguration:")
    print(f"  • Seed: {config['seed']}")
    print(f"  • Years: {config['years']}")
    print(f"  • Scenario: {config['scenario']}")
    print(f"  • Customers: {config['n_customers']}")
    print(f"  • Retailers: {config['n_retailers']}")
    print()

    # Generate full 11-year dataset using simulation
    full_dataset = gen_data(config)

    print("\n" + "-" * 60)
    print("Saving datasets...")
    print("-" * 60)

    # Save full dataset
    save_dataset(full_dataset, 'data/sim_supply_chain_data_full.json')

    # Save training data (10 years)
    training_data = get_training_data(full_dataset, training_years=10)
    save_dataset(training_data, 'data/sim_supply_chain_data_training.json')

    # Save test data (year 11)
    test_data = get_test_data(full_dataset, test_year=11)
    with open('data/sim_supply_chain_data_test.json', 'w') as f:
        json.dump(test_data, f, indent=2)
    print(f"✓ Dataset saved to data/sim_supply_chain_data_test.json")

    print("\n" + "-" * 60)
    print("Dataset Generation Complete!")
    print("-" * 60)
    print(f"Total months: {len(full_dataset['historical_data'])}")
    print(f"Training months: {len(training_data['historical_data'])}")
    print(f"Test months: {len(test_data)}")

    # Print sample statistics
    print("\n" + "=" * 60)
    print("Sample Statistics (Year 1):")
    print("=" * 60)

    year1_data = full_dataset['historical_data'][:12]
    for watch in full_dataset['metadata']['watches']:
        watch_id = watch['id']
        watch_name = watch['name']

        demands = [m['watches'][watch_id-1]['demand'] for m in year1_data]
        revenues = [m['watches'][watch_id-1]['revenue'] for m in year1_data]

        print(f"\n{watch_name}:")
        print(f"  Avg Monthly Demand: {np.mean(demands):.1f} units")
        print(f"  Avg Monthly Revenue: CHF {np.mean(revenues):,.2f}")
        print(f"  Annual Revenue: CHF {np.sum(revenues):,.2f}")

    print("\n" + "=" * 60)
    print("✓ All files generated successfully!")
    print("=" * 60)
    print("\nGenerated files:")
    print("  • data/sim_supply_chain_data_full.json")
    print("  • data/sim_supply_chain_data_training.json")
    print("  • data/sim_supply_chain_data_test.json")
    print()


if __name__ == "__main__":
    main()