Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ erl_crash.dump
# QuickCheck files
/.eqc-info
/*.eqc

# Ignore logs from lexical
/.lexical
37 changes: 37 additions & 0 deletions .lexical/lexical.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
19:58:35.632 [debug] Child {LoggerFileBackend, :general_log} of Supervisor Logger.Backends.Supervisor started
Pid: #PID<0.114.0>
Start Call: Logger.Backends.Watcher.start_link({{LoggerFileBackend, :general_log}, {LoggerFileBackend, :general_log}})
Restart: :transient
Shutdown: 5000
Type: :worker
19:58:35.632 [info] Child Logger.Backends.Supervisor of Supervisor Logger.Backends.Internal started
Pid: #PID<0.113.0>
Start Call: Logger.Backends.Supervisor.start_link([{LoggerFileBackend, :general_log}])
Restart: :permanent
Shutdown: :infinity
Type: :supervisor
19:58:35.632 [info] Child Logger.Backends.Internal of Supervisor Logger.Supervisor started
Pid: #PID<0.109.0>
Start Call: Logger.Backends.Internal.start_link([])
Restart: :permanent
Shutdown: :infinity
Type: :supervisor
19:58:35.633 [info] Application logger started at :nonode@nohost
19:58:36.702 [error] FATAL: Lexical is not compatible with Elixir 1.18.1

Lexical is compatible with the following versions of Elixir:

>= 1.13.0
>= 1.14.0
>= 1.15.3
>= 1.16.0


FATAL: Lexical is not compatible with Erlang/OTP 27.1.3

Lexical is compatible with the following versions of Erlang/OTP:

>= 24.3.4
>= 25.0.0
>= 26.0.2

143 changes: 93 additions & 50 deletions lib/graph.ex
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please double check that I've not mixed up incident and emanating edges here.

Original file line number Diff line number Diff line change
Expand Up @@ -800,72 +800,88 @@ defmodule Graph do
"""
@spec replace_vertex(t, vertex, vertex) :: t | {:error, :no_such_vertex}
def replace_vertex(
%__MODULE__{out_edges: oe, in_edges: ie, edges: em, vertex_identifier: vertex_identifier} =
%__MODULE__{
vertices: vs,
vertex_labels: labels,
out_edges: oe,
in_edges: ie,
edges: em,
vertex_identifier: vertex_identifier
} =
g,
v,
rv
) do
vs = g.vertices
labels = g.vertex_labels

with v_id <- vertex_identifier.(v),
true <- Map.has_key?(vs, v_id),
rv_id <- vertex_identifier.(rv),
vs <- Map.put(Map.delete(vs, v_id), rv_id, rv) do
oe =
for {from_id, to} = e <- oe, into: %{} do
fid = if from_id == v_id, do: rv_id, else: from_id
vs <- Map.put(Map.delete(vs, v_id), rv_id, rv),
{vlbls, lbls} = Map.pop(labels, v_id),
{ovs, oe} = Map.pop(oe, v_id),
{ivs, ie} = Map.pop(ie, v_id) do
{em, oe, ie} =
em
|> Enum.reduce({em, oe, ie}, fn
{{^v_id, ^v_id} = k, meta}, {e, o, i} ->
o =
if is_nil(ovs) do
o
else
Map.put(o, rv_id, ovs)
end

cond do
MapSet.member?(to, v_id) ->
{fid, MapSet.put(MapSet.delete(to, v_id), rv_id)}
i =
if is_nil(ivs) do
i
else
Map.put(i, rv_id, ivs)
end

from_id != fid ->
{fid, to}
{Map.put(Map.delete(e, k), {rv_id, rv_id}, meta), o, i}

:else ->
e
end
end
{{^v_id, id2} = k, meta}, {e, o, i} ->
o =
if is_nil(ovs) do
o
else
Map.put(o, rv_id, ovs)
end

ie =
for {to_id, from} = e <- ie, into: %{} do
tid = if to_id == v_id, do: rv_id, else: to_id
i =
Map.update!(i, id2, fn set -> set |> MapSet.delete(v_id) |> MapSet.put(rv_id) end)

cond do
MapSet.member?(from, v_id) ->
{tid, MapSet.put(MapSet.delete(from, v_id), rv_id)}
{Map.put(Map.delete(e, k), {rv_id, id2}, meta), o, i}

to_id != tid ->
{tid, from}
{{id1, ^v_id} = k, meta}, {e, o, i} ->
o =
Map.update!(o, id1, fn set -> set |> MapSet.delete(v_id) |> MapSet.put(rv_id) end)

:else ->
e
end
end
i =
if is_nil(ivs) do
i
else
Map.put(i, rv_id, ivs)
end

meta =
em
|> Stream.map(fn
{{^v_id, ^v_id}, meta} -> {{rv_id, rv_id}, meta}
{{^v_id, v2_id}, meta} -> {{rv_id, v2_id}, meta}
{{v1_id, ^v_id}, meta} -> {{v1_id, rv_id}, meta}
edge -> edge
{Map.put(Map.delete(e, k), {id1, rv_id}, meta), o, i}

_, acc ->
acc
end)
|> Enum.into(%{})

labels =
case Map.get(labels, v_id) do
nil -> labels
label -> Map.put(Map.delete(labels, v_id), rv_id, label)
if is_nil(vlbls) do
lbls
else
Map.put(lbls, rv_id, vlbls)
end

%__MODULE__{
g
| vertices: vs,
out_edges: oe,
in_edges: ie,
edges: meta,
edges: em,
vertex_labels: labels
}
else
Expand All @@ -889,22 +905,49 @@ defmodule Graph do
"""
@spec delete_vertex(t, vertex) :: t
def delete_vertex(
%__MODULE__{out_edges: oe, in_edges: ie, edges: em, vertex_identifier: vertex_identifier} =
%__MODULE__{
vertices: vs,
vertex_labels: ls,
out_edges: oe,
in_edges: ie,
edges: em,
vertex_identifier: vertex_identifier
} =
g,
v
) do
vs = g.vertices
ls = g.vertex_labels

with v_id <- vertex_identifier.(v),
true <- Map.has_key?(vs, v_id),
oe <- Map.delete(oe, v_id),
ie <- Map.delete(ie, v_id),
{outs, oe} <- Map.pop(oe, v_id),
{ins, ie} <- Map.pop(ie, v_id),
vs <- Map.delete(vs, v_id),
ls <- Map.delete(ls, v_id) do
oe = for {id, ns} <- oe, do: {id, MapSet.delete(ns, v_id)}, into: %{}
ie = for {id, ns} <- ie, do: {id, MapSet.delete(ns, v_id)}, into: %{}
em = for {{id1, id2}, _} = e <- em, v_id != id1 && v_id != id2, do: e, into: %{}
{ie, em} =
case outs do
nil ->
{ie, em}

_ ->
outs
|> Enum.reduce({ie, em}, fn id1, {i, e} ->
{Map.update!(i, id1, fn ns -> MapSet.delete(ns, v_id) end),
Map.delete(e, {v_id, id1})}
end)
end

{oe, em} =
case ins do
nil ->
{oe, em}

_ ->
ins
|> Enum.reduce({oe, em}, fn id1, {o, e} ->
{Map.update!(o, id1, fn ns -> MapSet.delete(ns, v_id) end),
Map.delete(e, {id1, v_id})}
end)
end

%__MODULE__{g | vertices: vs, vertex_labels: ls, out_edges: oe, in_edges: ie, edges: em}
else
_ -> g
Expand Down
2 changes: 1 addition & 1 deletion test/priority_queue_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule PriorityQueue.Test do
end)

str = "#{inspect(pq)}"
assert "#PriorityQueue<size: 5, queue: 'abcde'>" = str
assert "#PriorityQueue<size: 5, queue: ~c\"abcde\">" = str
end

test "can enqueue random elements and pull them out in priority order" do
Expand Down
Loading