feat: adiciona quadro de horários formatado com tabulate ao Modelo 2
This commit is contained in:
76
create_nb.py
76
create_nb.py
@@ -371,6 +371,82 @@ for i in aeroportos_malha:
|
||||
gerou_vazio = True
|
||||
if not gerou_vazio:
|
||||
print(" Nenhum voo de reposicionamento vazio foi necessário! A malha já é circular/balanceada.")
|
||||
|
||||
# GERAR TABELA DE HORÁRIOS COM TABULATE E DATETIME
|
||||
from tabulate import tabulate
|
||||
import datetime
|
||||
|
||||
# 1. Construir a lista de todos os voos a serem realizados
|
||||
voos_para_fazer = []
|
||||
|
||||
# Cópia para saber quantos voos de passageiros faltam alocar
|
||||
D_copy = {k: v for k, v in D.items()}
|
||||
|
||||
for i in aeroportos_malha:
|
||||
for j in aeroportos_malha:
|
||||
total_voos = D[(i, j)] + int(Y[(i, j)].varValue)
|
||||
for _ in range(total_voos):
|
||||
if D_copy[(i, j)] > 0:
|
||||
tipo = 'Passageiro'
|
||||
D_copy[(i, j)] -= 1
|
||||
else:
|
||||
tipo = 'Vazio (Reposicionamento)'
|
||||
voos_para_fazer.append({'origem': i, 'destino': j, 'tipo': tipo, 'tempo': tempos_voo[(i, j)]})
|
||||
|
||||
# 2. Simular a alocação sequencial de horários
|
||||
tabela_horarios = []
|
||||
aeronave_id = 1
|
||||
|
||||
while voos_para_fazer:
|
||||
voo_atual = voos_para_fazer.pop(0)
|
||||
hora_atual = datetime.datetime(2025, 1, 1, 0, 0, 0)
|
||||
|
||||
tempo_delta = datetime.timedelta(hours=voo_atual['tempo'])
|
||||
hora_chegada = hora_atual + tempo_delta
|
||||
|
||||
tabela_horarios.append([
|
||||
f"Aeronave {aeronave_id}",
|
||||
voo_atual['origem'],
|
||||
voo_atual['destino'],
|
||||
voo_atual['tipo'],
|
||||
hora_atual.strftime('%H:%M'),
|
||||
hora_chegada.strftime('%H:%M'),
|
||||
f"{voo_atual['tempo']:.2f} h"
|
||||
])
|
||||
|
||||
hora_atual = hora_chegada
|
||||
local_atual = voo_atual['destino']
|
||||
|
||||
# Continuar traçando o caminho para esta aeronave até que não caiba mais nas 24h
|
||||
while True:
|
||||
prox_voo = None
|
||||
for idx, v in enumerate(voos_para_fazer):
|
||||
if v['origem'] == local_atual:
|
||||
if (hora_atual - datetime.datetime(2025, 1, 1, 0, 0, 0) + datetime.timedelta(hours=v['tempo'])).total_seconds() <= 24 * 3600:
|
||||
prox_voo = voos_para_fazer.pop(idx)
|
||||
break
|
||||
|
||||
if prox_voo:
|
||||
tempo_delta = datetime.timedelta(hours=prox_voo['tempo'])
|
||||
hora_chegada = hora_atual + tempo_delta
|
||||
tabela_horarios.append([
|
||||
f"Aeronave {aeronave_id}",
|
||||
prox_voo['origem'],
|
||||
prox_voo['destino'],
|
||||
prox_voo['tipo'],
|
||||
hora_atual.strftime('%H:%M'),
|
||||
hora_chegada.strftime('%H:%M'),
|
||||
f"{prox_voo['tempo']:.2f} h"
|
||||
])
|
||||
hora_atual = hora_chegada
|
||||
local_atual = prox_voo['destino']
|
||||
else:
|
||||
break
|
||||
|
||||
aeronave_id += 1
|
||||
|
||||
print("\\n== QUADRO DE HORÁRIOS DIÁRIOS ==")
|
||||
print(tabulate(tabela_horarios, headers=["Aeronave", "Origem", "Destino", "Tipo", "Partida", "Chegada", "Duração"], tablefmt="github"))
|
||||
"""))
|
||||
|
||||
nb.cells = cells
|
||||
|
||||
179
modelos.ipynb
179
modelos.ipynb
@@ -2,7 +2,7 @@
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "07d7e46d",
|
||||
"id": "d163e704",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Alocação de Frotas (Fleet Scheduling) - Aeronaves C-97\n",
|
||||
@@ -21,13 +21,13 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "3f9fa4c6",
|
||||
"id": "1cda871c",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-06-07T23:37:16.312196Z",
|
||||
"iopub.status.busy": "2026-06-07T23:37:16.311487Z",
|
||||
"iopub.status.idle": "2026-06-07T23:37:16.933888Z",
|
||||
"shell.execute_reply": "2026-06-07T23:37:16.933301Z"
|
||||
"iopub.execute_input": "2026-06-07T23:41:13.265917Z",
|
||||
"iopub.status.busy": "2026-06-07T23:41:13.265674Z",
|
||||
"iopub.status.idle": "2026-06-07T23:41:13.946892Z",
|
||||
"shell.execute_reply": "2026-06-07T23:41:13.946177Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
@@ -53,7 +53,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6054dba5",
|
||||
"id": "3aa25feb",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1. Leitura e Limpeza dos Dados\n",
|
||||
@@ -63,13 +63,13 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "da258d7f",
|
||||
"id": "5f12213f",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-06-07T23:37:16.935502Z",
|
||||
"iopub.status.busy": "2026-06-07T23:37:16.935296Z",
|
||||
"iopub.status.idle": "2026-06-07T23:37:17.297220Z",
|
||||
"shell.execute_reply": "2026-06-07T23:37:17.296482Z"
|
||||
"iopub.execute_input": "2026-06-07T23:41:13.949035Z",
|
||||
"iopub.status.busy": "2026-06-07T23:41:13.948756Z",
|
||||
"iopub.status.idle": "2026-06-07T23:41:14.387479Z",
|
||||
"shell.execute_reply": "2026-06-07T23:41:14.386681Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
@@ -101,7 +101,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "2424db2d",
|
||||
"id": "29a370cf",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Análise dos Esquadrões e Matrículas (Aeronaves)\n",
|
||||
@@ -111,13 +111,13 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "8b308e12",
|
||||
"id": "4f559f60",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-06-07T23:37:17.298752Z",
|
||||
"iopub.status.busy": "2026-06-07T23:37:17.298630Z",
|
||||
"iopub.status.idle": "2026-06-07T23:37:17.310776Z",
|
||||
"shell.execute_reply": "2026-06-07T23:37:17.310206Z"
|
||||
"iopub.execute_input": "2026-06-07T23:41:14.388969Z",
|
||||
"iopub.status.busy": "2026-06-07T23:41:14.388784Z",
|
||||
"iopub.status.idle": "2026-06-07T23:41:14.401597Z",
|
||||
"shell.execute_reply": "2026-06-07T23:41:14.401016Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
@@ -176,7 +176,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4909bfef",
|
||||
"id": "3d637614",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Análise Estatística das Demandas Diárias\n",
|
||||
@@ -187,13 +187,13 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "b38abd07",
|
||||
"id": "ca8b936f",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-06-07T23:37:17.312196Z",
|
||||
"iopub.status.busy": "2026-06-07T23:37:17.312078Z",
|
||||
"iopub.status.idle": "2026-06-07T23:37:17.621631Z",
|
||||
"shell.execute_reply": "2026-06-07T23:37:17.620923Z"
|
||||
"iopub.execute_input": "2026-06-07T23:41:14.403000Z",
|
||||
"iopub.status.busy": "2026-06-07T23:41:14.402870Z",
|
||||
"iopub.status.idle": "2026-06-07T23:41:14.726896Z",
|
||||
"shell.execute_reply": "2026-06-07T23:41:14.726161Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
@@ -424,7 +424,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6bab0068",
|
||||
"id": "782a4736",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Diagrama de Rede dos Trechos\n",
|
||||
@@ -434,13 +434,13 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "6198127c",
|
||||
"id": "9fedd535",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-06-07T23:37:17.623083Z",
|
||||
"iopub.status.busy": "2026-06-07T23:37:17.622958Z",
|
||||
"iopub.status.idle": "2026-06-07T23:37:17.740324Z",
|
||||
"shell.execute_reply": "2026-06-07T23:37:17.739229Z"
|
||||
"iopub.execute_input": "2026-06-07T23:41:14.728337Z",
|
||||
"iopub.status.busy": "2026-06-07T23:41:14.728199Z",
|
||||
"iopub.status.idle": "2026-06-07T23:41:14.849420Z",
|
||||
"shell.execute_reply": "2026-06-07T23:41:14.848842Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
@@ -497,7 +497,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "35633067",
|
||||
"id": "551febf3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Fleet Assignment Model (FAM) - Nível Brasil\n",
|
||||
@@ -514,13 +514,13 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "c9a2018d",
|
||||
"id": "bb15ee0b",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-06-07T23:37:17.742588Z",
|
||||
"iopub.status.busy": "2026-06-07T23:37:17.742459Z",
|
||||
"iopub.status.idle": "2026-06-07T23:37:17.764890Z",
|
||||
"shell.execute_reply": "2026-06-07T23:37:17.764350Z"
|
||||
"iopub.execute_input": "2026-06-07T23:41:14.850971Z",
|
||||
"iopub.status.busy": "2026-06-07T23:41:14.850776Z",
|
||||
"iopub.status.idle": "2026-06-07T23:41:14.876417Z",
|
||||
"shell.execute_reply": "2026-06-07T23:41:14.875894Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
@@ -609,7 +609,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "666ba740",
|
||||
"id": "37f9e364",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5. Modelo 2: Minimização de Aeronaves\n",
|
||||
@@ -623,13 +623,13 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "7b9b8019",
|
||||
"id": "08433efd",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-06-07T23:37:17.766458Z",
|
||||
"iopub.status.busy": "2026-06-07T23:37:17.766338Z",
|
||||
"iopub.status.idle": "2026-06-07T23:37:19.072202Z",
|
||||
"shell.execute_reply": "2026-06-07T23:37:19.071522Z"
|
||||
"iopub.execute_input": "2026-06-07T23:41:14.877926Z",
|
||||
"iopub.status.busy": "2026-06-07T23:41:14.877797Z",
|
||||
"iopub.status.idle": "2026-06-07T23:41:16.250728Z",
|
||||
"shell.execute_reply": "2026-06-07T23:41:16.250087Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
@@ -646,7 +646,22 @@
|
||||
"Taxa de ocupação da frota (Tempo Voo / Tempo Disponível): 69.6%\n",
|
||||
"\n",
|
||||
"Voos de Reposicionamento Vazio Gerados (Y) para fechar o ciclo diário:\n",
|
||||
" -> De SBAN para SBSJ: 1 voo(s) vazio(s) | Tempo de voo: 2.1h\n"
|
||||
" -> De SBAN para SBSJ: 1 voo(s) vazio(s) | Tempo de voo: 2.1h\n",
|
||||
"\n",
|
||||
"== QUADRO DE HORÁRIOS DIÁRIOS ==\n",
|
||||
"| Aeronave | Origem | Destino | Tipo | Partida | Chegada | Duração |\n",
|
||||
"|------------|----------|-----------|--------------------------|-----------|-----------|-----------|\n",
|
||||
"| Aeronave 1 | SBGL | SBGR | Passageiro | 00:00 | 00:51 | 0.86 h |\n",
|
||||
"| Aeronave 1 | SBGR | SBGL | Passageiro | 00:51 | 01:43 | 0.86 h |\n",
|
||||
"| Aeronave 1 | SBGL | SBSJ | Passageiro | 01:43 | 02:24 | 0.69 h |\n",
|
||||
"| Aeronave 1 | SBSJ | SBGL | Passageiro | 02:24 | 03:06 | 0.69 h |\n",
|
||||
"| Aeronave 1 | SBGL | SBBR | Passageiro | 03:06 | 05:26 | 2.33 h |\n",
|
||||
"| Aeronave 1 | SBBR | SBGL | Passageiro | 05:26 | 07:45 | 2.33 h |\n",
|
||||
"| Aeronave 2 | SBGR | SBBR | Passageiro | 00:00 | 02:10 | 2.17 h |\n",
|
||||
"| Aeronave 2 | SBBR | SBGR | Passageiro | 02:10 | 04:20 | 2.17 h |\n",
|
||||
"| Aeronave 3 | SBAN | SBSJ | Vazio (Reposicionamento) | 00:00 | 02:08 | 2.14 h |\n",
|
||||
"| Aeronave 3 | SBSJ | SBBR | Passageiro | 02:08 | 04:17 | 2.15 h |\n",
|
||||
"| Aeronave 3 | SBBR | SBAN | Passageiro | 04:17 | 04:35 | 0.30 h |\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -739,7 +754,83 @@
|
||||
" print(f\" -> De {i} para {j}: {int(Y[(i, j)].varValue)} voo(s) vazio(s) | Tempo de voo: {tempos_voo[(i,j)]*Y[(i,j)].varValue:.1f}h\")\n",
|
||||
" gerou_vazio = True\n",
|
||||
"if not gerou_vazio:\n",
|
||||
" print(\" Nenhum voo de reposicionamento vazio foi necessário! A malha já é circular/balanceada.\")\n"
|
||||
" print(\" Nenhum voo de reposicionamento vazio foi necessário! A malha já é circular/balanceada.\")\n",
|
||||
"\n",
|
||||
"# GERAR TABELA DE HORÁRIOS COM TABULATE E DATETIME\n",
|
||||
"from tabulate import tabulate\n",
|
||||
"import datetime\n",
|
||||
"\n",
|
||||
"# 1. Construir a lista de todos os voos a serem realizados\n",
|
||||
"voos_para_fazer = []\n",
|
||||
"\n",
|
||||
"# Cópia para saber quantos voos de passageiros faltam alocar\n",
|
||||
"D_copy = {k: v for k, v in D.items()}\n",
|
||||
"\n",
|
||||
"for i in aeroportos_malha:\n",
|
||||
" for j in aeroportos_malha:\n",
|
||||
" total_voos = D[(i, j)] + int(Y[(i, j)].varValue)\n",
|
||||
" for _ in range(total_voos):\n",
|
||||
" if D_copy[(i, j)] > 0:\n",
|
||||
" tipo = 'Passageiro'\n",
|
||||
" D_copy[(i, j)] -= 1\n",
|
||||
" else:\n",
|
||||
" tipo = 'Vazio (Reposicionamento)'\n",
|
||||
" voos_para_fazer.append({'origem': i, 'destino': j, 'tipo': tipo, 'tempo': tempos_voo[(i, j)]})\n",
|
||||
"\n",
|
||||
"# 2. Simular a alocação sequencial de horários\n",
|
||||
"tabela_horarios = []\n",
|
||||
"aeronave_id = 1\n",
|
||||
"\n",
|
||||
"while voos_para_fazer:\n",
|
||||
" voo_atual = voos_para_fazer.pop(0)\n",
|
||||
" hora_atual = datetime.datetime(2025, 1, 1, 0, 0, 0)\n",
|
||||
" \n",
|
||||
" tempo_delta = datetime.timedelta(hours=voo_atual['tempo'])\n",
|
||||
" hora_chegada = hora_atual + tempo_delta\n",
|
||||
" \n",
|
||||
" tabela_horarios.append([\n",
|
||||
" f\"Aeronave {aeronave_id}\",\n",
|
||||
" voo_atual['origem'],\n",
|
||||
" voo_atual['destino'],\n",
|
||||
" voo_atual['tipo'],\n",
|
||||
" hora_atual.strftime('%H:%M'),\n",
|
||||
" hora_chegada.strftime('%H:%M'),\n",
|
||||
" f\"{voo_atual['tempo']:.2f} h\"\n",
|
||||
" ])\n",
|
||||
" \n",
|
||||
" hora_atual = hora_chegada\n",
|
||||
" local_atual = voo_atual['destino']\n",
|
||||
" \n",
|
||||
" # Continuar traçando o caminho para esta aeronave até que não caiba mais nas 24h\n",
|
||||
" while True:\n",
|
||||
" prox_voo = None\n",
|
||||
" for idx, v in enumerate(voos_para_fazer):\n",
|
||||
" if v['origem'] == local_atual:\n",
|
||||
" if (hora_atual - datetime.datetime(2025, 1, 1, 0, 0, 0) + datetime.timedelta(hours=v['tempo'])).total_seconds() <= 24 * 3600:\n",
|
||||
" prox_voo = voos_para_fazer.pop(idx)\n",
|
||||
" break\n",
|
||||
" \n",
|
||||
" if prox_voo:\n",
|
||||
" tempo_delta = datetime.timedelta(hours=prox_voo['tempo'])\n",
|
||||
" hora_chegada = hora_atual + tempo_delta\n",
|
||||
" tabela_horarios.append([\n",
|
||||
" f\"Aeronave {aeronave_id}\",\n",
|
||||
" prox_voo['origem'],\n",
|
||||
" prox_voo['destino'],\n",
|
||||
" prox_voo['tipo'],\n",
|
||||
" hora_atual.strftime('%H:%M'),\n",
|
||||
" hora_chegada.strftime('%H:%M'),\n",
|
||||
" f\"{prox_voo['tempo']:.2f} h\"\n",
|
||||
" ])\n",
|
||||
" hora_atual = hora_chegada\n",
|
||||
" local_atual = prox_voo['destino']\n",
|
||||
" else:\n",
|
||||
" break\n",
|
||||
" \n",
|
||||
" aeronave_id += 1\n",
|
||||
"\n",
|
||||
"print(\"\\n== QUADRO DE HORÁRIOS DIÁRIOS ==\")\n",
|
||||
"print(tabulate(tabela_horarios, headers=[\"Aeronave\", \"Origem\", \"Destino\", \"Tipo\", \"Partida\", \"Chegada\", \"Duração\"], tablefmt=\"github\"))\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -13,5 +13,6 @@ dependencies = [
|
||||
"pulp>=3.3.2",
|
||||
"pymap3d>=3.2.0",
|
||||
"seaborn>=0.13.2",
|
||||
"tabulate>=0.10.0",
|
||||
"vincenty>=0.1.4",
|
||||
]
|
||||
|
||||
11
uv.lock
generated
11
uv.lock
generated
@@ -176,6 +176,7 @@ dependencies = [
|
||||
{ name = "pulp" },
|
||||
{ name = "pymap3d" },
|
||||
{ name = "seaborn" },
|
||||
{ name = "tabulate" },
|
||||
{ name = "vincenty" },
|
||||
]
|
||||
|
||||
@@ -189,6 +190,7 @@ requires-dist = [
|
||||
{ name = "pulp", specifier = ">=3.3.2" },
|
||||
{ name = "pymap3d", specifier = ">=3.2.0" },
|
||||
{ name = "seaborn", specifier = ">=0.13.2" },
|
||||
{ name = "tabulate", specifier = ">=0.10.0" },
|
||||
{ name = "vincenty", specifier = ">=0.1.4" },
|
||||
]
|
||||
|
||||
@@ -1965,6 +1967,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tabulate"
|
||||
version = "0.10.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/46/58/8c37dea7bbf769b20d58e7ace7e5edfe65b849442b00ffcdd56be88697c6/tabulate-0.10.0.tar.gz", hash = "sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d", size = 91754, upload-time = "2026-03-04T18:55:34.402Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814, upload-time = "2026-03-04T18:55:31.284Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminado"
|
||||
version = "0.18.1"
|
||||
|
||||
Reference in New Issue
Block a user