La acción minCostFlow calcula el flujo de coste mínimo de una red. Este problema consiste en encontrar un flujo a través de una red dirigida que minimice el coste total, respetando las capacidades de los arcos y los balances de flujo en los nodos. Es fundamental en logística, planificación de transporte y gestión de cadenas de suministro para optimizar la distribución de bienes o recursos desde puntos de origen (oferta) a puntos de destino (demanda) al menor coste posible.
| Parámetro | Descripción |
|---|---|
| deterministic | Cuando se establece en TRUE, asegura que cada invocación (con la misma configuración de máquina y parámetros) produzca el mismo resultado final. Útil para la reproducibilidad. |
| direction | Especifica si el grafo de entrada debe considerarse como dirigido o no dirigido. En problemas de flujo, generalmente es "DIRECTED". |
| graph | Especifica el grafo en memoria a utilizar, previamente cargado con loadGraph. |
| indexOffset | Especifica el desplazamiento de índice para los identificadores en los registros y las tablas de datos de salida. |
| links | Especifica la tabla de datos de entrada que contiene la información de los arcos del grafo (conexiones). |
| linksVar | Especifica los nombres de las variables de datos para la tabla de arcos, como 'from', 'to', 'weight' (coste), 'lower' (capacidad mínima) y 'upper' (capacidad máxima). |
| logFreq | Especifica la frecuencia para mostrar los registros de iteración para los cálculos que utilizan el algoritmo simplex de red. |
| logLevel | Controla la cantidad de información que se muestra en el log de SAS (NONE, BASIC, MODERATE, AGGRESSIVE). |
| maxTime | Especifica la cantidad máxima de tiempo (en segundos) que el algoritmo debe emplear. |
| multiLinks | Cuando se establece en TRUE, incluye multienlaces (múltiples arcos entre los mismos dos nodos) al leer un grafo de entrada. |
| nodes | Especifica la tabla de datos de entrada que contiene la información de los nodos del grafo. |
| nodesVar | Especifica los nombres de las variables de datos para la tabla de nodos, como 'node', 'lower' (demanda) y 'upper' (oferta). |
| outLinks | Especifica la tabla de datos de salida para contener la información de los arcos del grafo junto con los resultados, como el flujo calculado. |
| outNodes | Especifica la tabla de datos de salida para contener la información de los nodos del grafo junto con los resultados, como los potenciales duales. |
Se crean dos tablas: una para los nodos con su oferta (valor positivo) o demanda (valor negativo), y otra para los arcos con sus costes y capacidades. Los nodos de oferta tienen un límite inferior de 0 y un límite superior igual a la cantidad que ofrecen. Los nodos de demanda tienen un límite superior de 0 y un límite inferior igual a la demanda (en negativo).
| 1 | DATA mycas.nodos_oferta_demanda; |
| 2 | INFILE DATALINES delimiter=','; |
| 3 | INPUT node $ demand; |
| 4 | IF demand > 0 THEN DO; lower = 0; upper = demand; END; |
| 5 | ELSE IF demand < 0 THEN DO; lower = demand; upper = 0; END; |
| 6 | ELSE DO; lower = 0; upper = 0; END; |
| 7 | DATALINES; |
| 8 | A,10 |
| 9 | B,20 |
| 10 | D,-5 |
| 11 | E,-15 |
| 12 | F,-10 |
| 13 | ; |
| 14 | RUN; |
| 15 | |
| 16 | DATA mycas.arcos_costo; |
| 17 | INFILE DATALINES delimiter=','; |
| 18 | INPUT from $ to $ weight capacity; |
| 19 | DATALINES; |
| 20 | A,B,1,15 |
| 21 | A,D,2,10 |
| 22 | B,D,1,10 |
| 23 | B,E,4,10 |
| 24 | B,C,3,10 |
| 25 | C,E,1,5 |
| 26 | C,F,3,10 |
| 27 | D,F,2,10 |
| 28 | E,F,1,15 |
| 29 | ; |
| 30 | RUN; |
Este ejemplo calcula el flujo de coste mínimo para la red definida en las tablas `nodos_oferta_demanda` y `arcos_costo`. La acción utiliza los parámetros `weight` para los costes de los arcos y `upper` y `lower` para las capacidades de los arcos y las demandas/ofertas de los nodos. Los resultados, incluyendo el flujo óptimo por arco, se guardan en la tabla `mycas.out_links`.
| 1 | PROC CAS; |
| 2 | optNetwork.minCostFlow / |
| 3 | direction = "DIRECTED" |
| 4 | links = {name = "arcos_costo"} |
| 5 | nodes = {name = "nodos_oferta_demanda"} |
| 6 | linksVar = {weight = "weight", upper = "capacity"} |
| 7 | nodesVar = {lower = "lower", upper = "upper"} |
| 8 | outLinks = {name = "out_links", replace=true}; |
| 9 | RUN; |
| 10 | QUIT; |
Este ejemplo amplía el caso simple añadiendo una capacidad de flujo mínima ('lower') para cada arco. Esto obliga a que, si se utiliza un arco, debe transportar al menos una cierta cantidad. Se define una nueva tabla de arcos `arcos_costo_limites` con esta información adicional. La acción `minCostFlow` se invoca especificando `lower` en el parámetro `linksVar` para tener en cuenta esta nueva restricción, lo que puede llevar a una solución de mayor coste total para satisfacer los flujos mínimos.
| 1 | DATA mycas.arcos_costo_limites; |
| 2 | SET mycas.arcos_costo; |
| 3 | IF from='A' and to='D' THEN lower = 2; |
| 4 | ELSE IF from='B' and to='E' THEN lower = 1; |
| 5 | ELSE lower = 0; |
| 6 | RUN; |
| 7 | |
| 8 | PROC CAS; |
| 9 | optNetwork.minCostFlow / |
| 10 | direction = "DIRECTED" |
| 11 | links = {name = "arcos_costo_limites"} |
| 12 | nodes = {name = "nodos_oferta_demanda"} |
| 13 | linksVar = {weight = "weight", upper = "capacity", lower="lower"} |
| 14 | nodesVar = {lower = "lower", upper = "upper"} |
| 15 | outLinks = {name = "out_links_detallado", replace=true} |
| 16 | outNodes = {name = "out_nodes_detallado", replace=true}; |
| 17 | RUN; |
| 18 | QUIT; |