File size: 4,292 Bytes
fa7b8b5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
714bb14
fa7b8b5
714bb14
 
 
fa7b8b5
 
714bb14
 
 
 
 
fa7b8b5
 
 
 
714bb14
fa7b8b5
 
714bb14
 
fa7b8b5
 
 
 
b1ead6c
 
fa7b8b5
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import gradio as gr
import pandas as pd
import numpy as np
import json
from io import StringIO


def dynamic_huff_model(df_distances, df_attractiveness, alpha, beta, df_capacity, df_population=None, iterations=5, crowding_threshold=1.0):
    """
    Iteratively calculates the distribution of people/visitors to destinations considering capacity and crowding based on an extended Huff model with linear decay function.

    Parameters:
    - df_distances, df_attractiveness, alpha, beta, df_capacity, df_population are the same as before.
    - iterations (int): The number of iterations to distribute the population.
    - crowding_threshold (float): The ratio of current visitors to capacity at which the decay of attractiveness starts.

    Returns:
    - pd.DataFrame: A DataFrame with the final distribution of visitors to each destination.
    """
    if df_population is None:
        df_population = pd.Series(np.ones(df_distances.shape[0]), index=df_distances.index)

    # Initialize the visitors DataFrame
    df_visitors = pd.DataFrame(0, index=df_distances.index, columns=df_distances.columns)
    
    # Distribute the population over the iterations
    df_population_per_iteration = df_population / iterations

    # Run the iterative distribution process
    for _ in range(iterations):
        attractiveness = df_attractiveness.copy()
        current_visitors = df_visitors.sum(axis=0)
        
        # Calculate the decay based on the relative share of free capacity
        relative_crowding = current_visitors / df_capacity
        decay_factor = np.where(relative_crowding < crowding_threshold, 1, 1 - (relative_crowding - crowding_threshold) / (1 - crowding_threshold))
        attractiveness *= decay_factor
        
        # Calculate Huff model probabilities
        distance_term = df_distances ** -beta
        numerator = (attractiveness ** alpha).multiply(distance_term, axis='columns')
        denominator = numerator.sum(axis='columns')
        probabilities = numerator.div(denominator, axis='index').fillna(0)
        
        # Distribute visitors based on probabilities and population
        visitors_this_iteration = probabilities.multiply(df_population_per_iteration, axis='index')
        
        # Adjust for excess visitors beyond capacity
        potential_new_visitors = df_visitors + visitors_this_iteration
        excess_visitors = potential_new_visitors.sum(axis=0) - df_capacity
        excess_visitors[excess_visitors < 0] = 0
        visitors_this_iteration -= visitors_this_iteration.multiply(excess_visitors, axis='columns') / visitors_this_iteration.sum(axis=0)
        
        df_visitors += visitors_this_iteration

    # Return the final distribution of visitors
    return df_visitors

def app_function(input_json):
    # Parse the input JSON string
    inputs = json.loads(input_json)
    
    # Assuming 'inputs["df_distances"]' is a JSON string of a CSV, use StringIO to convert it to a DataFrame
    df_distances = pd.read_csv(StringIO(inputs["df_distances"]))
    
    # Assuming 'inputs["df_attractiveness"]' and others are already in list format in the JSON
    df_attractiveness = pd.Series(inputs["df_attractiveness"])
    alpha = inputs["alpha"]
    beta = inputs["beta"]
    df_capacity = pd.Series(inputs["df_capacity"])
    
    # Check if 'df_population' is in inputs and convert to Series, else default to None
    df_population = pd.Series(inputs["df_population"]) if "df_population" in inputs else None
    
    iterations = inputs.get("iterations", 5)
    crowding_threshold = inputs.get("crowding_threshold", 1.0)
    
    # Call the dynamic Huff model function with these parameters
    # Ensure 'dynamic_huff_model' is defined and ready to accept these parameters
    result = dynamic_huff_model(df_distances, df_attractiveness, alpha, beta, df_capacity, df_population, iterations, crowding_threshold)
    
    # Convert the result DataFrame to a JSON string for output
    return result.to_json(orient='split')

# Define the Gradio interface with a single JSON input
iface = gr.Interface(
    fn=app_function,
    inputs=gr.Textbox(label="Input JSON", lines=20, placeholder="Enter JSON with all parameters here..."),
    outputs=gr.JSON(label="Output JSON"),
    title="Dynamic Huff Model"
)

iface.launch()