Sudeeksha-07's picture
Deploy Emergency Resource Environment
7266370
Raw
History Blame Contribute Delete
7.27 kB
import numpy as np
from typing import Dict, List, Optional, Tuple, Any
from dataclasses import dataclass, asdict
from datetime import datetime
import random
from .models import Observation, Action, Reward, State, ServiceRequest
class EmergencyResourceEnv:
"""
Emergency Resource Allocation Environment
Grid-based city where agent allocates resources to service requests
"""
def __init__(self, grid_size: int = 5, max_time_steps: int = 50):
self.grid_size = grid_size
self.max_time_steps = max_time_steps
# Environment state
self.agent_pos: Tuple[int, int] = (0, 0)
self.requests: List[ServiceRequest] = []
self.time_left: int = max_time_steps
self.resources_left: int = 10
self.current_step: int = 0
self.total_reward: float = 0.0
self.done: bool = False
self.task_config: Dict[str, Any] = {}
def reset(self, task_config: Optional[Dict[str, Any]] = None) -> Observation:
"""Reset environment to initial state"""
self.agent_pos = (0, 0)
self.time_left = self.max_time_steps
self.resources_left = 10
self.current_step = 0
self.total_reward = 0.0
self.done = False
# Load task configuration
self.task_config = task_config or {}
# Generate service requests based on task
self._generate_requests()
return self._get_observation()
def _generate_requests(self):
"""Generate service requests based on task difficulty"""
task_difficulty = self.task_config.get('difficulty', 'medium')
if task_difficulty == 'easy':
num_requests = 3
critical_ratio = 0.33 # 1 critical, 2 normal
elif task_difficulty == 'medium':
num_requests = 5
critical_ratio = 0.4 # 2 critical, 3 normal
else: # hard
num_requests = 8
critical_ratio = 0.5 # 4 critical, 4 normal
self.requests = []
for i in range(num_requests):
priority = 'critical' if random.random() < critical_ratio else 'normal'
# Ensure critical requests aren't too clustered
if priority == 'critical' and len([r for r in self.requests if r.priority == 'critical']) >= num_requests * critical_ratio:
priority = 'normal'
# Generate position not overlapping with existing requests
while True:
pos = (random.randint(0, self.grid_size-1),
random.randint(0, self.grid_size-1))
if not any(r.position == pos for r in self.requests):
break
self.requests.append(ServiceRequest(
id=i,
position=pos,
priority=priority,
allocated=False,
created_at=self.current_step
))
def step(self, action: Action) -> Tuple[Observation, Reward, bool, Dict]:
"""Execute action and return new state"""
if self.done:
return self._get_observation(), Reward(score=0.0), True, {"error": "Episode already done"}
# Execute action
action_type = action.action_type
error = None
try:
if action_type == "move":
self._move(action.direction)
elif action_type == "allocate":
reward_change = self._allocate_resources()
else:
error = f"Unknown action type: {action_type}"
reward_change = -1.0
except Exception as e:
error = str(e)
reward_change = -1.0
# Apply step penalty
step_penalty = -0.5
self.total_reward += step_penalty
self.current_step += 1
self.time_left -= 1
# Check episode termination
all_requests_served = all(r.allocated for r in self.requests)
time_out = self.time_left <= 0
resources_depleted = self.resources_left <= 0
if all_requests_served:
self.total_reward += 30 # Completion bonus
self.done = True
elif time_out:
self.total_reward -= 20 # Time out penalty
self.done = True
elif resources_depleted:
self.done = True
elif self.current_step >= self.max_time_steps:
self.done = True
# Get final reward
reward = Reward(score=max(0.0, min(1.0, (self.total_reward + 50) / 100)))
return self._get_observation(), reward, self.done, {"error": error}
def _move(self, direction: str):
"""Move agent in grid"""
x, y = self.agent_pos
if direction == "up" and x > 0:
self.agent_pos = (x - 1, y)
elif direction == "down" and x < self.grid_size - 1:
self.agent_pos = (x + 1, y)
elif direction == "left" and y > 0:
self.agent_pos = (x, y - 1)
elif direction == "right" and y < self.grid_size - 1:
self.agent_pos = (x, y + 1)
def _allocate_resources(self) -> float:
"""Allocate resources at current position"""
reward_change = 0.0
# Check if any request at current position
for request in self.requests:
if not request.allocated and request.position == self.agent_pos:
if self.resources_left > 0:
request.allocated = True
self.resources_left -= 1
if request.priority == "critical":
reward_change = 20.0
else:
reward_change = 10.0
self.total_reward += reward_change
break
return reward_change
def _get_observation(self) -> Observation:
"""Get current observation"""
# Create grid representation
grid = np.zeros((self.grid_size, self.grid_size, 3)) # 3 channels: agent, critical, normal
# Agent position
grid[self.agent_pos[0], self.agent_pos[1], 0] = 1
# Requests
for req in self.requests:
if not req.allocated:
channel = 1 if req.priority == "critical" else 2
grid[req.position[0], req.position[1], channel] = 1
return Observation(
agent_position=self.agent_pos,
grid=grid.tolist(),
requests=[r for r in self.requests if not r.allocated],
time_left=self.time_left,
resources_left=self.resources_left,
step=self.current_step,
task_config=self.task_config
)
def state(self) -> State:
"""Get current state"""
return State(
agent_position=self.agent_pos,
requests=[asdict(r) for r in self.requests],
time_left=self.time_left,
resources_left=self.resources_left,
current_step=self.current_step,
done=self.done,
total_reward=self.total_reward
)