Commit 883282d4 authored by Barthelet Thibault's avatar Barthelet Thibault
Browse files

sim v2

parent 1abedcae
Loading
Loading
Loading
Loading
+234 −0
Original line number Diff line number Diff line
#!/usr/bin/env python3
"""
Demo script showing how to use the prediction phase in the supply chain simulation.

This demonstrates both scenarios:
1. Basic scenario - normal operations
2. Unplanned problem scenario - 50% demand drop in months 3-4
"""

import sys
import os
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from supply_chain_sim.simulation import run_simulation_with_student_predictions
from supply_chain_sim.synthetic_setup import SyntheticEntitySetup

def demo_basic_scenario():
    """Demonstrate the basic scenario with good predictions."""
    
    print("\n" + "="*70)
    print(" DEMO 1: BASIC SCENARIO WITH GOOD PREDICTIONS ".center(70))
    print("="*70)
    
    # Configuration
    config = {
        'seed': 42,
        'n_brands': 1,
        'n_suppliers': 4,
        'n_components': 8,
        'n_watches': 3,  # 3 products to predict
        'n_warehouses': 1,
        'n_retailers': 4,
        'n_customers': 200,
        'n_months': 6,  # 6 months simulation
        'scenario': 'basic'  # Normal operations
    }
    
    # First, let's see what products we have
    print("\n[SETUP] Generating products...")
    setup = SyntheticEntitySetup(seed=config['seed'])
    setup.generate_all(config)
    
    print("\nProducts in simulation:")
    for watch in setup.watches:
        print(f"  • Watch ID {watch.id}: {watch.name} ({watch.category})")
        print(f"    Cost: ${watch.base_cost:.0f}, Price: ${watch.sell_price:.0f}")
    
    # Student makes predictions for each product, each month
    print("\n[PREDICTION PHASE] Student enters predictions...")
    print("Student predicts demand for 6 months:\n")
    
    # Example: Good predictions (close to realistic values)
    predictions = {
        0: [3, 4, 4, 3, 5, 4],      # Luxury watch - low volume
        1: [15, 18, 16, 17, 19, 15], # Sport watch - medium volume  
        2: [25, 28, 26, 24, 30, 27]  # Casual watch - high volume
    }
    
    for watch_id, monthly_pred in predictions.items():
        watch = next(w for w in setup.watches if w.id == watch_id)
        print(f"  {watch.name}: {monthly_pred}")
    
    print("\n[SIMULATION] Running simulation with student predictions...")
    print("Supply chain will order components based on these predictions.\n")
    
    # Run simulation
    sim = run_simulation_with_student_predictions(config, predictions)
    
    print("\n" + "="*70)
    print(" DEMO 1 COMPLETE ".center(70))
    print("="*70)
    
    return sim


def demo_unplanned_problem_scenario():
    """Demonstrate the unplanned problem scenario with a sudden demand drop."""
    
    print("\n\n" + "="*70)
    print(" DEMO 2: UNPLANNED PROBLEM SCENARIO ".center(70))
    print("="*70)
    print("\n⚠️  In this scenario, demand drops 50% in months 3-4 (unexpected!)")
    print("The student's predictions won't account for this.\n")
    
    # Configuration with unplanned problem
    config = {
        'seed': 42,
        'n_brands': 1,
        'n_suppliers': 4,
        'n_components': 8,
        'n_watches': 3,
        'n_warehouses': 1,
        'n_retailers': 4,
        'n_customers': 200,
        'n_months': 6,
        'scenario': 'unplanned_problem'  # Problem scenario
    }
    
    print("[PREDICTION PHASE] Student enters predictions (unaware of problem)...")
    print("Student predicts stable demand:\n")
    
    # Student predicts stable demand, but doesn't know about the problem
    predictions = {
        0: [3, 4, 4, 4, 5, 4],       # Predicts steady demand
        1: [15, 18, 16, 16, 19, 15], # Predicts steady demand
        2: [25, 28, 26, 26, 30, 27]  # Predicts steady demand
    }
    
    setup = SyntheticEntitySetup(seed=config['seed'])
    setup.generate_all(config)
    
    for watch_id, monthly_pred in predictions.items():
        watch = next(w for w in setup.watches if w.id == watch_id)
        print(f"  {watch.name}: {monthly_pred}")
    
    print("\n[SIMULATION] Running simulation...")
    print("⚠️  Actual demand will drop 50% in months 3-4!")
    print("This will cause overstock since predictions were too high.\n")
    
    # Run simulation
    sim = run_simulation_with_student_predictions(config, predictions)
    
    print("\n" + "="*70)
    print(" DEMO 2 COMPLETE ".center(70))
    print("="*70)
    
    print("\nNOTE: Compare the prediction reports between both scenarios.")
    print("Scenario 2 should show larger errors and overstock in months 3-4.")
    
    return sim


def demo_bad_predictions():
    """Demonstrate what happens with poor predictions."""
    
    print("\n\n" + "="*70)
    print(" DEMO 3: POOR PREDICTIONS (LEARNING OPPORTUNITY) ".center(70))
    print("="*70)
    print("\nStudent makes bad predictions to see the impact.\n")
    
    config = {
        'seed': 42,
        'n_brands': 1,
        'n_suppliers': 4,
        'n_components': 8,
        'n_watches': 3,
        'n_warehouses': 1,
        'n_retailers': 4,
        'n_customers': 200,
        'n_months': 6,
        'scenario': 'basic'
    }
    
    print("[PREDICTION PHASE] Student enters predictions (intentionally poor)...")
    
    # Deliberately bad predictions - way too high
    predictions = {
        0: [50, 50, 50, 50, 50, 50],  # Luxury: predicting 50, reality ~3-5
        1: [100, 100, 100, 100, 100, 100],  # Sport: predicting 100, reality ~15-20
        2: [200, 200, 200, 200, 200, 200]   # Casual: predicting 200, reality ~25-30
    }
    
    setup = SyntheticEntitySetup(seed=config['seed'])
    setup.generate_all(config)
    
    for watch_id, monthly_pred in predictions.items():
        watch = next(w for w in setup.watches if w.id == watch_id)
        print(f"  {watch.name}: {monthly_pred}")
    
    print("\n[SIMULATION] Running simulation...")
    print("Expected outcome: Massive overstock, high costs, poor GMROI\n")
    
    sim = run_simulation_with_student_predictions(config, predictions)
    
    print("\n" + "="*70)
    print(" DEMO 3 COMPLETE ".center(70))
    print("="*70)
    
    print("\nLEARNING POINT: Overpredicting leads to:")
    print("  • Excessive component orders")
    print("  • High inventory holding costs")
    print("  • Poor GMROI (return on inventory investment)")
    print("  • Wasted capital")
    
    return sim


def main():
    """Run all demos."""
    
    print("\n" + "="*70)
    print(" SUPPLY CHAIN SIMULATION WITH PREDICTION PHASE ".center(70))
    print(" EDUCATIONAL DEMO ".center(70))
    print("="*70)
    
    print("\nThis demo shows three scenarios:")
    print("  1. Basic scenario with good predictions")
    print("  2. Unplanned problem scenario (50% demand drop)")
    print("  3. Poor predictions (learning opportunity)")
    
    print("\nPress Enter to start Demo 1...")
    input()
    
    # Demo 1: Good predictions
    demo_basic_scenario()
    
    print("\n\nPress Enter to start Demo 2...")
    input()
    
    # Demo 2: Unplanned problem
    demo_unplanned_problem_scenario()
    
    print("\n\nPress Enter to start Demo 3...")
    input()
    
    # Demo 3: Bad predictions
    demo_bad_predictions()
    
    print("\n\n" + "="*70)
    print(" ALL DEMOS COMPLETE ".center(70))
    print("="*70)
    
    print("\nKEY TAKEAWAYS:")
    print("  ✓ Prediction accuracy directly impacts supply chain performance")
    print("  ✓ Overpredicting causes overstock and waste")
    print("  ✓ Underpredicting causes stockouts and lost sales")
    print("  ✓ Unplanned problems require adaptability")
    print("  ✓ GMROI measures return on inventory investment")
    
    print("\n" + "="*70)


if __name__ == "__main__":
    main()
+140 −0
Original line number Diff line number Diff line
from flask import Flask, render_template, request, jsonify, session
from flask_session import Session
import sys
import os

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

from simulation_engine_new import SimulationEngine

app = Flask(__name__)

# Configure Flask-Session
app.config['SECRET_KEY'] = 'dev-secret-key-supply-chain-2024'
app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_FILE_DIR'] = './flask_session'
app.config['SESSION_PERMANENT'] = False

Session(app)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/configure')
def configure():
    return render_template('configure.html')

@app.route('/setup_prediction', methods=['POST'])
def setup_prediction():
    """Setup the simulation and proceed to prediction phase."""
    try:
        data = request.json
        
        # Configuration
        config = {
            'seed': int(data.get('seed', 42)),
            'n_watches': int(data.get('n_watches', 3)),
            'n_customers': int(data.get('n_customers', 200)),
            'n_retailers': int(data.get('n_retailers', 4)),
            'n_months': int(data.get('n_months', 12)),
            'scenario': data.get('scenario', 'basic'),  # 'basic' or 'unplanned_problem'
            # Additional required parameters
            'n_brands': 1,
            'n_suppliers': 4,
            'n_components': 10,
            'n_warehouses': 1
        }
        
        # Validate
        if not (1 <= config['n_months'] <= 24):
            return jsonify({'success': False, 'error': 'Mois: 1-24'})
        if not (1 <= config['n_watches'] <= 6):
            return jsonify({'success': False, 'error': 'Montres: 1-6'})
        if not (50 <= config['n_customers'] <= 5000):
            return jsonify({'success': False, 'error': 'Clients: 50-5000'})
        if not (2 <= config['n_retailers'] <= 8):
            return jsonify({'success': False, 'error': 'Détaillants: 2-8'})
        
        # Initialize simulation engine
        engine = SimulationEngine(config)
        
        # Get prediction data
        prediction_data = engine.get_prediction_data()
        
        # Store in session
        session['config'] = config
        session['prediction_data'] = prediction_data
        
        return jsonify({'success': True})
    
    except Exception as e:
        import traceback
        print(traceback.format_exc())
        return jsonify({'success': False, 'error': str(e)})

@app.route('/predict')
def predict():
    """Show prediction interface."""
    prediction_data = session.get('prediction_data')
    config = session.get('config')
    
    if not prediction_data or not config:
        return render_template('error.html', 
                             message="Configuration non trouvée. Veuillez recommencer depuis la configuration.")
    
    return render_template('predict.html', 
                          products=prediction_data['products'],
                          historical=prediction_data['historical'],
                          config=config)

@app.route('/run_simulation_with_predictions', methods=['POST'])
def run_simulation_with_predictions():
    """Run simulation with student predictions."""
    try:
        data = request.json
        predictions = data.get('predictions', {})
        
        config = session.get('config')
        
        if not config:
            return jsonify({'success': False, 'error': 'Configuration non trouvée'})
        
        # Convert string keys to integers
        predictions = {int(k): v for k, v in predictions.items()}
        
        # Re-initialize engine and run simulation
        engine = SimulationEngine(config)
        results = engine.run_simulation(predictions)
        
        # Store results in session
        session['results'] = results
        session['predictions'] = predictions
        
        return jsonify({'success': True})
    
    except Exception as e:
        import traceback
        print(traceback.format_exc())
        return jsonify({'success': False, 'error': str(e)})

@app.route('/results')
def results():
    """Show simulation results."""
    results = session.get('results')
    config = session.get('config')
    predictions = session.get('predictions')
    
    if not results:
        return render_template('error.html', 
                             message="Aucune simulation. Lancez-en une d'abord.")
    
    return render_template('results.html', 
                          results=results, 
                          config=config,
                          predictions=predictions)

if __name__ == '__main__':
    os.makedirs('flask_session', exist_ok=True)
    app.run(debug=True, host='0.0.0.0', port=5000)
+9 B

File added.

No diff preview for this file type.

+32.5 KiB

File added.

No diff preview for this file type.

+2.17 KiB

File added.

No diff preview for this file type.

Loading