https://github.com/dfleta/greedy-search
Set covering problem: USA radio stations
https://github.com/dfleta/greedy-search
greedy-search ia-algorithms optimization-algorithms optimization-problem python-sets set-covering-problem
Last synced: about 1 month ago
JSON representation
Set covering problem: USA radio stations
- Host: GitHub
- URL: https://github.com/dfleta/greedy-search
- Owner: dfleta
- Created: 2025-03-05T16:14:40.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2025-11-26T14:20:16.000Z (6 months ago)
- Last Synced: 2025-11-28T02:30:59.823Z (6 months ago)
- Topics: greedy-search, ia-algorithms, optimization-algorithms, optimization-problem, python-sets, set-covering-problem
- Language: Python
- Homepage:
- Size: 231 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Optimización de Cobertura de Estaciones de Radio
## Descripción del Problema
Este proyecto aborda un problema clásico de optimización en Inteligencia Artificial conocido como "_Set Covering Problem_".
El objetivo es encontrar el número mínimo de estaciones de radio necesarias para cubrir todos los estados de Estados Unidos (específicamente, los estados del oeste y centro del país).
Está basado en el ejercicio propuesto en el capítulo 8 _Greedy Algorithms_ del libro grokking [_Algorithms: An illustrated guide for programmers and other curious people_ de Aditya Y. Bhargava](https://github.com/egonSchiele/grokking_algorithms)
## Instalación y Configuración
### Requisitos Previos
- Python ≥ 3.11
- [uv](https://github.com/astral-sh/uv) (gestor de paquetes de Python)
### Tkinter
`plt.show()` con Python 3.12 necesita un backend interactivo (TkAgg, Qt5Agg, Gtk3Agg) y una librería GUI instalada.
En Linux, por ejemplo:
`sudo apt-get install -y python3-tk` para TkAgg
o
`pip install PyQt5` para Qt5Agg
### Instalación
1. Clonar el repositorio:
```bash
git clone https://github.com/dfleta/greedy-search.git
cd greedy-search
```
2. Crear y activar un entorno virtual con uv:
```bash
python -m pip install uv
uv venv
source .venv/bin/activate # En Linux/MacOS
# o
.venv\Scripts\activate # En Windows
```
3. Instalar las dependencias:
```bash
uv sync
```
4. (Opcional) Instalar dependencias de desarrollo:
```bash
uv sync --all-groups
```
o
```bash
uv add --group dev
```
### Dependencias Principales
- matplotlib ≥ 3.10.1
#### Dependencias de desarrollo
- pytest >= 9.0.1
- ruff ≥ 0.9.9 (para linting, opcional)
### Uso
`uv run main.py`
o
`python3 main.py`
### Testing
`uv run pytest`
Con _markers_ listados en [pyproject.toml](./pyproject.toml)
`uv run pytest -m "greedy_search_global"`
`uv run pytest -m "find_best_station"`
### Contexto
- Necesitamos cobertura de radio en un conjunto de estados, todos los situados al oeste del río Mississippi para promocionar el disco _country_ de Beyoncé _Cowboy Carter_.
- Existen varias estaciones de radio, cada una cubriendo diferentes conjuntos de estados.
- Queremos seleccionar el menor número de estaciones posible que cubran todos los estados requeridos, porque Beyoncé -en modo gano o muero- paga la promoción del disco de su bolsillo. Las estaciones al oeste del Misisipi tienen un código que empieza por la letra `K`.
### Cobertura de Estaciones
La siguiente tabla muestra los estados que cubre cada estación de radio:
| Estación | Estados Cubiertos |
|------------|------------------|
| kone | Idaho (ID), Nevada (NV), Utah (UT) |
| ktwo | Washington (WA), Idaho (ID), Montana (MT) |
| kthree | Oregon (OR), Nevada (NV), California (CA) |
| kfour | Nevada (NV), Utah (UT) |
| kfive | California (CA), Arizona (AZ) |
| ksix | New Mexico (NM), Texas (TX), Oklahoma (OK) |
| kseven | Oklahoma (OK), Kansas (KS), Colorado (CO) |
| keight | Kansas (KS), Colorado (CO), Nebraska (NE) |
| knine | Nebraska (NE), South Dakota (SD), Wyoming (WY) |
| kten | North Dakota (ND), Iowa (IA) |
| keleven | Minnesota (MN), Missouri (MO), Arkansas (AR) |
| ktwelve | Louisiana (LA) |
| kthirteen | Missouri (MO), Arkansas (AR) |

*K/W Call Letters in the United States*

*List of U.S. state and territory abbreviations*
## Implementación
El proyecto implementa dos estrategias diferentes de búsqueda:
### 1. Búsqueda Ávida Global (`greedy_search_global`)
Esta función implementa una estrategia de búsqueda voraz (_greedy_) que:
- En cada paso, selecciona la estación que cubre el mayor número de estados no cubiertos hasta el momento.
- Mantiene un registro de los estados cubiertos y las estaciones seleccionadas.
- Escapa de mínimos locales al considerar siempre la mejor opción global disponible.

*La gráfica muestra cómo cada estación seleccionada contribuye a la cobertura total de estados*
### 2. Búsqueda Ávida Local (`greedy_search_local`)
Esta función demuestra el problema de los mínimos locales:
- Realiza múltiples intentos aleatorios seleccionando 10 estaciones en cada iteración.
- No considera la optimización global, sino que se basa en selecciones aleatorias.
- Queda atrapada en mínimos locales, resultando en soluciones subóptimas.

*La gráfica muestra cómo diferentes iteraciones quedan atrapadas en mínimos locales, aún alcanzando en una de ellas el mínimo global.*

*La gráfica muestra cómo diferentes iteraciones quedan atrapadas en mínimos locales, sin alcanzar la cobertura total.*
## Resultados
- La búsqueda ávida global encuentra una solución óptima o cercana a la óptima.
- La búsqueda local demuestra cómo las estrategias no optimizadas pueden quedar atrapadas en soluciones subóptimas.
- Las gráficas permiten comparar la efectividad de ambos enfoques.
#### Lógica del Algoritmo
`greedy_search_global`
**Consulta el [_notebook_ conjuntos / sets](https://github.com/dfleta/python-fundamentals-nb/blob/main/notebooks/conjuntos.ipynb) para estudiar las operaciones sobre esta colección Python** de las que vamos a hacer uso.
1. **Inicialización**:
- Mantiene un conjunto `covered_states` para registrar los estados ya cubiertos.
- Una lista `stations_needed` para almacenar las estaciones seleccionadas.
- Listas `gradients` y `num_states_covered` para monitorizar el progreso.
2. **Bucle Principal**:
Mientras existan estados sin cubrir (`covered_states < needed_states`):
a. **Selección de la Mejor Estación**:
- Para cada estación restante, calcula cuántos nuevos estados cubriría: `new_states = station_states - covered_states`.
- Selecciona la estación que cubra el mayor número de estados nuevos
b. **Actualización del Estado**:
- Registra el gradiente (número de nuevos estados cubiertos).
- Actualiza el conjunto de estados cubiertos.
- Añade la estación a la lista de seleccionadas.
- Elimina la estación seleccionada del conjunto disponible.
3. **Visualización**:
- Genera un gráfico de barras mostrando:
- Eje X: Estaciones seleccionadas en orden.
- Eje Y: Número total de estados cubiertos en cada paso.
#### Características Clave
- **Optimización Global**: En cada paso, selecciona la mejor opción disponible.
- **Sin Retroceso**: Las decisiones tomadas son definitivas.
- **Monitorización**: Registra el progreso y la efectividad de cada selección.
- **Terminación**: El algoritmo se detiene cuando se cubren todos los estados necesarios.
## Referencias
- [Call Letters in the United States](https://earlyradiohistory.us/kwtrivia.htm)
- [Call signs in the United States](https://en.wikipedia.org/wiki/Call_signs_in_the_United_States)
- [List of FM radio stations in the United States by call sign (initial letters KK–KM)](https://en.wikipedia.org/wiki/List_of_FM_radio_stations_in_the_United_States_by_call_sign_(initial_letters_KK%E2%80%93KM))
- [List of U.S. state and territory abbreviations](https://en.wikipedia.org/wiki/List_of_U.S._state_and_territory_abbreviations)