diff --git a/Project.toml b/Project.toml index c626109..efe2b4f 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "UnitDiskMapping" uuid = "1b61a8d9-79ed-4491-8266-ef37f39e1727" authors = ["QuEra Computing Inc."] -version = "0.3.1" +version = "0.3.2" [deps] Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" @@ -9,7 +9,7 @@ LuxorGraphPlot = "1f49bdf2-22a7-4bc4-978b-948dc219fbbc" [compat] Graphs = "1.6" -LuxorGraphPlot = "0.2" +LuxorGraphPlot = "0.3" julia = "1" [extras] diff --git a/README.md b/README.md index f5d152f..f8a9298 100644 --- a/README.md +++ b/README.md @@ -29,27 +29,27 @@ pkg> add UnitDiskMapping ## Examples -Please check this [notebook](https://queracomputing.github.io/UnitDiskMapping.jl/notebooks/tutorial.html), which contains the following examples: +Please check the following notebooks: +1. [Unit Disk Mapping](https://queracomputing.github.io/UnitDiskMapping.jl/notebooks/tutorial.html), which contains the examples in ["Quantum Optimization with Arbitrary Connectivity Using Rydberg Atom Arrays"](https://journals.aps.org/prxquantum/abstract/10.1103/PRXQuantum.4.010316): + * Reduction from a generic weighted or unweighted maximum independent set (MIS) problem to that on a King's subgraph (KSG). + * Reduction from a generic or square-lattice QUBO problem to an MIS problem on a unit-disk grid graph. + * Reduction from an integer factorization problem to an MIS problem on a unit-disk grid graph. -* Reduction from a generic weighted or unweighted maximum independent set (MIS) problem to that on a diagonal coupled unit-disk grid graph (DUGG). -* Reduction from a generic or square-lattice QUBO problem to an MIS problem on a unit-disk grid graph. -* Reduction from an integer factorization problem to an MIS problem on a unit-disk grid graph. +2. [Unweighted KSG reduction of the independent set problem](https://queracomputing.github.io/UnitDiskMapping.jl/notebooks/unweighted.html), which contains the unweighted reduction from a general graph to a King's subgraph. It covers all example graphs in paper: "Computer-Assisted Gadget Design and Problem Reduction of Unweighted Maximum Independent Set" (To be published). ![](https://user-images.githubusercontent.com/6257240/198861111-4499c17d-9938-406b-8253-943b01f4633c.png) -To run the notebook locally, you will need the [Pluto](https://github.com/fonsp/Pluto.jl) and [GenericTensorNetworks](https://github.com/QuEraComputing/GenericTensorNetworks.jl) Julia packages installed. You can run the following after entering the Package mode: - -``` -pkg> add Pluto -pkg> add GenericTensorNetworks +To run the notebook locally, you will need to activate and instantiate the local environment that specified in the [`notebooks`](notebooks) directory: +```bash +$ cd notebooks +$ julia --project -e 'using Pkg; Pkg.instantiate()' ``` -and returning to the Julia REPL (you can do this by hitting Backspace in the Package mode) to run: - -``` -julia> import Pluto; Pluto.run() +To run the notebook, just type in the same terminal: +```bash +julia --project -e "import Pluto; Pluto.run()" ``` -in the `notebooks` directory of this project. At this point, your browser should automatically launch and display a list of available notebooks you can run. You should just see `tutorial.jl` listed. +At this point, your browser should automatically launch and display a list of available notebooks you can run. You should just see the notebooks listed. ## Supporting and Citing diff --git a/examples/petersen.jl b/examples/petersen.jl deleted file mode 100644 index 5809fdb..0000000 --- a/examples/petersen.jl +++ /dev/null @@ -1,22 +0,0 @@ -using UnitDiskMapping, Graphs - -function petersen_graph() - graph = SimpleGraph(10) - for (i, j) in [(1,2), (1,4), (1,9), (2,3), (2, 7), (3,5), (3, 10), (4, 5), (4,6), (5, 8), (6, 7), (6,10), (7,8),(8,9),(9,10)] - add_edge!(graph, i, j) - end - @assert all(==(3), degree.(Ref(graph), 1:10)) - return graph -end - -g = petersen_graph() -ug = embed_graph(g) -G, tape = apply_gadgets!(copy(ug)) -locs = coordinates(G) - -using GenericTensorNetworks -s1 = solve(IndependentSet(g), SizeMax()) -s2 = solve(IndependentSet(SimpleGraph(G)), SizeMax()) -mis_overhead0 = 2 * nv(g) * (nv(g)-1) + nv(g) -mis_overhead1 = sum(x->mis_overhead(x[1]), tape) -s1[].n == s2[].n - mis_overhead0 - mis_overhead1 \ No newline at end of file diff --git a/notebooks/tutorial.jl b/notebooks/tutorial.jl index 7488869..59ff128 100644 --- a/notebooks/tutorial.jl +++ b/notebooks/tutorial.jl @@ -1,5 +1,5 @@ ### A Pluto.jl notebook ### -# v0.19.27 +# v0.19.32 using Markdown using InteractiveUtils @@ -46,7 +46,7 @@ using UnitDiskMapping, Graphs, GenericTensorNetworks, LinearAlgebra # ╔═╡ 98459516-4833-4e4a-916f-d5ea3e657ceb # Visualization setup. # To make the plots dark-mode friendly, we use white-background color. -using UnitDiskMapping.LuxorGraphPlot.Luxor, LuxorGraphPlot; LuxorGraphPlot.DEFAULT_UNIT[] = 25; LuxorGraphPlot.DEFAULT_BACKGROUND_COLOR[]="white"; +using UnitDiskMapping.LuxorGraphPlot.Luxor, LuxorGraphPlot; GraphDisplayConfig.unit[] = 25; GraphDisplayConfig.background_color[]="white"; # ╔═╡ eac6ceda-f5d4-11ec-23db-b7b4d00eaddf md"# Unit Disk Mapping" diff --git a/notebooks/unweighted.jl b/notebooks/unweighted.jl new file mode 100644 index 0000000..43496df --- /dev/null +++ b/notebooks/unweighted.jl @@ -0,0 +1,267 @@ +### A Pluto.jl notebook ### +# v0.19.32 + +using Markdown +using InteractiveUtils + +# ╔═╡ f55dbf80-8425-11ee-2e7d-4d1ad4f693af +# ╠═╡ show_logs = false +begin + using Pkg; Pkg.activate(".") + using Revise + using PlutoUI + # left right layout + function leftright(a, b; width=600) + HTML(""" + + + + + + +
$(html(a))$(html(b))
+""") + end + + # up down layout + function updown(a, b; width=nothing) + HTML(""" + + + + + +
$(html(a))
$(html(b))
+""") + end + PlutoUI.TableOfContents() +end + +# ╔═╡ be011e30-74e6-49cd-b45a-288972dc5f18 +using UnitDiskMapping, Graphs # for mapping graphs to a King's subgraph (KSG) + +# ╔═╡ 31250cb9-6f3a-429a-975d-752cb7c07883 +using GenericTensorNetworks # for solving the maximum independent sets + +# ╔═╡ 9017a42c-9791-4933-84a4-9ff509967323 +md""" +# Unweighted KSG reduction of the independent set problem +""" + +# ╔═╡ f0e7c030-4e43-4356-a5bb-717a7f382a17 +md"This notebook contains examples from the paper, "Computer-Assisted Gadget Design and Problem Reduction of Unweighted Maximum Independent Set"." + +# ╔═╡ cb4a9655-6df2-46b3-8969-8b6f2db7c59a +md""" +## Example 1: The 5-vertex graph +The five vertex demo graph in the paper. +""" + +# ╔═╡ 956a5c3a-b8c6-4040-9553-3b4e2337b163 +md"#### Step 1: Prepare a source graph." + +# ╔═╡ d858f57e-1706-4b73-bc23-53f7af073b0c +# the demo graph in the main text +function demograph() + g = SimpleGraph(5) + for (i, j) in [(1, 2), (2, 4), (3, 4), (1, 3), (4, 5), (1, 5)] + add_edge!(g, i, j) + end + return g +end + +# ╔═╡ a3a86c62-ee6e-4a3b-99b3-c484de3b5220 +g5 = demograph() + +# ╔═╡ e6170e72-0804-401e-b9e5-65b8ee7d7edb +show_graph(g5) + +# ╔═╡ 625bdcf4-e37e-4bb8-bd1a-907cdcc5fe24 +md""" +#### Step 2: Map the source graph to an unweighted King's subgraph (KSG) +The vertex order is optimized with the Branching path decomposition algorithm +""" + +# ╔═╡ f9e57a6b-1186-407e-a8b1-cb8f31a17bd2 +g5res = UnitDiskMapping.map_graph(g5; vertex_order=Branching()) + +# ╔═╡ e64e7ca4-b297-4c74-8699-bec4b4fbb843 +md"Visualize the mapped KSG graph in terminal" + +# ╔═╡ 0a860597-0610-48f6-b1ee-711939712de4 +print(g5res.grid_graph) + +# ╔═╡ eeae7074-ee21-44fc-9605-3555acb84cee +md"or in a plotting plane" + +# ╔═╡ 3fa6052b-74c2-453d-a473-68f4b3ca0490 +show_graph(g5res.grid_graph) + +# ╔═╡ 942e8dfb-b89d-4f2d-b1db-f4636d4e5de6 +md"#### Step 3: Solve the MIS size of the mapped graph" + +# ╔═╡ 766018fa-81bd-4c37-996a-0cf77b0909af +md"The independent set size can be obtained by solving the `SizeMax()` property using the [generic tensor network](https://github.com/QuEraComputing/GenericTensorNetworks.jl) method." + +# ╔═╡ 67fd2dd2-5add-4402-9618-c9b7c7bfe95b +missize_g5_ksg = solve(IndependentSet(SimpleGraph(g5res.grid_graph)), SizeMax())[] + +# ╔═╡ aaee9dbc-5b9c-41b1-b0d4-35d2cac7c773 +md"The predicted MIS size for the source graph is:" + +# ╔═╡ 114e2c42-aaa3-470b-a267-e5a7c6b08607 +missize_g5_ksg.n - g5res.mis_overhead + +# ╔═╡ e6fa2404-cbe9-4f9b-92a0-0d6fdb649c44 +md""" +One of the best solutions can be obtained by solving the `SingleConfigMax()` property. +""" + +# ╔═╡ 0142f661-0855-45b4-852a-78f560e98c67 +mis_g5_ksg = solve(IndependentSet(SimpleGraph(g5res.grid_graph)), SingleConfigMax())[].c.data + +# ╔═╡ fa046f3c-fd7d-4e91-b3f5-fc4591d3cae2 +md"Plot the solution" + +# ╔═╡ 0cbcd2a6-b8ae-47ff-8541-963b9dae700a +show_config(g5res.grid_graph, mis_g5_ksg) + +# ╔═╡ 4734dc0b-0770-4f84-8046-95a74104936f +md"#### Step 4: Map the KSG solution back" + +# ╔═╡ 0f27de9f-2e06-4d5e-b96f-b7c7fdadabca +md"In the following, we will show how to obtain an MIS of the source graph from that of its KSG reduction." + +# ╔═╡ fc968df0-832b-44c9-8335-381405b92199 +mis_g5 = UnitDiskMapping.map_config_back(g5res, collect(mis_g5_ksg)) + +# ╔═╡ 29458d07-b2b2-49af-a696-d0cb0ad35481 +md"Show that the overhead in the MIS size is correct" + +# ╔═╡ fa4888b2-fc67-4285-8305-da655c42a898 +md"Verify the result:" + +# ╔═╡ e84102e8-d3f2-4f91-87be-dba8e81462fb +# the extracted solution is an independent set +UnitDiskMapping.is_independent_set(g5, mis_g5) + +# ╔═╡ 88ec52b3-73fd-4853-a69b-442f5fd2e8f7 +# and its size is maximized +count(isone, mis_g5) + +# ╔═╡ 5621bb2a-b1c6-4f0d-921e-980b2ce849d5 +solve(IndependentSet(g5), SizeMax())[].n + +# ╔═╡ 1fe6c679-2962-4c1b-8b12-4ceb77ed9e0f +md""" +## Example 2: The Petersen graph + +We just quickly go through a second example, the Petersen graph. +""" + +# ╔═╡ ea379863-95dd-46dd-a0a3-0a564904476a +petersen = smallgraph(:petersen) + +# ╔═╡ d405e7ec-50e3-446c-8d19-18f1a66c1e3b +show_graph(petersen) + +# ╔═╡ 409b03d1-384b-48d3-9010-8079cbf66dbf +md"We first map it to a grid graph (unweighted)." + +# ╔═╡ a0e7da6b-3b71-43d4-a1da-f1bd953e4b50 +petersen_res = UnitDiskMapping.map_graph(petersen) + +# ╔═╡ 4f1f0ca0-dd2a-4768-9b4e-80813c9bb544 +md"The MIS size of the petersen graph is 4." + +# ╔═╡ bf97a268-cd96-4dbc-83c6-10eb1b03ddcc +missize_petersen = solve(IndependentSet(petersen), SizeMax())[] + +# ╔═╡ 2589f112-5de5-4c98-bcd1-138b6143cd30 +md" The MIS size of the mapped KSG graph is much larger" + +# ╔═╡ 1b946455-b152-4d6f-9968-7dc6e22d171a +missize_petersen_ksg = solve(IndependentSet(SimpleGraph(petersen_res.grid_graph)), SizeMax())[] + +# ╔═╡ 4e7f7d9e-fae4-46d2-b95d-110d36b691d9 +md"The difference in the MIS size is:" + +# ╔═╡ d0e49c1f-457d-4b61-ad0e-347afb029114 +petersen_res.mis_overhead + +# ╔═╡ 03d8adb3-0bf4-44e6-9b0a-fffc90410cfc +md"Find an MIS of the mapped KSG and map it back an MIS on the source graph." + +# ╔═╡ 0d08cb1a-f7f3-4d63-bd70-78103db086b3 +mis_petersen_ksg = solve(IndependentSet(SimpleGraph(petersen_res.grid_graph)), SingleConfigMax())[].c.data + +# ╔═╡ c27d8aed-c81f-4eb7-85bf-a4ed88c2537f +mis_petersen = UnitDiskMapping.map_config_back(petersen_res, collect(mis_petersen_ksg)) + +# ╔═╡ 20f81eef-12d3-4f2a-9b91-ccf2705685ad +md"""The obtained solution is an independent set and its size is maximized.""" + +# ╔═╡ 0297893c-c978-4818-aae8-26e60d8c9e9e +UnitDiskMapping.is_independent_set(petersen, mis_petersen) + +# ╔═╡ 5ffe0e4f-bd2c-4d3e-98ca-61673a7e5230 +count(isone, mis_petersen) + +# ╔═╡ 8c1d46e8-dc36-41bd-9d9b-5a72c380ef26 +md"The number printed should be consistent with the MIS size of the petersen graph." + +# ╔═╡ Cell order: +# ╟─f55dbf80-8425-11ee-2e7d-4d1ad4f693af +# ╟─9017a42c-9791-4933-84a4-9ff509967323 +# ╟─f0e7c030-4e43-4356-a5bb-717a7f382a17 +# ╠═be011e30-74e6-49cd-b45a-288972dc5f18 +# ╠═31250cb9-6f3a-429a-975d-752cb7c07883 +# ╟─cb4a9655-6df2-46b3-8969-8b6f2db7c59a +# ╟─956a5c3a-b8c6-4040-9553-3b4e2337b163 +# ╠═d858f57e-1706-4b73-bc23-53f7af073b0c +# ╠═a3a86c62-ee6e-4a3b-99b3-c484de3b5220 +# ╠═e6170e72-0804-401e-b9e5-65b8ee7d7edb +# ╟─625bdcf4-e37e-4bb8-bd1a-907cdcc5fe24 +# ╠═f9e57a6b-1186-407e-a8b1-cb8f31a17bd2 +# ╟─e64e7ca4-b297-4c74-8699-bec4b4fbb843 +# ╠═0a860597-0610-48f6-b1ee-711939712de4 +# ╟─eeae7074-ee21-44fc-9605-3555acb84cee +# ╠═3fa6052b-74c2-453d-a473-68f4b3ca0490 +# ╟─942e8dfb-b89d-4f2d-b1db-f4636d4e5de6 +# ╟─766018fa-81bd-4c37-996a-0cf77b0909af +# ╠═67fd2dd2-5add-4402-9618-c9b7c7bfe95b +# ╟─aaee9dbc-5b9c-41b1-b0d4-35d2cac7c773 +# ╠═114e2c42-aaa3-470b-a267-e5a7c6b08607 +# ╟─e6fa2404-cbe9-4f9b-92a0-0d6fdb649c44 +# ╠═0142f661-0855-45b4-852a-78f560e98c67 +# ╟─fa046f3c-fd7d-4e91-b3f5-fc4591d3cae2 +# ╠═0cbcd2a6-b8ae-47ff-8541-963b9dae700a +# ╟─4734dc0b-0770-4f84-8046-95a74104936f +# ╟─0f27de9f-2e06-4d5e-b96f-b7c7fdadabca +# ╠═fc968df0-832b-44c9-8335-381405b92199 +# ╟─29458d07-b2b2-49af-a696-d0cb0ad35481 +# ╟─fa4888b2-fc67-4285-8305-da655c42a898 +# ╠═e84102e8-d3f2-4f91-87be-dba8e81462fb +# ╠═88ec52b3-73fd-4853-a69b-442f5fd2e8f7 +# ╠═5621bb2a-b1c6-4f0d-921e-980b2ce849d5 +# ╟─1fe6c679-2962-4c1b-8b12-4ceb77ed9e0f +# ╠═ea379863-95dd-46dd-a0a3-0a564904476a +# ╠═d405e7ec-50e3-446c-8d19-18f1a66c1e3b +# ╟─409b03d1-384b-48d3-9010-8079cbf66dbf +# ╠═a0e7da6b-3b71-43d4-a1da-f1bd953e4b50 +# ╟─4f1f0ca0-dd2a-4768-9b4e-80813c9bb544 +# ╠═bf97a268-cd96-4dbc-83c6-10eb1b03ddcc +# ╟─2589f112-5de5-4c98-bcd1-138b6143cd30 +# ╠═1b946455-b152-4d6f-9968-7dc6e22d171a +# ╟─4e7f7d9e-fae4-46d2-b95d-110d36b691d9 +# ╠═d0e49c1f-457d-4b61-ad0e-347afb029114 +# ╟─03d8adb3-0bf4-44e6-9b0a-fffc90410cfc +# ╠═0d08cb1a-f7f3-4d63-bd70-78103db086b3 +# ╠═c27d8aed-c81f-4eb7-85bf-a4ed88c2537f +# ╟─20f81eef-12d3-4f2a-9b91-ccf2705685ad +# ╠═0297893c-c978-4818-aae8-26e60d8c9e9e +# ╠═5ffe0e4f-bd2c-4d3e-98ca-61673a7e5230 +# ╟─8c1d46e8-dc36-41bd-9d9b-5a72c380ef26 diff --git a/src/visualize.jl b/src/visualize.jl index 5a8f021..9a6a1cc 100644 --- a/src/visualize.jl +++ b/src/visualize.jl @@ -1,47 +1,36 @@ # normalized to minimum weight and maximum weight function LuxorGraphPlot.show_graph(gg::GridGraph; - vertex_colors=nothing, - vertex_sizes=nothing, - vertex_shapes=nothing, - vertex_stroke_colors=nothing, - vertex_text_colors=nothing, - edge_colors=nothing, - texts = nothing, format=:svg, filename=nothing, vertex_size=0.35, fontsize=20, kwargs...) # transpose (i, j) to make them consistent with terminal output + unit = GraphDisplayConfig.unit[] locs = [(j,i) for (i,j) in coordinates(gg)] length(locs) == 0 && return _draw(()->nothing, 100, 100; format, filename) edges = [(e.src, e.dst) for e in Graphs.edges(graph_and_weights(gg)[1])] # configure canvas and plot - xmin, ymin, xmax, ymax = LuxorGraphPlot.get_bounding_box(locs) - config = LuxorGraphPlot.GraphDisplayConfig(; vertex_size, fontsize, kwargs...) - Dx, Dy = ((xmax-xmin)+2*config.xpad)*config.unit, ((ymax-ymin)+2*config.ypad)*config.unit - transform(loc) = loc[1]-xmin+config.xpad, loc[2]-ymin+config.ypad - + config = LuxorGraphPlot.graphsizeconfig(locs) + transform(loc) = loc[1]-config.xmin+config.xpad, loc[2]-config.ymin+config.ypad + Dx, Dy = ((config.xmax-config.xmin)+2*config.xpad)*unit, ((config.ymax-config.ymin)+2*config.ypad)*unit # compute empty locations empty_locations = Tuple{Int,Int}[] - for i=xmin:xmax, j=ymin:ymax + for i=config.xmin:config.xmax, j=config.ymin:config.ymax (i, j) ∉ locs && push!(empty_locations, (i, j)) end # plot! LuxorGraphPlot._draw(Dx, Dy; format, filename) do - LuxorGraphPlot._show_graph(locs, edges; - vertex_colors, vertex_stroke_colors, - vertex_text_colors, vertex_sizes, - vertex_shapes, edge_colors, texts, - vertex_size, fontsize, kwargs...) + LuxorGraphPlot.@temp GraphDisplayConfig.vertex_size[] = vertex_size GraphDisplayConfig.fontsize[] = fontsize begin + LuxorGraphPlot._show_graph(locs, edges; + vertex_size, fontsize, kwargs...) + end # visualize dots - LuxorGraphPlot._show_graph(empty_locations, []; - texts=fill("", length(empty_locations)), - vertex_size=config.vertex_size/10, - vertex_fill_color="#333333", - vertex_stroke_color="transparent", background_color="transparent", kwargs...) + LuxorGraphPlot.@temp GraphDisplayConfig.vertex_size[] = vertex_size/10 GraphDisplayConfig.fontsize[] = fontsize GraphDisplayConfig.vertex_color[]="#333333" GraphDisplayConfig.vertex_stroke_color[]="transparent" GraphDisplayConfig.background_color[]="transparent" begin + LuxorGraphPlot._show_graph(empty_locations, []; texts=fill("", length(empty_locations))) + end end end