Spaces:
Sleeping
Sleeping
Commit ·
867d483
1
Parent(s): 47438e4
Update README to match Container Yard behavior
Browse files
README.md
CHANGED
|
@@ -24,7 +24,7 @@ Port container yards are critical logistics infrastructure where thousands of co
|
|
| 24 |
|
| 25 |
### How It Works
|
| 26 |
1. **Containers Arrive**: Containers arrive sequentially, each with a retrieval priority (1=earliest, 3=latest)
|
| 27 |
-
2. **Placement Decision**: Agent must choose
|
| 28 |
3. **Rehandle Penalty**: If a high-priority container is placed below a low-priority container, it must be rehandled during retrieval
|
| 29 |
4. **Reward Signal**: Agent receives immediate feedback based on placement efficiency
|
| 30 |
|
|
@@ -232,22 +232,31 @@ The deployed space includes:
|
|
| 232 |
## Environment Details
|
| 233 |
|
| 234 |
### Action
|
| 235 |
-
**ContainerYardAction**: Contains a single field
|
| 236 |
-
- `
|
| 237 |
|
| 238 |
### Observation
|
| 239 |
-
**ContainerYardObservation**:
|
| 240 |
-
- `
|
| 241 |
-
- `
|
| 242 |
-
- `
|
| 243 |
-
- `
|
| 244 |
-
- `
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 245 |
|
| 246 |
### Reward
|
| 247 |
-
The reward is calculated
|
| 248 |
-
-
|
| 249 |
-
-
|
| 250 |
-
-
|
|
|
|
|
|
|
|
|
|
| 251 |
|
| 252 |
## Advanced Usage
|
| 253 |
|
|
@@ -257,13 +266,14 @@ If you already have a Container Yard environment server running, you can connect
|
|
| 257 |
|
| 258 |
```python
|
| 259 |
from Container_Yard import ContainerYardEnv
|
|
|
|
| 260 |
|
| 261 |
# Connect to existing server
|
| 262 |
Container_Yardenv = ContainerYardEnv(base_url="<ENV_HTTP_URL_HERE>")
|
| 263 |
|
| 264 |
# Use as normal
|
| 265 |
result = Container_Yardenv.reset()
|
| 266 |
-
result = Container_Yardenv.step(ContainerYardAction(
|
| 267 |
```
|
| 268 |
|
| 269 |
Note: When connecting to an existing server, `Container_Yardenv.close()` will NOT stop the server.
|
|
@@ -278,11 +288,15 @@ from Container_Yard import ContainerYardAction, ContainerYardEnv
|
|
| 278 |
# Connect with context manager (auto-connects and closes)
|
| 279 |
with ContainerYardEnv(base_url="http://localhost:8000") as env:
|
| 280 |
result = env.reset()
|
| 281 |
-
print(f"
|
| 282 |
# Multiple steps with low latency
|
| 283 |
-
for
|
| 284 |
-
result = env.step(ContainerYardAction(
|
| 285 |
-
print(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 286 |
```
|
| 287 |
|
| 288 |
The client uses WebSocket connections for:
|
|
@@ -314,9 +328,15 @@ from concurrent.futures import ThreadPoolExecutor
|
|
| 314 |
def run_episode(client_id: int):
|
| 315 |
with ContainerYardEnv(base_url="http://localhost:8000") as env:
|
| 316 |
result = env.reset()
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 320 |
|
| 321 |
# Run 4 episodes concurrently
|
| 322 |
with ThreadPoolExecutor(max_workers=4) as executor:
|
|
|
|
| 24 |
|
| 25 |
### How It Works
|
| 26 |
1. **Containers Arrive**: Containers arrive sequentially, each with a retrieval priority (1=earliest, 3=latest)
|
| 27 |
+
2. **Placement Decision**: Agent must choose a valid stack index (0 to num_stacks-1) for the current task
|
| 28 |
3. **Rehandle Penalty**: If a high-priority container is placed below a low-priority container, it must be rehandled during retrieval
|
| 29 |
4. **Reward Signal**: Agent receives immediate feedback based on placement efficiency
|
| 30 |
|
|
|
|
| 232 |
## Environment Details
|
| 233 |
|
| 234 |
### Action
|
| 235 |
+
**ContainerYardAction**: Contains a single required field
|
| 236 |
+
- `stack_index` (int) - Index of the stack to place the current container into
|
| 237 |
|
| 238 |
### Observation
|
| 239 |
+
**ContainerYardObservation**:
|
| 240 |
+
- `stacks` (List[List[int]]) - Current stack states as container IDs
|
| 241 |
+
- `containers_placed` (int) - Number of placed containers
|
| 242 |
+
- `total_containers` (int) - Episode container count
|
| 243 |
+
- `current_container_id` (int) - Next container to place, `-1` if done
|
| 244 |
+
- `current_container_priority` (int) - Priority in range `1..3`
|
| 245 |
+
- `rehandles_so_far` (int) - Accumulated rehandles
|
| 246 |
+
- `num_stacks` (int) - Number of stacks in the current task
|
| 247 |
+
- `max_stack_height` (int) - Capacity per stack
|
| 248 |
+
- `action_error` (Optional[str]) - Validation error for invalid/full stack actions
|
| 249 |
+
- `reward` (float) - Step reward
|
| 250 |
+
- `done` (bool) - Whether episode is complete
|
| 251 |
|
| 252 |
### Reward
|
| 253 |
+
The reward is calculated per valid placement:
|
| 254 |
+
- `+0.1` base reward for a valid placement
|
| 255 |
+
- `-0.5 * rehandles_caused` penalty for new rehandles introduced by this move
|
| 256 |
+
- `+0.3` bonus when placement causes zero rehandles
|
| 257 |
+
- `+0.2` bonus when the container is stacked on same-priority container
|
| 258 |
+
|
| 259 |
+
Invalid actions (out-of-range index or full stack) return `reward=0.0` and set `action_error`.
|
| 260 |
|
| 261 |
## Advanced Usage
|
| 262 |
|
|
|
|
| 266 |
|
| 267 |
```python
|
| 268 |
from Container_Yard import ContainerYardEnv
|
| 269 |
+
from models import ContainerYardAction
|
| 270 |
|
| 271 |
# Connect to existing server
|
| 272 |
Container_Yardenv = ContainerYardEnv(base_url="<ENV_HTTP_URL_HERE>")
|
| 273 |
|
| 274 |
# Use as normal
|
| 275 |
result = Container_Yardenv.reset()
|
| 276 |
+
result = Container_Yardenv.step(ContainerYardAction(stack_index=0))
|
| 277 |
```
|
| 278 |
|
| 279 |
Note: When connecting to an existing server, `Container_Yardenv.close()` will NOT stop the server.
|
|
|
|
| 288 |
# Connect with context manager (auto-connects and closes)
|
| 289 |
with ContainerYardEnv(base_url="http://localhost:8000") as env:
|
| 290 |
result = env.reset()
|
| 291 |
+
print(f"Current container: {result.observation.current_container_id}")
|
| 292 |
# Multiple steps with low latency
|
| 293 |
+
for _ in range(3):
|
| 294 |
+
result = env.step(ContainerYardAction(stack_index=0))
|
| 295 |
+
print(
|
| 296 |
+
f"Placed={result.observation.containers_placed} "
|
| 297 |
+
f"rehandles={result.observation.rehandles_so_far} "
|
| 298 |
+
f"reward={result.reward:.2f}"
|
| 299 |
+
)
|
| 300 |
```
|
| 301 |
|
| 302 |
The client uses WebSocket connections for:
|
|
|
|
| 328 |
def run_episode(client_id: int):
|
| 329 |
with ContainerYardEnv(base_url="http://localhost:8000") as env:
|
| 330 |
result = env.reset()
|
| 331 |
+
while not result.done:
|
| 332 |
+
# Simple policy: choose first non-full stack
|
| 333 |
+
obs = result.observation
|
| 334 |
+
next_stack = next(
|
| 335 |
+
idx for idx, stack in enumerate(obs.stacks)
|
| 336 |
+
if len(stack) < obs.max_stack_height
|
| 337 |
+
)
|
| 338 |
+
result = env.step(ContainerYardAction(stack_index=next_stack))
|
| 339 |
+
return client_id, result.observation.rehandles_so_far
|
| 340 |
|
| 341 |
# Run 4 episodes concurrently
|
| 342 |
with ThreadPoolExecutor(max_workers=4) as executor:
|