Nagaraj81 commited on
Commit
cc12261
·
verified ·
1 Parent(s): 10f538f

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +213 -0
  2. requirements.txt +3 -0
app.py ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ import pandas as pd
4
+ import plotly.express as px
5
+ import plotly.graph_objects as go
6
+ import random
7
+
8
+ # Constants
9
+ regions = ["Riyadh", "Makkah", "Eastern", "Madinah", "Qassim", "Asir", "Tabuk", "Hail", "Northern",
10
+ "Jazan", "Najran", "Bahah", "Jawf"]
11
+ income_bands = ["Low", "Mid", "High"]
12
+ property_types = ["Land", "Off-plan", "Ready", "Self-build"]
13
+
14
+ def default_subsidy_values():
15
+ base = 300_000
16
+ factor = 0.5
17
+ return {(r, i, p): int((base - 100_000 * income_bands.index(i)) * factor)
18
+ for r in regions for i in income_bands for p in property_types}
19
+
20
+ def default_supply_cost_values():
21
+ return {(p, r): {"Supply": random.randint(1000, 10000), "Discount (SAR)": random.randint(50_000, 300_000)}
22
+ for p in ["Land", "Off-plan"] for r in regions}
23
+
24
+ def monte_carlo_optimization(subsidies, budget_limit, target_contracts, supply_dict, interest_rate, demand_increase, n_trials=10000):
25
+ keys = list(subsidies.keys())
26
+ best_result = None
27
+ best_score = float('-inf')
28
+ fairness_penalty_weight = 10_000_000
29
+
30
+ demand_multiplier = 1 + (demand_increase / 100)
31
+ cost_multiplier = 1 + (interest_rate / 100)
32
+
33
+ for _ in range(n_trials):
34
+ contracts = {}
35
+ total_budget = 0
36
+ total_contracts = 0
37
+ shuffled_subs = {k: int(random.randint(150000, 400000) * cost_multiplier) for k in keys}
38
+ available_supply = {(r, p): supply_dict.get((p, r), 0) for (p, r) in supply_dict}
39
+
40
+ for k in keys:
41
+ r, i, p = k
42
+ max_supply = available_supply.get((r, p), 10000)
43
+ max_demand = int(max_supply * demand_multiplier)
44
+ max_possible_contracts = int(min((budget_limit - total_budget) // shuffled_subs[k], max_demand)) if shuffled_subs[k] > 0 else 0
45
+ c = random.randint(0, max_possible_contracts) if max_possible_contracts > 0 else 0
46
+ contracts[k] = c
47
+ total_budget += shuffled_subs[k] * c
48
+ total_contracts += c
49
+
50
+ if total_budget > budget_limit:
51
+ continue
52
+
53
+ achieved_regions = set(r for (r, i, p) in contracts if contracts[(r, i, p)] > 0)
54
+ achieved_income = set(i for (r, i, p) in contracts if contracts[(r, i, p)] > 0)
55
+ achieved_props = set(p for (r, i, p) in contracts if contracts[(r, i, p)] > 0)
56
+ fairness_penalty = (
57
+ len(regions) - len(achieved_regions) +
58
+ len(income_bands) - len(achieved_income) +
59
+ len(property_types) - len(achieved_props)
60
+ ) * fairness_penalty_weight
61
+
62
+ score = total_contracts - fairness_penalty
63
+
64
+ if score > best_score:
65
+ best_score = score
66
+ best_result = (contracts, total_budget, total_contracts, shuffled_subs)
67
+
68
+ return best_result if best_result else ({}, 0, 0, subsidies)
69
+
70
+ def create_gauge_chart(value, title, max_value=100):
71
+ fig = go.Figure(go.Indicator(
72
+ mode="gauge+number",
73
+ value=value,
74
+ gauge={
75
+ 'axis': {'range': [0, max_value]},
76
+ 'bar': {'color': "darkblue"},
77
+ 'steps': [
78
+ {'range': [0, max_value * 0.5], 'color': "lightgray"},
79
+ {'range': [max_value * 0.5, max_value], 'color': "lightgreen"}
80
+ ]
81
+ },
82
+ title={'text': title}
83
+ ))
84
+ fig.update_layout(height=350, width=450, margin=dict(t=40, b=40, l=40, r=40))
85
+ return fig
86
+
87
+ def build_app():
88
+ supply_costs = default_supply_cost_values()
89
+
90
+ with gr.Blocks() as app:
91
+ gr.Markdown("# 🏨 Strategic Gears Housing Simulator – Auto Optimization")
92
+
93
+ with gr.Tab("Inputs"):
94
+ with gr.Row():
95
+ with gr.Column():
96
+ ir = gr.Slider(0, 10, 5, label="Interest Rate (%)")
97
+ dp = gr.Slider(0, 100, 10, label="Demand Increase (%)")
98
+ n = gr.Slider(100, 10000, 1000, step=100, label="Number of Simulations")
99
+ budget_limit = gr.Slider(10_000_000, 1_000_000_000, 500_000_000, step=10_000_000, label="Budget Limit (SAR)")
100
+ target_contracts = gr.Slider(1000, 20000, 5000, step=100, label="Target Contracts")
101
+ supply_inputs = {}
102
+
103
+ with gr.Accordion("Supply Inputs by Region and Property Type", open=False):
104
+ for p in ["Land", "Off-plan"]:
105
+ with gr.Accordion(p, open=False):
106
+ for r in regions:
107
+ supply_inputs[(p, r)] = gr.Slider(minimum=1, maximum=10000,
108
+ value=supply_costs[(p, r)]["Supply"],
109
+ step=1,
110
+ label=f"{r} {p} Supply")
111
+ run = gr.Button("Run Simulation")
112
+
113
+ with gr.Tab("Outputs"):
114
+ summary = gr.Markdown("Optimization summary will appear here.")
115
+
116
+ with gr.Row():
117
+ with gr.Column():
118
+ df_subsidy_policy = gr.Dataframe(label="1️⃣ Recommended Subsidy Support (SAR)")
119
+ subsidy_by_income_bar = gr.Plot(label="Average Subsidy by Income Band")
120
+ with gr.Column():
121
+ df_contract_summary = gr.Dataframe(label="2️⃣ Contract Distribution")
122
+ contracts_by_region_bar = gr.Plot(label="Contracts by Region")
123
+
124
+ with gr.Row():
125
+ with gr.Column():
126
+ df_budget_summary = gr.Dataframe(label="3️⃣ Budget Distribution")
127
+ budget_util_gauge = gr.Plot(label="Budget Utilization (%)")
128
+ with gr.Column():
129
+ df_discount_table = gr.Dataframe(label="4️⃣ Discount Table")
130
+ contracts_by_property_pie = gr.Plot(label="Contract Distribution by Property Type")
131
+ target_achievement_gauge = gr.Plot(label="Target Achievement (%)")
132
+ total_contracts_gauge = gr.Plot(label="Total Contracts (Scaled to Target)")
133
+
134
+ def run_sim(interest, demand, sims, budget, target, *supplies):
135
+ supply_dict = {(p, r): supplies[i] for i, (p, r) in enumerate(supply_inputs)}
136
+ result, total_bgt, total_con, final_subs = monte_carlo_optimization(
137
+ default_subsidy_values(), budget, target, supply_dict, interest, demand, sims
138
+ )
139
+
140
+ df = pd.DataFrame([{
141
+ "Region": r, "Income Band": i, "Property Type": p,
142
+ "Contracts": result.get((r, i, p), 0),
143
+ "Subsidy (SAR)": final_subs[(r, i, p)],
144
+ "Budget (SAR)": result.get((r, i, p), 0) * final_subs[(r, i, p)]
145
+ } for (r, i, p) in final_subs])
146
+
147
+ subsidy_df = df[["Region", "Income Band", "Property Type", "Subsidy (SAR)"]].sort_values(by="Subsidy (SAR)", ascending=False)
148
+ contract_df = df[["Region", "Income Band", "Property Type", "Contracts"]].sort_values(by="Contracts", ascending=False)
149
+ budget_df = df[["Region", "Income Band", "Property Type", "Budget (SAR)"]].sort_values(by="Budget (SAR)", ascending=False)
150
+
151
+ df_discount = pd.DataFrame([{
152
+ "Region": r, "Property Type": p,
153
+ "Discount (SAR)": random.randint(50_000, 300_000)
154
+ } for p in ["Land", "Off-plan"] for r in regions])
155
+
156
+ summary_text = f"""
157
+ **Optimization Summary:**
158
+ - Total Budget Used: {total_bgt:,.0f} SAR
159
+ - Budget Utilization: {(total_bgt / budget) * 100:.1f}%
160
+ - Total Contracts: {total_con:,}
161
+ - Target Achievement: {(total_con / target) * 100:.1f}%
162
+ """
163
+
164
+ # Gauges
165
+ budget_util_pct = (total_bgt / budget) * 100
166
+ target_achieved_pct = (total_con / target) * 100
167
+ total_contracts_scaled = min(100, (total_con / target) * 100)
168
+
169
+ gauge_budget = create_gauge_chart(budget_util_pct, "Budget Utilization (%)")
170
+ gauge_target = create_gauge_chart(target_achieved_pct, "Target Achievement (%)")
171
+ gauge_contracts = create_gauge_chart(total_contracts_scaled, "Contracts (Scaled to Target %)")
172
+
173
+ # Contracts by Region Bar
174
+ contracts_region = df.groupby("Region")["Contracts"].sum().reset_index()
175
+ bar_contract_region = px.bar(contracts_region, x="Region", y="Contracts", title="Contracts by Region")
176
+ min_y = 10
177
+ max_y = contracts_region["Contracts"].max() * 1.1
178
+ bar_contract_region.update_layout(
179
+ height=350, width=450,
180
+ yaxis=dict(title="Contracts", tickformat=",d", range=[min_y, max_y]),
181
+ margin=dict(t=50, b=40, l=60, r=40)
182
+ )
183
+
184
+ # Subsidy by Income Band
185
+ subsidy_income = df.groupby("Income Band")["Subsidy (SAR)"].mean().reset_index()
186
+ bar_subsidy_income = px.bar(subsidy_income, x="Income Band", y="Subsidy (SAR)", title="Average Subsidy by Income Band")
187
+ bar_subsidy_income.update_layout(
188
+ height=350, width=450,
189
+ yaxis=dict(tickprefix="SAR ", tickformat="~s"),
190
+ margin=dict(t=50, b=40, l=60, r=40)
191
+ )
192
+
193
+ # Property Type Pie
194
+ contracts_property = df.groupby("Property Type")["Contracts"].sum().reset_index()
195
+ pie_property = px.pie(contracts_property, names="Property Type", values="Contracts", title="Contract Distribution by Property Type")
196
+ pie_property.update_layout(height=350, width=450, margin=dict(t=50, b=40, l=40, r=40))
197
+
198
+ return summary_text, subsidy_df, contract_df, budget_df, df_discount, gauge_budget, gauge_target, gauge_contracts, bar_contract_region, bar_subsidy_income, pie_property
199
+
200
+ run.click(
201
+ fn=run_sim,
202
+ inputs=[ir, dp, n, budget_limit, target_contracts] + list(supply_inputs.values()),
203
+ outputs=[
204
+ summary, df_subsidy_policy, df_contract_summary, df_budget_summary, df_discount_table,
205
+ budget_util_gauge, target_achievement_gauge, total_contracts_gauge,
206
+ contracts_by_region_bar, subsidy_by_income_bar, contracts_by_property_pie
207
+ ]
208
+ )
209
+
210
+ return app
211
+
212
+ app = build_app()
213
+ app.launch()
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio
2
+ pandas
3
+ plotly