pgr_lineGraphFull
— Transforma un grafo dado en uno nuevo donde todos los vértices del grafo original se convierten en grafos de líneas.
Advertencia
Posible bloqueo del servidor
Advertencia
Funciones experimentales
Disponibilidad
Soporte
pgr_lineGraphFull, convierte un grafo dirigido original a un grafo lineal dirigido, convirtiendo cada vértice en un grafo completo y manteniendo todas las aristas originales. Las nuevas aristas de conexión tienen un costo de 0 y van entre las aristas originales adyacentes, respetando la direccionalidad.
Una posible aplicación del grafo resultante es «ruteo con restricciones en dos aristas»:
Esto es posible porque cada una de las intersecciones (vértices) en el grafo original ahora son grafos completos que tienen una nueva arista para cada posible giro a través de esa intersección.
Resumen
pgr_lineGraphFull(edges_sql)
RETURNS SET OF (seq, source, target, cost, edge)
OR EMPTY SET
Uso de valores predeterminados
pgr_lineGraphFull(TEXT edges_sql)
RETURNS SET OF (seq, source, target, cost, edge) OR EMPTY SET
Ejemplo: | Grafo de línea completa del subgrafo de las aristas \(\{4, 7, 8, 10\}\) |
---|
SELECT * FROM pgr_lineGraphFull(
'SELECT id, source, target, cost, reverse_cost
FROM edge_table
WHERE id IN (4,7,8,10)'
);
seq | source | target | cost | edge
-----+--------+--------+------+------
1 | -1 | 5 | 1 | 4
2 | 2 | -1 | 0 | 0
3 | -2 | 2 | 1 | -4
4 | -3 | 8 | 1 | -7
5 | -4 | 6 | 1 | 8
6 | -5 | 10 | 1 | 10
7 | 5 | -2 | 0 | 0
8 | 5 | -3 | 0 | 0
9 | 5 | -4 | 0 | 0
10 | 5 | -5 | 0 | 0
11 | -6 | -2 | 0 | 0
12 | -6 | -3 | 0 | 0
13 | -6 | -4 | 0 | 0
14 | -6 | -5 | 0 | 0
15 | -7 | -2 | 0 | 0
16 | -7 | -3 | 0 | 0
17 | -7 | -4 | 0 | 0
18 | -7 | -5 | 0 | 0
19 | -8 | -2 | 0 | 0
20 | -8 | -3 | 0 | 0
21 | -8 | -4 | 0 | 0
22 | -8 | -5 | 0 | 0
23 | -9 | -6 | 1 | 7
24 | 8 | -9 | 0 | 0
25 | -10 | -7 | 1 | -8
26 | 6 | -10 | 0 | 0
27 | -11 | -8 | 1 | -10
28 | 10 | -11 | 0 | 0
(28 rows)
Columna | Tipo | Valores predeterminados | Descripción |
---|---|---|---|
sql | TEXT |
Consulta SQL como se describió anteriormente. |
Columna | Tipo | Valores predeterminados | Descripción |
---|---|---|---|
id | ANY-INTEGER |
Identificador de la arista. | |
origen | ANY-INTEGER |
Identificador del primer punto final en el vértice de la arista. | |
objetivo | ANY-INTEGER |
Identificador del segundo punto final en el vértice de la arista. | |
cost | ANY-NUMERICAL |
Peso de la arista (source, target)
|
|
reverse_cost | ANY-NUMERICAL |
-1 | Peso de la arista (target, source),
|
Donde:
ANY-INTEGER: | SMALLINT, INTEGER, BIGINT |
---|---|
ANY-NUMERICAL: | SMALLINT, INTEGER, BIGINT, REAL, FLOAT |
Los ejemplos de esta sección se basan en la red Datos Muestra.
Los ejemplos incluyen el subgrafo que incluye las aristas 4, 7, 8 y 10 con reverse_cost.
Ejemplo: | Por generar el LineGraphFull |
---|
En este ejemplo se muestra cómo funciona esta transformación de grafo para crear aristas adicionales para cada giro posible en un grafoáfico.
SELECT id, source, target, cost, reverse_cost
FROM edge_table
WHERE id IN (4,7,8,10);
SELECT * FROM pgr_lineGraphFull('SELECT id,
source,
target,
cost,
reverse_cost
FROM edge_table
WHERE id IN (4,7,8,10)');
En el grafo transformado, todas las aristas del grafo original siguen presentes (amarillos), pero ahora tenemos aristas adicionales para cada giro que se podría hacer a través del vértice 6 (naranja).
Ejemplo: | Para crear una tabla que identifique vértices transformados |
---|
Los vértices del grafo transformado se crean dividiendo los vértices en el grafo original. A menos que un vértice en el grafo original sea un vértice de hoja, generará más de un vértice en el grafo transformado. A uno de los vértices recién creados en el grafo transformado se le dará el mismo vértice-id que el vértice desde el que se creó en el grafo original, pero el resto de los vértices recién creados tendrán identificadores de vértices negativos. A continuación se muestra un ejemplo de cómo generar una tabla que mapea los identificadores de los vértices recién creados con el vértice original que se crearon a partir de
El primer paso es almacenar el grafo de resultados en una tabla y, a continuación, crear la tabla de asignación de vértices con una fila para cada identificador de vértice distinto en el grafo resultante.
CREATE TABLE lineGraph_edges AS SELECT * FROM pgr_lineGraphFull(
$$SELECT id, source, target, cost, reverse_cost
FROM edge_table WHERE id IN (4,7,8,10)$$
);
SELECT 28
CREATE TABLE lineGraph_vertices AS
SELECT *, NULL::BIGINT AS original_id
FROM (SELECT source AS id FROM lineGraph_edges
UNION
SELECT target FROM lineGraph_edges) as foo
ORDER BY id;
SELECT 16
A continuación, establecemos el original_id de todos los vértices en el grafo de resultados a los que se les dio el mismo identificador de vértice que el vértice desde el que se creó en el grafo original.
UPDATE lineGraph_vertices AS r
SET original_id = v.id
FROM edge_table_vertices_pgr AS v
WHERE v.id = r.id;
UPDATE 5
A continuación, cruzamos la referencia a todos los otros vértices recién creados que no tienen el mismo original_id y establecemos sus valores original_id.
WITH
unassignedVertices
AS (SELECT e.id, e.original_id
FROM lineGraph_vertices AS e
WHERE original_id IS NOT NULL),
edgesWithUnassignedSource
AS (SELECT *
FROM lineGraph_edges
WHERE cost = 0 and source IN (SELECT id FROM unassignedVertices)),
edgesWithUnassignedSourcePlusVertices
AS (SELECT *
FROM edgesWithUnassignedSource
JOIN lineGraph_vertices
ON(source = id)),
verticesFromEdgesWithUnassignedSource
AS (SELECT DISTINCT edgesWithUnassignedSourcePlusVertices.target,
edgesWithUnassignedSourcePlusVertices.original_id
FROM edgesWithUnassignedSourcePlusVertices
JOIN lineGraph_vertices AS r
ON(target = r.id AND r.original_id IS NULL))
UPDATE lineGraph_vertices
SET original_id = verticesFromEdgesWithUnassignedSource.original_id
FROM verticesFromEdgesWithUnassignedSource
WHERE verticesFromEdgesWithUnassignedSource.target = id;
UPDATE 8
WITH
unassignedVertices
AS (SELECT e.id, e.original_id
FROM lineGraph_vertices AS e
WHERE original_id IS NOT NULL),
edgesWithUnassignedTarget
AS (SELECT *
FROM lineGraph_edges
WHERE cost = 0 and target IN (SELECT id FROM unassignedVertices)),
edgesWithUnassignedTargetPlusVertices
AS (SELECT *
FROM edgesWithUnassignedTarget
JOIN lineGraph_vertices
ON(target = id)),
verticesFromEdgesWithUnassignedTarget
AS (SELECT DISTINCT edgesWithUnassignedTargetPlusVertices.source,
edgesWithUnassignedTargetPlusVertices.original_id
FROM edgesWithUnassignedTargetPlusVertices
JOIN lineGraph_vertices AS r
ON(source = r.id AND r.original_id IS NULL))
UPDATE lineGraph_vertices
SET original_id = verticesFromEdgesWithUnassignedTarget.original_id
FROM verticesFromEdgesWithUnassignedTarget
WHERE verticesFromEdgesWithUnassignedTarget.source = id;
UPDATE 3
Los únicos vértices que quedan que no se han asignado son algunos de los vértices de hoja del grafo original. El siguiente sql completa el mapeo para estos vértices hoja (en el caso de este grafo de ejemplo no hay vértices de hoja, pero esto es necesario para grafos más grandes).
WITH
unassignedVertexIds
AS (SELECT id
FROM lineGraph_vertices
WHERE original_id IS NULL),
edgesWithUnassignedSource
AS (SELECT source,edge
FROM lineGraph_edges
WHERE source IN (SELECT id FROM unassignedVertexIds)),
originalEdgesWithUnassignedSource
AS (SELECT id,source
FROM edge_table
WHERE id IN (SELECT edge FROM edgesWithUnassignedSource))
UPDATE lineGraph_vertices AS d
SET original_id = (SELECT source
FROM originalEdgesWithUnassignedSource
WHERE originalEdgesWithUnassignedSource.id =
(SELECT edge
FROM edgesWithUnassignedSource
WHERE edgesWithUnassignedSource.source = d.id))
WHERE id IN (SELECT id FROM unassignedVertexIds);
UPDATE 0
WITH
unassignedVertexIds
AS (SELECT id
FROM lineGraph_vertices
WHERE original_id IS NULL),
edgesWithUnassignedTarget
AS (SELECT target,edge
FROM lineGraph_edges
WHERE target IN (SELECT id FROM unassignedVertexIds)),
originalEdgesWithUnassignedTarget
AS (SELECT id,target
FROM edge_table
WHERE id IN (SELECT edge FROM edgesWithUnassignedTarget))
UPDATE lineGraph_vertices AS d
SET original_id = (SELECT target
FROM originalEdgesWithUnassignedTarget
WHERE originalEdgesWithUnassignedTarget.id =
(SELECT edge
FROM edgesWithUnassignedTarget
WHERE edgesWithUnassignedTarget.target = d.id))
WHERE id IN (SELECT id FROM unassignedVertexIds);
UPDATE 0
Ahora nuestra tabla de mapeo de vértices está completa:
SELECT * FROM lineGraph_vertices;
id | original_id
-----+-------------
2 | 2
5 | 5
6 | 6
8 | 8
10 | 10
-11 | 10
-10 | 6
-9 | 8
-5 | 5
-4 | 5
-3 | 5
-2 | 5
-1 | 2
-8 | 5
-7 | 5
-6 | 5
(16 rows)
Ejemplo: | Por ejecutar la ruta más corta dijkstra con penalizaciones de giro |
---|
Un caso de uso para esta transformación de grafo es poder ejecutar una búsqueda de ruta más corta que tenga en cuenta el costo o la limitación del giro. A continuación se muestra un ejemplo de cómo ejecutar una ruta más corta dijkstra desde el vértice 2 hasta el vértice 8 en el grafo original, mientras que agrega un costo de penalización de giro de 100 al giro desde el borde 4 hasta el borde -7.
En primer lugar debemos aumentar el costo de hacer el turno a 100:
UPDATE lineGraph_edges
SET cost = 100
WHERE source IN (SELECT target
FROM lineGraph_edges
WHERE edge = 4) AND target IN (SELECT source
FROM lineGraph_edges
WHERE edge = -7);
UPDATE 1
A continuación, debemos ejecutar una búsqueda de ruta más corta dijkstra utilizando todos los vértices del nuevo grafo que se crearon a partir del vértice 2 como punto de partida, y todos los vértices del nuevo grafo que se crearon a partir del vértice 8 como punto final.
SELECT * FROM
(SELECT * FROM
(SELECT * FROM pgr_dijkstra($$SELECT seq AS id, * FROM lineGraph_edges$$,
(SELECT array_agg(id) FROM lineGraph_vertices where original_id = 2),
(SELECT array_agg(id) FROM lineGraph_vertices where original_id = 8)
)) as shortestPaths
WHERE start_vid = 2 AND end_vid = 8 AND (cost != 0 OR edge = -1)) as b;
seq | path_seq | start_vid | end_vid | node | edge | cost | agg_cost
-----+----------+-----------+---------+------+------+------+----------
29 | 2 | 2 | 8 | -1 | 1 | 1 | 0
31 | 4 | 2 | 8 | -4 | 5 | 1 | 1
33 | 6 | 2 | 8 | -10 | 25 | 1 | 2
35 | 8 | 2 | 8 | -3 | 4 | 1 | 3
36 | 9 | 2 | 8 | 8 | -1 | 0 | 4
(5 rows)
Normalmente la ruta más corta desde el vértice 2 hasta el vértice 8 tendría un costo agregado de 2, pero como hay una gran penalización por hacer el giro necesario para obtener este costo, la ruta pasa por el vértice 6 para evitar este giro.
Si hace referencia cruzada a la columna de nodo en los resultados de dijkstra con la tabla de mapeo de id de vértices, esto le mostrará que la ruta va desde v2 -> v5 -> v6 -> v5 -> v8 en el grafo original.
Índices y tablas