# Evaluation

This document describes the DQN evaluation workflow implemented in `eval.py`.

The evaluation script loads a trained DQN policy network, runs the policy in the custom 3D path-planning environment, and reports mission-level performance metrics.

## Overview

The evaluation workflow is used to test whether a trained DQN policy can guide the drone from a start position to a goal position.

The script supports:

- loading known trained model checkpoints
- reconstructing the correct DQN architecture
- running a single evaluation episode
- running batch evaluations across multiple goal positions
- reporting goal-achievement accuracy
- reporting final distance from the goal
- optionally rendering the resulting path

## Model Registry

`eval.py` contains a `NETWORKS` dictionary that maps known model IDs to their architecture settings.

Each entry stores:

```text
model_id: (hidden_nodes, hidden_layers)
```

For example:

```python
NETWORKS = {
    "final_DQN": (512, 2),
    "_27_16_10": (512, 3),
    "_26_23_6": (512, 2),
}
```

This allows the evaluation script to automatically reconstruct the correct network architecture before loading the saved policy weights.

If a model ID is not listed in `NETWORKS`, the number of hidden layers and hidden nodes must be provided manually using command-line arguments.

## Evaluation Class

The main evaluation logic is implemented in the `Eval` class.

```python
eval_runner = Eval()
eval_runner.run()
```

The class handles:

- environment creation
- policy network creation
- checkpoint loading
- path planning using the trained policy
- single-test evaluation
- batch-test evaluation
- metric reporting

## Main Functions

## `parse_range`

```python
parse_range(range_str)
```

Parses a command-line range string into a Python `range`.

For example:

```bash
--goal_range 250-1000
```

is parsed into:

```python
range(250, 1001)
```

## `parse_bool`

```python
parse_bool(bool_str)
```

Parses command-line boolean values such as:

```text
true, false, t, f, 1, 0, yes, no, y, n
```

This is mainly used for flags such as `--render`.

## `parse_opt`

```python
parse_opt()
```

Defines and parses command-line arguments for evaluation.

## `input_handling`

```python
input_handling(opt)
```

Checks whether the requested model ID is known.

If the model ID is listed in `NETWORKS`, the correct number of hidden nodes and hidden layers is filled in automatically.

If the model ID is not known, the user must provide:

```bash
--neurons
--layers
```

If rendering is enabled for a single test, the function also increases verbosity so that path logs are available for rendering.

## `Eval.plan_path`

```python
plan_path()
```

Runs the trained policy in the environment until a termination condition is reached.

During each step:

1. The current state is processed into a tensor.
2. The policy network predicts Q-values.
3. The action with the highest Q-value is selected.
4. The environment applies the action.
5. The environment checks for collision or goal completion.

The method also includes safeguards to stop evaluation if the drone repeats positions or if the episode becomes too long.

Pressing `esc` during evaluation can also interrupt the run.

## `Eval.batch_test`

```python
batch_test()
```

Runs multiple evaluation episodes and prints summary metrics.

This is the default evaluation mode.

Batch evaluation can use:

- random goal distances from a range
- a constant goal distance
- ascending goal distances using a multiplier

## `Eval.test`

```python
test()
```

Runs a single evaluation episode.

If rendering is enabled, the resulting path is rendered after the episode.

## `Eval.run`

```python
run()
```

Runs either a single test or a batch test depending on `test_mode`.

## Command-Line Arguments

| Argument | Description | Default |
|---|---|---|
| `--id` | Model ID to evaluate | `final_DQN` |
| `--model_dir` | Directory containing saved model checkpoints | `models` |
| `--neurons` | Number of hidden nodes for unknown models | `None` |
| `--layers` | Number of hidden layers for unknown models | `None` |
| `--batch_size` | Number of evaluation episodes | `10` |
| `--mode` | Goal-distance mode | `random` |
| `--test_mode` | Evaluation mode: `single` or `batch` | `batch` |
| `--multiplier` | Distance multiplier for ascending mode | `1` |
| `--verbosity` | Environment logging level | `0` |
| `--render` | Whether to render the path after a single test | `False` |
| `--goal_dist` | Goal distance for single or constant-distance tests | `500` |
| `--goal_range` | Goal-distance range for random batch tests | `250-1000` |
| `--step_length` | Environment step length | `10` |
| `--threshold` | Distance threshold for goal completion | `40` |

## Usage

Run evaluation from the project root.

### Default Batch Evaluation

```bash
python -m dqn_path_planning.eval
```

This evaluates the default model using 10 test episodes.

### Evaluate a Specific Model

```bash
python -m dqn_path_planning.eval --id final_DQN
```

### Batch Evaluation with 100 Episodes

```bash
python -m dqn_path_planning.eval --batch_size 100
```

### Single Evaluation Episode

```bash
python -m dqn_path_planning.eval --test_mode single
```

### Single Evaluation with Rendering

```bash
python -m dqn_path_planning.eval --test_mode single --render true --verbosity 2
```

### Evaluate an Unknown Model Architecture

If a model is not listed in `NETWORKS`, provide the architecture manually:

```bash
python -m dqn_path_planning.eval \
    --id custom_model \
    --neurons 512 \
    --layers 3
```

The expected model checkpoint name is:

```text
<model_id>_policy_net.pth
```

For example:

```text
final_DQN_policy_net.pth
```

## Output Metrics

For a standard 10-episode batch evaluation, the output includes:

- elapsed evaluation time
- number of goals achieved
- number of goals not achieved
- goal-achievement accuracy
- per-episode final distance from the goal
- per-episode termination status
- per-episode initial distance
- average failed-mission distances

Example:

```text
Time elapsed:   0.32541847229003906
---------------------------------------------
Goal Achieved Count:                    7
Goal Not Achieved Count:                3
Accuracy:                               70.00%
---------------------------------------------
Episode 0. Distance from goal 33.83784863137726. Termination event 1. Initial distance 598.652653882032.
Episode 1. Distance from goal 39.67366884975475. Termination event 1. Initial distance 362.6761640913282.
Episode 2. Distance from goal 51.39066063011839. Termination event 0. Initial distance 766.0815883442181.
Failed missions: average initial distance 680.4885109285924, final distance 55.269048740505134
```

When the batch size is greater than 20, individual episode metrics are not printed. This keeps the output readable for larger evaluations.

Example:

```bash
python -m dqn_path_planning.eval --batch_size 100
```

```text
Time elapsed:   2.457918882369995
---------------------------------------------
Goal Achieved Count:                    69
Goal Not Achieved Count:                31
Accuracy:                               69.00%
---------------------------------------------
Failed missions: average initial distance 680.4885109285924, final distance 55.269048740505134
```

## Evaluation Modes

## Random Goal Distance

Random goal distances are sampled from `goal_range`.

```bash
python -m dqn_path_planning.eval --mode random --goal_range 250-1000
```

This is the default batch-evaluation setup.

## Constant Goal Distance

A fixed goal distance can be used by setting `mode` to a non-random mode and passing `goal_dist`.

```bash
python -m dqn_path_planning.eval --mode constant --goal_dist 500
```

## Ascending Distance

The `multiplier` argument can be used to increase the target distance between tests when using a non-random distance mode.

```bash
python -m dqn_path_planning.eval --mode ascending --goal_dist 250 --multiplier 1.1
```

## Rendering

Rendering is intended for single-test evaluation.

```bash
python -m dqn_path_planning.eval --test_mode single --render true --verbosity 2
```

When rendering is enabled, the environment logs the drone path and then visualizes the recorded trajectory.

## Notes

- Evaluation uses the trained policy network only.
- The target network is not required for evaluation.
- The selected action is the action with the highest predicted Q-value.
- The default evaluation state excludes `"prev_position"`, matching the training setup.
- The `keyboard` package is used to allow evaluation runs to be interrupted by pressing `esc`.
- The evaluation script includes an optional ESC-key interruption check using the `keyboard` package. In environments without direct keyboard-device access, such as Docker containers, this check is safely ignored.
- The model checkpoint must match the architecture used to create the network.
- If the model is not listed in `NETWORKS`, provide `--neurons` and `--layers`.
