We built a decision engine in Python. It generates every plant-to-market assignment and logistics mix, runs each through Monte Carlo demand and carbon-price scenarios, filters by hard constraints, and scores survivors on weighted profiles. If nothing is feasible, a relaxation step names the binding constraint.
SCMA International Case Competition, Arizona State University. Team with Emiliano Navarro, Lizbeth González and Karyme Ventura.
The notebook holds three versions of the engine, all used in the case.
Version 1 · 297 strategies, one shipping mix for all markets
Code
import numpy as npimport pandas as pdimport itertoolsfrom collections import defaultdict# --- Configuration & Foundational Data ---N_SCENARIOS = 5000ACTUAL_GPU_SUPPLY_2026 = 185000GPUS_PER_SERVER = 1.2MAX_SERVERS_2026 = int(ACTUAL_GPU_SUPPLY_2026 / GPUS_PER_SERVER)# Financial & Operational DataGPU_BENCHMARK_COST = 30000OTHER_COMPONENTS_COST = 9840SERVER_REVENUE = 49090.91PLANT_FC = {'US': 7800e3, 'Mexico': 7200e3, 'Malaysia': 6900e3}SHIPPING_LANE_FC = { ('US', 'NA'): 450e3, ('US', 'APAC'): 850e3, ('US', 'EU'): 650e3, ('Mexico', 'NA'): 500e3, ('Mexico', 'APAC'): 900e3, ('Mexico', 'EU'): 700e3, ('Malaysia', 'NA'): 700e3, ('Malaysia', 'APAC'): 500e3, ('Malaysia', 'EU'): 600e3,}LOGISTICS_VC = {'Ocean': 180, 'Air': 620}CO2_EMISSIONS = {'Ocean': 50, 'Air': 310} # In kg per unit# Simulation AssumptionsDEMAND_BASELINE = 215000DEMAND_VOLATILITY = 0.20CARBON_PRICE_RANGE = (50, 150)DEMAND_MIX = {'NA': 0.45, 'APAC': 0.35, 'EU': 0.20}class StrategicDecisionEngine: """A complete engine for strategic simulation, feasibility analysis, and decision support.""" def __init__(self, decision_inputs): self.inputs = decision_inputs self.all_strategy_results = [] self.feasible_strategies = [] self.infeasible_strategies = [] self.hard_constraints = self.inputs['hard_constraints'] self.soft_constraints = self.inputs['soft_constraints'] self.weights = self.inputs['objective_weights'] def _evaluate_single_strategy(self, strategy_def): """Runs a full Monte Carlo simulation for one strategy.""" plant_map = strategy_def['plant_map'] logistics_mix = strategy_def['logistics_mix'] fixed_cost = sum(PLANT_FC[plant] for plant in set(plant_map.values())) for region, plant in plant_map.items(): fixed_cost += SHIPPING_LANE_FC.get((plant, region), 0) total_bom_vc = (GPUS_PER_SERVER * GPU_BENCHMARK_COST) + OTHER_COMPONENTS_COST avg_logistics_vc = (logistics_mix['Ocean'] * LOGISTICS_VC['Ocean']) + (logistics_mix['Air'] * LOGISTICS_VC['Air']) avg_co2_kg = (logistics_mix['Ocean'] * CO2_EMISSIONS['Ocean']) + (logistics_mix['Air'] * CO2_EMISSIONS['Air']) scenarios = [] for _ in range(N_SCENARIOS): demand = np.random.normal(DEMAND_BASELINE, DEMAND_VOLATILITY) carbon_price = np.random.uniform(CARBON_PRICE_RANGE[0], CARBON_PRICE_RANGE[1]) units_sold = min(demand, MAX_SERVERS_2026) carbon_cost_per_unit = (avg_co2_kg / 1000) * carbon_price # kg -> tons for price total_vc_per_unit = total_bom_vc + avg_logistics_vc + carbon_cost_per_unit total_cost = fixed_cost + (units_sold * total_vc_per_unit) profit = (units_sold * SERVER_REVENUE) - total_cost # *** BUG FIX IS HERE *** # Convert total kg to thousands of tons (k-tons) by dividing by 1 million co2_k_tons = (units_sold * avg_co2_kg) / 1_000_000 scenarios.append({'profit': profit, 'co2_k_tons': co2_k_tons, 'units_sold': units_sold}) scenario_df = pd.DataFrame(scenarios) num_unique_plants = len(set(plant_map.values())) resilience_score = {1: 10, 2: 60, 3: 100}.get(num_unique_plants, 0) return { "definition": strategy_def, "results_df": scenario_df, "metrics": { "profit": scenario_df['profit'].mean(), "growth": scenario_df['units_sold'].mean(), "sustainability": scenario_df['co2_k_tons'].mean(), "resilience": resilience_score } } def _check_feasibility_and_penalties(self, result): """Analyzes a strategy's results against hard and soft constraints.""" df = result['results_df'] violations = { 'profit': (df['profit'] < self.hard_constraints['min_profit_M'] * 1e6).mean(), 'co2': (df['co2_k_tons'] > self.hard_constraints['max_co2_ktons']).mean(), 'ocean': (result['definition']['logistics_mix']['Ocean'] < self.hard_constraints['min_ocean_share']), 'resilience': (result['metrics']['resilience'] < self.hard_constraints['min_resilience_score']) } total_violation_prob = 1 - (1 - violations['profit']) * (1 - violations['co2']) is_feasible = (total_violation_prob < 0.05) and not violations['ocean'] and not violations['resilience'] profit_shortfall = np.maximum(0, self.soft_constraints['target_profit_M'] * 1e6 - df['profit']).mean() co2_excess = np.maximum(0, df['co2_k_tons'] - self.soft_constraints['target_co2_ktons']).mean() profit_penalty, co2_penalty = profit_shortfall / 1e6, co2_excess / 0.1 total_penalty = profit_penalty + co2_penalty result['feasibility'] = {'is_feasible': is_feasible, 'violation_probability': total_violation_prob, 'violations': violations} result['penalty_score'] = total_penalty return result def _score_strategies(self): """Calculates a weighted Strategic Score for all feasible strategies.""" if not self.feasible_strategies: return min_vals = {key: min(s['metrics'][key] for s in self.feasible_strategies) for key in self.weights} max_vals = {key: max(s['metrics'][key] for s in self.feasible_strategies) for key in self.weights} for strat in self.feasible_strategies: total_score = 0 for objective, weight in self.weights.items(): val, range_val = strat['metrics'][objective], max_vals[objective] - min_vals[objective] norm_score = 100 if range_val == 0 else 100 * (val - min_vals[objective]) / range_val if objective == 'sustainability': norm_score = 100 - norm_score total_score += norm_score * (weight / 100.0) strat['strategic_score'] = total_score self.feasible_strategies.sort(key=lambda x: x['strategic_score'], reverse=True) def run(self): """Executes the entire end-to-end analysis.""" plants, regions = ['US', 'Mexico', 'Malaysia'], ['NA', 'APAC', 'EU'] all_plant_maps = [dict(zip(regions, p)) for p in itertools.product(plants, repeat=len(regions))] all_logistics_mixes = [{'Ocean': i/10, 'Air': (10-i)/10} for i in range(11)] strategy_definitions = [{'plant_map': p_map, 'logistics_mix': l_mix} for p_map in all_plant_maps for l_mix in all_logistics_mixes] print(f"Analyzing {len(strategy_definitions)} potential strategies across {N_SCENARIOS} scenarios each...") for i, strat_def in enumerate(strategy_definitions): print(f" - Evaluating strategy {i+1}/{len(strategy_definitions)}...", end='\r') result = self._evaluate_single_strategy(strat_def) result = self._check_feasibility_and_penalties(result) self.all_strategy_results.append(result) if result['feasibility']['is_feasible']: self.feasible_strategies.append(result) else: self.infeasible_strategies.append(result) print("\nAnalysis complete.") self._score_strategies() self._display_report() def _display_report(self): """Prints the final, formatted executive summary.""" print("\n" + "="*80 + "\n** Executive Summary: Strategic Analysis for 2026 **\n" + "="*80) if not self.feasible_strategies: print("\n**Feasibility Check: No strategy was found that meets all hard constraints.**\n") self._display_relaxation_advice() else: prob = self.feasible_strategies[0]['feasibility']['violation_probability'] print(f"\n**Feasibility Check: Found {len(self.feasible_strategies)} feasible strategies.**") print(f"The top-ranked strategy is feasible in {100*(1-prob):.1f}% of simulated scenarios.\n") print("-" * 80 + "\n** Strategy Recommendations **\n" + "-" * 80) if self.feasible_strategies: self._print_strategy_card("Recommended Strategy (Highest Strategic Score)", self.feasible_strategies[0]) self._print_strategy_card("Most Profitable Strategy", max(self.all_strategy_results, key=lambda x: x['metrics']['profit']), is_alt=True) self._print_strategy_card("Most Resilient Strategy", max(self.all_strategy_results, key=lambda x: x['metrics']['resilience']), is_alt=True) if not self.feasible_strategies and self.infeasible_strategies: self._print_strategy_card("Least Infeasible Strategy (Best effort)", min(self.infeasible_strategies, key=lambda x: x['penalty_score']), is_alt=True) def _print_strategy_card(self, title, strat, is_alt=False): """Prints a formatted summary of a single strategy with a detailed operational plan.""" print(f"\n--- {title} ---") if is_alt and not strat['feasibility']['is_feasible']: prob = strat['feasibility']['violation_probability'] print(f" **Warning:** This strategy is NOT feasible (violates constraints in {prob:.1%} of scenarios).") metrics, definition = strat['metrics'], strat['definition'] print(f" - Profile: Expected Profit: ${metrics['profit']/1e6:,.1f}M | Expected CO2: {metrics['sustainability']:,.2f} k-tons | Resilience: {metrics['resilience']:.0f}/100") print("\n - Operational Plan:") for region in ['NA', 'APAC', 'EU']: plant = definition['plant_map'][region] units = metrics['growth'] * DEMAND_MIX[region] logistics = definition['logistics_mix'] print(f" - {region} Market ({units:,.0f} units):") print(f" - Assemble In: '{plant}'") print(f" - Ship Via: {logistics['Ocean'] * 100:.0f}% Ocean, {logistics['Air'] * 100:.0f}% Air") def _display_relaxation_advice(self): """Provides actionable advice if no feasible solutions were found.""" print("-" * 80 + "\n** Relaxation Engine: Advice to find a feasible solution **\n" + "-" * 80) best_infeasible = min(self.infeasible_strategies, key=lambda x: x['penalty_score']) violations = best_infeasible['feasibility']['violations'] print("The primary reason for infeasibility is the combination of ambitious constraints.") print("The 'least infeasible' strategy failed because:") if violations['resilience']: print(f" - The Resilience Score of {best_infeasible['metrics']['resilience']:.0f} did not meet the required minimum of {self.hard_constraints['min_resilience_score']:.0f}.") if violations['profit'] > 0.05: profit_miss = self.hard_constraints['min_profit_M'] - (best_infeasible['metrics']['profit'] / 1e6) print(f" - The Profit Constraint (${self.hard_constraints['min_profit_M']:.0f}M) was missed by ~${profit_miss:.1f}M on average.") if violations['co2'] > 0.05: co2_excess = best_infeasible['metrics']['sustainability'] - self.hard_constraints['max_co2_ktons'] print(f" - The CO2 Constraint ({self.hard_constraints['max_co2_ktons']:.1f} k-tons) was exceeded by ~{co2_excess:.2f} k-tons on average.") if violations['ocean']: print(f" - The Ocean Freight Constraint was violated (actual was {best_infeasible['definition']['logistics_mix']['Ocean']*100:.0f}% vs. required {self.hard_constraints['min_ocean_share']*100:.0f}%).") print("\n**Recommendation:** To find a feasible solution, consider one of the following trade-offs:") if violations['resilience']: print(f" 1. Relax the Minimum Resilience Score from {self.hard_constraints['min_resilience_score']:.0f} to a lower tier (e.g., 10 or 60).") print(f" 2. Relax the Minimum Profit target from ${self.hard_constraints['min_profit_M']:.0f}M to ${self.hard_constraints['min_profit_M']*0.98:.0f}M.") print(f" 3. Relax the Maximum CO2 target from {self.hard_constraints['max_co2_ktons']:.1f} k-tons to {self.hard_constraints['max_co2_ktons']*1.05:.1f} k-tons.") if violations['ocean']: print(f" 4. Relax the Minimum Ocean Freight Share from {self.hard_constraints['min_ocean_share']*100:.0f}% to {self.hard_constraints['min_ocean_share']*0.95*100:.0f}%.") print("Re-running the tool with one of these relaxed constraints is likely to yield feasible strategies.")def get_interactive_inputs(): """Guides the user through a questionnaire to build the decision_input dictionary.""" profiles = { "1": {"name": "Profit First", "weights": {"profit": 60, "resilience": 10, "sustainability": 30}}, "2": {"name": "Balanced Growth", "weights": {"profit": 40, "resilience": 30, "sustainability": 30}}, "3": {"name": "Resilience First", "weights": {"profit": 20, "resilience": 50, "sustainability": 30}}, } print("="*80 + "\nStep 1: Choose a Strategic Profile\n" + "-"*80) for key, val in profiles.items(): print(f" [{key}] {val['name']}") choice = input("Select a profile [1-3] or press Enter for custom: ") if choice in profiles: weights = profiles[choice]['weights'] print(f"Selected '{profiles[choice]['name']}'.") else: print("\n-- Custom Priority Weights --\nPlease allocate 100 points across the following objectives:") weights = {} while True: try: weights['profit'] = int(input(f" - Points for Profit: ")) weights['resilience'] = int(input(f" - Points for Resilience: ")) weights['sustainability'] = int(input(f" - Points for Sustainability (Low CO2): ")) if sum(weights.values()) == 100: break else: print(f"Error: Points sum to {sum(weights.values())}, not 100. Please try again.\n") except ValueError: print("Error: Please enter whole numbers.\n") print("\n" + "="*80 + "\nStep 2: Define Constraints (Your Non-Negotiable Rules)\n" + "-"*80) hard_constraints, soft_constraints = {}, {} try: hard_constraints['min_resilience_score'] = int(input(" - Hard Constraint: Minimum Resilience Score (10=Low, 60=Med, 100=High, e.g., 60): ")) hard_constraints['min_profit_M'] = float(input(" - Hard Constraint: Minimum Profit (in millions, e.g., 210): ")) soft_constraints['target_profit_M'] = float(input(" - Soft Target: Target Profit (in millions, e.g., 220): ")) hard_constraints['max_co2_ktons'] = float(input(" - Hard Constraint: Maximum CO2 (in k-tons, e.g., 8.0): ")) soft_constraints['target_co2_ktons'] = float(input(" - Soft Target: Target CO2 (in k-tons, e.g., 7.5): ")) hard_constraints['min_ocean_share'] = float(input(" - Hard Constraint: Minimum Ocean Freight Share (decimal, e.g., 0.8): ")) except ValueError: print("Invalid input. Using default values.") hard_constraints = {'min_resilience_score': 60, 'min_profit_M': 210, 'max_co2_ktons': 8.0, 'min_ocean_share': 0.8} soft_constraints = {'target_profit_M': 220, 'target_co2_ktons': 7.5} return {"objective_weights": weights, "hard_constraints": hard_constraints, "soft_constraints": soft_constraints}if __name__ == '__main__': executive_inputs = get_interactive_inputs() sde = StrategicDecisionEngine(executive_inputs) sde.run()
Saved result
================================================================================
Step 1: Choose a Strategic Profile
--------------------------------------------------------------------------------
[1] Profit First
[2] Balanced Growth
[3] Resilience First
Select a profile [1-3] or press Enter for custom: 2
Selected 'Balanced Growth'.
================================================================================
Step 2: Define Constraints (Your Non-Negotiable Rules)
--------------------------------------------------------------------------------
- Hard Constraint: Minimum Resilience Score (10=Low, 60=Med, 100=High, e.g., 60): 60
- Hard Constraint: Minimum Profit (in millions, e.g., 210): 210
- Soft Target: Target Profit (in millions, e.g., 220): 220
- Hard Constraint: Maximum CO2 (in k-tons, e.g., 8.0): 17
- Soft Target: Target CO2 (in k-tons, e.g., 7.5): 8
- Hard Constraint: Minimum Ocean Freight Share (decimal, e.g., 0.8): .8
Analyzing 297 potential strategies across 5000 scenarios each...
- Evaluating strategy 297/297...
Analysis complete.
================================================================================
** Executive Summary: Strategic Analysis for 2026 **
================================================================================
**Feasibility Check: Found 72 feasible strategies.**
The top-ranked strategy is feasible in 100.0% of simulated scenarios.
--------------------------------------------------------------------------------
** Strategy Recommendations **
--------------------------------------------------------------------------------
--- Recommended Strategy (Highest Strategic Score) ---
- Profile: Expected Profit: $449.1M | Expected CO2: 7.71 k-tons | Resilience: 100/100
- Operational Plan:
- NA Market (69,375 units):
- Assemble In: 'Mexico'
- Ship Via: 100% Ocean, 0% Air
- APAC Market (53,958 units):
- Assemble In: 'Malaysia'
- Ship Via: 100% Ocean, 0% Air
- EU Market (30,833 units):
- Assemble In: 'US'
- Ship Via: 100% Ocean, 0% Air
--- Most Profitable Strategy ---
**Warning:** This strategy is NOT feasible (violates constraints in 0.0% of scenarios).
- Profile: Expected Profit: $464.0M | Expected CO2: 7.71 k-tons | Resilience: 10/100
- Operational Plan:
- NA Market (69,375 units):
- Assemble In: 'Malaysia'
- Ship Via: 100% Ocean, 0% Air
- APAC Market (53,958 units):
- Assemble In: 'Malaysia'
- Ship Via: 100% Ocean, 0% Air
- EU Market (30,833 units):
- Assemble In: 'Malaysia'
- Ship Via: 100% Ocean, 0% Air
--- Most Resilient Strategy ---
**Warning:** This strategy is NOT feasible (violates constraints in 100.0% of scenarios).
- Profile: Expected Profit: $377.0M | Expected CO2: 47.79 k-tons | Resilience: 100/100
- Operational Plan:
- NA Market (69,375 units):
- Assemble In: 'US'
- Ship Via: 0% Ocean, 100% Air
- APAC Market (53,958 units):
- Assemble In: 'Mexico'
- Ship Via: 0% Ocean, 100% Air
- EU Market (30,833 units):
- Assemble In: 'Malaysia'
- Ship Via: 0% Ocean, 100% Air
Version 2 · 729 strategies, a shipping mix for each market
Code
import numpy as npimport pandas as pdimport itertoolsfrom collections import defaultdictimport math# --- Configuration & Foundational Data ---N_SCENARIOS = 5000ACTUAL_GPU_SUPPLY_2026 = 185000GPUS_PER_SERVER = 1.2MAX_SERVERS_2026 = int(ACTUAL_GPU_SUPPLY_2026 / GPUS_PER_SERVER)# Financial & Operational DataGPU_BENCHMARK_COST = 30000OTHER_COMPONENTS_COST = 9840SERVER_REVENUE = 49090.91PLANT_FC = {'US': 7800e3, 'Mexico': 7200e3, 'Malaysia': 6900e3}SHIPPING_LANE_FC = { ('US', 'NA'): 450e3, ('US', 'APAC'): 850e3, ('US', 'EU'): 650e3, ('Mexico', 'NA'): 500e3, ('Mexico', 'APAC'): 900e3, ('Mexico', 'EU'): 700e3, ('Malaysia', 'NA'): 700e3, ('Malaysia', 'APAC'): 500e3, ('Malaysia', 'EU'): 600e3,}LOGISTICS_VC = {'Ocean': 180, 'Air': 620}CO2_EMISSIONS = {'Ocean': 50, 'Air': 310} # In kg per unit# Simulation AssumptionsDEMAND_BASELINE = 215000DEMAND_VOLATILITY = 0.20DEMAND_MIX = {'NA': 0.45, 'APAC': 0.35, 'EU': 0.20}CARBON_PRICE_RANGE = (50, 150)class StrategicDecisionEngine: """A complete engine for strategic simulation with per-market logistics.""" def __init__(self, decision_inputs): self.inputs = decision_inputs self.all_strategy_results = [] self.feasible_strategies = [] self.infeasible_strategies = [] self.hard_constraints = self.inputs['hard_constraints'] self.soft_constraints = self.inputs['soft_constraints'] self.weights = self.inputs['objective_weights'] def _evaluate_single_strategy(self, strategy_def): plant_map = strategy_def['plant_map'] logistics_plan = strategy_def['logistics_plan'] fixed_cost = sum(PLANT_FC[plant] for plant in set(plant_map.values())) for region, plant in plant_map.items(): fixed_cost += SHIPPING_LANE_FC.get((plant, region), 0) demand_std_dev = DEMAND_BASELINE * DEMAND_VOLATILITY scenarios = [] for _ in range(N_SCENARIOS): total_demand = np.random.normal(DEMAND_BASELINE, demand_std_dev) units_sold_total = min(total_demand, MAX_SERVERS_2026) total_profit, total_co2_k_tons = 0, 0 for region, mix_share in DEMAND_MIX.items(): units_for_region = units_sold_total * mix_share logistics_mix = logistics_plan[region] avg_logistics_vc = (logistics_mix['Ocean'] * LOGISTICS_VC['Ocean']) + (logistics_mix['Air'] * LOGISTICS_VC['Air']) avg_co2_kg = (logistics_mix['Ocean'] * CO2_EMISSIONS['Ocean']) + (logistics_mix['Air'] * CO2_EMISSIONS['Air']) carbon_price = np.random.uniform(*CARBON_PRICE_RANGE) carbon_cost_per_unit = (avg_co2_kg / 1000) * carbon_price total_vc_per_unit = (GPUS_PER_SERVER * GPU_BENCHMARK_COST) + OTHER_COMPONENTS_COST + avg_logistics_vc + carbon_cost_per_unit total_profit += units_for_region * (SERVER_REVENUE - total_vc_per_unit) total_co2_k_tons += (units_for_region * avg_co2_kg) / 1_000_000 total_profit -= fixed_cost scenarios.append({'profit': total_profit, 'co2_k_tons': total_co2_k_tons, 'units_sold': units_sold_total}) scenario_df = pd.DataFrame(scenarios) resilience_score = {1: 10, 2: 60, 3: 100}.get(len(set(plant_map.values())), 0) return { "definition": strategy_def, "results_df": scenario_df, "metrics": {"profit": scenario_df['profit'].mean(), "growth": scenario_df['units_sold'].mean(), "sustainability": scenario_df['co2_k_tons'].mean(), "resilience": resilience_score} } def _check_feasibility_and_penalties(self, result): df = result['results_df'] ocean_violation = any(result['definition']['logistics_plan'][r]['Ocean'] > self.hard_constraints['max_ocean_share'] for r in DEMAND_MIX) violations = { 'profit': (df['profit'] < self.hard_constraints['min_profit_M'] * 1e6).mean(), 'co2': (df['co2_k_tons'] > self.hard_constraints['max_co2_ktons']).mean(), 'ocean': ocean_violation, 'resilience': (result['metrics']['resilience'] < self.hard_constraints['min_resilience_score']) } total_violation_prob = 1 - (1 - violations['profit']) * (1 - violations['co2']) is_feasible = (total_violation_prob < 0.05) and not violations['ocean'] and not violations['resilience'] profit_shortfall = np.maximum(0, self.soft_constraints['target_profit_M'] * 1e6 - df['profit']).mean() co2_excess = np.maximum(0, df['co2_k_tons'] - self.soft_constraints['target_co2_ktons']).mean() total_penalty = (profit_shortfall / 1e6) + (co2_excess / 0.1) result['feasibility'] = {'is_feasible': is_feasible, 'violation_probability': total_violation_prob, 'violations': violations} result['penalty_score'] = total_penalty return result def _score_strategies(self): if not self.feasible_strategies: return min_vals = {key: min(s['metrics'][key] for s in self.feasible_strategies) for key in self.weights} max_vals = {key: max(s['metrics'][key] for s in self.feasible_strategies) for key in self.weights} for strat in self.feasible_strategies: total_score = 0 for objective, weight in self.weights.items(): val = strat['metrics'][objective] range_val = max_vals[objective] - min_vals[objective] norm_score = 100 if range_val == 0 else 100 * (val - min_vals[objective]) / range_val if objective == 'sustainability': norm_score = 100 - norm_score # Lower is better for CO2 total_score += norm_score * (weight / 100.0) strat['strategic_score'] = total_score self.feasible_strategies.sort(key=lambda x: x['strategic_score'], reverse=True) def run(self): plants, regions = ['US', 'Mexico', 'Malaysia'], ['NA', 'APAC', 'EU'] all_plant_maps = [dict(zip(regions, p)) for p in itertools.product(plants, repeat=len(regions))] logistics_options = [{'Ocean': 0.1, 'Air': 0.9}, {'Ocean': 0.8, 'Air': 0.2}, {'Ocean': 1.0, 'Air': 0.0}] logistics_combinations = list(itertools.product(logistics_options, repeat=len(regions))) all_logistics_plans = [dict(zip(regions, combo)) for combo in logistics_combinations] strategy_definitions = [{'plant_map': p_map, 'logistics_plan': l_plan} for p_map in all_plant_maps for l_plan in all_logistics_plans] print(f"\nAnalyzing {len(strategy_definitions)} potential strategies...") for i, strat_def in enumerate(strategy_definitions): print(f" - Evaluating strategy {i+1}/{len(strategy_definitions)}...", end='\r') result = self._evaluate_single_strategy(strat_def) result = self._check_feasibility_and_penalties(result) (self.feasible_strategies if result['feasibility']['is_feasible'] else self.infeasible_strategies).append(result) print("\nAnalysis complete.") self._score_strategies() self._display_report() def _display_report(self): print("\n" + "="*80 + "\n** Executive Summary: Strategic Analysis for 2026 **\n" + "="*80) if not self.feasible_strategies: print("\n**Feasibility Check: No strategy was found that meets all hard constraints.**\n") if self.infeasible_strategies: self._display_relaxation_advice() else: top_score = self.feasible_strategies[0]['strategic_score'] print(f"\n**Feasibility Check: Found {len(self.feasible_strategies)} feasible strategies.**") print(f"The top-ranked strategy achieved a Strategic Score of {top_score:.1f}/100 based on your priorities.\n") print("-" * 80 + "\n** Strategy Recommendations **\n" + "-" * 80) if self.feasible_strategies: self._print_strategy_card(f"Recommended Strategy (Score: {self.feasible_strategies[0]['strategic_score']:.1f})", self.feasible_strategies[0]) if len(self.feasible_strategies) > 1: self._print_strategy_card(f"Alternative Strategy (Score: {self.feasible_strategies[1]['strategic_score']:.1f})", self.feasible_strategies[1], is_alt=True) elif self.infeasible_strategies: best_infeasible = min(self.infeasible_strategies, key=lambda x: x['penalty_score']) self._print_strategy_card("Least Infeasible Strategy (For Analysis)", best_infeasible, is_alt=True) def _print_strategy_card(self, title, strat, is_alt=False): print(f"\n--- {title} ---") if not strat['feasibility']['is_feasible']: print(f" **Warning:** This strategy is NOT feasible.") metrics, definition = strat['metrics'], strat['definition'] print(f" - Profile: Profit: ${metrics['profit']/1e6:,.1f}M | CO2: {metrics['sustainability']:,.2f} k-tons | Resilience: {metrics['resilience']:.0f}/100") print("\n - Operational Plan:") for region in ['NA', 'APAC', 'EU']: plant, logistics = definition['plant_map'][region], definition['logistics_plan'][region] units = metrics['growth'] * DEMAND_MIX[region] print(f" - {region} Market ({units:,.0f} units): Assemble in '{plant}', Ship via {logistics['Ocean']:.0%} Ocean / {logistics['Air']:.0%} Air") def _display_relaxation_advice(self): print("-" * 80 + "\n** Relaxation Engine: Path to a Feasible Solution **\n" + "-" * 80) compliant_infeasible = [ s for s in self.infeasible_strategies if not s['feasibility']['violations']['ocean'] and not s['feasibility']['violations']['resilience'] ] if not compliant_infeasible: print("No strategies could be found that satisfy even the basic Ocean Freight and Resilience constraints.") print("Consider relaxing one of these two fundamental business rules first.") return best_infeasible = min(compliant_infeasible, key=lambda x: x['penalty_score']) violations = best_infeasible['feasibility']['violations'] metrics = best_infeasible['metrics'] print("After enforcing your core Ocean and Resilience rules, no strategy was feasible.") print("Analysis of the 'closest compliant' strategy shows the following gaps:") recommendations = [] if violations['profit'] > 0.05: required_M, actual_M = self.hard_constraints['min_profit_M'], metrics['profit'] / 1e6 gap_M = required_M - actual_M if gap_M > 0: new_profit_target = math.floor(actual_M) recommendations.append(f" 1. Lower the 'Minimum Profit' from ${required_M:,.1f}M to ${new_profit_target:,.1f}M.") print(f" - PROFIT: Minimum of ${required_M:,.1f}M was missed by ${gap_M:,.1f}M.") if violations['co2'] > 0.05: required_ktons, actual_ktons = self.hard_constraints['max_co2_ktons'], metrics['sustainability'] gap_ktons = actual_ktons - required_ktons if gap_ktons > 0: new_co2_target = math.ceil(actual_ktons * 10) / 10 recommendations.append(f" 2. Increase the 'Maximum CO2' from {required_ktons:,.2f} to {new_co2_target:,.2f} k-tons.") print(f" - CO2: Maximum of {required_ktons:,.2f} k-tons was exceeded by {gap_ktons:,.2f} k-tons.") if recommendations: print("\n**Recommendation:** To achieve a feasible strategy while respecting your Ocean/Resilience rules,") print("you must make a trade-off. Re-run with ONE of the following adjustments:") for rec in recommendations: print(rec) else: print("\nNo single clear adjustment found. The closest strategy fails on a combination of factors.")def get_interactive_inputs(): """Guides the user through a questionnaire to build the decision_input dictionary.""" profiles = { "1": {"name": "Profit First", "weights": {"profit": 60, "resilience": 10, "sustainability": 30}}, "2": {"name": "Balanced Growth", "weights": {"profit": 40, "resilience": 30, "sustainability": 30}}, "3": {"name": "Resilience First", "weights": {"profit": 20, "resilience": 50, "sustainability": 30}}, } print("="*80 + "\nStep 1: Choose a Strategic Profile\n" + "-"*80) for key, val in profiles.items(): print(f" [{key}] {val['name']}") choice = input("Select a profile [1-3] or press Enter for custom: ") if choice in profiles: weights = profiles[choice]['weights'] print(f"Selected '{profiles[choice]['name']}'.") else: print("\n-- Custom Priority Weights --\nPlease allocate 100 points across the following objectives:") weights = {} while True: try: weights['profit'] = int(input(f" - Points for Profit: ")) weights['resilience'] = int(input(f" - Points for Resilience: ")) weights['sustainability'] = int(input(f" - Points for Sustainability (Low CO2): ")) if sum(weights.values()) == 100: break else: print(f"Error: Points sum to {sum(weights.values())}, not 100. Please try again.\n") except ValueError: print("Error: Please enter whole numbers.\n") print("\n" + "="*80 + "\nStep 2: Define Constraints (Your Non-Negotiable Rules)\n" + "-"*80) hard_constraints, soft_constraints = {}, {} try: hard_constraints['min_resilience_score'] = int(input(" - Min Resilience Score (10, 60, 100): ")) hard_constraints['min_profit_M'] = float(input(" - Min Profit (in millions): ")) soft_constraints['target_profit_M'] = float(input(" - Target Profit (in millions): ")) hard_constraints['max_co2_ktons'] = float(input(" - Max CO2 (in k-tons): ")) soft_constraints['target_co2_ktons'] = float(input(" - Target CO2 (in k-tons): ")) hard_constraints['max_ocean_share'] = float(input(" - Max Ocean Freight Share per Market (0.0 to 1.0): ")) except ValueError: print("\nInvalid input. Using default values for demonstration.") hard_constraints = {'min_resilience_score': 60, 'min_profit_M': 210, 'max_co2_ktons': 8.5, 'max_ocean_share': 0.8} soft_constraints = {'target_profit_M': 220, 'target_co2_ktons': 8.0} return {"objective_weights": weights, "hard_constraints": hard_constraints, "soft_constraints": soft_constraints}if __name__ == '__main__': executive_inputs = get_interactive_inputs() sde = StrategicDecisionEngine(executive_inputs) sde.run()
Saved result
================================================================================
Step 1: Choose a Strategic Profile
--------------------------------------------------------------------------------
[1] Profit First
[2] Balanced Growth
[3] Resilience First
Select a profile [1-3] or press Enter for custom: 2
Selected 'Balanced Growth'.
================================================================================
Step 2: Define Constraints (Your Non-Negotiable Rules)
--------------------------------------------------------------------------------
- Min Resilience Score (10, 60, 100): 60
- Min Profit (in millions): 200
- Target Profit (in millions): 220
- Max CO2 (in k-tons): 18
- Target CO2 (in k-tons): 9
- Max Ocean Freight Share per Market (0.0 to 1.0): .8
Analyzing 729 potential strategies...
- Evaluating strategy 729/729...
Analysis complete.
================================================================================
** Executive Summary: Strategic Analysis for 2026 **
================================================================================
**Feasibility Check: Found 24 feasible strategies.**
The top-ranked strategy achieved a Strategic Score of 62.7/100 based on your priorities.
--------------------------------------------------------------------------------
** Strategy Recommendations **
--------------------------------------------------------------------------------
--- Recommended Strategy (Score: 62.7) ---
- Profile: Profit: $436.5M | CO2: 15.55 k-tons | Resilience: 60/100
- Operational Plan:
- NA Market (68,589 units): Assemble in 'US', Ship via 80% Ocean / 20% Air
- APAC Market (53,347 units): Assemble in 'US', Ship via 80% Ocean / 20% Air
- EU Market (30,484 units): Assemble in 'Malaysia', Ship via 80% Ocean / 20% Air
--- Alternative Strategy (Score: 62.3) ---
- Profile: Profit: $437.3M | CO2: 15.55 k-tons | Resilience: 60/100
- Operational Plan:
- NA Market (68,613 units): Assemble in 'Malaysia', Ship via 80% Ocean / 20% Air
- APAC Market (53,366 units): Assemble in 'Malaysia', Ship via 80% Ocean / 20% Air
- EU Market (30,495 units): Assemble in 'Mexico', Ship via 80% Ocean / 20% Air
Version 3 · the per-market model, fully commented
Code
import numpy as npimport pandas as pdimport itertoolsfrom collections import defaultdictimport math# ==============================================================================# --- Configuration & Foundational Data ---# This section contains all the core assumptions and data points for the simulation.# ==============================================================================# --- Simulation Control ---N_SCENARIOS = 5000 # Number of Monte Carlo simulations to run for each strategy.# --- Production & Supply Chain Data ---ACTUAL_GPU_SUPPLY_2026 = 185000 # Total number of high-end GPUs available for the year.GPUS_PER_SERVER = 1.2 # Average number of GPUs used per server unit.MAX_SERVERS_2026 = int(ACTUAL_GPU_SUPPLY_2026 / GPUS_PER_SERVER) # The absolute maximum number of servers we can produce.# --- Financial Data ---GPU_BENCHMARK_COST = 30000 # Cost of GPUs per server.OTHER_COMPONENTS_COST = 9840 # Cost of all other components (CPU, RAM, chassis, etc.) per server.SERVER_REVENUE = 49090.91 # Revenue generated from selling one server.# --- Fixed Costs ---# Annual fixed costs associated with operating each manufacturing plant.PLANT_FC = {'US': 7800e3, 'Mexico': 7200e3, 'Malaysia': 6900e3}# Annual fixed costs for maintaining a logistics channel from a plant to a market region.SHIPPING_LANE_FC = { ('US', 'NA'): 450e3, ('US', 'APAC'): 850e3, ('US', 'EU'): 650e3, ('Mexico', 'NA'): 500e3, ('Mexico', 'APAC'): 900e3, ('Mexico', 'EU'): 700e3, ('Malaysia', 'NA'): 700e3, ('Malaysia', 'APAC'): 500e3, ('Malaysia', 'EU'): 600e3,}# --- Variable Costs & Environmental Impact ---# Variable costs for shipping one server unit by different methods.LOGISTICS_VC = {'Ocean': 180, 'Air': 620}# CO2 emissions in kilograms for shipping one server unit. Note the high impact of air freight.CO2_EMISSIONS = {'Ocean': 50, 'Air': 310}# --- Market & Economic Assumptions ---DEMAND_BASELINE = 215000 # Expected average total market demand for servers in 2026.DEMAND_VOLATILITY = 0.20 # The standard deviation of demand, as a percentage of the baseline.# The geographical mix of total demand. Must sum to 1.0.DEMAND_MIX = {'NA': 0.45, 'APAC': 0.35, 'EU': 0.20}# The potential range for the price of carbon in $/ton. This simulates regulatory uncertainty.CARBON_PRICE_RANGE = (50, 150)class StrategicDecisionEngine: """ A comprehensive simulation engine to analyze and recommend global supply chain strategies. This class takes high-level business objectives and constraints, simulates thousands of potential futures for hundreds of different strategies, and provides a clear, data-driven recommendation. It helps answer the question: "What is the best way to structure our global operations to maximize profit, resilience, and sustainability, given future uncertainty?" """ def __init__(self, decision_inputs): """Initializes the engine with the user's strategic priorities and rules.""" self.inputs = decision_inputs self.all_strategy_results = [] self.feasible_strategies = [] self.infeasible_strategies = [] # Extract user-defined rules and priorities for easy access. self.hard_constraints = self.inputs['hard_constraints'] self.soft_constraints = self.inputs['soft_constraints'] self.weights = self.inputs['objective_weights'] def _evaluate_single_strategy(self, strategy_def): """ Runs a full Monte Carlo simulation for a single proposed strategy. Args: strategy_def (dict): A dictionary defining the strategy, containing: - 'plant_map': Which plant serves which market (e.g., {'NA': 'Mexico', ...}). - 'logistics_plan': The Ocean/Air shipping mix for each market. Returns: dict: A dictionary containing the strategy's definition, raw simulation results, and key performance metrics (profit, CO2, etc.). """ plant_map = strategy_def['plant_map'] logistics_plan = strategy_def['logistics_plan'] # --- Calculate Total Fixed Costs for the Strategy --- # 1. Add plant costs (only for unique plants used in the strategy). fixed_cost = sum(PLANT_FC[plant] for plant in set(plant_map.values())) # 2. Add the costs for each active shipping lane. for region, plant in plant_map.items(): fixed_cost += SHIPPING_LANE_FC.get((plant, region), 0) # --- Run the Monte Carlo Simulation --- demand_std_dev = DEMAND_BASELINE * DEMAND_VOLATILITY scenarios = [] for _ in range(N_SCENARIOS): # Simulate total demand for this one scenario (future). total_demand = np.random.normal(DEMAND_BASELINE, demand_std_dev) # We can't sell more servers than we can produce. units_sold_total = min(total_demand, MAX_SERVERS_2026) total_profit = 0 total_co2_k_tons = 0 # Calculate profit and CO2 contributions from each market region. for region, mix_share in DEMAND_MIX.items(): units_for_region = units_sold_total * mix_share logistics_mix = logistics_plan[region] # Get the specific logistics mix for this region. # Calculate the weighted average variable costs and emissions for this region. avg_logistics_vc = (logistics_mix['Ocean'] * LOGISTICS_VC['Ocean']) + (logistics_mix['Air'] * LOGISTICS_VC['Air']) avg_co2_kg = (logistics_mix['Ocean'] * CO2_EMISSIONS['Ocean']) + (logistics_mix['Air'] * CO2_EMISSIONS['Air']) # Simulate a random carbon price for this scenario to model regulatory risk. carbon_price = np.random.uniform(*CARBON_PRICE_RANGE) # Calculate the carbon tax cost per server. carbon_cost_per_unit = (avg_co2_kg / 1000) * carbon_price # Convert kg to tons for pricing. # Calculate the total variable cost for one server shipped to this region. total_vc_per_unit = (GPUS_PER_SERVER * GPU_BENCHMARK_COST) + OTHER_COMPONENTS_COST + avg_logistics_vc + carbon_cost_per_unit # Calculate the total profit and CO2 for this region and add to the totals. total_profit += units_for_region * (SERVER_REVENUE - total_vc_per_unit) total_co2_k_tons += (units_for_region * avg_co2_kg) / 1_000_000 # Convert kg to kilo-tons. # Subtract the total fixed costs at the end to get the final profit for this scenario. total_profit -= fixed_cost scenarios.append({'profit': total_profit, 'co2_k_tons': total_co2_k_tons, 'units_sold': units_sold_total}) # --- Aggregate Simulation Results --- scenario_df = pd.DataFrame(scenarios) # Calculate resilience score: more plants = more resilient. resilience_score = {1: 10, 2: 60, 3: 100}.get(len(set(plant_map.values())), 0) return { "definition": strategy_def, "results_df": scenario_df, "metrics": { "profit": scenario_df['profit'].mean(), "growth": scenario_df['units_sold'].mean(), "sustainability": scenario_df['co2_k_tons'].mean(), "resilience": resilience_score } } def _check_feasibility_and_penalties(self, result): """ Checks if a simulated strategy meets the user's 'hard constraints'. Args: result (dict): The output from the `_evaluate_single_strategy` method. Returns: dict: The original result dictionary, updated with feasibility information and a 'penalty_score' for ranking infeasible options. """ df = result['results_df'] # Check for violations of the hard constraints. # 'ocean' and 'resilience' are simple checks on the strategy's definition. ocean_violation = any(result['definition']['logistics_plan'][r]['Ocean'] > self.hard_constraints['max_ocean_share'] for r in DEMAND_MIX) resilience_violation = result['metrics']['resilience'] < self.hard_constraints['min_resilience_score'] # For 'profit' and 'co2', we calculate the *probability* of violating the constraint across all scenarios. profit_violation_prob = (df['profit'] < self.hard_constraints['min_profit_M'] * 1e6).mean() co2_violation_prob = (df['co2_k_tons'] > self.hard_constraints['max_co2_ktons']).mean() violations_summary = { 'profit': profit_violation_prob, 'co2': co2_violation_prob, 'ocean': ocean_violation, 'resilience': resilience_violation } # A strategy is considered 'feasible' if it doesn't violate the simple rules AND the probability # of violating the financial/CO2 rules is less than 5%. is_feasible = (profit_violation_prob < 0.05) and (co2_violation_prob < 0.05) and not ocean_violation and not resilience_violation # Calculate a penalty score for ranking infeasible strategies (how badly did it miss?). profit_shortfall = np.maximum(0, self.soft_constraints['target_profit_M'] * 1e6 - df['profit']).mean() co2_excess = np.maximum(0, df['co2_k_tons'] - self.soft_constraints['target_co2_ktons']).mean() total_penalty = (profit_shortfall / 1e6) + (co2_excess / 0.1) result['feasibility'] = {'is_feasible': is_feasible, 'violations': violations_summary} result['penalty_score'] = total_penalty return result def _score_strategies(self): """Calculates a weighted 'Strategic Score' for all feasible strategies.""" if not self.feasible_strategies: return # To score fairly, we first normalize each metric from 0 to 100. min_vals = {key: min(s['metrics'][key] for s in self.feasible_strategies) for key in self.weights} max_vals = {key: max(s['metrics'][key] for s in self.feasible_strategies) for key in self.weights} for strat in self.feasible_strategies: total_score = 0 for objective, weight in self.weights.items(): val = strat['metrics'][objective] range_val = max_vals[objective] - min_vals[objective] # Normalize the value to a 0-100 scale. norm_score = 100 if range_val == 0 else 100 * (val - min_vals[objective]) / range_val # For sustainability, lower is better, so we flip the score. if objective == 'sustainability': norm_score = 100 - norm_score # Apply the user's chosen weights. total_score += norm_score * (weight / 100.0) strat['strategic_score'] = total_score # Sort the feasible strategies by their final score, from best to worst. self.feasible_strategies.sort(key=lambda x: x['strategic_score'], reverse=True) def run(self): """ Executes the entire end-to-end analysis. This is the main driver function of the class. """ plants, regions = ['US', 'Mexico', 'Malaysia'], ['NA', 'APAC', 'EU'] # --- Generate All Possible Strategies --- # 1. Generate every possible combination of plants serving regions (3^3 = 27). all_plant_maps = [dict(zip(regions, p)) for p in itertools.product(plants, repeat=len(regions))] # 2. Define the discrete logistics options we want to test. logistics_options = [{'Ocean': 0.1, 'Air': 0.9}, {'Ocean': 0.8, 'Air': 0.2}, {'Ocean': 1.0, 'Air': 0.0}] # 3. Generate every combination of these logistics options across the 3 regions (3^3 = 27). all_logistics_plans = [dict(zip(regions, combo)) for combo in itertools.product(logistics_options, repeat=len(regions))] # 4. Create the final list of all strategies to test (27 * 27 = 729). strategy_definitions = [{'plant_map': p_map, 'logistics_plan': l_plan} for p_map in all_plant_maps for l_plan in all_logistics_plans] # --- Evaluate and Classify Each Strategy --- print(f"\nAnalyzing {len(strategy_definitions)} potential strategies...") for i, strat_def in enumerate(strategy_definitions): print(f" - Evaluating strategy {i+1}/{len(strategy_definitions)}...", end='\r') result = self._evaluate_single_strategy(strat_def) result = self._check_feasibility_and_penalties(result) # Add the result to the appropriate list based on its feasibility. if result['feasibility']['is_feasible']: self.feasible_strategies.append(result) else: self.infeasible_strategies.append(result) print("\nAnalysis complete.") # Score and rank the results, then display the final report. self._score_strategies() self._display_report() def _display_report(self): """Prints the final, formatted executive summary and recommendations.""" print("\n" + "="*80 + "\n** Executive Summary: Strategic Analysis for 2026 **\n" + "="*80) if not self.feasible_strategies: print("\n**Feasibility Check: No strategy was found that meets all hard constraints.**\n") if self.infeasible_strategies: self._display_relaxation_advice() # Provide advice on how to find a feasible solution. else: top_score = self.feasible_strategies[0]['strategic_score'] print(f"\n**Feasibility Check: Found {len(self.feasible_strategies)} feasible strategies.**") print(f"The top-ranked strategy achieved a Strategic Score of {top_score:.1f}/100 based on your priorities.\n") print("-" * 80 + "\n** Strategy Recommendations **\n" + "-" * 80) if self.feasible_strategies: # Show the top-ranked strategy. self._print_strategy_card(f"Recommended Strategy (Score: {self.feasible_strategies[0]['strategic_score']:.1f})", self.feasible_strategies[0]) # If available, show the next-best option as an alternative. if len(self.feasible_strategies) > 1: self._print_strategy_card(f"Alternative Strategy (Score: {self.feasible_strategies[1]['strategic_score']:.1f})", self.feasible_strategies[1], is_alt=True) elif self.infeasible_strategies: # If no strategies were feasible, show the "least bad" one for analysis. best_infeasible = min(self.infeasible_strategies, key=lambda x: x['penalty_score']) self._print_strategy_card("Least Infeasible Strategy (For Analysis)", best_infeasible, is_alt=True) def _print_strategy_card(self, title, strat, is_alt=False): """Prints a formatted summary card for a single strategy.""" print(f"\n--- {title} ---") if not strat['feasibility']['is_feasible']: print(f" **Warning:** This strategy is NOT feasible and is shown for analysis only.") metrics, definition = strat['metrics'], strat['definition'] print(f" - Profile: Profit: ${metrics['profit']/1e6:,.1f}M | CO2: {metrics['sustainability']:,.2f} k-tons | Resilience: {metrics['resilience']:.0f}/100") print("\n - Operational Plan:") for region in ['NA', 'APAC', 'EU']: plant, logistics = definition['plant_map'][region], definition['logistics_plan'][region] units = metrics['growth'] * DEMAND_MIX[region] print(f" - {region} Market ({units:,.0f} units): Assemble in '{plant}', Ship via {logistics['Ocean']:.0%} Ocean / {logistics['Air']:.0%} Air") def _display_relaxation_advice(self): """ Provides intelligent advice if no feasible solutions were found. This function prioritizes the user's agility/resilience constraints. """ print("-" * 80 + "\n** Relaxation Engine: Path to a Feasible Solution **\n" + "-" * 80) # 1. Filter out any strategies that already violate the most important business rules (ocean share and resilience). compliant_infeasible = [ s for s in self.infeasible_strategies if not s['feasibility']['violations']['ocean'] and not s['feasibility']['violations']['resilience'] ] if not compliant_infeasible: print("No strategies could be found that satisfy even the basic Ocean Freight and Resilience constraints.") print("This suggests the constraints are fundamentally too tight. Consider relaxing one of these first.") return # 2. From the compliant-but-infeasible pool, find the 'best' one (the one that failed by the smallest margin on profit/CO2). best_infeasible = min(compliant_infeasible, key=lambda x: x['penalty_score']) violations = best_infeasible['feasibility']['violations'] metrics = best_infeasible['metrics'] print("After enforcing your core Ocean and Resilience rules, no strategy was feasible.") print("Analysis of the 'closest compliant' strategy shows the following financial gaps:") recommendations = [] # 3. Generate advice based on the gaps in this 'best compliant' strategy. if violations['profit'] > 0.05: required_M, actual_M = self.hard_constraints['min_profit_M'], metrics['profit'] / 1e6 gap_M = required_M - actual_M if gap_M > 0: new_profit_target = math.floor(actual_M) recommendations.append(f" 1. Lower the 'Minimum Profit' from ${required_M:,.1f}M to ${new_profit_target:,.1f}M.") print(f" - PROFIT: Minimum of ${required_M:,.1f}M was missed by ${gap_M:,.1f}M.") if violations['co2'] > 0.05: required_ktons, actual_ktons = self.hard_constraints['max_co2_ktons'], metrics['sustainability'] gap_ktons = actual_ktons - required_ktons if gap_ktons > 0: new_co2_target = math.ceil(actual_ktons * 10) / 10 recommendations.append(f" 2. Increase the 'Maximum CO2' from {required_ktons:,.2f} to {new_co2_target:,.2f} k-tons.") print(f" - CO2: Maximum of {required_ktons:,.2f} k-tons was exceeded by {gap_ktons:,.2f} k-tons.") if recommendations: print("\n**Recommendation:** To find a feasible solution while respecting your Ocean/Resilience rules,") print("you must make a trade-off. Re-run with ONE of the following adjustments:") for rec in recommendations: print(rec) else: print("\nNo single clear adjustment found. The closest strategy fails on a combination of factors.")def get_interactive_inputs(): """Guides the user through a questionnaire to build the decision_input dictionary.""" # Define the preset profiles for easy selection. profiles = { "1": {"name": "Profit First", "weights": {"profit": 60, "resilience": 10, "sustainability": 30}}, "2": {"name": "Balanced Growth", "weights": {"profit": 40, "resilience": 30, "sustainability": 30}}, "3": {"name": "Resilience First", "weights": {"profit": 20, "resilience": 50, "sustainability": 30}}, } # --- Step 1: Get Strategic Priorities (Weights) --- print("="*80 + "\nStep 1: Choose a Strategic Profile\n" + "-"*80) for key, val in profiles.items(): print(f" [{key}] {val['name']}") choice = input("Select a profile [1-3] or press Enter for custom: ") if choice in profiles: weights = profiles[choice]['weights'] print(f"Selected '{profiles[choice]['name']}'.") else: # Custom weights input if the user doesn't choose a preset. print("\n-- Custom Priority Weights --\nPlease allocate 100 points across the following objectives:") weights = {} while True: try: weights['profit'] = int(input(f" - Points for Profit: ")) weights['resilience'] = int(input(f" - Points for Resilience: ")) weights['sustainability'] = int(input(f" - Points for Sustainability (Low CO2): ")) if sum(weights.values()) == 100: break else: print(f"Error: Points sum to {sum(weights.values())}, not 100. Please try again.\n") except ValueError: print("Error: Please enter whole numbers.\n") # --- Step 2: Get Hard and Soft Constraints --- print("\n" + "="*80 + "\nStep 2: Define Constraints (Your Non-Negotiable Rules)\n" + "-"*80) hard_constraints, soft_constraints = {}, {} try: hard_constraints['min_resilience_score'] = int(input(" - Min Resilience Score (10, 60, 100): ")) hard_constraints['min_profit_M'] = float(input(" - Min Profit (in millions): ")) soft_constraints['target_profit_M'] = float(input(" - Target Profit (in millions): ")) hard_constraints['max_co2_ktons'] = float(input(" - Max CO2 (in k-tons): ")) soft_constraints['target_co2_ktons'] = float(input(" - Target CO2 (in k-tons): ")) hard_constraints['max_ocean_share'] = float(input(" - Max Ocean Freight Share per Market (0.0 to 1.0): ")) except ValueError: print("\nInvalid input. Using default values for demonstration.") hard_constraints = {'min_resilience_score': 60, 'min_profit_M': 210, 'max_co2_ktons': 8.5, 'max_ocean_share': 0.8} soft_constraints = {'target_profit_M': 220, 'target_co2_ktons': 8.0} # Return all the user inputs in a single dictionary. return {"objective_weights": weights, "hard_constraints": hard_constraints, "soft_constraints": soft_constraints}if __name__ == '__main__': """ Main execution block. This code runs when the script is executed directly. """ # 1. Get all the necessary inputs from the user. executive_inputs = get_interactive_inputs() # 2. Create an instance of the decision engine with those inputs. sde = StrategicDecisionEngine(executive_inputs) # 3. Run the full analysis. sde.run()