Files
boc/iom/decision_support/autonomous_recommendations.py
T

349 lines
11 KiB
Python
Raw Normal View History

"""
Autonomous Recommendations
AI generates action plans automatically
"""
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass
from datetime import datetime
@dataclass
class ActionPlan:
"""An autonomous action plan"""
plan_id: str
target_goal: str
budget_usd: float
actions: List[Dict]
expected_outcome: Dict
confidence: float
timeline_months: int
def to_dict(self) -> Dict:
return {
"plan_id": self.plan_id,
"target_goal": self.target_goal,
"budget_usd": self.budget_usd,
"actions": self.actions,
"expected_outcome": self.expected_outcome,
"confidence": round(self.confidence, 2),
"timeline_months": self.timeline_months
}
class AutonomousRecommendationEngine:
"""Generates autonomous action plans"""
def __init__(self):
self.action_library = self._load_action_library()
def _load_action_library(self) -> Dict:
"""Load available actions and their effects"""
return {
"replace_lighting": {
"name": "Replace street lighting with LED",
"cost_per_unit": 5000,
"typical_units": 100,
"effects": {
"safety_index": +15,
"night_activity": +20,
"energy_efficiency": +25
},
"timeline_months": 4
},
"repair_sidewalks": {
"name": "Repair damaged sidewalks",
"cost_per_unit": 2000,
"typical_units": 50,
"effects": {
"walkability": +20,
"safety_index": +10,
"accessibility": +15
},
"timeline_months": 3
},
"plant_trees": {
"name": "Plant trees along streets",
"cost_per_unit": 500,
"typical_units": 40,
"effects": {
"shade_index": +25,
"heat_stress": -15,
"walkability": +10,
"property_value": +5
},
"timeline_months": 12
},
"remove_graffiti": {
"name": "Remove graffiti and paint walls",
"cost_per_unit": 1000,
"typical_units": 20,
"effects": {
"visual_maintenance": +30,
"safety_index": +8,
"property_value": +3
},
"timeline_months": 1
},
"add_bike_lanes": {
"name": "Add dedicated bike lanes",
"cost_per_unit": 15000,
"typical_units": 10,
"effects": {
"bicycle_friendliness": +40,
"walkability": +10,
"traffic_intensity": -5
},
"timeline_months": 6
},
"improve_crossings": {
"name": "Improve pedestrian crossings",
"cost_per_unit": 3000,
"typical_units": 15,
"effects": {
"walkability": +15,
"safety_index": +12,
"accessibility": +10
},
"timeline_months": 2
}
}
def generate_plan(
self,
target_goal: str,
current_state: Dict[str, float],
budget_usd: float,
constraints: Optional[Dict] = None
) -> ActionPlan:
"""
Generate autonomous action plan
Example:
"Increase safety by 15% within 25M SEK budget"
"""
# Parse goal
target_metric, target_improvement = self._parse_goal(target_goal)
# Select best actions
selected_actions = self._select_actions(
target_metric, target_improvement, current_state, budget_usd
)
# Calculate expected outcome
expected_outcome = self._calculate_outcome(current_state, selected_actions)
# Calculate confidence
confidence = self._calculate_confidence(selected_actions, target_improvement)
# Calculate timeline
timeline = max(a["timeline_months"] for a in selected_actions) if selected_actions else 12
return ActionPlan(
plan_id=f"PLAN-{datetime.utcnow().strftime('%Y%m%d-%H%M%S')}",
target_goal=target_goal,
budget_usd=budget_usd,
actions=selected_actions,
expected_outcome=expected_outcome,
confidence=confidence,
timeline_months=timeline
)
def _parse_goal(self, goal: str) -> Tuple[str, float]:
"""Parse goal string"""
# Simple parsing
if "safety" in goal.lower():
return "safety_index", 15
elif "family" in goal.lower():
return "family_friendly", 12
elif "walk" in goal.lower():
return "walkability", 20
elif "green" in goal.lower():
return "greenery", 25
else:
return "safety_index", 15
def _select_actions(
self,
target_metric: str,
target_improvement: float,
current_state: Dict[str, float],
budget_usd: float
) -> List[Dict]:
"""Select best actions to achieve goal"""
candidates = []
for action_id, action in self.action_library.items():
# Calculate effect on target metric
effect = action["effects"].get(target_metric, 0)
if effect > 0:
cost = action["cost_per_unit"] * action["typical_units"]
efficiency = effect / max(cost / 100000, 1)
candidates.append({
"action_id": action_id,
"name": action["name"],
"cost": cost,
"effect": effect,
"efficiency": efficiency,
"timeline_months": action["timeline_months"],
"units": action["typical_units"]
})
# Sort by efficiency
candidates.sort(key=lambda x: x["efficiency"], reverse=True)
# Select actions within budget
selected = []
total_cost = 0
total_effect = 0
for candidate in candidates:
if total_cost + candidate["cost"] <= budget_usd and total_effect < target_improvement:
selected.append(candidate)
total_cost += candidate["cost"]
total_effect += candidate["effect"]
return selected
def _calculate_outcome(
self,
current_state: Dict[str, float],
actions: List[Dict]
) -> Dict:
"""Calculate expected outcome"""
outcome = current_state.copy()
for action in actions:
action_id = action["action_id"]
action_def = self.action_library.get(action_id, {})
for metric, effect in action_def.get("effects", {}).items():
if metric in outcome:
outcome[metric] = min(100, outcome[metric] + effect)
return {k: round(v, 1) for k, v in outcome.items()}
def _calculate_confidence(self, actions: List[Dict], target: float) -> float:
"""Calculate confidence in plan"""
if not actions:
return 0
# More actions = higher confidence
action_confidence = min(0.9, len(actions) / 5)
# Higher total effect = higher confidence
total_effect = sum(a["effect"] for a in actions)
effect_confidence = min(0.9, total_effect / target) if target > 0 else 0.5
return (action_confidence + effect_confidence) / 2
def optimize_budget(
self,
target_goal: str,
current_state: Dict[str, float],
budget_range: List[float]
) -> List[Dict]:
"""
Compare plans at different budget levels
Returns:
List of plans with different budgets
"""
plans = []
for budget in budget_range:
plan = self.generate_plan(target_goal, current_state, budget)
plans.append({
"budget": budget,
"actions_count": len(plan.actions),
"expected_improvement": self._get_improvement(current_state, plan.expected_outcome),
"confidence": plan.confidence,
"timeline_months": plan.timeline_months,
"cost_per_improvement": budget / max(self._get_improvement(current_state, plan.expected_outcome), 1)
})
return plans
def _get_improvement(
self,
baseline: Dict[str, float],
outcome: Dict[str, float]
) -> float:
"""Calculate total improvement"""
improvements = []
for metric, baseline_value in baseline.items():
if metric in outcome:
improvement = outcome[metric] - baseline_value
improvements.append(improvement)
return sum(improvements) / len(improvements) if improvements else 0
# Example usage
def example_autonomous_plan():
"""Example: Generate autonomous action plan"""
engine = AutonomousRecommendationEngine()
# Current state
current_state = {
"safety_index": 45,
"walkability": 60,
"night_activity": 35,
"energy_efficiency": 40,
"greenery": 25,
"heat_stress": 80,
"visual_maintenance": 30,
"bicycle_friendliness": 30,
"accessibility": 50
}
# Generate plan
print("=== Autonomous Action Plan ===")
plan = engine.generate_plan(
target_goal="Increase safety by 15%",
current_state=current_state,
budget_usd=25000000 # 25M SEK ≈ 2.5M USD
)
print(f"Plan ID: {plan.plan_id}")
print(f"Goal: {plan.target_goal}")
print(f"Budget: ${plan.budget_usd:,}")
print(f"Timeline: {plan.timeline_months} months")
print(f"Confidence: {plan.confidence}")
print("\nActions:")
for i, action in enumerate(plan.actions, 1):
print(f" {i}. {action['name']}")
print(f" Cost: ${action['cost']:,}")
print(f" Effect: +{action['effect']} safety")
print(f" Timeline: {action['timeline_months']} months")
print("\nExpected Outcome:")
for metric, value in plan.expected_outcome.items():
old_value = current_state.get(metric, 0)
if value != old_value:
print(f" {metric}: {old_value}{value} ({value - old_value:+.1f})")
# Budget optimization
print("\n=== Budget Optimization ===")
budgets = [1000000, 2500000, 5000000, 10000000]
comparisons = engine.optimize_budget("Increase safety", current_state, budgets)
print("Budget | Actions | Improvement | Confidence | Cost/Eff")
print("-" * 60)
for comp in comparisons:
print(f"${comp['budget']:>8,} | {comp['actions_count']:>7} | {comp['expected_improvement']:>11.1f} | {comp['confidence']:>10.2f} | ${comp['cost_per_improvement']:>7.0f}")
return plan
if __name__ == '__main__':
example_autonomous_plan()