diff --git a/docs/src/ref.md b/docs/src/ref.md index 8a7f02b6..322335cd 100644 --- a/docs/src/ref.md +++ b/docs/src/ref.md @@ -134,8 +134,11 @@ MergeGreedy #### Graph ```@docs show_graph -show_gallery +show_configs show_einsum +GraphDisplayConfig +Layout +render_locs diagonal_coupled_graph square_lattice_graph diff --git a/examples/Coloring.jl b/examples/Coloring.jl index a737afef..572f5cca 100644 --- a/examples/Coloring.jl +++ b/examples/Coloring.jl @@ -55,14 +55,14 @@ is_vertex_coloring(graph, single_solution.c.data) vertex_color_map = Dict(0=>"red", 1=>"green", 2=>"blue") -show_graph(graph; locs=locations, format=:svg, vertex_colors=[vertex_color_map[Int(c)] +show_graph(graph, locations; format=:svg, vertex_colors=[vertex_color_map[Int(c)] for c in single_solution.c.data]) # Let us try to solve the same issue on its line graph, a graph that generated by mapping an edge to a vertex and two edges sharing a common vertex will be connected. linegraph = line_graph(graph) -show_graph(linegraph; locs=[0.5 .* (locations[e.src] .+ locations[e.dst]) - for e in edges(graph)], format=:svg) +show_graph(linegraph, [0.5 .* (locations[e.src] .+ locations[e.dst]) + for e in edges(graph)]; format=:svg) # Let us construct the tensor network and see if there are solutions. lineproblem = Coloring{3}(linegraph); diff --git a/examples/DominatingSet.jl b/examples/DominatingSet.jl index 3dd979a8..1cb154a0 100644 --- a/examples/DominatingSet.jl +++ b/examples/DominatingSet.jl @@ -74,7 +74,7 @@ all(c->is_dominating_set(graph, c), min_configs) # -show_gallery(graph, (2, 5); locs=locations, vertex_configs=min_configs, format=:svg) +show_configs(graph, locations, reshape(collect(min_configs), 2, 5); padding_left=20) # Similarly, if one is only interested in computing one of the minimum dominating sets, # one can use the graph property [`SingleConfigMin`](@ref). diff --git a/examples/IndependentSet.jl b/examples/IndependentSet.jl index 72777d35..46d0d687 100644 --- a/examples/IndependentSet.jl +++ b/examples/IndependentSet.jl @@ -132,8 +132,8 @@ all_max_configs = solve(problem, ConfigsMax(; bounded=true))[] all_max_configs.c.data -# These solutions can be visualized with the [`show_gallery`](@ref) function. -show_gallery(graph, (1, length(all_max_configs.c)); locs=locations, vertex_configs=all_max_configs.c, format=:svg) +# These solutions can be visualized with the [`show_configs`](@ref) function. +show_configs(graph, locations, reshape(collect(all_max_configs.c), 1, length(all_max_configs.c)); padding_left=20) # We can use [`ConfigsAll`](@ref) to enumerate all sets satisfying the independence constraint. all_independent_sets = solve(problem, ConfigsAll())[] diff --git a/examples/Matching.jl b/examples/Matching.jl index 4ac8f7d5..775f89ce 100644 --- a/examples/Matching.jl +++ b/examples/Matching.jl @@ -66,7 +66,7 @@ matching_poly = solve(problem, GraphPolynomial())[] match_config = solve(problem, SingleConfigMax())[] # Let us show the result by coloring the matched edges to red -show_graph(graph; locs=locations, format=:svg, edge_colors= +show_graph(graph, locations; format=:svg, edge_colors= [isone(match_config.c.data[i]) ? "red" : "black" for i=1:ne(graph)]) # where we use edges with red color to related pairs of matched vertices. diff --git a/examples/MaxCut.jl b/examples/MaxCut.jl index 57209d90..f3672727 100644 --- a/examples/MaxCut.jl +++ b/examples/MaxCut.jl @@ -76,7 +76,7 @@ max_cut_size_verify = cut_size(graph, max_vertex_config) # You should see a consistent result as above `max_cut_size`. -show_graph(graph; locs=locations, vertex_colors=[ +show_graph(graph, locations; vertex_colors=[ iszero(max_vertex_config[i]) ? "white" : "red" for i=1:nv(graph)], format=:svg) # where red vertices and white vertices are separated by the cut. diff --git a/examples/MaximalIS.jl b/examples/MaximalIS.jl index 67023fef..19f4d357 100644 --- a/examples/MaximalIS.jl +++ b/examples/MaximalIS.jl @@ -72,7 +72,7 @@ all(c->is_maximal_independent_set(graph, c), maximal_configs) # -show_gallery(graph, (3, 5); locs=locations, vertex_configs=maximal_configs, format=:svg) +show_configs(graph, locations, reshape(collect(maximal_configs), 3, 5); padding_left=20) # This result should be consistent with that given by the [Bron Kerbosch algorithm](https://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm) on the complement of Petersen graph. cliques = maximal_cliques(complement(graph)) @@ -83,7 +83,7 @@ cliques = maximal_cliques(complement(graph)) # It is the [`ConfigsMin`](@ref) property in the program. minimum_maximal_configs = solve(problem, ConfigsMin())[].c -show_gallery(graph, (2, 5); locs=locations, vertex_configs=minimum_maximal_configs, format=:svg) +show_configs(graph, locations, reshape(collect(minimum_maximal_configs), 2, 5); padding_left=20) # Similarly, if one is only interested in computing one of the minimum sets, # one can use the graph property [`SingleConfigMin`](@ref). diff --git a/examples/PaintShop.jl b/examples/PaintShop.jl index f030e06c..e5697644 100644 --- a/examples/PaintShop.jl +++ b/examples/PaintShop.jl @@ -90,9 +90,9 @@ best_configs = solve(problem, ConfigsMin())[] painting1 = paint_shop_coloring_from_config(pshop, best_configs.c.data[1]) -show_graph(graph; locs=locations, format=:svg, texts=string.(sequence), +show_graph(graph, locations; format=:svg, texts=string.(sequence), edge_colors=[sequence[e.src] == sequence[e.dst] ? "blue" : "black" for e in edges(graph)], - vertex_colors=[isone(c) ? "red" : "black" for c in painting1], vertex_text_color="white") + vertex_colors=[isone(c) ? "red" : "black" for c in painting1], config=GraphDisplayConfig(;vertex_text_color="white")) # Since we have different choices of initial color, the number of best solution is 2. diff --git a/examples/weighted.jl b/examples/weighted.jl index 0b54fa31..de26f867 100644 --- a/examples/weighted.jl +++ b/examples/weighted.jl @@ -41,5 +41,4 @@ max5_configs = solve(problem, SingleConfigMax(5))[] max5_configs.orders # Let us visually check these configurations -show_gallery(graph, (1, 5); locs=locations, format=:svg, vertex_configs=[max5_configs.orders[k].c.data for k=1:5]) - +show_configs(graph, locations, [max5_configs.orders[j].c.data for i=1:1, j=1:5]; padding_left=20) \ No newline at end of file diff --git a/src/GenericTensorNetworks.jl b/src/GenericTensorNetworks.jl index a0ebda1e..42062091 100644 --- a/src/GenericTensorNetworks.jl +++ b/src/GenericTensorNetworks.jl @@ -7,6 +7,7 @@ using OMEinsum: contraction_complexity, timespace_complexity, timespacereadwrite using Graphs, Random using DelimitedFiles, Serialization, Printf using LuxorGraphPlot +using LuxorGraphPlot.Luxor.Colors: @colorant_str import Polynomials using Polynomials: Polynomial, LaurentPolynomial, printpoly, fit using FFTW @@ -59,7 +60,7 @@ export solve, SizeMax, SizeMin, PartitionFunction, CountingAll, CountingMax, Cou export save_configs, load_configs, hamming_distribution, save_sumproduct, load_sumproduct # Visualization -export show_graph, spring_layout!, show_gallery, show_einsum +export show_graph, spring_layout!, show_configs, show_einsum, GraphDisplayConfig, Layout, render_locs project_relative_path(xs...) = normpath(joinpath(dirname(dirname(pathof(@__MODULE__))), xs...)) diff --git a/src/visualize.jl b/src/visualize.jl index 5d070ad5..8b191a02 100644 --- a/src/visualize.jl +++ b/src/visualize.jl @@ -3,16 +3,16 @@ tensor_locs=nothing, label_locs=nothing, # dict spring::Bool=true, - optimal_distance=1.0, + optimal_distance=25.0, - tensor_size=0.3, + tensor_size=15, tensor_color="black", tensor_text_color="white", annotate_tensors=false, - label_size=0.15, + label_size=7, label_color="black", - open_label_color="red", + open_label_color="black", annotate_labels=true, kwargs... ) @@ -46,7 +46,7 @@ $(LuxorGraphPlot.CONFIGHELP) function show_einsum(ein::AbstractEinsum; label_size=7, label_color="black", - open_label_color="red", + open_label_color="black", tensor_size=15, tensor_color="black", tensor_text_color="white", @@ -56,7 +56,13 @@ function show_einsum(ein::AbstractEinsum; label_locs=nothing, # dict layout::Symbol=:auto, optimal_distance=25.0, - kwargs... + filename=nothing, + format=:svg, + padding_left=10.0, + padding_right=10.0, + padding_top=10.0, + padding_bottom=10.0, + config=LuxorGraphPlot.GraphDisplayConfig(; vertex_line_width=0.0), ) ixs = getixsv(ein) iy = getiyv(ein) @@ -75,7 +81,7 @@ function show_einsum(ein::AbstractEinsum; end end if label_locs === nothing && tensor_locs === nothing - locs = LuxorGraphPlot.render_locs(graph, Layout(layout; optimal_distance, spring_mask = trues(nv(graph)))) + locs = LuxorGraphPlot.render_locs(graph, LuxorGraphPlot.Layout(layout; optimal_distance, spring_mask = trues(nv(graph)))) elseif label_locs === nothing # infer label locs from tensor locs label_locs = [(lst = [iloc for (iloc,ix) in zip(tensor_locs, ixs) if l ∈ ix]; reduce((x,y)->x .+ y, lst) ./ length(lst)) for l in labels] @@ -89,5 +95,29 @@ function show_einsum(ein::AbstractEinsum; end show_graph(GraphViz(; locs, edges=[(e.src, e.dst) for e in edges(graph)], texts, vertex_colors=colors, vertex_text_colors, - vertex_sizes=sizes); config=LuxorGraphPlot.GraphDisplayConfig(vertex_line_width=0, kwargs...)) -end \ No newline at end of file + vertex_sizes=sizes); + filename, format, + padding_left, padding_right, padding_top, padding_bottom, config + ) +end + +""" + show_configs(gp::GraphProblem, locs, configs::AbstractMatrix; kwargs...) + show_configs(graph::SimpleGraph, locs, configs::AbstractMatrix; nflavor=2, kwargs...) + +Show a gallery of configurations on a graph. +""" +function show_configs(gp::GraphProblem, locs, configs::AbstractMatrix; kwargs...) + show_configs(gp.graph, locs, configs; nflavor=nflavor(gp), kwargs...) +end +function show_configs(graph::SimpleGraph, locs, configs::AbstractMatrix; + nflavor::Int=2, + kwargs...) + cmap = range(colorant"white", stop=colorant"red", length=nflavor) + locs = render_locs(graph, locs) + graphs = map(configs) do cfg + @assert all(0 .<= cfg .<= nflavor-1) + GraphViz(graph; locs, vertex_colors=cmap[cfg .+ 1]) + end + show_gallery(graphs; kwargs...) +end diff --git a/test/Project.toml b/test/Project.toml index 8d6e033d..cdc224b7 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -3,6 +3,7 @@ CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +LuxorGraphPlot = "1f49bdf2-22a7-4bc4-978b-948dc219fbbc" OMEinsum = "ebe7aa44-baf0-506c-a96f-8464559b3922" Polynomials = "f27b6e38-b328-58d1-80ce-0feddd5e7a45" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" diff --git a/test/visualize.jl b/test/visualize.jl index c3246b4d..2747f0f5 100644 --- a/test/visualize.jl +++ b/test/visualize.jl @@ -1,8 +1,11 @@ using GenericTensorNetworks, Test, Graphs +using LuxorGraphPlot: Layout @testset "visualize" begin graph = smallgraph(:petersen) @test show_graph(graph) isa Any + configs = [rand(Bool, 10) for i=1:5, j=1:3] + @test show_configs(graph, Layout(:stress), configs) isa Any end @testset "einsum" begin