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
19 changes: 13 additions & 6 deletions .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,23 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
otp: ['24.2', '25.0']
elixir: ['1.12.3', '1.13.3', '1.14.0']
exclude:
- otp: '25.0'
elixir: '1.12.3'
include:
- elixir: 1.14.5
otp: 24.3

- elixir: 1.15.8
otp: 25.3

- elixir: 1.16.3
otp: 26.2

- elixir: 1.18.2
otp: 27.2
steps:
- uses: actions/checkout@v2
- uses: erlef/setup-beam@v1
with:
otp-version: ${{matrix.otp}}
elixir-version: ${{matrix.elixir}}
- run: mix deps.get
- run: mix test
- run: mix test
26 changes: 18 additions & 8 deletions lib/graph.ex
Original file line number Diff line number Diff line change
Expand Up @@ -425,9 +425,11 @@ defmodule Graph do
out_neighbors
|> Enum.flat_map(fn out_neighbor ->
target = Map.get(vs, out_neighbor)
meta = Map.get(meta, {source_id, out_neighbor})
edge_meta = Map.get(meta, {source_id, out_neighbor})

Enum.map(meta, fn {label, weight} ->
edge_meta
|> Enum.sort()
|> Enum.map(fn {label, weight} ->
Edge.new(source, target, label: label, weight: weight)
end)
end)
Expand Down Expand Up @@ -531,19 +533,23 @@ defmodule Graph do
end

defp edge_list(v1, v2, edge_meta, :undirected) do
for {label, weight} <- edge_meta do
edge_meta
|> Enum.sort()
|> Enum.map(fn {label, weight} ->
if v1 > v2 do
Edge.new(v2, v1, label: label, weight: weight)
else
Edge.new(v1, v2, label: label, weight: weight)
end
end
end)
end

defp edge_list(v1, v2, edge_meta, _) do
for {label, weight} <- edge_meta do
edge_meta
|> Enum.sort()
|> Enum.map(fn {label, weight} ->
Edge.new(v1, v2, label: label, weight: weight)
end
end)
end

@doc """
Expand Down Expand Up @@ -2138,7 +2144,9 @@ defmodule Graph do
Enum.flat_map(v_in, fn v1_id ->
v1 = Map.get(vs, v1_id)

Enum.map(Map.get(meta, {v1_id, v_id}), fn {label, weight} ->
Map.get(meta, {v1_id, v_id})
|> Enum.sort()
|> Enum.map(fn {label, weight} ->
Edge.new(v1, v, label: label, weight: weight)
end)
end)
Expand Down Expand Up @@ -2205,7 +2213,9 @@ defmodule Graph do
Enum.flat_map(v_out, fn v2_id ->
v2 = Map.get(vs, v2_id)

Enum.map(Map.get(meta, {v_id, v2_id}), fn {label, weight} ->
Map.get(meta, {v_id, v2_id})
|> Enum.sort()
|> Enum.map(fn {label, weight} ->
Edge.new(v, v2, label: label, weight: weight)
end)
end)
Expand Down
4 changes: 3 additions & 1 deletion lib/graph/inspect.ex
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ defimpl Inspect, for: Graph do
out_v = Map.get(vs, out_id)
out_v_doc = Inspect.Algebra.to_doc(out_v, opts)

Enum.map(Map.fetch!(meta, {v_id, out_id}), fn
Map.fetch!(meta, {v_id, out_id})
|> Enum.sort()
|> Enum.map(fn
{nil, _} when type == :directed ->
[v, " -> ", out_v_doc]

Expand Down
3 changes: 2 additions & 1 deletion lib/graph/pathfinding.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ defmodule Graph.Pathfinding do

@type heuristic_fun :: (Graph.vertex() -> integer)

@spec bellman_ford(Graph.t, Graph.vertex) :: %{Graph.vertex() => integer() | :infinity} | nil
@spec bellman_ford(Graph.t(), Graph.vertex()) ::
%{Graph.vertex() => integer() | :infinity} | nil
def bellman_ford(g, a), do: Graph.Pathfindings.BellmanFord.call(g, a)

@doc """
Expand Down
4 changes: 3 additions & 1 deletion lib/graph/serializers/dot.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ defmodule Graph.Serializers.DOT do

defp serialize_nodes(%Graph{vertices: vertices} = g) do
Enum.reduce(vertices, "", fn {id, v}, acc ->
acc <> Serializer.indent(1) <> "#{id}" <> "[label=" <> Serializer.get_vertex_label(g, id, v) <> "]\n"
acc <>
Serializer.indent(1) <>
"#{id}" <> "[label=" <> Serializer.get_vertex_label(g, id, v) <> "]\n"
end)
end

Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ defmodule Graph.Mixfile do
defp deps do
[
{:benchee, "~> 1.0", only: [:bench]},
{:stream_data, "~> 0.5", only: [:test]},
{:stream_data, "~> 1.0", only: [:test]},
{:excoveralls, "~> 0.7", only: [:test]},
{:dialyxir, "~> 1.0", only: [:dev], runtime: false},
{:ex_doc, ">= 0.0.0", only: :dev},
Expand Down
28 changes: 14 additions & 14 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
%{
"benchee": {:hex, :benchee, "1.1.0", "f3a43817209a92a1fade36ef36b86e1052627fd8934a8b937ac9ab3a76c43062", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}], "hexpm", "7da57d545003165a012b587077f6ba90b89210fd88074ce3c60ce239eb5e6d93"},
"benchee": {:hex, :benchee, "1.5.0", "4d812c31d54b0ec0167e91278e7de3f596324a78a096fd3d0bea68bb0c513b10", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.1", [hex: :statistex, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "5b075393aea81b8ae74eadd1c28b1d87e8a63696c649d8293db7c4df3eb67535"},
"certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
"dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"},
"earmark_parser": {:hex, :earmark_parser, "1.4.26", "f4291134583f373c7d8755566122908eb9662df4c4b63caa66a0eabe06569b0a", [:mix], [], "hexpm", "48d460899f8a0c52c5470676611c01f64f3337bad0b26ddab43648428d94aabc"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"ex_doc": {:hex, :ex_doc, "0.28.5", "3e52a6d2130ce74d096859e477b97080c156d0926701c13870a4e1f752363279", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "d2c4b07133113e9aa3e9ba27efb9088ba900e9e51caa383919676afdf09ab181"},
"excoveralls": {:hex, :excoveralls, "0.14.6", "610e921e25b180a8538229ef547957f7e04bd3d3e9a55c7c5b7d24354abbba70", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "0eceddaa9785cfcefbf3cd37812705f9d8ad34a758e513bb975b081dce4eb11e"},
"dialyxir": {:hex, :dialyxir, "1.4.6", "7cca478334bf8307e968664343cbdb432ee95b4b68a9cba95bdabb0ad5bdfd9a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "8cf5615c5cd4c2da6c501faae642839c8405b49f8aa057ad4ae401cb808ef64d"},
"earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"},
"erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"},
"ex_doc": {:hex, :ex_doc, "0.39.1", "e19d356a1ba1e8f8cfc79ce1c3f83884b6abfcb79329d435d4bbb3e97ccc286e", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "8abf0ed3e3ca87c0847dfc4168ceab5bedfe881692f1b7c45f4a11b232806865"},
"excoveralls": {:hex, :excoveralls, "0.18.5", "e229d0a65982613332ec30f07940038fe451a2e5b29bce2a5022165f0c9b157e", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "523fe8a15603f86d64852aab2abe8ddbd78e68579c8525ae765facc5eae01562"},
"hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"},
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
"makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"},
"makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"},
"makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"},
"stream_data": {:hex, :stream_data, "0.5.0", "b27641e58941685c75b353577dc602c9d2c12292dd84babf506c2033cd97893e", [:mix], [], "hexpm", "012bd2eec069ada4db3411f9115ccafa38540a3c78c4c0349f151fc761b9e271"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"statistex": {:hex, :statistex, "1.1.0", "7fec1eb2f580a0d2c1a05ed27396a084ab064a40cfc84246dbfb0c72a5c761e5", [:mix], [], "hexpm", "f5950ea26ad43246ba2cce54324ac394a4e7408fdcf98b8e230f503a0cba9cf5"},
"stream_data": {:hex, :stream_data, "1.2.0", "58dd3f9e88afe27dc38bef26fce0c84a9e7a96772b2925c7b32cd2435697a52b", [:mix], [], "hexpm", "eb5c546ee3466920314643edf68943a5b14b32d1da9fe01698dc92b73f89a9ed"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
}
2 changes: 1 addition & 1 deletion test/graph_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ defmodule GraphTest do
end

defp build_complex_signed_graph do
Graph.new
Graph.new()
|> Graph.add_edge(:a, :b, weight: -1)
|> Graph.add_edge(:b, :e, weight: 2)
|> Graph.add_edge(:e, :d, weight: -3)
Expand Down
4 changes: 3 additions & 1 deletion test/priority_queue_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ defmodule PriorityQueue.Test do
end)

str = "#{inspect(pq)}"
assert "#PriorityQueue<size: 5, queue: 'abcde'>" = str
# In Elixir 1.18+, charlists are represented as ~c"..." instead of '...'
assert str == "#PriorityQueue<size: 5, queue: 'abcde'>" or
str == "#PriorityQueue<size: 5, queue: ~c\"abcde\">"
end

test "can enqueue random elements and pull them out in priority order" do
Expand Down
24 changes: 13 additions & 11 deletions test/reducer_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,19 @@ defmodule Graph.Reducer.Test do
end

test "can walk a graph breadth-first, when the starting points had their in-edges deleted" do
g = Graph.new
|> Graph.add_vertices([:a, :b, :c, :d, :e, :f, :g])
|> Graph.add_edge(:a, :b)
|> Graph.add_edge(:a, :d)
|> Graph.add_edge(:b, :c)
|> Graph.add_edge(:b, :d)
|> Graph.add_edge(:c, :e)
|> Graph.add_edge(:d, :f)
|> Graph.add_edge(:f, :g)
|> Graph.add_edge(:b, :a) # Add this edge and then remove it
|> Graph.delete_edge(:b, :a)
g =
Graph.new()
|> Graph.add_vertices([:a, :b, :c, :d, :e, :f, :g])
|> Graph.add_edge(:a, :b)
|> Graph.add_edge(:a, :d)
|> Graph.add_edge(:b, :c)
|> Graph.add_edge(:b, :d)
|> Graph.add_edge(:c, :e)
|> Graph.add_edge(:d, :f)
|> Graph.add_edge(:f, :g)
# Add this edge and then remove it
|> Graph.add_edge(:b, :a)
|> Graph.delete_edge(:b, :a)

expected = [:a, :b, :d, :c, :f, :e, :g]
assert ^expected = Graph.Reducers.Bfs.map(g, fn v -> v end)
Expand Down
5 changes: 4 additions & 1 deletion test/utils_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ defmodule Graph.UtilsTest do

test "sizeof/1" do
assert 64 = sizeof({1, :foo, "bar"})
assert 440 = sizeof(String.duplicate("bar", 128))

# String internal representation changed in OTP 27, accepting both old (440) and new (456) sizes
string_size = sizeof(String.duplicate("bar", 128))
assert string_size == 440 or string_size == 456
assert 8 = sizeof([])
assert 24 = sizeof([1 | 2])
assert 56 = sizeof([1, 2, 3])
Expand Down
Loading