=== GENERATED PROMPT FOR AGENT ===

# Universal MiniZinc Instance Characteristics Extraction

Create a Python script that extracts instance characteristics from the problem instance 'example.json'. These characteristics will be used by a separate process to determine optimal solver parameters.

## Input Format

# JSON Schema for Vehicle Routing Problem (VRP)

This document describes the JSON format for Vehicle Routing Problem instances.

## Schema

```json
{
  "N": <integer>,
  "Capacity": <integer>,
  "Demand": [<integer>, ...],
  "Distance": [<integer>, ...]
}
```

## Fields

- **N**: Number of customer nodes (excluding the depot)
- **Capacity**: Vehicle capacity constraint
- **Demand**: Array of demands for each customer node (length N)
- **Distance**: Flattened distance matrix as a 1D array of length (N+1)²

## Distance Matrix Representation

The distance matrix is represented as a flattened 1D array where:
- The matrix includes the depot (node 0) plus N customer nodes
- Total size is (N+1) × (N+1)
- Element at position `i * (N+1) + j` represents the distance from node i to node j
- The depot is always node 0

## Example

```json
{
  "N": 4,
  "Capacity": 100,
  "Demand": [20, 30, 10, 40],
  "Distance": [
    0, 10, 20, 30, 40,
    10, 0, 15, 25, 35,
    20, 15, 0, 30, 20,
    30, 25, 30, 0, 15,
    40, 35, 20, 15, 0
  ]
}
```

This represents:
- 4 customer nodes plus 1 depot (5 nodes total)
- Vehicle capacity of 100
- Customer demands: node 1=20, node 2=30, node 3=10, node 4=40
- 5×5 distance matrix flattened into a 25-element array

## Constraint Model 

```
%------------------------------------------------------------------------------%
% vrp.mzn
% Jakob Puchinger
% July 2009
% vim: ft=zinc ts=4 sw=4 et tw=0
%------------------------------------------------------------------------------%

    % The number of Nodes, Node 0 corresponds to the depot
int: N;
    % Vehicle capacity
int: Capacity;
    % Maximum number of vehicles
int: K = N;    
    % Demand at Node
array[1..N] of int: Demand;
    % Distances between the nodes
array[1..N+1, 1..N+1] of int: Distance;
    % Decision variables, is arc ij part of a route?
array[0..N, 0..N] of var 0..1: x;
    % Additional variables representing the load of vehicle after visiting
    % node i for subtour elimination
array[1..N] of var 0..Capacity: u;

    % Indegree constraints
constraint
    forall(j in 1..N)(
        sum(i in 0..N)(x[i, j]) = 1
    );
    
    % Outdegree constraints
constraint
    forall(i in 1..N)(
        sum(j in 0..N)(x[i, j]) = 1
    );

    % Indegree Depot
constraint
    sum(i in 0..N)(x[i, 0]) <= K;

    % Outdegree Depot
constraint
    sum(j in 0..N)(x[0, j]) <= K;

    % Subtour elimination (Miller, Tucker Zemlin)
constraint
    forall( i in 1..N, j in 1..N)(
        u[i] - u[j] + Capacity * x[i, j] <= Capacity - Demand[j]
    )
    /\ forall(i in 1..N)(
        Demand[i] <= u[i]
    );

var int: objective =
    sum( i in 0..N, j in 0..N ) (Distance[i+1, j+1] * x[i, j]); 

solve 
    :: int_search(u ++ [x[i, j] | i in 1..N, j in 1..N],
        first_fail, indomain_min, complete) 
    minimize objective;

output [
    "x = ", show(x), "\n",
    "objective = ", show(objective),"\n"
];

```

## Background

Understanding the structural characteristics of constraint programming instances is crucial for optimal solver performance. Different instance characteristics (graph density, problem size, connectivity patterns, etc.) influence which solver parameters work best.

The MiniZinc model provided above formalizes the problem. Your task is to analyze the instance structure and extract relevant characteristics that will be used by a separate system to configure solver parameters.

## Tasks

**MANDATORY FIRST STEP**: Begin your script with EXACTLY these imports (copy-paste them):

```python
# Import helper functions for input/output
from lmtune_helpers import input_data, output_results

# Import standard libraries for data analysis
import networkx as nx
import numpy as np
```

**WARNING**: 
- If you don't include the line `from lmtune_helpers import input_data, output_results`, your script will fail with NameError!
- DO NOT wrap this import in a try/except block!
- DO NOT check if the helpers are available!
- These functions WILL be available when your script runs!

Your script should:

1. Get the instance data using the `input_data()` function:
   ```python
   # Get the instance data using the helper function
   instance_data = input_data()
   ```
   
   **Important**: Your script should NOT perform any file I/O operations. All data input and output is handled by the framework through the imported helper functions.
   
   At the end of your script, you must use the `output_results()` function to return your findings:
   ```python
   # Return the results using the helper function
   output_results(result_dict)
   ```
   
   Where `result_dict` is a dictionary containing your instance characteristics analysis.

2. Analyze the instance structure and extract relevant characteristics. Use appropriate libraries like NetworkX for graph problems:
   
   Consider extracting metrics such as:
   - **Problem size**: Number of variables, constraints, decision points
   - **Graph properties** (for graph-based problems): Size, density, degree distribution, clustering coefficient, centrality measures, connectivity patterns
   - **Data distribution**: Statistical properties of weights, costs, capacities, demands
   - **Structural complexity**: Symmetries, regularity patterns, sparsity
   - **Problem-specific features**: Domain-specific characteristics that may influence solver behavior
   
   **Important**: You should analyze the MiniZinc model to understand what characteristics are most relevant for this specific problem type. Different problems require different analysis approaches.

3. Extract and compute the most relevant characteristics based on the problem structure shown in the MiniZinc model.

4. **MANDATORY TESTING**: You MUST call the `execute_script()` tool to test your script. If it fails, you MUST fix the errors and test again.

5. Return the instance characteristics using the `output_results(result_dict)` function as shown above.

## Expected Output Format

Your results should be a dictionary containing the extracted instance characteristics. **The dictionary MUST contain these specific keys:**

1. **"README"** (MANDATORY FIRST KEY): A text of approximately 200 words describing:
   - How the instance was analyzed (e.g., how graphs were constructed, what metrics were computed)
   - The methodology used to extract the characteristics
   - What each parameter represents and why it's relevant for this problem type

2. **Exactly 50 instance characteristic parameters** that describe key properties of this specific instance.

**CRITICAL OUTPUT FORMAT REQUIREMENT**: You MUST use standardized characteristic names `characteristic_1` through `characteristic_50`. This format is required for compatibility with the parallel processing system.

Example format:
```python
{
    "README": "This instance was analyzed by constructing a graph where nodes represent... The analysis focused on extracting structural properties that characterize the problem difficulty. The graph_density parameter measures the ratio of edges to possible edges, indicating constraint tightness. The clustering_coefficient captures local structure... [approximately 200 words total]",
    
    "characteristic_1": 100,      # n_customers
    "characteristic_2": 10,       # n_vehicles  
    "characteristic_3": 200,      # vehicle_capacity
    "characteristic_4": 1850,     # total_demand
    "characteristic_5": 18.5,     # avg_demand
    "characteristic_6": 5.4,      # std_demand
    "characteristic_7": 5,        # min_demand
    "characteristic_8": 34,       # max_demand
    "characteristic_9": 0.72,     # demand_skewness
    "characteristic_10": 3.1,     # demand_kurtosis
    "characteristic_11": 125000.0, # bounding_box_area
    "characteristic_12": 1.4,     # bounding_box_aspect_ratio
    "characteristic_13": 42.3,    # avg_distance_to_depot
    "characteristic_14": 12.7,    # std_distance_to_depot
    "characteristic_15": 10.2,    # min_distance_to_depot
    "characteristic_16": 75.6,    # max_distance_to_depot
    "characteristic_17": 37.2,    # avg_pairwise_distance
    "characteristic_18": 9.3,     # std_pairwise_distance
    "characteristic_19": 3.1,     # min_pairwise_distance
    "characteristic_20": 83.5,    # max_pairwise_distance
    "characteristic_21": 0.925,   # demand_to_capacity_ratio
    "characteristic_22": 0.0925,  # avg_demand_to_capacity_ratio
    "characteristic_23": 0.17,    # max_demand_to_capacity_ratio
    "characteristic_24": 0.12,    # pct_customers_high_demand
    "characteristic_25": 0.1,     # pct_routes_overloaded_estimate
    "characteristic_26": 0.89,    # capacity_utilization_estimate
    "characteristic_27": 1230.0,  # estimated_total_distance
    "characteristic_28": 11,      # estimated_n_routes
    "characteristic_29": 9.1,     # avg_customers_per_route
    "characteristic_30": 111.8,   # avg_route_distance
    "characteristic_31": 15.2,    # route_distance_std
    "characteristic_32": 12.5,    # graph_avg_degree
    "characteristic_33": 0.75,    # graph_density
    "characteristic_34": 1,       # graph_connectivity
    "characteristic_35": 8,       # graph_diameter
    "characteristic_36": 3.6,     # graph_avg_shortest_path
    "characteristic_37": 0.42,    # graph_clustering_coefficient
    "characteristic_38": 1095.7,  # mst_total_length
    "characteristic_39": 10.1,    # mst_std_edge_length
    "characteristic_40": 0.62,    # depot_centrality
    "characteristic_41": 12.7,    # customer_x_std
    "characteristic_42": 14.6,    # customer_y_std
    "characteristic_43": 0.73,    # spatial_entropy
    "characteristic_44": 0.31,    # spatial_gini_index
    "characteristic_45": 315.6,   # kmeans_inertia
    "characteristic_46": 0.41,    # silhouette_score
    "characteristic_47": 6,       # n_clusters_kmeans
    "characteristic_48": 16.7,    # avg_cluster_size
    "characteristic_49": 4.1,     # cluster_size_std
    "characteristic_50": 45.3     # inter_cluster_distance
}
```

**MANDATORY REQUIREMENTS**:
- The first key MUST be "README" with a ~200 word description
- You MUST include exactly 50 instance characteristic parameters (meaningful numeric values that describe the instance)
- **CRITICAL**: The 50 characteristics MUST be named `characteristic_1`, `characteristic_2`, ..., `characteristic_50` (NOT descriptive names)
- These parameters should capture essential properties like size, density, distribution, complexity, or structure
- You can add comments after each characteristic to indicate what it represents (as shown in the example)

**Important**: The 50 parameters should be the most informative characteristics that would help understand the instance's structure and difficulty. Use the standardized `characteristic_N` naming format for compatibility with the parallel processing system. You can document what each characteristic represents using inline comments as shown in the example above.

## Implementation Requirements

- Analyze the MiniZinc model to understand the problem structure
- Extract characteristics that are relevant for constraint solver performance
- Use appropriate analysis techniques (NetworkX for graphs, NumPy for statistics, etc.)
- Focus on structural and statistical properties that influence solving difficulty
- **MANDATORY**: Call `execute_script()` to test your implementation with the example data
- Ensure your results are well-structured with meaningful characteristics

Remember to use the imported `input_data()` and `output_results()` functions. Your script should not perform any file I/O operations - all data access is handled through these helper functions.

## Complete Example Script

Here's a complete example showing the REQUIRED structure:

```python
# Import helper functions for input/output
# IMPORTANT: You MUST import these functions at the beginning of your script
# DO NOT define your own versions of these functions!
from lmtune_helpers import input_data, output_results

# Import standard libraries for data analysis
import networkx as nx
import numpy as np

# DO NOT create a get_instance_data() function!
# DO NOT import inside functions!
# DO NOT use try/except for imports!

def main():
    """Extract instance characteristics from the problem data."""
    
    # Get the instance data using the helper function
    instance_data = input_data()
    
    # Initialize results dictionary with required structure
    results = {
        "README": "This instance was analyzed by... [your ~200 word description]",
        "characteristic_1": 0.0,
        "characteristic_2": 0.0,
        "characteristic_3": 0.0,
        "characteristic_4": 0.0,
        "characteristic_5": 0.0,
        "characteristic_6": 0.0,
        "characteristic_7": 0.0,
        "characteristic_8": 0.0,
        "characteristic_9": 0.0,
        "characteristic_10": 0.0,
        "characteristic_11": 0.0,
        "characteristic_12": 0.0,
        "characteristic_13": 0.0,
        "characteristic_14": 0.0,
        "characteristic_15": 0.0,
        "characteristic_16": 0.0,
        "characteristic_17": 0.0,
        "characteristic_18": 0.0,
        "characteristic_19": 0.0,
        "characteristic_20": 0.0,
        "characteristic_21": 0.0,
        "characteristic_22": 0.0,
        "characteristic_23": 0.0,
        "characteristic_24": 0.0,
        "characteristic_25": 0.0,
        "characteristic_26": 0.0,
        "characteristic_27": 0.0,
        "characteristic_28": 0.0,
        "characteristic_29": 0.0,
        "characteristic_30": 0.0,
        "characteristic_31": 0.0,
        "characteristic_32": 0.0,
        "characteristic_33": 0.0,
        "characteristic_34": 0.0,
        "characteristic_35": 0.0,
        "characteristic_36": 0.0,
        "characteristic_37": 0.0,
        "characteristic_38": 0.0,
        "characteristic_39": 0.0,
        "characteristic_40": 0.0,
        "characteristic_41": 0.0,
        "characteristic_42": 0.0,
        "characteristic_43": 0.0,
        "characteristic_44": 0.0,
        "characteristic_45": 0.0,
        "characteristic_46": 0.0,
        "characteristic_47": 0.0,
        "characteristic_48": 0.0,
        "characteristic_49": 0.0,
        "characteristic_50": 0.0
    }
    
    try:
        # Extract basic problem parameters
        # (Adapt based on the actual fields in your problem's JSON schema)
        n = instance_data.get('N', 0)
        capacity = instance_data.get('Capacity', 0)
        
        # Analyze the instance and compute your 5 characteristic parameters
        # ... your analysis code here ...
        
        # Update the results with computed values
        results["README"] = "Your detailed ~200 word description..."
        results["characteristic_1"] = computed_value_1
        # ... etc ...
        
    except Exception as e:
        # Handle errors gracefully
        results["error"] = str(e)
    
    # Return the results using the helper function
    output_results(results)

if __name__ == "__main__":
    main()
```

**CRITICAL**: 
- You MUST import `from lmtune_helpers import input_data, output_results`
- You MUST use `input_data()` to get the instance data (not hard-code it)
- You MUST use `output_results(results)` to output the results dictionary
- You MUST use standardized names `characteristic_1` through `characteristic_50` in your results dictionary
- You MUST test your script with `execute_script()` and fix any errors - no exceptions!