# Universal MiniZinc Instance Characteristics Extraction

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

## Input Format

${SCHEMA}

## Constraint Model 

${MODEL}

## 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!