walopy 0.2.6__tar.gz → 0.2.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {walopy-0.2.6/src/walopy.egg-info → walopy-0.2.7}/PKG-INFO +158 -24
- {walopy-0.2.6 → walopy-0.2.7}/README.md +157 -23
- {walopy-0.2.6 → walopy-0.2.7}/pyproject.toml +1 -1
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy/__init__.py +8 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy/inventory.py +384 -0
- {walopy-0.2.6 → walopy-0.2.7/src/walopy.egg-info}/PKG-INFO +158 -24
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy.egg-info/SOURCES.txt +2 -0
- walopy-0.2.7/tests/test_exchange_curve.py +147 -0
- walopy-0.2.7/tests/test_safety_stock_curve.py +172 -0
- {walopy-0.2.6 → walopy-0.2.7}/LICENSE +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/setup.cfg +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy/__main__.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy/_utils.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy/advanced.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy/bottleneck.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy/fitting.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy/kpi.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy/network.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy/operations.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy/plotting.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy/queuing.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy/reliability.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy/scheduling.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy/solver.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy.egg-info/dependency_links.txt +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy.egg-info/requires.txt +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/src/walopy.egg-info/top_level.txt +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/tests/test_advanced.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/tests/test_bottleneck.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/tests/test_fitting.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/tests/test_inventory.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/tests/test_inventory_new.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/tests/test_kpi.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/tests/test_mg1.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/tests/test_network.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/tests/test_new_models.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/tests/test_operations.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/tests/test_queuing.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/tests/test_solver.py +0 -0
- {walopy-0.2.6 → walopy-0.2.7}/tests/test_v026.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: walopy
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: Queuing theory, operations analysis, OEE, bottleneck analysis and KPI trees for Python
|
|
5
5
|
Author-email: LeoSanta15 <angelsanta1@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -63,17 +63,18 @@ pip install walopy
|
|
|
63
63
|
9. [Análisis de cuellos de botella](#9-análisis-de-cuellos-de-botella)
|
|
64
64
|
10. [Balance de línea y tiempo takt](#10-balance-de-línea-y-tiempo-takt)
|
|
65
65
|
11. [Análisis de punto de equilibrio](#11-análisis-de-punto-de-equilibrio)
|
|
66
|
-
12. [
|
|
67
|
-
13. [
|
|
68
|
-
14. [
|
|
69
|
-
15. [
|
|
70
|
-
16. [
|
|
71
|
-
17. [
|
|
72
|
-
18. [
|
|
73
|
-
19. [
|
|
74
|
-
20. [
|
|
75
|
-
21. [
|
|
76
|
-
22. [
|
|
66
|
+
12. [Curvas de intercambio](#12-curvas-de-intercambio)
|
|
67
|
+
13. [Programación de producción (scheduling)](#13-programación-de-producción-scheduling)
|
|
68
|
+
14. [Confiabilidad](#14-confiabilidad--reliability)
|
|
69
|
+
15. [Árboles de KPI](#15-árboles-de-kpi)
|
|
70
|
+
16. [Solvers y optimización](#16-solvers-y-optimización)
|
|
71
|
+
17. [Análisis de sensibilidad](#17-análisis-de-sensibilidad)
|
|
72
|
+
18. [Escenarios en lote (batch_model)](#18-escenarios-en-lote-batch_model)
|
|
73
|
+
19. [Comparar múltiples resultados](#19-comparar-múltiples-resultados)
|
|
74
|
+
20. [Gráficas](#20-gráficas)
|
|
75
|
+
21. [CLI](#21-cli)
|
|
76
|
+
22. [Referencia de módulos](#22-referencia-de-módulos)
|
|
77
|
+
23. [Requisitos](#23-requisitos)
|
|
77
78
|
|
|
78
79
|
---
|
|
79
80
|
|
|
@@ -1057,7 +1058,7 @@ print(r.margin_of_safety_pct) # 0.375 — porcentaje del margen de seguridad
|
|
|
1057
1058
|
|
|
1058
1059
|
---
|
|
1059
1060
|
|
|
1060
|
-
##
|
|
1061
|
+
## 15. Árboles de KPI
|
|
1061
1062
|
|
|
1062
1063
|
Los árboles de KPI crean jerarquías interactivas visualizadas como **treemap** o **sunburst** con Plotly.
|
|
1063
1064
|
|
|
@@ -1110,7 +1111,7 @@ fig.show()
|
|
|
1110
1111
|
|
|
1111
1112
|
---
|
|
1112
1113
|
|
|
1113
|
-
##
|
|
1114
|
+
## 16. Solvers y optimización
|
|
1114
1115
|
|
|
1115
1116
|
### `solve_lam(metric, target, *, mu, model)` — Máxima tasa de llegada
|
|
1116
1117
|
|
|
@@ -1157,7 +1158,7 @@ r.plot() # gráfica de costo vs número de servidores
|
|
|
1157
1158
|
|
|
1158
1159
|
---
|
|
1159
1160
|
|
|
1160
|
-
##
|
|
1161
|
+
## 17. Análisis de sensibilidad
|
|
1161
1162
|
|
|
1162
1163
|
### `sensitivity(model_fn, param, values, **fixed_kwargs)` — Barrido paramétrico
|
|
1163
1164
|
|
|
@@ -1188,7 +1189,7 @@ fig.show()
|
|
|
1188
1189
|
|
|
1189
1190
|
---
|
|
1190
1191
|
|
|
1191
|
-
##
|
|
1192
|
+
## 18. Escenarios en lote (batch_model)
|
|
1192
1193
|
|
|
1193
1194
|
### `batch_model(model_fn, df, **fixed_kwargs)` — Aplicar modelo a un DataFrame
|
|
1194
1195
|
|
|
@@ -1223,7 +1224,7 @@ print(resultado[resultado["_error"].notna()]) # filas fallidas
|
|
|
1223
1224
|
|
|
1224
1225
|
---
|
|
1225
1226
|
|
|
1226
|
-
##
|
|
1227
|
+
## 19. Comparar múltiples resultados
|
|
1227
1228
|
|
|
1228
1229
|
### `compare(*results, labels)` — DataFrame comparativo
|
|
1229
1230
|
|
|
@@ -1248,7 +1249,7 @@ df2 = wl.compare(wl.mm1(1, 5), wl.mm1(2, 5), wl.mm1(3, 5))
|
|
|
1248
1249
|
|
|
1249
1250
|
---
|
|
1250
1251
|
|
|
1251
|
-
##
|
|
1252
|
+
## 20. Gráficas
|
|
1252
1253
|
|
|
1253
1254
|
Todos los resultados exponen `.plot()` que devuelve una figura de Matplotlib o Plotly. También se pueden llamar directamente desde `walopy.plotting`.
|
|
1254
1255
|
|
|
@@ -1284,7 +1285,7 @@ fig.show()
|
|
|
1284
1285
|
|
|
1285
1286
|
---
|
|
1286
1287
|
|
|
1287
|
-
##
|
|
1288
|
+
## 21. CLI
|
|
1288
1289
|
|
|
1289
1290
|
walopy incluye una interfaz de línea de comandos para uso rápido sin escribir código.
|
|
1290
1291
|
|
|
@@ -1326,7 +1327,140 @@ Wq : 0.3 (avg wait time in queue)
|
|
|
1326
1327
|
|
|
1327
1328
|
---
|
|
1328
1329
|
|
|
1329
|
-
## 12.
|
|
1330
|
+
## 12. Curvas de intercambio
|
|
1331
|
+
|
|
1332
|
+
Herramientas para tomar decisiones de política agregada en familias de artículos.
|
|
1333
|
+
|
|
1334
|
+
### Tipo 1 — ciclo: `exchange_curve`
|
|
1335
|
+
|
|
1336
|
+
Traza la hipérbola entre número de pedidos por año (N) e inversión promedio en inventario de ciclo (I):
|
|
1337
|
+
|
|
1338
|
+
```
|
|
1339
|
+
N(k) = N* / k I(k) = k · I* → N · I = N* · I* (constante)
|
|
1340
|
+
```
|
|
1341
|
+
|
|
1342
|
+
Dado un target de N o de I, resuelve el multiplicador k óptimo y recalcula Q para cada artículo.
|
|
1343
|
+
|
|
1344
|
+
```python
|
|
1345
|
+
import walopy as wl
|
|
1346
|
+
|
|
1347
|
+
items = [
|
|
1348
|
+
{"name": "A", "demand": 1000, "ordering_cost": 50, "holding_cost": 2, "unit_value": 10},
|
|
1349
|
+
{"name": "B", "demand": 500, "ordering_cost": 30, "holding_cost": 1, "unit_value": 5},
|
|
1350
|
+
{"name": "C", "demand": 2000, "ordering_cost": 100, "holding_cost": 4, "unit_value": 8},
|
|
1351
|
+
]
|
|
1352
|
+
|
|
1353
|
+
# Sin target → punto EOQ (k = 1)
|
|
1354
|
+
r = wl.exchange_curve(items)
|
|
1355
|
+
print(r)
|
|
1356
|
+
```
|
|
1357
|
+
|
|
1358
|
+
```
|
|
1359
|
+
Target : eoq
|
|
1360
|
+
Multiplier k : 1.0000
|
|
1361
|
+
N orders/yr (EOQ) : 87.27
|
|
1362
|
+
N orders/yr (optimal) : 87.27
|
|
1363
|
+
Investment (EOQ) : 5430
|
|
1364
|
+
Investment (optimal) : 5430
|
|
1365
|
+
```
|
|
1366
|
+
|
|
1367
|
+
```python
|
|
1368
|
+
# Reducir a 20 pedidos/año (k > 1 → Q más grandes → más inversión)
|
|
1369
|
+
r = wl.exchange_curve(items, target_orders=20)
|
|
1370
|
+
|
|
1371
|
+
# Limitar inversión a 3 000 (k < 1 → Q más pequeños → más pedidos)
|
|
1372
|
+
r = wl.exchange_curve(items, target_investment=3000)
|
|
1373
|
+
|
|
1374
|
+
# Tabla por artículo
|
|
1375
|
+
df = r.to_frame()
|
|
1376
|
+
# columnas: name | Q_eoq | Q_optimal | n_orders | investment
|
|
1377
|
+
|
|
1378
|
+
# Hipérbola para graficar
|
|
1379
|
+
curve = r.curve_to_frame()
|
|
1380
|
+
# columnas: N | I
|
|
1381
|
+
```
|
|
1382
|
+
|
|
1383
|
+
**Parámetros de cada artículo**
|
|
1384
|
+
|
|
1385
|
+
| Clave | Requerido | Descripción |
|
|
1386
|
+
|-------|-----------|-------------|
|
|
1387
|
+
| `demand` | ✓ | Demanda anual Di |
|
|
1388
|
+
| `ordering_cost` | ✓ | Costo de pedido Ki |
|
|
1389
|
+
| `holding_cost` | ✓ | Costo de mantenimiento hi |
|
|
1390
|
+
| `unit_value` | — | Valor unitario vi (default 1) |
|
|
1391
|
+
| `name` | — | Etiqueta (default I1, I2, …) |
|
|
1392
|
+
|
|
1393
|
+
---
|
|
1394
|
+
|
|
1395
|
+
### Tipo 2 — seguridad: `safety_stock_curve`
|
|
1396
|
+
|
|
1397
|
+
Traza la curva entre inversión en stock de seguridad e nivel de servicio por ciclo usando una **política z común** para toda la familia:
|
|
1398
|
+
|
|
1399
|
+
```
|
|
1400
|
+
SS_i(z) = z · σᵢ_DLT · vᵢ σᵢ_DLT = √(Lᵢ·σ²_Di + D²ᵢ·σ²_Li)
|
|
1401
|
+
SS_total(z) = z · Σ σᵢ_DLT · vᵢ SL(z) = Φ(z)
|
|
1402
|
+
```
|
|
1403
|
+
|
|
1404
|
+
```python
|
|
1405
|
+
items = [
|
|
1406
|
+
{"name": "A", "demand_rate": 100, "demand_std": 10, "lead_time": 2, "unit_value": 10},
|
|
1407
|
+
{"name": "B", "demand_rate": 50, "demand_std": 5, "lead_time": 1, "unit_value": 5},
|
|
1408
|
+
{"name": "C", "demand_rate": 200, "demand_std": 20, "lead_time": 3, "unit_value": 8},
|
|
1409
|
+
]
|
|
1410
|
+
|
|
1411
|
+
# Target: nivel de servicio 95%
|
|
1412
|
+
r = wl.safety_stock_curve(items, target_service_level=0.95)
|
|
1413
|
+
print(r)
|
|
1414
|
+
```
|
|
1415
|
+
|
|
1416
|
+
```
|
|
1417
|
+
Target : service_level=95.0000%
|
|
1418
|
+
z : 1.6449
|
|
1419
|
+
Service level : 95.0000%
|
|
1420
|
+
SS investment : 1 847
|
|
1421
|
+
```
|
|
1422
|
+
|
|
1423
|
+
```python
|
|
1424
|
+
# Target: presupuesto máximo de SS
|
|
1425
|
+
r = wl.safety_stock_curve(items, target_ss_investment=1000)
|
|
1426
|
+
|
|
1427
|
+
# Tabla por artículo (incluye punto de reorden cuando se da demand_rate)
|
|
1428
|
+
df = r.to_frame()
|
|
1429
|
+
# columnas: name | sigma_dlt | safety_stock | investment | reorder_point
|
|
1430
|
+
|
|
1431
|
+
# Curva completa (z de −2 a 4)
|
|
1432
|
+
curve = r.curve_to_frame()
|
|
1433
|
+
# columnas: z | service_level | ss_investment
|
|
1434
|
+
```
|
|
1435
|
+
|
|
1436
|
+
**Parámetros de cada artículo**
|
|
1437
|
+
|
|
1438
|
+
| Clave | Requerido | Descripción |
|
|
1439
|
+
|-------|-----------|-------------|
|
|
1440
|
+
| `demand_std` | ✓ | Desviación estándar de la demanda |
|
|
1441
|
+
| `lead_time` | ✓ | Lead time medio |
|
|
1442
|
+
| `demand_rate` | — | Demanda media; activa columna `reorder_point` |
|
|
1443
|
+
| `lead_time_std` | — | Desviación estándar del lead time (default 0) |
|
|
1444
|
+
| `unit_value` | — | Valor unitario (default 1) |
|
|
1445
|
+
| `name` | — | Etiqueta (default I1, I2, …) |
|
|
1446
|
+
|
|
1447
|
+
---
|
|
1448
|
+
|
|
1449
|
+
### Relación entre ambas curvas
|
|
1450
|
+
|
|
1451
|
+
| | Tipo 1 (ciclo) | Tipo 2 (seguridad) |
|
|
1452
|
+
|---|---|---|
|
|
1453
|
+
| **Función** | `exchange_curve` | `safety_stock_curve` |
|
|
1454
|
+
| **Decide** | Tamaño de lote Q | Punto de reorden r |
|
|
1455
|
+
| **Tradeoff** | N pedidos/año ↔ Inversión ciclo | Nivel de servicio ↔ SS |
|
|
1456
|
+
| **Resultado** | `ExchangeCurveResult` | `SafetyStockCurveResult` |
|
|
1457
|
+
| **Parámetro** | Multiplicador k | Factor z |
|
|
1458
|
+
|
|
1459
|
+
Usadas juntas cubren la política completa `(Q, r)` para toda la familia.
|
|
1460
|
+
|
|
1461
|
+
---
|
|
1462
|
+
|
|
1463
|
+
## 13. Programación de producción (scheduling)
|
|
1330
1464
|
|
|
1331
1465
|
### Máquina única — `schedule_single`
|
|
1332
1466
|
|
|
@@ -1409,7 +1543,7 @@ df = r.to_frame()
|
|
|
1409
1543
|
|
|
1410
1544
|
---
|
|
1411
1545
|
|
|
1412
|
-
##
|
|
1546
|
+
## 14. Confiabilidad — `reliability`
|
|
1413
1547
|
|
|
1414
1548
|
Modelos de confiabilidad con distribución exponencial (tasa de falla constante).
|
|
1415
1549
|
|
|
@@ -1485,14 +1619,14 @@ r.R(t=200) # evalúa R(t) en cualquier tiempo posterior
|
|
|
1485
1619
|
|
|
1486
1620
|
---
|
|
1487
1621
|
|
|
1488
|
-
##
|
|
1622
|
+
## 22. Referencia de módulos
|
|
1489
1623
|
|
|
1490
1624
|
| Módulo | Funciones y clases principales |
|
|
1491
1625
|
|---|---|
|
|
1492
1626
|
| `queuing` | `mm1`, `mmc`, `md1`, `kingman`, `mg1`, `littles_law`, `QueueResult`, `cv2_normal`, `cv2_triangular`, `cv2_uniform`, `cv2_erlang`, `cv2_gamma`, `cv2_lognormal`, `cv2_weibull` |
|
|
1493
1627
|
| `advanced` | `mm1k`, `mmck`, `erlang_b`, `mm1_priority`, `monte_carlo_gg1`, `takt_time`, `line_balance`, `break_even`, `break_even_multi`, `break_even_sales`, `queue_length_pmf`, `sojourn_cdf`, `PriorityQueueResult`, `SimulationResult`, `LineBalanceResult`, `BreakEvenResult`, `BreakEvenMultiResult` |
|
|
1494
1628
|
| `fitting` | `fit_from_data`, `FitResult` |
|
|
1495
|
-
| `inventory` | `eoq`, `ebq`, `eoq_multi`, `ebq_multi`, `eoq_multi_constrained`, `lot_for_lot`, `silver_meal`, `eoq_quantity_discount`, `wagner_whitin`, `rq_policy`, `rs_policy`, `reorder_point`, `newsvendor`, `EOQResult`, `EBQResult`, `MultiItemResult`, `ConstrainedMultiEOQResult`, `LotSizingResult`, `QuantityDiscountResult`, `ReorderResult`, `NewsvendorResult`, `RQPolicyResult`, `RSPolicyResult` |
|
|
1629
|
+
| `inventory` | `eoq`, `ebq`, `eoq_multi`, `ebq_multi`, `eoq_multi_constrained`, `lot_for_lot`, `silver_meal`, `eoq_quantity_discount`, `wagner_whitin`, `rq_policy`, `rs_policy`, `exchange_curve`, `safety_stock_curve`, `reorder_point`, `newsvendor`, `EOQResult`, `EBQResult`, `MultiItemResult`, `ConstrainedMultiEOQResult`, `LotSizingResult`, `QuantityDiscountResult`, `ReorderResult`, `NewsvendorResult`, `RQPolicyResult`, `RSPolicyResult`, `ExchangeCurveResult`, `SafetyStockCurveResult` |
|
|
1496
1630
|
| `scheduling` | `schedule_single`, `johnson_flowshop`, `ScheduleResult`, `JobSchedule`, `FlowShopResult` |
|
|
1497
1631
|
| `reliability` | `mtbf_analysis`, `series_system`, `parallel_system`, `koon_system`, `ReliabilityResult` |
|
|
1498
1632
|
| `network` | `jackson_network`, `JacksonResult`, `StationMetrics` |
|
|
@@ -1504,7 +1638,7 @@ r.R(t=200) # evalúa R(t) en cualquier tiempo posterior
|
|
|
1504
1638
|
|
|
1505
1639
|
---
|
|
1506
1640
|
|
|
1507
|
-
##
|
|
1641
|
+
## 23. Requisitos
|
|
1508
1642
|
|
|
1509
1643
|
```
|
|
1510
1644
|
Python ≥ 3.9
|
|
@@ -26,17 +26,18 @@ pip install walopy
|
|
|
26
26
|
9. [Análisis de cuellos de botella](#9-análisis-de-cuellos-de-botella)
|
|
27
27
|
10. [Balance de línea y tiempo takt](#10-balance-de-línea-y-tiempo-takt)
|
|
28
28
|
11. [Análisis de punto de equilibrio](#11-análisis-de-punto-de-equilibrio)
|
|
29
|
-
12. [
|
|
30
|
-
13. [
|
|
31
|
-
14. [
|
|
32
|
-
15. [
|
|
33
|
-
16. [
|
|
34
|
-
17. [
|
|
35
|
-
18. [
|
|
36
|
-
19. [
|
|
37
|
-
20. [
|
|
38
|
-
21. [
|
|
39
|
-
22. [
|
|
29
|
+
12. [Curvas de intercambio](#12-curvas-de-intercambio)
|
|
30
|
+
13. [Programación de producción (scheduling)](#13-programación-de-producción-scheduling)
|
|
31
|
+
14. [Confiabilidad](#14-confiabilidad--reliability)
|
|
32
|
+
15. [Árboles de KPI](#15-árboles-de-kpi)
|
|
33
|
+
16. [Solvers y optimización](#16-solvers-y-optimización)
|
|
34
|
+
17. [Análisis de sensibilidad](#17-análisis-de-sensibilidad)
|
|
35
|
+
18. [Escenarios en lote (batch_model)](#18-escenarios-en-lote-batch_model)
|
|
36
|
+
19. [Comparar múltiples resultados](#19-comparar-múltiples-resultados)
|
|
37
|
+
20. [Gráficas](#20-gráficas)
|
|
38
|
+
21. [CLI](#21-cli)
|
|
39
|
+
22. [Referencia de módulos](#22-referencia-de-módulos)
|
|
40
|
+
23. [Requisitos](#23-requisitos)
|
|
40
41
|
|
|
41
42
|
---
|
|
42
43
|
|
|
@@ -1020,7 +1021,7 @@ print(r.margin_of_safety_pct) # 0.375 — porcentaje del margen de seguridad
|
|
|
1020
1021
|
|
|
1021
1022
|
---
|
|
1022
1023
|
|
|
1023
|
-
##
|
|
1024
|
+
## 15. Árboles de KPI
|
|
1024
1025
|
|
|
1025
1026
|
Los árboles de KPI crean jerarquías interactivas visualizadas como **treemap** o **sunburst** con Plotly.
|
|
1026
1027
|
|
|
@@ -1073,7 +1074,7 @@ fig.show()
|
|
|
1073
1074
|
|
|
1074
1075
|
---
|
|
1075
1076
|
|
|
1076
|
-
##
|
|
1077
|
+
## 16. Solvers y optimización
|
|
1077
1078
|
|
|
1078
1079
|
### `solve_lam(metric, target, *, mu, model)` — Máxima tasa de llegada
|
|
1079
1080
|
|
|
@@ -1120,7 +1121,7 @@ r.plot() # gráfica de costo vs número de servidores
|
|
|
1120
1121
|
|
|
1121
1122
|
---
|
|
1122
1123
|
|
|
1123
|
-
##
|
|
1124
|
+
## 17. Análisis de sensibilidad
|
|
1124
1125
|
|
|
1125
1126
|
### `sensitivity(model_fn, param, values, **fixed_kwargs)` — Barrido paramétrico
|
|
1126
1127
|
|
|
@@ -1151,7 +1152,7 @@ fig.show()
|
|
|
1151
1152
|
|
|
1152
1153
|
---
|
|
1153
1154
|
|
|
1154
|
-
##
|
|
1155
|
+
## 18. Escenarios en lote (batch_model)
|
|
1155
1156
|
|
|
1156
1157
|
### `batch_model(model_fn, df, **fixed_kwargs)` — Aplicar modelo a un DataFrame
|
|
1157
1158
|
|
|
@@ -1186,7 +1187,7 @@ print(resultado[resultado["_error"].notna()]) # filas fallidas
|
|
|
1186
1187
|
|
|
1187
1188
|
---
|
|
1188
1189
|
|
|
1189
|
-
##
|
|
1190
|
+
## 19. Comparar múltiples resultados
|
|
1190
1191
|
|
|
1191
1192
|
### `compare(*results, labels)` — DataFrame comparativo
|
|
1192
1193
|
|
|
@@ -1211,7 +1212,7 @@ df2 = wl.compare(wl.mm1(1, 5), wl.mm1(2, 5), wl.mm1(3, 5))
|
|
|
1211
1212
|
|
|
1212
1213
|
---
|
|
1213
1214
|
|
|
1214
|
-
##
|
|
1215
|
+
## 20. Gráficas
|
|
1215
1216
|
|
|
1216
1217
|
Todos los resultados exponen `.plot()` que devuelve una figura de Matplotlib o Plotly. También se pueden llamar directamente desde `walopy.plotting`.
|
|
1217
1218
|
|
|
@@ -1247,7 +1248,7 @@ fig.show()
|
|
|
1247
1248
|
|
|
1248
1249
|
---
|
|
1249
1250
|
|
|
1250
|
-
##
|
|
1251
|
+
## 21. CLI
|
|
1251
1252
|
|
|
1252
1253
|
walopy incluye una interfaz de línea de comandos para uso rápido sin escribir código.
|
|
1253
1254
|
|
|
@@ -1289,7 +1290,140 @@ Wq : 0.3 (avg wait time in queue)
|
|
|
1289
1290
|
|
|
1290
1291
|
---
|
|
1291
1292
|
|
|
1292
|
-
## 12.
|
|
1293
|
+
## 12. Curvas de intercambio
|
|
1294
|
+
|
|
1295
|
+
Herramientas para tomar decisiones de política agregada en familias de artículos.
|
|
1296
|
+
|
|
1297
|
+
### Tipo 1 — ciclo: `exchange_curve`
|
|
1298
|
+
|
|
1299
|
+
Traza la hipérbola entre número de pedidos por año (N) e inversión promedio en inventario de ciclo (I):
|
|
1300
|
+
|
|
1301
|
+
```
|
|
1302
|
+
N(k) = N* / k I(k) = k · I* → N · I = N* · I* (constante)
|
|
1303
|
+
```
|
|
1304
|
+
|
|
1305
|
+
Dado un target de N o de I, resuelve el multiplicador k óptimo y recalcula Q para cada artículo.
|
|
1306
|
+
|
|
1307
|
+
```python
|
|
1308
|
+
import walopy as wl
|
|
1309
|
+
|
|
1310
|
+
items = [
|
|
1311
|
+
{"name": "A", "demand": 1000, "ordering_cost": 50, "holding_cost": 2, "unit_value": 10},
|
|
1312
|
+
{"name": "B", "demand": 500, "ordering_cost": 30, "holding_cost": 1, "unit_value": 5},
|
|
1313
|
+
{"name": "C", "demand": 2000, "ordering_cost": 100, "holding_cost": 4, "unit_value": 8},
|
|
1314
|
+
]
|
|
1315
|
+
|
|
1316
|
+
# Sin target → punto EOQ (k = 1)
|
|
1317
|
+
r = wl.exchange_curve(items)
|
|
1318
|
+
print(r)
|
|
1319
|
+
```
|
|
1320
|
+
|
|
1321
|
+
```
|
|
1322
|
+
Target : eoq
|
|
1323
|
+
Multiplier k : 1.0000
|
|
1324
|
+
N orders/yr (EOQ) : 87.27
|
|
1325
|
+
N orders/yr (optimal) : 87.27
|
|
1326
|
+
Investment (EOQ) : 5430
|
|
1327
|
+
Investment (optimal) : 5430
|
|
1328
|
+
```
|
|
1329
|
+
|
|
1330
|
+
```python
|
|
1331
|
+
# Reducir a 20 pedidos/año (k > 1 → Q más grandes → más inversión)
|
|
1332
|
+
r = wl.exchange_curve(items, target_orders=20)
|
|
1333
|
+
|
|
1334
|
+
# Limitar inversión a 3 000 (k < 1 → Q más pequeños → más pedidos)
|
|
1335
|
+
r = wl.exchange_curve(items, target_investment=3000)
|
|
1336
|
+
|
|
1337
|
+
# Tabla por artículo
|
|
1338
|
+
df = r.to_frame()
|
|
1339
|
+
# columnas: name | Q_eoq | Q_optimal | n_orders | investment
|
|
1340
|
+
|
|
1341
|
+
# Hipérbola para graficar
|
|
1342
|
+
curve = r.curve_to_frame()
|
|
1343
|
+
# columnas: N | I
|
|
1344
|
+
```
|
|
1345
|
+
|
|
1346
|
+
**Parámetros de cada artículo**
|
|
1347
|
+
|
|
1348
|
+
| Clave | Requerido | Descripción |
|
|
1349
|
+
|-------|-----------|-------------|
|
|
1350
|
+
| `demand` | ✓ | Demanda anual Di |
|
|
1351
|
+
| `ordering_cost` | ✓ | Costo de pedido Ki |
|
|
1352
|
+
| `holding_cost` | ✓ | Costo de mantenimiento hi |
|
|
1353
|
+
| `unit_value` | — | Valor unitario vi (default 1) |
|
|
1354
|
+
| `name` | — | Etiqueta (default I1, I2, …) |
|
|
1355
|
+
|
|
1356
|
+
---
|
|
1357
|
+
|
|
1358
|
+
### Tipo 2 — seguridad: `safety_stock_curve`
|
|
1359
|
+
|
|
1360
|
+
Traza la curva entre inversión en stock de seguridad e nivel de servicio por ciclo usando una **política z común** para toda la familia:
|
|
1361
|
+
|
|
1362
|
+
```
|
|
1363
|
+
SS_i(z) = z · σᵢ_DLT · vᵢ σᵢ_DLT = √(Lᵢ·σ²_Di + D²ᵢ·σ²_Li)
|
|
1364
|
+
SS_total(z) = z · Σ σᵢ_DLT · vᵢ SL(z) = Φ(z)
|
|
1365
|
+
```
|
|
1366
|
+
|
|
1367
|
+
```python
|
|
1368
|
+
items = [
|
|
1369
|
+
{"name": "A", "demand_rate": 100, "demand_std": 10, "lead_time": 2, "unit_value": 10},
|
|
1370
|
+
{"name": "B", "demand_rate": 50, "demand_std": 5, "lead_time": 1, "unit_value": 5},
|
|
1371
|
+
{"name": "C", "demand_rate": 200, "demand_std": 20, "lead_time": 3, "unit_value": 8},
|
|
1372
|
+
]
|
|
1373
|
+
|
|
1374
|
+
# Target: nivel de servicio 95%
|
|
1375
|
+
r = wl.safety_stock_curve(items, target_service_level=0.95)
|
|
1376
|
+
print(r)
|
|
1377
|
+
```
|
|
1378
|
+
|
|
1379
|
+
```
|
|
1380
|
+
Target : service_level=95.0000%
|
|
1381
|
+
z : 1.6449
|
|
1382
|
+
Service level : 95.0000%
|
|
1383
|
+
SS investment : 1 847
|
|
1384
|
+
```
|
|
1385
|
+
|
|
1386
|
+
```python
|
|
1387
|
+
# Target: presupuesto máximo de SS
|
|
1388
|
+
r = wl.safety_stock_curve(items, target_ss_investment=1000)
|
|
1389
|
+
|
|
1390
|
+
# Tabla por artículo (incluye punto de reorden cuando se da demand_rate)
|
|
1391
|
+
df = r.to_frame()
|
|
1392
|
+
# columnas: name | sigma_dlt | safety_stock | investment | reorder_point
|
|
1393
|
+
|
|
1394
|
+
# Curva completa (z de −2 a 4)
|
|
1395
|
+
curve = r.curve_to_frame()
|
|
1396
|
+
# columnas: z | service_level | ss_investment
|
|
1397
|
+
```
|
|
1398
|
+
|
|
1399
|
+
**Parámetros de cada artículo**
|
|
1400
|
+
|
|
1401
|
+
| Clave | Requerido | Descripción |
|
|
1402
|
+
|-------|-----------|-------------|
|
|
1403
|
+
| `demand_std` | ✓ | Desviación estándar de la demanda |
|
|
1404
|
+
| `lead_time` | ✓ | Lead time medio |
|
|
1405
|
+
| `demand_rate` | — | Demanda media; activa columna `reorder_point` |
|
|
1406
|
+
| `lead_time_std` | — | Desviación estándar del lead time (default 0) |
|
|
1407
|
+
| `unit_value` | — | Valor unitario (default 1) |
|
|
1408
|
+
| `name` | — | Etiqueta (default I1, I2, …) |
|
|
1409
|
+
|
|
1410
|
+
---
|
|
1411
|
+
|
|
1412
|
+
### Relación entre ambas curvas
|
|
1413
|
+
|
|
1414
|
+
| | Tipo 1 (ciclo) | Tipo 2 (seguridad) |
|
|
1415
|
+
|---|---|---|
|
|
1416
|
+
| **Función** | `exchange_curve` | `safety_stock_curve` |
|
|
1417
|
+
| **Decide** | Tamaño de lote Q | Punto de reorden r |
|
|
1418
|
+
| **Tradeoff** | N pedidos/año ↔ Inversión ciclo | Nivel de servicio ↔ SS |
|
|
1419
|
+
| **Resultado** | `ExchangeCurveResult` | `SafetyStockCurveResult` |
|
|
1420
|
+
| **Parámetro** | Multiplicador k | Factor z |
|
|
1421
|
+
|
|
1422
|
+
Usadas juntas cubren la política completa `(Q, r)` para toda la familia.
|
|
1423
|
+
|
|
1424
|
+
---
|
|
1425
|
+
|
|
1426
|
+
## 13. Programación de producción (scheduling)
|
|
1293
1427
|
|
|
1294
1428
|
### Máquina única — `schedule_single`
|
|
1295
1429
|
|
|
@@ -1372,7 +1506,7 @@ df = r.to_frame()
|
|
|
1372
1506
|
|
|
1373
1507
|
---
|
|
1374
1508
|
|
|
1375
|
-
##
|
|
1509
|
+
## 14. Confiabilidad — `reliability`
|
|
1376
1510
|
|
|
1377
1511
|
Modelos de confiabilidad con distribución exponencial (tasa de falla constante).
|
|
1378
1512
|
|
|
@@ -1448,14 +1582,14 @@ r.R(t=200) # evalúa R(t) en cualquier tiempo posterior
|
|
|
1448
1582
|
|
|
1449
1583
|
---
|
|
1450
1584
|
|
|
1451
|
-
##
|
|
1585
|
+
## 22. Referencia de módulos
|
|
1452
1586
|
|
|
1453
1587
|
| Módulo | Funciones y clases principales |
|
|
1454
1588
|
|---|---|
|
|
1455
1589
|
| `queuing` | `mm1`, `mmc`, `md1`, `kingman`, `mg1`, `littles_law`, `QueueResult`, `cv2_normal`, `cv2_triangular`, `cv2_uniform`, `cv2_erlang`, `cv2_gamma`, `cv2_lognormal`, `cv2_weibull` |
|
|
1456
1590
|
| `advanced` | `mm1k`, `mmck`, `erlang_b`, `mm1_priority`, `monte_carlo_gg1`, `takt_time`, `line_balance`, `break_even`, `break_even_multi`, `break_even_sales`, `queue_length_pmf`, `sojourn_cdf`, `PriorityQueueResult`, `SimulationResult`, `LineBalanceResult`, `BreakEvenResult`, `BreakEvenMultiResult` |
|
|
1457
1591
|
| `fitting` | `fit_from_data`, `FitResult` |
|
|
1458
|
-
| `inventory` | `eoq`, `ebq`, `eoq_multi`, `ebq_multi`, `eoq_multi_constrained`, `lot_for_lot`, `silver_meal`, `eoq_quantity_discount`, `wagner_whitin`, `rq_policy`, `rs_policy`, `reorder_point`, `newsvendor`, `EOQResult`, `EBQResult`, `MultiItemResult`, `ConstrainedMultiEOQResult`, `LotSizingResult`, `QuantityDiscountResult`, `ReorderResult`, `NewsvendorResult`, `RQPolicyResult`, `RSPolicyResult` |
|
|
1592
|
+
| `inventory` | `eoq`, `ebq`, `eoq_multi`, `ebq_multi`, `eoq_multi_constrained`, `lot_for_lot`, `silver_meal`, `eoq_quantity_discount`, `wagner_whitin`, `rq_policy`, `rs_policy`, `exchange_curve`, `safety_stock_curve`, `reorder_point`, `newsvendor`, `EOQResult`, `EBQResult`, `MultiItemResult`, `ConstrainedMultiEOQResult`, `LotSizingResult`, `QuantityDiscountResult`, `ReorderResult`, `NewsvendorResult`, `RQPolicyResult`, `RSPolicyResult`, `ExchangeCurveResult`, `SafetyStockCurveResult` |
|
|
1459
1593
|
| `scheduling` | `schedule_single`, `johnson_flowshop`, `ScheduleResult`, `JobSchedule`, `FlowShopResult` |
|
|
1460
1594
|
| `reliability` | `mtbf_analysis`, `series_system`, `parallel_system`, `koon_system`, `ReliabilityResult` |
|
|
1461
1595
|
| `network` | `jackson_network`, `JacksonResult`, `StationMetrics` |
|
|
@@ -1467,7 +1601,7 @@ r.R(t=200) # evalúa R(t) en cualquier tiempo posterior
|
|
|
1467
1601
|
|
|
1468
1602
|
---
|
|
1469
1603
|
|
|
1470
|
-
##
|
|
1604
|
+
## 23. Requisitos
|
|
1471
1605
|
|
|
1472
1606
|
```
|
|
1473
1607
|
Python ≥ 3.9
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "walopy"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.7"
|
|
8
8
|
description = "Queuing theory, operations analysis, OEE, bottleneck analysis and KPI trees for Python"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -117,9 +117,13 @@ from .network import (
|
|
|
117
117
|
from .inventory import (
|
|
118
118
|
RQPolicyResult,
|
|
119
119
|
RSPolicyResult,
|
|
120
|
+
ExchangeCurveResult,
|
|
121
|
+
SafetyStockCurveResult,
|
|
120
122
|
rq_policy,
|
|
121
123
|
rs_policy,
|
|
122
124
|
wagner_whitin,
|
|
125
|
+
exchange_curve,
|
|
126
|
+
safety_stock_curve,
|
|
123
127
|
)
|
|
124
128
|
|
|
125
129
|
# Scheduling
|
|
@@ -235,9 +239,13 @@ __all__ = [
|
|
|
235
239
|
# inventory additions
|
|
236
240
|
"RQPolicyResult",
|
|
237
241
|
"RSPolicyResult",
|
|
242
|
+
"ExchangeCurveResult",
|
|
243
|
+
"SafetyStockCurveResult",
|
|
238
244
|
"rq_policy",
|
|
239
245
|
"rs_policy",
|
|
240
246
|
"wagner_whitin",
|
|
247
|
+
"exchange_curve",
|
|
248
|
+
"safety_stock_curve",
|
|
241
249
|
# scheduling
|
|
242
250
|
"JobSchedule",
|
|
243
251
|
"ScheduleResult",
|