From 7a31603d9437405ab25aa7abd51fdfa15bf0c81c Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Mon, 24 Jun 2024 15:33:51 +0800 Subject: [PATCH 1/5] update --- Project.toml | 2 +- notebooks/Project.toml | 11 +++++++ notebooks/tutorial.jl | 33 ++++++++++--------- notebooks/unweighted.jl | 14 ++++---- src/mapping.jl | 2 +- src/visualize.jl | 67 +++++++++++++++++++++----------------- test/dragondrop.jl | 11 +++---- test/extracting_results.jl | 6 ++-- test/gadgets.jl | 4 +-- test/logicgates.jl | 2 +- test/mapping.jl | 12 +++---- test/multiplier.jl | 9 +++-- test/runtests.jl | 4 +++ test/visualize.jl | 43 ++++++++++++++++++++++++ test/weighted.jl | 16 ++++----- 15 files changed, 151 insertions(+), 85 deletions(-) create mode 100644 test/visualize.jl diff --git a/Project.toml b/Project.toml index efe2b4f..b81edb6 100644 --- a/Project.toml +++ b/Project.toml @@ -9,7 +9,7 @@ LuxorGraphPlot = "1f49bdf2-22a7-4bc4-978b-948dc219fbbc" [compat] Graphs = "1.6" -LuxorGraphPlot = "0.3" +LuxorGraphPlot = "0.5" julia = "1" [extras] diff --git a/notebooks/Project.toml b/notebooks/Project.toml index cd9d00e..e08dfde 100644 --- a/notebooks/Project.toml +++ b/notebooks/Project.toml @@ -7,3 +7,14 @@ PlutoSliderServer = "2fc8631c-6f24-4c5b-bca7-cbb509c42db4" PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8" Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" UnitDiskMapping = "1b61a8d9-79ed-4491-8266-ef37f39e1727" + +[compat] +GenericTensorNetworks = "2" +Graphs = "1.6" +LinearAlgebra = "1" +LuxorGraphPlot = "0.4" +PlutoSliderServer = "0.3" +PlutoUI = "0.7" +Revise = "3" +UnitDiskMapping = "0.4" +julia = "1" \ No newline at end of file diff --git a/notebooks/tutorial.jl b/notebooks/tutorial.jl index 59ff128..cdb9d73 100644 --- a/notebooks/tutorial.jl +++ b/notebooks/tutorial.jl @@ -1,5 +1,5 @@ ### A Pluto.jl notebook ### -# v0.19.32 +# v0.19.42 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; GraphDisplayConfig.unit[] = 25; GraphDisplayConfig.background_color[]="white"; +using UnitDiskMapping.LuxorGraphPlot.Luxor, LuxorGraphPlot # ╔═╡ eac6ceda-f5d4-11ec-23db-b7b4d00eaddf md"# Unit Disk Mapping" @@ -64,7 +64,7 @@ md"Let the source graph be the Petersen graph." graph = smallgraph(:petersen) # ╔═╡ 0302be92-076a-4ebe-8d6d-4b352a77cfce -LuxorGraphPlot.show_graph(graph; unit=50) +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." @@ -86,9 +86,11 @@ fieldnames(unweighted_res |> typeof) md"The field `grid_graph` is the mapped grid graph." # ╔═╡ 520fbc23-927c-4328-8dc6-5b98853fb90d -# `unit` is the number of pixels per unit distance 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. ``` @@ -121,7 +123,7 @@ unweighted_res.mis_overhead md"We can solve the mapped graph with [`GenericTensorNetworks`](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/)." # ╔═╡ f084b98b-097d-4b33-a0d3-0d0a981f735e -res = solve(IndependentSet(SimpleGraph(unweighted_res.grid_graph)), SingleConfigMax())[] +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." @@ -180,7 +182,7 @@ md"Now that we have both the graph and the weights, let us solve the mapped prob wmap_config = let graph, _ = graph_and_weights(weighted_res.grid_graph) collect(Int, - solve(IndependentSet(graph; weights=mapped_weights), SingleConfigMax())[].c.data + solve(GenericTensorNetwork(IndependentSet(graph, mapped_weights)), SingleConfigMax())[].c.data ) end @@ -197,7 +199,7 @@ map_config_back(weighted_res, wmap_config) # ╔═╡ beb7c0e5-6221-4f20-9166-2bd56902be1b # Directly solving the source graph collect(Int, - solve(IndependentSet(graph; weights=source_weights), SingleConfigMax())[].c.data + solve(GenericTensorNetwork(IndependentSet(graph, source_weights)), SingleConfigMax())[].c.data ) # ╔═╡ cf7e88cb-432e-4e3a-ae8b-8fa12689e485 @@ -248,7 +250,7 @@ show_grayscale(qubo.grid_graph) md"By solving this maximum independent set problem, we will get the following configuration." # ╔═╡ ef149d9a-6aa9-4f34-b936-201b9d77543c -qubo_mapped_solution = collect(Int, solve(IndependentSet(qubo_graph; weights=qubo_weights), SingleConfigMax())[].c.data) +qubo_mapped_solution = collect(Int, solve(GenericTensorNetwork(IndependentSet(qubo_graph, qubo_weights)), SingleConfigMax())[].c.data) # ╔═╡ 4ea4f26e-746d-488e-9968-9fc584c04bcf show_config(qubo.grid_graph, qubo_mapped_solution) @@ -264,8 +266,8 @@ map_config_back(qubo, collect(Int, qubo_mapped_solution)) md"This solution is consistent with the exact solution:" # ╔═╡ 7dd900fc-9531-4bd6-8b6d-3aac3d5a2386 -# Directly solving the source graph -collect(Int, solve(SpinGlass(J, h), SingleConfigMax())[].c.data) +# Directly solving the source graph, due to the convention issue, we flip the signs of `J` and `h` +collect(Int, solve(GenericTensorNetwork(spin_glass_from_matrix(-J, -h)), SingleConfigMax())[].c.data) # ╔═╡ 13f952ce-642a-4396-b574-00ea6584008c md"### QUBO problem on a square lattice" @@ -308,7 +310,7 @@ md"Let us solve the independent set problem on the mapped graph." square_graph, square_weights = UnitDiskMapping.graph_and_weights(qubo_square.grid_graph); # ╔═╡ 5c25abb7-e3ee-4104-9a82-eb4aa4e773d2 -config_square = collect(Int, solve(IndependentSet(square_graph; weights=square_weights), SingleConfigMax())[].c.data); +config_square = collect(Int, solve(GenericTensorNetwork(IndependentSet(square_graph, square_weights)), SingleConfigMax())[].c.data); # ╔═╡ 4cec7232-8fbc-4ac1-96bb-6c7fea5fe117 md"We will get the following configuration." @@ -343,7 +345,7 @@ let for (i,j,h) in square_onsite hs[i+(j-1)*n] = h end - collect(Int, solve(SpinGlass(g2; J=Js, h=hs), SingleConfigMax())[].c.data) + collect(Int, solve(GenericTensorNetwork(SpinGlass(g2, -Js, -hs)), SingleConfigMax())[].c.data) end # ╔═╡ 9db831d6-7f10-47be-93d3-ebc892c4b3f2 @@ -386,7 +388,7 @@ md"To solve this factoring problem, one can use the following statement:" # ╔═╡ e5da7214-0e69-4b5a-a65e-ed92d0616c71 multiplier_output = UnitDiskMapping.solve_factoring(mres, 6) do g, ws - collect(Int, solve(IndependentSet(g; weights=ws), SingleConfigMax())[].c.data) + collect(Int, solve(GenericTensorNetwork(IndependentSet(g, ws)), SingleConfigMax())[].c.data) end # ╔═╡ 9dc01591-5c37-4d83-b640-83280513941e @@ -416,7 +418,7 @@ md"2. Then, we solve this new grid graph." # ╔═╡ 57f7e085-9589-4a6c-ac14-488ea9924692 config_factoring6 = let mg, mw = graph_and_weights(mapped_grid_graph) - solve(IndependentSet(mg; weights=mw), SingleConfigMax())[].c.data + solve(GenericTensorNetwork(IndependentSet(mg, mw)), SingleConfigMax())[].c.data end; # ╔═╡ 4c7d72f1-688a-4a70-8ce6-a4801127bb9a @@ -440,7 +442,7 @@ md"## Logic Gates" md"Let us define a helper function for visualization." # ╔═╡ c17bca17-a00a-4118-a212-d21da09af9b5 -parallel_show(gate) = leftright(show_pins(Gate(gate); format=:png, unit=80), show_grayscale(gate_gadget(Gate(gate))[1]; format=:png, unit=80, wmax=2)); +parallel_show(gate) = leftright(show_pins(Gate(gate)), show_grayscale(gate_gadget(Gate(gate))[1], wmax=2)); # ╔═╡ 6aee2288-1934-4fc5-9a9c-f45b7ce4e767 md"1. NOT gate: ``y_1 =\neg x_1``" @@ -485,6 +487,7 @@ md"Since most logic gates have 3 pins, it is natural to embed a circuit to a 3D # ╠═ae5c8359-6bdb-4a2a-8b54-cd2c7d2af4bd # ╟─56bdcaa6-c8b9-47de-95d4-6e95204af0f2 # ╠═520fbc23-927c-4328-8dc6-5b98853fb90d +# ╠═af162d39-2da9-4a06-9cde-8306e811ba7a # ╟─96ca41c0-ac77-404c-ada3-0cdc4a426e44 # ╠═5dfa8a74-26a5-45c4-a80c-47ba4a6a4ae9 # ╟─a64c2094-9a51-4c45-b9d1-41693c89a212 diff --git a/notebooks/unweighted.jl b/notebooks/unweighted.jl index 5abad8e..f117753 100644 --- a/notebooks/unweighted.jl +++ b/notebooks/unweighted.jl @@ -1,5 +1,5 @@ ### A Pluto.jl notebook ### -# v0.19.32 +# v0.19.42 using Markdown using InteractiveUtils @@ -107,7 +107,7 @@ md"#### Step 3: Solve the MIS size of the mapped graph" 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())[] +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:" @@ -121,7 +121,7 @@ One of the best solutions can be obtained by solving the `SingleConfigMax()` pro """ # ╔═╡ 0142f661-0855-45b4-852a-78f560e98c67 -mis_g5_ksg = solve(IndependentSet(SimpleGraph(g5res.grid_graph)), SingleConfigMax())[].c.data +mis_g5_ksg = solve(GenericTensorNetwork(IndependentSet(SimpleGraph(g5res.grid_graph))), SingleConfigMax())[].c.data # ╔═╡ fa046f3c-fd7d-4e91-b3f5-fc4591d3cae2 md"Plot the solution" @@ -153,7 +153,7 @@ UnitDiskMapping.is_independent_set(g5, mis_g5) count(isone, mis_g5) # ╔═╡ 5621bb2a-b1c6-4f0d-921e-980b2ce849d5 -solve(IndependentSet(g5), SizeMax())[].n +solve(GenericTensorNetwork(IndependentSet(g5)), SizeMax())[].n # ╔═╡ 1fe6c679-2962-4c1b-8b12-4ceb77ed9e0f md""" @@ -178,13 +178,13 @@ petersen_res = UnitDiskMapping.map_graph(petersen) md"The MIS size of the petersen graph is 4." # ╔═╡ bf97a268-cd96-4dbc-83c6-10eb1b03ddcc -missize_petersen = solve(IndependentSet(petersen), SizeMax())[] +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(IndependentSet(SimpleGraph(petersen_res.grid_graph)), SizeMax())[] +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:" @@ -196,7 +196,7 @@ petersen_res.mis_overhead 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 +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)) diff --git a/src/mapping.jl b/src/mapping.jl index 2dfddcc..4a1c4e1 100644 --- a/src/mapping.jl +++ b/src/mapping.jl @@ -368,7 +368,7 @@ struct MappingResult{NT} end """ - map_graph([mode=Weighted(),] g::SimpleGraph; vertex_order=Branching(), ruleset=[...]) + map_graph([mode=UnWeighted(),] g::SimpleGraph; vertex_order=Branching(), ruleset=[...]) Map a graph to a unit disk grid graph that being "equivalent" to the original graph, and return a `MappingResult` instance. Here "equivalent" means a maximum independent set in the grid graph can be mapped back to diff --git a/src/visualize.jl b/src/visualize.jl index 9a6a1cc..4f46e1c 100644 --- a/src/visualize.jl +++ b/src/visualize.jl @@ -1,41 +1,46 @@ # normalized to minimum weight and maximum weight function LuxorGraphPlot.show_graph(gg::GridGraph; - 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 - 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=config.xmin:config.xmax, j=config.ymin:config.ymax - (i, j) ∉ locs && push!(empty_locations, (i, j)) - end - + format = :svg, + filename = nothing, + padding_left = 10, + padding_right = 10, + padding_top = 10, + padding_bottom = 10, + show_number = false, + config = GraphDisplayConfig(), + texts = nothing, + vertex_colors=nothing, + ) + texts !== nothing && show_number && @warn "not showing number due to the manually specified node texts." # plot! - LuxorGraphPlot._draw(Dx, Dy; format, filename) do - LuxorGraphPlot.@temp GraphDisplayConfig.vertex_size[] = vertex_size GraphDisplayConfig.fontsize[] = fontsize begin - LuxorGraphPlot._show_graph(locs, edges; - vertex_size, fontsize, kwargs...) + unit = 33.0 + coos = coordinates(gg) + xmin, xmax = extrema(first.(coos)) + ymin, ymax = extrema(last.(coos)) + nodestore() do ns + filledlocs = map(coo->circle!((unit * (coo[2] - 1), -unit * (coo[1] - 1)), config.vertex_size), coos) + emptylocs, edges = [], [] + for i=xmin:xmax, j=ymin:ymax + (i, j) ∉ coos && push!(emptylocs, circle!(((j-1) * unit, -(i-1) * unit), config.vertex_size/10)) end - - # visualize dots - 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))) + for e in Graphs.edges(graph_and_weights(gg)[1]) + i, j = e.src, e.dst + push!(edges, Connection(filledlocs[i], filledlocs[j])) + end + with_nodes(ns; format, filename, padding_bottom, padding_left, padding_right, padding_top, background=config.background) do + config2 = copy(config) + config2 = GraphDisplayConfig(; vertex_color="#333333", vertex_stroke_color="transparent") + texts = texts===nothing && show_number ? string.(1:length(filledlocs)) : texts + LuxorGraphPlot.render_nodes(filledlocs, config; texts, vertex_colors) + LuxorGraphPlot.render_edges(edges, config) + LuxorGraphPlot.render_nodes(emptylocs, config2; texts=nothing) end end end function show_grayscale(gg::GridGraph; wmax=nothing, kwargs...) - _, ws = graph_and_weights(gg) + _, ws0 = graph_and_weights(gg) + ws = tame_weights.(ws0) if wmax === nothing wmax = maximum(abs, ws) end @@ -46,6 +51,8 @@ function show_grayscale(gg::GridGraph; wmax=nothing, kwargs...) vertex_colors= [cmap[max(1, round(Int, 100+w/wmax*100))] for w in ws] show_graph(gg; vertex_colors, kwargs...) end +tame_weights(w::ONE) = 1.0 +tame_weights(w::Real) = w function show_pins(gg::GridGraph, color_pins::AbstractDict; kwargs...) vertex_colors=String[] @@ -90,7 +97,7 @@ function show_config(gg::GridGraph, config; kwargs...) show_graph(gg; vertex_colors, kwargs...) end -function show_pins(mres::MappingResult; kwargs...) +function show_pins(mres::MappingResult{<:WeightedNode}; kwargs...) locs = getfield.(mres.grid_graph.nodes, :loc) center_indices = map(loc->findfirst(==(loc), locs), trace_centers(mres)) color_pins = Dict{Int,Tuple{String,String}}() diff --git a/test/dragondrop.jl b/test/dragondrop.jl index e4f77a6..349d790 100644 --- a/test/dragondrop.jl +++ b/test/dragondrop.jl @@ -11,7 +11,7 @@ using Random @test show_pins(qubo) !== nothing println(qubo) graph, weights = UnitDiskMapping.graph_and_weights(qubo.grid_graph) - r1 = solve(IndependentSet(graph; weights), SingleConfigMax())[] + r1 = solve(GenericTensorNetwork(IndependentSet(graph, weights)), SingleConfigMax())[] J2 = vcat([Float64[J[i,j] for j=i+1:n] for i=1:n]...) r2 = solve(SpinGlass(complete_graph(n); J=J2, h=H), SingleConfigMax())[] @test r1.n - qubo.mis_overhead ≈ r2.n @@ -28,10 +28,9 @@ end n = nv(g0) w0 = ones(n) * 0.01 wmis = UnitDiskMapping.map_simple_wmis(g0, w0) - @test show_pins(wmis) !== nothing graph, weights = UnitDiskMapping.graph_and_weights(wmis.grid_graph) - r1 = solve(IndependentSet(graph; weights), SingleConfigMax())[] - r2 = solve(IndependentSet(g0; weights=w0), SingleConfigMax())[] + r1 = solve(GenericTensorNetwork(IndependentSet(graph, weights)), SingleConfigMax())[] + r2 = solve(GenericTensorNetwork(IndependentSet(g0, w0)), SingleConfigMax())[] @test r1.n - wmis.mis_overhead ≈ r2.n @test r1.n % 1 ≈ r2.n % 1 c1 = map_config_back(wmis, r1.c.data) @@ -47,7 +46,7 @@ end ] qubo = UnitDiskMapping.map_qubo_restricted(coupling) graph, weights = UnitDiskMapping.graph_and_weights(qubo.grid_graph) - r1 = solve(IndependentSet(graph; weights), SingleConfigMax())[] + r1 = solve(GenericTensorNetwork(IndependentSet(graph, weights)), SingleConfigMax())[] weights = Int[] @@ -70,7 +69,7 @@ end onsite = vec([(i, j, 0.01*randn()) for i=1:m, j=1:n]) qubo = UnitDiskMapping.map_qubo_square(coupling, onsite) graph, weights = UnitDiskMapping.graph_and_weights(qubo.grid_graph) - r1 = solve(IndependentSet(graph; weights), SingleConfigMax())[] + r1 = solve(GenericTensorNetwork(IndependentSet(graph, weights)), SingleConfigMax())[] # solve spin glass directly g2 = SimpleGraph(m*n) diff --git a/test/extracting_results.jl b/test/extracting_results.jl index cf74df2..9658da6 100644 --- a/test/extracting_results.jl +++ b/test/extracting_results.jl @@ -7,9 +7,9 @@ using GenericTensorNetworks locs, g, pins = mapped_graph(s) d1 = UnitDiskMapping.mapped_entry_to_compact(s) d2 = UnitDiskMapping.source_entry_to_configs(s) - m = solve(IndependentSet(g, openvertices=pins), ConfigsMax()) - t = solve(IndependentSet(g0, openvertices=pins0), SizeMax()) - for i=1:length(m) + m = solve(GenericTensorNetwork(IndependentSet(g), openvertices=pins), ConfigsMax()) + t = solve(GenericTensorNetwork(IndependentSet(g0), openvertices=pins0), SizeMax()) + for i in eachindex(m) for v in m[i].c.data bc = UnitDiskMapping.mapped_boundary_config(s, v) compact_bc = d1[bc] diff --git a/test/gadgets.jl b/test/gadgets.jl index c1d1695..1256ef7 100644 --- a/test/gadgets.jl +++ b/test/gadgets.jl @@ -9,8 +9,8 @@ using Graphs locs1, g1, pins1 = source_graph(s) locs2, g2, pins2 = mapped_graph(s) @assert length(locs1) == nv(g1) - m1 = mis_compactify!(solve(IndependentSet(g1, openvertices=pins1), SizeMax())) - m2 = mis_compactify!(solve(IndependentSet(g2, openvertices=pins2), SizeMax())) + m1 = mis_compactify!(solve(GenericTensorNetwork(IndependentSet(g1), openvertices=pins1), SizeMax())) + m2 = mis_compactify!(solve(GenericTensorNetwork(IndependentSet(g2), openvertices=pins2), SizeMax())) @test nv(g1) == length(locs1) && nv(g2) == length(locs2) sig, diff = UnitDiskMapping.is_diff_by_const(content.(m1), content.(m2)) @test diff == -mis_overhead(s) diff --git a/test/logicgates.jl b/test/logicgates.jl index b7f5912..cf5a0c4 100644 --- a/test/logicgates.jl +++ b/test/logicgates.jl @@ -7,7 +7,7 @@ using GenericTensorNetworks @info gate g, inputs, outputs = gate_gadget(Gate(gate)) @test UnitDiskMapping.truth_table(Gate(gate)) do graph, weights - collect.(Int, solve(IndependentSet(graph; weights), ConfigsMax())[].c.data) + collect.(Int, solve(GenericTensorNetwork(IndependentSet(graph, weights)), ConfigsMax())[].c.data) end == [f([x>>(i-1) & 1 == 1 for i=1:length(inputs)]...) for x in 0:1<mis_overhead(x[1]), tape) mis_overhead2 = sum(x->mis_overhead(x[1]), tape2) @show mis_overhead2 - gp = IndependentSet(SimpleGraph(ug3); optimizer=GreedyMethod(nrepeat=10), simplifier=MergeGreedy()) + gp = GenericTensorNetwork(IndependentSet(SimpleGraph(ug3)); optimizer=GreedyMethod(nrepeat=10)) missize_map = solve(gp, SizeMax())[].n - missize = solve(IndependentSet(g), SizeMax())[].n + missize = solve(GenericTensorNetwork(IndependentSet(g)), SizeMax())[].n @test mis_overhead0 + mis_overhead1 + mis_overhead2 + missize == missize_map misconfig = solve(gp, SingleConfigMax())[].c c = zeros(Int, size(ug3.content)) @@ -75,9 +75,9 @@ end res = map_graph(g) # checking size - gp = IndependentSet(SimpleGraph(res.grid_graph); optimizer=TreeSA(ntrials=1, niters=10), simplifier=MergeGreedy()) + gp = GenericTensorNetwork(IndependentSet(SimpleGraph(res.grid_graph)); optimizer=TreeSA(ntrials=1, niters=10)) missize_map = solve(gp, SizeMax())[].n - missize = solve(IndependentSet(g), SizeMax())[].n + missize = solve(GenericTensorNetwork(IndependentSet(g)), SizeMax())[].n @test res.mis_overhead + missize == missize_map # checking mapping back @@ -94,9 +94,9 @@ end res = map_graph(g) # checking size - gp = IndependentSet(SimpleGraph(res.grid_graph); optimizer=TreeSA(ntrials=1, niters=10), simplifier=MergeGreedy()) + gp = GenericTensorNetwork(IndependentSet(SimpleGraph(res.grid_graph)); optimizer=TreeSA(ntrials=1, niters=10)) missize_map = solve(gp, SizeMax())[].n - missize = solve(IndependentSet(g), SizeMax())[].n + missize = solve(GenericTensorNetwork(IndependentSet(g)), SizeMax())[].n @test res.mis_overhead + missize == missize_map # checking mapping back diff --git a/test/multiplier.jl b/test/multiplier.jl index ce3ba9e..708da46 100644 --- a/test/multiplier.jl +++ b/test/multiplier.jl @@ -5,7 +5,7 @@ using Test, UnitDiskMapping, Graphs @testset "multiplier" begin m, pins = UnitDiskMapping.multiplier() g, ws = UnitDiskMapping.graph_and_weights(m) - configs = solve(IndependentSet(g; weights=ws), ConfigsMax())[].c + configs = solve(GenericTensorNetwork(IndependentSet(g, ws)), ConfigsMax())[].c # completeness inputs = Int[] @@ -27,20 +27,19 @@ end @testset "factoring" begin mres = UnitDiskMapping.map_factoring(2, 2) - @test show_pins(mres) !== nothing res = UnitDiskMapping.solve_factoring(mres, 6) do g, ws - collect(Int, solve(IndependentSet(g; weights=ws), SingleConfigMax())[].c.data) + collect(Int, solve(GenericTensorNetwork(IndependentSet(g, ws)), SingleConfigMax())[].c.data) end @test res == (2, 3) || res == (3, 2) res = UnitDiskMapping.solve_factoring(mres, 9) do g, ws - collect(Int, solve(IndependentSet(g; weights=ws), SingleConfigMax())[].c.data) + collect(Int, solve(GenericTensorNetwork(IndependentSet(g, ws)), SingleConfigMax())[].c.data) end @test res == (3, 3) mres = UnitDiskMapping.map_factoring(2, 3) res = UnitDiskMapping.solve_factoring(mres, 15) do g, ws - collect(Int, solve(IndependentSet(g; weights=ws), SingleConfigMax())[].c.data) + collect(Int, solve(GenericTensorNetwork(IndependentSet(g, ws)), SingleConfigMax())[].c.data) end @test res == (5, 3) || res == (3, 5) end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index e62a05c..b983e25 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -44,3 +44,7 @@ end @testset "drag and drop" begin include("dragondrop.jl") end + +@testset "visualize" begin + include("visualize.jl") +end diff --git a/test/visualize.jl b/test/visualize.jl new file mode 100644 index 0000000..f9d9f87 --- /dev/null +++ b/test/visualize.jl @@ -0,0 +1,43 @@ +using UnitDiskMapping, Graphs, LuxorGraphPlot, LuxorGraphPlot.Luxor, LinearAlgebra +using Test + +@testset "show_graph" begin + g = smallgraph(:petersen) + res = map_graph(g) + @test show_graph(res.grid_graph) isa Luxor.Drawing + @test show_grayscale(res.grid_graph) isa Luxor.Drawing + @test show_pins(res.grid_graph, Dict("red"=>[1,2,4])) isa Luxor.Drawing + config = rand(0:1, length(coordinates(res.grid_graph))) + @test show_config(res.grid_graph, config; show_number=true) isa Drawing +end + +@testset "show_graph - weighted" begin + g = smallgraph(:petersen) + res = map_graph(Weighted(), g) + @test show_grayscale(res.grid_graph) isa Luxor.Drawing + @test show_pins(res) isa Luxor.Drawing +end + +@testset "show_pins, logic" begin + mres = UnitDiskMapping.map_factoring(2, 2) + @test show_pins(mres) isa Luxor.Drawing + gd = UnitDiskMapping.Gate(:AND) + @test show_pins(gd) isa Luxor.Drawing +end + +@testset "show_pins, qubo" begin + n = 7 + H = -randn(n) * 0.05 + J = triu(randn(n, n) * 0.001, 1); J += J' + qubo = UnitDiskMapping.map_qubo(J, H) + @test show_pins(qubo) isa Luxor.Drawing + + m, n = 6, 6 + coupling = [ + [(i,j,i,j+1,0.01*randn()) for i=1:m, j=1:n-1]..., + [(i,j,i+1,j,0.01*randn()) for i=1:m-1, j=1:n]... + ] + onsite = vec([(i, j, 0.01*randn()) for i=1:m, j=1:n]) + qubo = UnitDiskMapping.map_qubo_square(coupling, onsite) + @test show_pins(qubo) isa Luxor.Drawing +end \ No newline at end of file diff --git a/test/weighted.jl b/test/weighted.jl index f50121a..b8331a9 100644 --- a/test/weighted.jl +++ b/test/weighted.jl @@ -13,8 +13,8 @@ using UnitDiskMapping: is_independent_set w2 = getfield.(locs2, :weight) w1[pins1] .-= 1 w2[pins2] .-= 1 - gp1 = IndependentSet(g1, openvertices=pins1, weights=w1) - gp2 = IndependentSet(g2, openvertices=pins2, weights=w2) + gp1 = GenericTensorNetwork(IndependentSet(g1, w1), openvertices=pins1) + gp2 = GenericTensorNetwork(IndependentSet(g2, w2), openvertices=pins2) m1 = solve(gp1, SizeMax()) m2 = solve(gp2, SizeMax()) mm1 = maximum(m1) @@ -44,7 +44,7 @@ end add_edge!(g, i, i-1) end end - gp = IndependentSet(g; weights=weights) + gp = GenericTensorNetwork(IndependentSet(g, weights)) @test solve(gp, SizeMax())[].n == UnitDiskMapping.mis_overhead_copyline(Weighted(), tc) end end @@ -66,9 +66,9 @@ end weights = fill(0.5, nv(g)) r = UnitDiskMapping.MappingResult(GridGraph(ug3), ug3.lines, ug3.padding, [tape..., tape2...], mis_overhead0+mis_overhead1+mis_overhead2) mapped_weights = UnitDiskMapping.map_weights(r, weights) - gp = IndependentSet(mgraph; optimizer=GreedyMethod(nrepeat=10), simplifier=MergeGreedy(), weights=mapped_weights) + gp = GenericTensorNetwork(IndependentSet(mgraph, mapped_weights); optimizer=GreedyMethod(nrepeat=10)) missize_map = solve(gp, CountingMax())[] - missize = solve(IndependentSet(g; weights=weights), CountingMax())[] + missize = solve(GenericTensorNetwork(IndependentSet(g, weights)), CountingMax())[] @test mis_overhead0 + mis_overhead1 + mis_overhead2 + missize.n == missize_map.n @test missize.c == missize_map.c @@ -98,15 +98,15 @@ end ws = rand(nv(g)) weights = UnitDiskMapping.map_weights(res, ws) - gp = IndependentSet(mgraph; optimizer=TreeSA(ntrials=1, niters=10), simplifier=MergeGreedy(), weights=weights) + gp = GenericTensorNetwork(IndependentSet(mgraph, weights); optimizer=TreeSA(ntrials=1, niters=10)) missize_map = solve(gp, SizeMax())[].n - missize = solve(IndependentSet(g; weights=ws), SizeMax())[].n + missize = solve(GenericTensorNetwork(IndependentSet(g, ws)), SizeMax())[].n @test res.mis_overhead + missize == missize_map # checking mapping back T = GenericTensorNetworks.sampler_type(nv(mgraph), 2) misconfig = solve(gp, SingleConfigMax())[].c original_configs = map_config_back(res, collect(misconfig.data)) - @test count(isone, original_configs) == solve(IndependentSet(g), SizeMax())[].n + @test count(isone, original_configs) == solve(GenericTensorNetwork(IndependentSet(g)), SizeMax())[].n @test is_independent_set(g, original_configs) end From d55dc586cad4288ec7facccc33810ff05d1f9e08 Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Tue, 25 Jun 2024 00:03:28 +0800 Subject: [PATCH 2/5] update --- test/dragondrop.jl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/dragondrop.jl b/test/dragondrop.jl index 349d790..0bc00bb 100644 --- a/test/dragondrop.jl +++ b/test/dragondrop.jl @@ -13,11 +13,12 @@ using Random graph, weights = UnitDiskMapping.graph_and_weights(qubo.grid_graph) r1 = solve(GenericTensorNetwork(IndependentSet(graph, weights)), SingleConfigMax())[] J2 = vcat([Float64[J[i,j] for j=i+1:n] for i=1:n]...) - r2 = solve(SpinGlass(complete_graph(n); J=J2, h=H), SingleConfigMax())[] + # note the different sign convention of J + r2 = solve(GenericTensorNetwork(SpinGlass(complete_graph(n), -J2, H)), SingleConfigMax())[] @test r1.n - qubo.mis_overhead ≈ r2.n @test r1.n % 1 ≈ r2.n % 1 c1 = map_config_back(qubo, r1.c.data) - @test spinglass_energy(complete_graph(n), c1; J=J2, h=H) ≈ spinglass_energy(complete_graph(n), r2.c.data; J=J2, h=H) + @test spinglass_energy(complete_graph(n), c1; J=-J2, h=H) ≈ spinglass_energy(complete_graph(n), r2.c.data; J=-J2, h=H) #display(MappingGrid(UnitDiskMapping.CopyLine[], 0, qubo)) end @@ -55,7 +56,7 @@ end add_edge!(g2, (i-1)*n+j, (i2-1)*n+j2) push!(weights, J) end - r2 = solve(SpinGlass(g2; J=weights), SingleConfigMax())[] + r2 = solve(GenericTensorNetwork(SpinGlass(g2, -weights)), SingleConfigMax())[] @show r1, r2 end @@ -87,9 +88,9 @@ end for (i,j,h) in onsite hs[i+(j-1)*m] = h end - r2 = solve(SpinGlass(g2; J=Js, h=hs), SingleConfigMax())[] + r2 = solve(GenericTensorNetwork(SpinGlass(g2, -Js, hs)), SingleConfigMax())[] @test r1.n - qubo.mis_overhead ≈ r2.n c1 = map_config_back(qubo, collect(Int,r1.c.data)) c2 = collect(r2.c.data) - @test spinglass_energy(g2, c1; J=Js, h=hs) ≈ spinglass_energy(g2, c2; J=Js, h=hs) + @test spinglass_energy(g2, c1; J=-Js, h=hs) ≈ spinglass_energy(g2, c2; J=-Js, h=hs) end \ No newline at end of file From 63033ca15e4152ec627364ece3d95920b899bdaf Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Tue, 25 Jun 2024 00:13:50 +0800 Subject: [PATCH 3/5] update deps --- notebooks/Project.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/notebooks/Project.toml b/notebooks/Project.toml index e08dfde..38d7eaf 100644 --- a/notebooks/Project.toml +++ b/notebooks/Project.toml @@ -12,9 +12,9 @@ UnitDiskMapping = "1b61a8d9-79ed-4491-8266-ef37f39e1727" GenericTensorNetworks = "2" Graphs = "1.6" LinearAlgebra = "1" -LuxorGraphPlot = "0.4" +LuxorGraphPlot = "0.5" PlutoSliderServer = "0.3" PlutoUI = "0.7" Revise = "3" -UnitDiskMapping = "0.4" -julia = "1" \ No newline at end of file +UnitDiskMapping = "0.3" +julia = "1" From c9b2c3d4b7e40bdf50f8604ae8c4dc636fa0f392 Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Tue, 25 Jun 2024 00:58:44 +0800 Subject: [PATCH 4/5] rename Branching to MinhThi Trick --- Project.toml | 3 ++- notebooks/tutorial.jl | 6 +++--- notebooks/unweighted.jl | 4 ++-- src/UnitDiskMapping.jl | 4 +++- src/mapping.jl | 16 +++++++------- src/pathdecomposition/pathdecomposition.jl | 23 +++++++++++++++++---- test/pathdecomposition/pathdecomposition.jl | 2 +- 7 files changed, 38 insertions(+), 20 deletions(-) diff --git a/Project.toml b/Project.toml index b81edb6..acfe5d7 100644 --- a/Project.toml +++ b/Project.toml @@ -14,8 +14,9 @@ julia = "1" [extras] GenericTensorNetworks = "3521c873-ad32-4bb4-b63d-f4f178f42b49" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test", "Random", "GenericTensorNetworks"] +test = ["Test", "Random", "GenericTensorNetworks", "LinearAlgebra"] diff --git a/notebooks/tutorial.jl b/notebooks/tutorial.jl index cdb9d73..f54ed28 100644 --- a/notebooks/tutorial.jl +++ b/notebooks/tutorial.jl @@ -70,10 +70,10 @@ LuxorGraphPlot.show_graph(graph) 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=Branching()); +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 `Branching()` 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. +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 @@ -150,7 +150,7 @@ md"## Generic Weighted Mapping" 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=Branching()); +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." diff --git a/notebooks/unweighted.jl b/notebooks/unweighted.jl index f117753..6fc1613 100644 --- a/notebooks/unweighted.jl +++ b/notebooks/unweighted.jl @@ -82,11 +82,11 @@ 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 +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=Branching()) +g5res = UnitDiskMapping.map_graph(g5; vertex_order=MinhThiTrick()) # ╔═╡ e64e7ca4-b297-4c74-8699-bec4b4fbb843 md"Visualize the mapped KSG graph in terminal" diff --git a/src/UnitDiskMapping.jl b/src/UnitDiskMapping.jl index 247bdbd..628f921 100644 --- a/src/UnitDiskMapping.jl +++ b/src/UnitDiskMapping.jl @@ -37,7 +37,9 @@ export @gg export is_independent_set, unitdisk_graph # path decomposition -export pathwidth, PathDecompositionMethod, Branching, Greedy +export pathwidth, PathDecompositionMethod, MinhThiTrick, Greedy + +@deprecate Branching MinhThiTrick include("utils.jl") include("Core.jl") diff --git a/src/mapping.jl b/src/mapping.jl index 4a1c4e1..1297393 100644 --- a/src/mapping.jl +++ b/src/mapping.jl @@ -318,16 +318,16 @@ function crossat(ug::MappingGrid, v, w) end """ - embed_graph([mode,] g::SimpleGraph; vertex_order=Branching()) + embed_graph([mode,] g::SimpleGraph; vertex_order=MinhThiTrick()) Embed graph `g` into a unit disk grid, where the optional argument `mode` can be `Weighted()` or `UnWeighted`. The `vertex_order` can be a vector or one of the following inputs * `Greedy()` fast but non-optimal. - * `Branching()` slow but optimal. + * `MinhThiTrick()` slow but optimal. """ -embed_graph(g::SimpleGraph; vertex_order=Branching()) = embed_graph(UnWeighted(), g; vertex_order) -function embed_graph(mode, g::SimpleGraph; vertex_order=Branching()) +embed_graph(g::SimpleGraph; vertex_order=MinhThiTrick()) = embed_graph(UnWeighted(), g; vertex_order) +function embed_graph(mode, g::SimpleGraph; vertex_order=MinhThiTrick()) if vertex_order isa AbstractVector L = PathDecomposition.Layout(g, collect(vertex_order[end:-1:1])) else @@ -368,7 +368,7 @@ struct MappingResult{NT} end """ - map_graph([mode=UnWeighted(),] g::SimpleGraph; vertex_order=Branching(), ruleset=[...]) + map_graph([mode=UnWeighted(),] g::SimpleGraph; vertex_order=MinhThiTrick(), ruleset=[...]) Map a graph to a unit disk grid graph that being "equivalent" to the original graph, and return a `MappingResult` instance. Here "equivalent" means a maximum independent set in the grid graph can be mapped back to @@ -385,13 +385,13 @@ Keyword Arguments Different vertex orders have different path width, i.e. different depth of mapped grid graph. It can be a vector or one of the following inputs * `Greedy()` fast but not optimal. - * `Branching()` slow but optimal. + * `MinhThiTrick()` slow but optimal. * `ruleset` specifies and extra set of optimization patterns (not the crossing patterns). """ -function map_graph(g::SimpleGraph; vertex_order=Branching(), ruleset=default_simplifier_ruleset(UnWeighted())) +function map_graph(g::SimpleGraph; vertex_order=MinhThiTrick(), ruleset=default_simplifier_ruleset(UnWeighted())) map_graph(UnWeighted(), g; ruleset=ruleset, vertex_order=vertex_order) end -function map_graph(mode, g::SimpleGraph; vertex_order=Branching(), ruleset=default_simplifier_ruleset(mode)) +function map_graph(mode, g::SimpleGraph; vertex_order=MinhThiTrick(), ruleset=default_simplifier_ruleset(mode)) ug = embed_graph(mode, g; vertex_order=vertex_order) mis_overhead0 = mis_overhead_copylines(ug) ug, tape = apply_crossing_gadgets!(mode, ug) diff --git a/src/pathdecomposition/pathdecomposition.jl b/src/pathdecomposition/pathdecomposition.jl index 8960d09..cc93781 100644 --- a/src/pathdecomposition/pathdecomposition.jl +++ b/src/pathdecomposition/pathdecomposition.jl @@ -1,7 +1,7 @@ module PathDecomposition using Graphs -export pathwidth, PathDecompositionMethod, Branching, Greedy +export pathwidth, PathDecompositionMethod, MinhThiTrick, Greedy struct Layout{T} vertices::Vector{T} @@ -78,7 +78,22 @@ Graphs.vertices(layout::Layout) = layout.vertices ##### Interfaces ##### abstract type PathDecompositionMethod end -struct Branching <: PathDecompositionMethod end +""" + MinhThiTrick <: PathDecompositionMethod + +A path decomposition method based on the Branching method. + +In memory of Minh-Thi Nguyen, one of the main developers of this method. +She left us in a truck accident at her 24 years old. +- https://www.cbsnews.com/boston/news/cyclist-killed-minh-thi-nguyen-cambridge-bike-safety/ +""" +struct MinhThiTrick <: PathDecompositionMethod end + +""" + Greedy <: PathDecompositionMethod + +A path decomposition method based on the Greedy method. +""" Base.@kwdef struct Greedy <: PathDecompositionMethod nrepeat::Int = 10 end @@ -90,9 +105,9 @@ Compute the optimal path decomposition of graph `g`, returns a `Layout` instance `method` can be * Greedy(; nrepeat=10) - * Branching + * MinhThiTrick """ -function pathwidth(g::AbstractGraph, ::Branching) +function pathwidth(g::AbstractGraph, ::MinhThiTrick) return branch_and_bound(g) end diff --git a/test/pathdecomposition/pathdecomposition.jl b/test/pathdecomposition/pathdecomposition.jl index f710f51..2be885d 100644 --- a/test/pathdecomposition/pathdecomposition.jl +++ b/test/pathdecomposition/pathdecomposition.jl @@ -16,7 +16,7 @@ using Graphs @test sum(length, arem) == nv(g) end g = smallgraph(:tutte) - res = pathwidth(g, Branching()) + res = pathwidth(g, MinhThiTrick()) @test vsep(res) == 6 g = smallgraph(:tutte) res = pathwidth(g, Greedy(nrepeat=50)) From f8998df5b97f8609d2f92402fcac5cb5712c735c Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Tue, 25 Jun 2024 01:04:21 +0800 Subject: [PATCH 5/5] fix ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 03accdf..5fefa46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,8 +57,8 @@ jobs: run: julia -e 'using Pkg; Pkg.add("PlutoUI"); Pkg.activate("notebooks"); - Pkg.instantiate(); Pkg.develop(path="."); + Pkg.instantiate(); using PlutoSliderServer; for file in readdir("notebooks") endswith(file, ".jl") && PlutoSliderServer.export_notebook(joinpath("notebooks", file))