Implicitly add vertices when adding edges to a DAG

This commit is contained in:
Mark Spanbroek 2021-08-02 13:37:13 +02:00
parent dd0685c96e
commit d15e23cf13
2 changed files with 14 additions and 39 deletions

View File

@ -25,6 +25,12 @@ type
func new*[V](_: type SortedDag[V]): SortedDag[V] = func new*[V](_: type SortedDag[V]): SortedDag[V] =
SortedDag[V]() SortedDag[V]()
func contains*[V](dag: SortedDag[V], vertex: V): bool =
vertex in dag.order
func contains*[V](dag: SortedDag[V], edge: Edge[V]): bool =
edge in dag.edges
func lookup[V](dag: SortedDag[V], vertex: V): SortedVertex[V] = func lookup[V](dag: SortedDag[V], vertex: V): SortedVertex[V] =
SortedVertex[V](vertex: vertex, index: dag.order[vertex]) SortedVertex[V](vertex: vertex, index: dag.order[vertex])
@ -82,23 +88,17 @@ func update[V](dag: SortedDag[V], lowerbound, upperbound: SortedVertex[V]) =
let backward = searchBackward(dag, upperbound, lowerbound) let backward = searchBackward(dag, upperbound, lowerbound)
dag.reorder(forward, backward) dag.reorder(forward, backward)
func add*[V](dag: SortedDag[V], vertex: V) = func add[V](dag: SortedDag[V], vertex: V) =
## Adds a vertex to the DAG if vertex notin dag:
dag.order[vertex] = -(dag.order.len) dag.order[vertex] = -(dag.order.len)
func add*[V](dag: SortedDag[V], edge: tuple[x, y: V]) = func add*[V](dag: SortedDag[V], edge: tuple[x, y: V]) =
## Adds an edge x -> y to the DAG ## Adds an edge x -> y to the DAG
doAssert edge.x in dag dag.add(edge.y)
doAssert edge.y in dag dag.add(edge.x)
dag.edges.incl(edge) dag.edges.incl(edge)
dag.update(dag.lookup(edge.y), dag.lookup(edge.x)) dag.update(dag.lookup(edge.y), dag.lookup(edge.x))
func contains*[V](dag: SortedDag[V], vertex: V): bool =
vertex in dag.order
func contains*[V](dag: SortedDag[V], edge: Edge[V]): bool =
edge in dag.edges
iterator visit*[V](dag: SortedDag[V], start: V): V = iterator visit*[V](dag: SortedDag[V], start: V): V =
## Visits all vertices that are reachable from the starting vertex. Vertices ## Visits all vertices that are reachable from the starting vertex. Vertices
## are visited in topological order, meaning that vertices close to the ## are visited in topological order, meaning that vertices close to the

View File

@ -8,31 +8,21 @@ suite "Sorted DAG":
test "contains vertices": test "contains vertices":
var dag = SortedDag[int].new var dag = SortedDag[int].new
dag.add(1) dag.add( (1, 2) )
check 1 in dag check 1 in dag
check 2 in dag
check 42 notin dag check 42 notin dag
dag.add(42) dag.add( (2, 42) )
check 42 in dag check 42 in dag
test "contains edges": test "contains edges":
var dag = SortedDag[int].new var dag = SortedDag[int].new
dag.add(1)
dag.add(2)
dag.add(3)
dag.add( (1, 2) ) dag.add( (1, 2) )
check (1, 2) in dag check (1, 2) in dag
check (2, 3) notin dag check (2, 3) notin dag
dag.add( (2, 3) ) dag.add( (2, 3) )
check (2, 3) in dag check (2, 3) in dag
test "raises when adding adding edge for unknown vertex":
var dag = SortedDag[int].new
dag.add(1)
expect Defect:
dag.add( (1, 2) )
expect Defect:
dag.add( (2, 1) )
test "visits reachable vertices, nearest first": test "visits reachable vertices, nearest first":
# ⓪ → ① # ⓪ → ①
@ -40,8 +30,6 @@ suite "Sorted DAG":
# ② # ②
var dag = SortedDag[int].new var dag = SortedDag[int].new
for vertex in 0..2:
dag.add(vertex)
for edge in [ (0, 1), (1, 2), (0, 2) ]: for edge in [ (0, 1), (1, 2), (0, 2) ]:
dag.add(edge) dag.add(edge)
@ -58,8 +46,6 @@ suite "Sorted DAG":
# ③ # ③
var dag = SortedDag[int].new var dag = SortedDag[int].new
for vertex in 0..5:
dag.add(vertex)
for edge in [ (5, 2), (5, 0), (4, 0), (4, 1), (2, 3), (3, 1) ]: for edge in [ (5, 2), (5, 0), (4, 0), (4, 1), (2, 3), (3, 1) ]:
dag.add(edge) dag.add(edge)
@ -79,8 +65,6 @@ suite "Sorted DAG":
# gain ← spend # gain ← spend
var dag = SortedDag[string].new var dag = SortedDag[string].new
for vertex in ["spend", "gain", "ack1", "ack2", "acks"]:
dag.add(vertex)
for edge in [("acks", "ack1"), for edge in [("acks", "ack1"),
("acks", "ack2"), ("acks", "ack2"),
("ack1", "gain"), ("ack1", "gain"),
@ -106,8 +90,6 @@ suite "Sorted DAG":
# ⑤ → ⑩ # ⑤ → ⑩
var dag = SortedDag[int].new var dag = SortedDag[int].new
for vertex in 0..10:
dag.add(vertex)
for vertex in [1,6]: for vertex in [1,6]:
dag.add((0, vertex)) dag.add((0, vertex))
for vertex in 1..<5: for vertex in 1..<5:
@ -126,11 +108,6 @@ suite "Sorted DAG":
var dag = SortedDag[int].new var dag = SortedDag[int].new
var vertices: seq[int] var vertices: seq[int]
for vertex in 0..100:
vertices.add(vertex)
vertices.shuffle()
for vertex in vertices:
dag.add(vertex)
for _ in 0..10_000: for _ in 0..10_000:
let x, y = rand(100) let x, y = rand(100)
@ -147,9 +124,7 @@ suite "Sorted DAG":
# ⓪ ← ① ← ② ← ... # ⓪ ← ① ← ② ← ...
var dag = SortedDag[int].new var dag = SortedDag[int].new
dag.add(0)
for i in 1..10_000: for i in 1..10_000:
dag.add(i)
dag.add((i, i-1)) dag.add((i, i-1))
var latest = 10_000 var latest = 10_000