diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 03b09c8..5bd0b4c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,26 +47,23 @@ jobs: docs: name: Documentation runs-on: ubuntu-latest + permissions: + actions: write # needed to allow julia-actions/cache to proactively delete old caches that it has created + contents: write + statuses: write steps: - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v2 with: version: '1' - - - name: Run Pluto notebooks - run: julia -e 'using Pkg; - Pkg.add("PlutoUI"); - Pkg.activate("notebooks"); - Pkg.develop(path="."); - Pkg.instantiate(); - using PlutoSliderServer; - for file in readdir("notebooks") - endswith(file, ".jl") && PlutoSliderServer.export_notebook(joinpath("notebooks", file)) - end - ' - - name: Deploy to gh-pages - uses: JamesIves/github-pages-deploy-action@releases/v3 - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BRANCH: gh-pages - FOLDER: . + - uses: julia-actions/cache@v2 + - name: Configure doc environment + shell: julia --project=docs --color=yes {0} + run: | + using Pkg + Pkg.develop(PackageSpec(path=pwd())) + Pkg.instantiate() + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-docdeploy@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 9251566..3defd3d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ _local/ *.log *.fdb_latexmk .vscode +/docs/build/ +/docs/src/generated/ \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1e1023c --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +JL = julia --project + +default: init test + +init: + $(JL) -e 'using Pkg; Pkg.precompile(); Pkg.activate("docs"); Pkg.develop(path="."), Pkg.precompile()' + +update: + $(JL) -e 'using Pkg; Pkg.update(); Pkg.precompile(); Pkg.activate("docs"); Pkg.update(); Pkg.precompile()' + +test: + $(JL) -e 'using Pkg; Pkg.test()' + +coverage: + $(JL) -e 'using Pkg; Pkg.test(; coverage=true)' + +serve: + $(JL) -e 'using Pkg; Pkg.activate("docs"); using LiveServer; servedocs(;skip_dirs=["docs/src/assets", "docs/src/generated"], literate_dir="examples")' + +fig: + for entry in "docs/src/assets/"*.typ; do \ + echo compiling $$entry to $${entry%.typ}.pdf; \ + typst compile $$entry $${entry%.typ}.pdf; \ + pdf2svg $${entry%.typ}.pdf $${entry%.typ}.svg; \ + done + +clean: + rm -rf docs/build + find . -name "*.cov" -type f -print0 | xargs -0 /bin/rm -f + +.PHONY: init test coverage serve clean update \ No newline at end of file diff --git a/README.md b/README.md index 208a120..a5fa4e1 100644 --- a/README.md +++ b/README.md @@ -19,30 +19,5 @@ pkg> add UnitDiskMapping ``` -## 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. - -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 to activate and instantiate the local environment that specified in the [`notebooks`](notebooks) directory: -```bash -$ cd notebooks -$ julia --project -e 'using Pkg; Pkg.instantiate()' -``` - -To run the notebook, just type in the same terminal: -```bash -julia --project -e "import Pluto; Pluto.run()" -``` -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 Much of the software in this ecosystem was developed as a part of an academic research project. If you would like to help support it, please star the repository. If you use our software as part of your research, teaching, or other activities, we would like to request you to cite our [work](https://arxiv.org/abs/2209.03965). The [CITATION.bib](CITATION.bib) file in the root of this repository lists the relevant papers. diff --git a/docs/Project.toml b/docs/Project.toml new file mode 100644 index 0000000..f055aa7 --- /dev/null +++ b/docs/Project.toml @@ -0,0 +1,9 @@ +[deps] +DocThemeIndigo = "8bac0ac5-51bf-41f9-885e-2bf1ac2bec5f" +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +GenericTensorNetworks = "3521c873-ad32-4bb4-b63d-f4f178f42b49" +Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" +Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" +LiveServer = "16fef848-5104-11e9-1b77-fb7a48bbb589" +LuxorGraphPlot = "1f49bdf2-22a7-4bc4-978b-948dc219fbbc" +UnitDiskMapping = "1b61a8d9-79ed-4491-8266-ef37f39e1727" diff --git a/docs/make.jl b/docs/make.jl new file mode 100644 index 0000000..fa8c0f1 --- /dev/null +++ b/docs/make.jl @@ -0,0 +1,42 @@ +using UnitDiskMapping +using Documenter +using Literate +using DocThemeIndigo + +# Literate +for each in readdir(pkgdir(UnitDiskMapping, "examples")) + input_file = pkgdir(UnitDiskMapping, "examples", each) + endswith(input_file, ".jl") || continue + @info "building" input_file + output_dir = pkgdir(UnitDiskMapping, "docs", "src", "generated") + Literate.markdown(input_file, output_dir; name=each[1:end-3], execute=false) +end + +DocMeta.setdocmeta!(UnitDiskMapping, :DocTestSetup, :(using UnitDiskMapping); recursive=true) +indigo = DocThemeIndigo.install(UnitDiskMapping) + +makedocs(; + modules=[UnitDiskMapping], + authors="GiggleLiu and contributors", + sitename="UnitDiskMapping.jl", + format=Documenter.HTML(; + canonical="https://QuEraComputing.github.io/UnitDiskMapping.jl", + edit_link="main", + assets=String[indigo], + ), + doctest = ("doctest=true" in ARGS), + pages=[ + "Home" => "index.md", + "Examples" => [ + "generated/tutorial.md", + "generated/unweighted.md" + ], + "Reference" => "ref.md", + ], + warnonly=[:missing_docs] +) + +deploydocs(; + repo="github.com/QuEraComputing/UnitDiskMapping.jl", + devbranch="main", +) diff --git a/docs/src/assets/indigo.css b/docs/src/assets/indigo.css new file mode 100644 index 0000000..7dafd68 --- /dev/null +++ b/docs/src/assets/indigo.css @@ -0,0 +1,88 @@ +@font-face { + font-family: JuliaMono; + src: local("JuliaMono"), url("https://cdn.jsdelivr.net/gh/cormullion/juliamono/webfonts/JuliaMono-Regular.woff2"); } + +html.theme--documenter-dark pre, +html.theme--documenter-dark code { + font-family: "JuliaMono"; } + +html:not(.theme--documenter-dark) body #documenter a { + color: #4595D1; } + +html:not(.theme--documenter-dark) body #documenter a:hover, html:not(.theme--documenter-dark) body #documenter a:focus { + color: #194E82; } + +html:not(.theme--documenter-dark) body #documenter .docs-sidebar { + box-shadow: none; + color: #FFFFFF; + background-color: #194E82; } + html:not(.theme--documenter-dark) body #documenter .docs-sidebar .docs-package-name a, html:not(.theme--documenter-dark) body #documenter .docs-sidebar .docs-package-name a:hover { + color: #FFFFFF; } + html:not(.theme--documenter-dark) body #documenter .docs-sidebar ul.docs-menu { + border-top: none; } + html:not(.theme--documenter-dark) body #documenter .docs-sidebar ul.docs-menu li.is-active ul.internal .tocitem:hover, html:not(.theme--documenter-dark) body #documenter .docs-sidebar ul.docs-menu li.is-active .tocitem:hover, html:not(.theme--documenter-dark) body #documenter .docs-sidebar ul.docs-menu li.is-active .tocitem, html:not(.theme--documenter-dark) body #documenter .docs-sidebar ul.docs-menu .tocitem:hover { + color: #FFFFFF; + background-color: #4595D1; } + html:not(.theme--documenter-dark) body #documenter .docs-sidebar ul.docs-menu .tocitem { + color: #FFFFFF; + background: none; } + html:not(.theme--documenter-dark) body #documenter .docs-sidebar ul.docs-menu li.is-active { + border-top: none; + border-bottom: none; } + html:not(.theme--documenter-dark) body #documenter .docs-sidebar ul.docs-menu li.is-active ul.internal { + margin: 0; + border-top: none; } + html:not(.theme--documenter-dark) body #documenter .docs-sidebar ul.docs-menu li.is-active ul.internal li { + margin-top: 0; } + html:not(.theme--documenter-dark) body #documenter .docs-sidebar ul.docs-menu li.is-active ul.internal .tocitem { + color: #194E82; + background-color: #FFFFFF; + padding: 0.5em; + padding-left: 1em; } + +html:not(.theme--documenter-dark) body #documenter article#documenter-page a.docs-heading-anchor { + color: #194E82; } + +html:not(.theme--documenter-dark) body #documenter pre, html:not(.theme--documenter-dark) body #documenter code { + color: inherit; + font-family: "JuliaMono"; } + html:not(.theme--documenter-dark) body #documenter pre .hljs-meta, html:not(.theme--documenter-dark) body #documenter code .hljs-meta { + color: #4595D1; } + html:not(.theme--documenter-dark) body #documenter pre .hljs-keyword, html:not(.theme--documenter-dark) body #documenter code .hljs-keyword { + color: #194E82; } + +.admonition.is-category-terminology { + background-color: #FFFEDD; + border-color: #FFEC8B; } + .admonition.is-category-terminology > .admonition-header { + background-color: #FFEC8B; + color: black; } + .admonition.is-category-terminology > .admonition-header:before { + content: "Terminology: "; + font-family: inherit; + font-weight: bold; } + +html.theme--documenter-dark .admonition.is-category-terminology { + border-color: #FFEC8B; } + +details { + padding-left: 1rem; + padding-right: 1rem; + padding-bottom: 1rem; + background: aliceblue; } + +html.theme--documenter-dark details { + background: #282f2f; } + +.video-container { + position: relative; + width: 100%; + padding-bottom: 56.25%; } + +.video-container > iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: 0; } diff --git a/docs/src/index.md b/docs/src/index.md new file mode 100644 index 0000000..dbacccf --- /dev/null +++ b/docs/src/index.md @@ -0,0 +1,15 @@ +```@meta +CurrentModule = UnitDiskMapping +``` + +# UnitDiskMapping + +Please check the following examples: +1. [Unit Disk Mapping](@ref), 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. + +2. [Unweighted KSG reduction of the independent set problem](@ref), 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) \ No newline at end of file diff --git a/docs/src/ref.md b/docs/src/ref.md new file mode 100644 index 0000000..63e502a --- /dev/null +++ b/docs/src/ref.md @@ -0,0 +1,5 @@ +# Reference + +```@autodocs +Modules = [UnitDiskMapping] +``` \ No newline at end of file diff --git a/examples/tutorial.jl b/examples/tutorial.jl new file mode 100644 index 0000000..c0aa91b --- /dev/null +++ b/examples/tutorial.jl @@ -0,0 +1,319 @@ +# # Unit Disk Mapping + +# ## Generic Unweighted Mapping +# The generic unweighted mapping aims to reduce a generic unweighted Maximum Independent Set (MIS) problem to one on a defected King's graph. +# Check [our paper (link to be added)]() for the mapping scheme. + +# Let the source graph be the Petersen graph. + +using UnitDiskMapping, Graphs, GenericTensorNetworks, LinearAlgebra + +# Visualization setup. +# To make the plots dark-mode friendly, we use white-background color. +using LuxorGraphPlot.Luxor, LuxorGraphPlot + +graph = smallgraph(:petersen) + +LuxorGraphPlot.show_graph(graph) + +# We can use the `map_graph` function to map the unweighted MIS problem on the Petersen graph to one on a defected King's graph. + +unweighted_res = map_graph(graph; vertex_order=MinhThiTrick()); + +# Here, the keyword argument `vertex_order` can be a vector of vertices in a specified order, or the method to compute the path decomposition that generates an order. The `MinhThiTrick()` method is an exact path decomposition solver, which is suited for small graphs (where number of vertices <= 50). The `Greedy()` method finds the vertex order much faster and works in all cases, but may not be optimal. +# A good vertex order can reduce the depth of the mapped graph. + +# The return value contains the following fields: + +fieldnames(unweighted_res |> typeof) + +# The field `grid_graph` is the mapped grid graph. + +LuxorGraphPlot.show_graph(unweighted_res.grid_graph) + +unweighted_res.grid_graph.size + +# The field `lines` is a vector of copy gadgets arranged in a `⊢` shape. These copy gadgets form a *crossing lattice*, in which two copy lines cross each other whenever their corresponding vertices in the source graph are connected by an edge. +# ``` +# vslot +# ↓ +# | ← vstart +# | +# |------- ← hslot +# | ↑ ← vstop +# hstop +# ``` + +unweighted_res.lines + +# The field `mapping_history` contains the rewrite rules applied to the crossing lattice. They contain important information for mapping a solution back. + +unweighted_res.mapping_history + +# The field `mis_overhead` is the difference between ``\alpha(G_M) - \alpha(G_S)``, where ``G_M`` and ``G_S`` are the mapped and source graph. + +unweighted_res.mis_overhead + +# We can solve the mapped graph with [`GenericTensorNetworks`](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/). + +res = solve(GenericTensorNetwork(IndependentSet(SimpleGraph(unweighted_res.grid_graph))), SingleConfigMax())[] + +# You might want to read [the documentation page of `GenericTensorNetworks`](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/) for a detailed explanation on this function. Here, we just visually check the solution configuration. + +show_config(unweighted_res.grid_graph, res.c.data) + +# By mapping the result back, we get a solution for the original Petersen graph. Its maximum independent set size is 4. + +# The solution obtained by solving the mapped graph +original_configs = map_config_back(unweighted_res, res.c.data) + +# Confirm that the solution from the mapped graph gives us +# a maximum independent set for the original graph +UnitDiskMapping.is_independent_set(graph, original_configs) + +# ## Generic Weighted Mapping + +# A Maximum Weight Independent Set (MWIS) problem on a general graph can be mapped to one on the defected King's graph. The first step is to do the same mapping as above but adding a new positional argument `Weighted()` as the first argument of `map_graph`. Let us still use the Petersen graph as an example. + +weighted_res = map_graph(Weighted(), graph; vertex_order=MinhThiTrick()); + +# The return value is similar to that for the unweighted mapping generated above, except each node in the mapped graph can have a weight 1, 2 or 3. Note here, we haven't added the weights in the original graph. + +show_grayscale(weighted_res.grid_graph) + +# The "pins" of the mapped graph have a one-to-one correspondence to the vertices in the source graph. + +show_pins(weighted_res) + +# The weights in the original graph can be added to the pins of this grid graph using the `map_weights` function. The added weights must be smaller than 1. + +source_weights = rand(10) + +mapped_weights = map_weights(weighted_res, source_weights) + +# Now that we have both the graph and the weights, let us solve the mapped problem! + +wmap_config = let + graph, _ = graph_and_weights(weighted_res.grid_graph) + collect(Int, + solve(GenericTensorNetwork(IndependentSet(graph, mapped_weights)), SingleConfigMax())[].c.data + ) +end + +show_config(weighted_res.grid_graph, wmap_config) + +# By reading the configurations of the pins, we obtain a solution for the source graph. + +# The solution obtained by solving the mapped graph +map_config_back(weighted_res, wmap_config) + +# Directly solving the source graph +collect(Int, + solve(GenericTensorNetwork(IndependentSet(graph, source_weights)), SingleConfigMax())[].c.data +) + +# ## QUBO problem + +# ### Generic QUBO mapping + +# A QUBO problem can be specified as the following energy model: +# ```math +# E(z) = -\sum_{i -table.nohover tr:hover td { - background-color: white !important; -} - - - - - -
$(html(a))$(html(b))
-""") - end - - # up down layout - function updown(a, b; width=nothing) - HTML(""" - - - - - -
$(html(a))
$(html(b))
-""") - end - PlutoUI.TableOfContents() -end - -# ╔═╡ 39bcea18-00b6-42ca-a1f2-53655f31fea7 -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 - -# ╔═╡ eac6ceda-f5d4-11ec-23db-b7b4d00eaddf -md"# Unit Disk Mapping" - -# ╔═╡ bbe26162-1ab7-4224-8870-9504b7c3aecf -md"## Generic Unweighted Mapping -The generic unweighted mapping aims to reduce a generic unweighted Maximum Independent Set (MIS) problem to one on a defected King's graph. -Check [our paper (link to be added)]() for the mapping scheme. -" - -# ╔═╡ b23f0215-8751-4105-aa7e-2c26e629e909 -md"Let the source graph be the Petersen graph." - -# ╔═╡ 7518d763-17a4-4c6e-bff0-941852ec1ccf -graph = smallgraph(:petersen) - -# ╔═╡ 0302be92-076a-4ebe-8d6d-4b352a77cfce -LuxorGraphPlot.show_graph(graph) - -# ╔═╡ 417b18f6-6a8f-45fb-b979-6ec9d12c6246 -md"We can use the `map_graph` function to map the unweighted MIS problem on the Petersen graph to one on a defected King's graph." - -# ╔═╡ c7315578-8bb0-40a0-a2a3-685a80674c9c -unweighted_res = map_graph(graph; vertex_order=MinhThiTrick()); - -# ╔═╡ 3f605eac-f587-40b2-8fac-8223777d3fad -md"Here, the keyword argument `vertex_order` can be a vector of vertices in a specified order, or the method to compute the path decomposition that generates an order. The `MinhThiTrick()` method is an exact path decomposition solver, which is suited for small graphs (where number of vertices <= 50). The `Greedy()` method finds the vertex order much faster and works in all cases, but may not be optimal. -A good vertex order can reduce the depth of the mapped graph." - -# ╔═╡ e5382b61-6387-49b5-bae8-0389fbc92153 -md"The return value contains the following fields:" - -# ╔═╡ ae5c8359-6bdb-4a2a-8b54-cd2c7d2af4bd -fieldnames(unweighted_res |> typeof) - -# ╔═╡ 56bdcaa6-c8b9-47de-95d4-6e95204af0f2 -md"The field `grid_graph` is the mapped grid graph." - -# ╔═╡ 520fbc23-927c-4328-8dc6-5b98853fb90d -LuxorGraphPlot.show_graph(unweighted_res.grid_graph) - -# ╔═╡ af162d39-2da9-4a06-9cde-8306e811ba7a -unweighted_res.grid_graph.size - -# ╔═╡ 96ca41c0-ac77-404c-ada3-0cdc4a426e44 -md"The field `lines` is a vector of copy gadgets arranged in a `⊢` shape. These copy gadgets form a *crossing lattice*, in which two copy lines cross each other whenever their corresponding vertices in the source graph are connected by an edge. -``` - vslot - ↓ - | ← vstart - | - |------- ← hslot - | ↑ ← vstop - hstop -``` -" - -# ╔═╡ 5dfa8a74-26a5-45c4-a80c-47ba4a6a4ae9 -unweighted_res.lines - -# ╔═╡ a64c2094-9a51-4c45-b9d1-41693c89a212 -md"The field `mapping_history` contains the rewrite rules applied to the crossing lattice. They contain important information for mapping a solution back." - -# ╔═╡ 52b904ad-6fb5-4a7e-a3db-ae7aff32be51 -unweighted_res.mapping_history - -# ╔═╡ ef828107-08ce-4d91-ba56-2b2c7862aa50 -md"The field `mis_overhead` is the difference between ``\alpha(G_M) - \alpha(G_S)``, where ``G_M`` and ``G_S`` are the mapped and source graph." - -# ╔═╡ acd7107c-c739-4ee7-b0e8-6383c54f714f -unweighted_res.mis_overhead - -# ╔═╡ 94feaf1f-77ea-4d6f-ba2f-2f9543e8c1bd -md"We can solve the mapped graph with [`GenericTensorNetworks`](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/)." - -# ╔═╡ f084b98b-097d-4b33-a0d3-0d0a981f735e -res = solve(GenericTensorNetwork(IndependentSet(SimpleGraph(unweighted_res.grid_graph))), SingleConfigMax())[] - -# ╔═╡ 86457b4e-b83e-4bf5-9d82-b5e14c055b4b -md"You might want to read [the documentation page of `GenericTensorNetworks`](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/) for a detailed explanation on this function. Here, we just visually check the solution configuration." - -# ╔═╡ 4abb86dd-67e2-46f4-ae6c-e97952b23fdc -show_config(unweighted_res.grid_graph, res.c.data) - -# ╔═╡ 5ec5e23a-6904-41cc-b2dc-659da9556d20 -md"By mapping the result back, we get a solution for the original Petersen graph. Its maximum independent set size is 4." - -# ╔═╡ 773ce349-ba72-426c-849d-cfb511773756 -# The solution obtained by solving the mapped graph -original_configs = map_config_back(unweighted_res, res.c.data) - -# ╔═╡ 7d921205-5133-40c0-bfa6-f76713dd4972 -# Confirm that the solution from the mapped graph gives us -# a maximum independent set for the original graph -UnitDiskMapping.is_independent_set(graph, original_configs) - -# ╔═╡ 3273f936-a182-4ed0-9662-26aab489776b -md"## Generic Weighted Mapping" - -# ╔═╡ 5e4500f5-beb6-4ef9-bd42-41dc13b60bce -md"A Maximum Weight Independent Set (MWIS) problem on a general graph can be mapped to one on the defected King's graph. The first step is to do the same mapping as above but adding a new positional argument `Weighted()` as the first argument of `map_graph`. Let us still use the Petersen graph as an example." - -# ╔═╡ 2fa704ee-d5c1-4205-9a6a-34ba0195fecf -weighted_res = map_graph(Weighted(), graph; vertex_order=MinhThiTrick()); - -# ╔═╡ 27acc8be-2db8-4322-85b4-230fdddac043 -md"The return value is similar to that for the unweighted mapping generated above, except each node in the mapped graph can have a weight 1, 2 or 3. Note here, we haven't added the weights in the original graph." - -# ╔═╡ b8879b2c-c6c2-47e2-a989-63a00c645676 -show_grayscale(weighted_res.grid_graph) - -# ╔═╡ 1262569f-d091-40dc-a431-cbbe77b912ab -md""" -The "pins" of the mapped graph have a one-to-one correspondence to the vertices in the source graph. -""" - -# ╔═╡ d5a64013-b7cc-412b-825d-b9d8f0737248 -show_pins(weighted_res) - -# ╔═╡ 3c46e050-0f93-42af-a6ff-1a83e7d0f6da -md"The weights in the original graph can be added to the pins of this grid graph using the `map_weights` function. The added weights must be smaller than 1." - -# ╔═╡ 39cbb6fc-1c55-42dd-bbf6-54e06f5c7048 -source_weights = rand(10) - -# ╔═╡ 41840a24-596e-4d93-9468-35329d57b0ce -mapped_weights = map_weights(weighted_res, source_weights) - -# ╔═╡ f77293c4-e5c3-4f14-95a2-ac9688fa3ba1 -md"Now that we have both the graph and the weights, let us solve the mapped problem!" - -# ╔═╡ cf910d3e-3e3c-42ef-acf3-d0990d6227ac -wmap_config = let - graph, _ = graph_and_weights(weighted_res.grid_graph) - collect(Int, - solve(GenericTensorNetwork(IndependentSet(graph, mapped_weights)), SingleConfigMax())[].c.data - ) -end - -# ╔═╡ d0648123-65fc-4dd7-8c0b-149b67920d8b -show_config(weighted_res.grid_graph, wmap_config) - -# ╔═╡ fdc0fd6f-369e-4f1b-b105-672ae4229f02 -md"By reading the configurations of the pins, we obtain a solution for the source graph." - -# ╔═╡ 317839b5-3c30-401f-970c-231c204331b5 -# The solution obtained by solving the mapped graph -map_config_back(weighted_res, wmap_config) - -# ╔═╡ beb7c0e5-6221-4f20-9166-2bd56902be1b -# Directly solving the source graph -collect(Int, - solve(GenericTensorNetwork(IndependentSet(graph, source_weights)), SingleConfigMax())[].c.data -) - -# ╔═╡ cf7e88cb-432e-4e3a-ae8b-8fa12689e485 -md"## QUBO problem" - -# ╔═╡ d16a6f2e-1ae2-47f1-8496-db6963800fd2 -md"### Generic QUBO mapping" - -# ╔═╡ b5d95984-cf8d-4bce-a73a-8eb2a7c6b830 -md""" -A QUBO problem can be specified as the following energy model: -```math -E(z) = -\sum_{i -table.nohover tr:hover td { - background-color: white !important; -} - - - - - -
$(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 - -# ╔═╡ e9a94e5a-274f-4740-ac05-bd3bb613df4d -using GenericTensorNetworks.ProblemReductions - -# ╔═╡ 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 (MinhThi's Trick) -""" - -# ╔═╡ f9e57a6b-1186-407e-a8b1-cb8f31a17bd2 -g5res = UnitDiskMapping.map_graph(g5; vertex_order=MinhThiTrick()) - -# ╔═╡ 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(GenericTensorNetwork(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(GenericTensorNetwork(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(GenericTensorNetwork(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(GenericTensorNetwork(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(GenericTensorNetwork(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(GenericTensorNetwork(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." - -# ╔═╡ fba5edd7-e5b7-4631-94cc-0c49240917ff -md""" -## Extension: ProblemReductions -Unit-disk mapping implements the unified interface for reduction in package [ProblemReductions.jl](https://github.com/GiggleLiu/ProblemReductions.jl) as an extension. -""" - -# ╔═╡ 0f12b761-fb74-455b-9123-6d1b720aaf52 -md""" -Step 1: perform the problem reduction. -""" - -# ╔═╡ 1113d5b9-8ebe-46fd-b24e-03e5fbc79435 -source_problem = IndependentSet(smallgraph(:petersen)) - -# ╔═╡ 333a8123-1683-491e-8891-83987bad16eb -# the Independent set problem with 2D GridGraph topology, unweighted. -target_problem_type = IndependentSet{ProblemReductions.GridGraph{2}, Int, UnitWeight} - -# ╔═╡ 339fd327-a594-4460-9e00-8b3304aa0a78 -# the result not only contains the target problem, but also the intermediate information -reduction_result = reduceto(target_problem_type, source_problem) - -# ╔═╡ 0e2f9caa-d84e-411f-ad5d-64c10cdaa028 -target_problem(reduction_result) - -# ╔═╡ 077045b9-3b88-4c41-a88c-354b8b30c31f -md"Step 2: solve the target problem." - -# ╔═╡ d7562423-06cd-4949-a1fd-92d8e5c31280 -# get single maximum independent set of the mapped problem -config = solve(GenericTensorNetwork(target_problem(reduction_result)), SingleConfigMax())[].c.data - -# ╔═╡ 51a9d53b-b92f-41c4-a60e-d8ceedd3fead -md"Step 3. Extract the solution back" - -# ╔═╡ 6ad557b1-04d3-4c7e-a350-20408c09b960 -extracted_config = extract_solution(reduction_result, config) - -# ╔═╡ f685ed77-151f-4778-8342-112903255932 -# finally, we check the validity of the solution. -UnitDiskMapping.is_independent_set(source_problem.graph, extracted_config) - -# ╔═╡ 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 -# ╟─fba5edd7-e5b7-4631-94cc-0c49240917ff -# ╠═e9a94e5a-274f-4740-ac05-bd3bb613df4d -# ╟─0f12b761-fb74-455b-9123-6d1b720aaf52 -# ╠═1113d5b9-8ebe-46fd-b24e-03e5fbc79435 -# ╠═333a8123-1683-491e-8891-83987bad16eb -# ╠═339fd327-a594-4460-9e00-8b3304aa0a78 -# ╠═0e2f9caa-d84e-411f-ad5d-64c10cdaa028 -# ╟─077045b9-3b88-4c41-a88c-354b8b30c31f -# ╠═d7562423-06cd-4949-a1fd-92d8e5c31280 -# ╟─51a9d53b-b92f-41c4-a60e-d8ceedd3fead -# ╠═6ad557b1-04d3-4c7e-a350-20408c09b960 -# ╠═f685ed77-151f-4778-8342-112903255932