Skip to content

change maxcut to spinglass #49

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "GenericTensorNetworks"
uuid = "3521c873-ad32-4bb4-b63d-f4f178f42b49"
authors = ["GiggleLiu <cacate0129@gmail.com> and contributors"]
version = "1.0.6"
version = "1.1.0"

[deps]
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The *solution space properties* include
* The enumeration of solutions at certain sizes.
* The direct sampling of solutions at certain sizes.

The solvable problems include [Independent set problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/IndependentSet/), [Maximal independent set problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/MaximalIS/), [Cutting problem (Spin-glass problem)](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/MaxCut/), [Vertex matching problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/Matching/), [Binary paint shop problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/PaintShop/), [Coloring problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/Coloring/), [Dominating set problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/DominatingSet/), [Set packing problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/SetPacking/), [Satisfiability problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/Satisfiability/) and [Set covering problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/SetCovering/).
The solvable problems include [Independent set problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/IndependentSet/), [Maximal independent set problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/MaximalIS/), [Cutting problem (Spin-glass problem)](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/SpinGlass/), [Vertex matching problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/Matching/), [Binary paint shop problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/PaintShop/), [Coloring problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/Coloring/), [Dominating set problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/DominatingSet/), [Set packing problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/SetPacking/), [Satisfiability problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/Satisfiability/) and [Set covering problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/SetCovering/).

## Installation
<p>
Expand Down
4 changes: 2 additions & 2 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ makedocs(;
"Problems" => [
"Independent set problem" => "generated/IndependentSet.md",
"Maximal independent set problem" => "generated/MaximalIS.md",
"Cutting problem" => "generated/MaxCut.md",
"Vertex Matching problem" => "generated/Matching.md",
"Spin glass problem" => "generated/SpinGlass.md",
"Vertex matching problem" => "generated/Matching.md",
"Binary paint shop problem" => "generated/PaintShop.md",
"Coloring problem" => "generated/Coloring.md",
"Dominating set problem" => "generated/DominatingSet.md",
Expand Down
2 changes: 2 additions & 0 deletions docs/serve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ function serve(;host::String="0.0.0.0", port::Int=8000)
skip_dirs=[
joinpath("docs", "src", "assets"),
joinpath("docs", "src", "generated"),
joinpath("docs", "src", "notebooks"),
joinpath("docs", "build"),
],
literate="examples",
host=\"$host\",
Expand Down
4 changes: 2 additions & 2 deletions docs/src/performancetips.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,9 @@ The graphs in all benchmarks are random three-regular graphs, which have treewid
Panel (a) shows the time and space complexity of tensor network contraction for different graph sizes. The contraction order is obtained using the `TreeSA` algorithm that implemented in [OMEinsumContractionOrders](https://github.com/TensorBFS/OMEinsumContractionOrders.jl). If we assume our contraction-order finding program has found the optimal treewidth, which is very likely to be true, the space complexity is the same as the treewidth of the problem graph.
Slicing technique has been used for graphs with space complexity greater than ``2^{27}`` (above the yellow dashed line) to fit the computation into a 16GB memory. One can see that all the computation times in panels (b), (c), and (d) have a strong correlation with the predicted time and space complexity.
While in panel (d), the computation time of configuration enumeration also strongly correlates with other factors such as the configuration space size.
Among these benchmarks, computational tasks with data types real numbers, complex numbers, or [Tropical](@ref) numbers (CPU only) can utilize fast basic linear algebra subprograms (BLAS) functions. These tasks usually compute much faster than ones with other element types in the same category.
Among these benchmarks, computational tasks with data types real numbers, complex numbers, or [`Tropical`](@ref) numbers (CPU only) can utilize fast basic linear algebra subprograms (BLAS) functions. These tasks usually compute much faster than ones with other element types in the same category.
Immutable data types with no reference to other values can be compiled to GPU devices that run much faster than CPUs in all cases when the problem scale is big enough.
These data types do not include those defined in [Polynomial](@ref), [ConfigEnumerator](@ref), [ExtendedTropical](@ref) and [SumProductTree](@ref) or a data type containing them as a part.
These data types do not include those defined in [`Polynomial`](@ref), [`ConfigEnumerator`](@ref), [`ExtendedTropical`](@ref) and [`SumProductTree`](@ref) or a data type containing them as a part.
In panel (c), one can see the Fourier transformation-based method is the fastest in computing the independence polynomial,
but it may suffer from round-off errors. The finite field (GF(p)) approach is the only method that does not have round-off errors and can be run on a GPU.
In panel (d), one can see the technique to bound the enumeration space (see paper) improves the performance for more than one order of magnitude in enumerating the MISs. The bounding technique can also reduce the memory usage significantly, without which the largest computable graph size is only ``\sim150`` on a device with 32GB main memory.
Expand Down
3 changes: 2 additions & 1 deletion docs/src/ref.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ MaximalIS
Matching
Coloring
DominatingSet
MaxCut
SpinGlass
PaintShop
Satisfiability
SetCovering
Expand Down Expand Up @@ -43,6 +43,7 @@ is_set_covering
is_set_packing

cut_size
spinglass_energy
num_paint_shop_color_switch
paint_shop_coloring_from_config
mis_compactify!
Expand Down
44 changes: 25 additions & 19 deletions examples/MaxCut.jl → examples/SpinGlass.jl
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
# # Cutting problem (Spin-glass problem)
# # Spin-glass problem (Cutting problem)

# !!! note
# It is highly recommended to read the [Independent set problem](@ref) chapter before reading this one.

# ## Problem definition
# In graph theory, a [cut](https://en.wikipedia.org/wiki/Cut_(graph_theory)) is a partition of the vertices of a graph into two disjoint subsets.
# It is closely related to the [spin-glass](https://en.wikipedia.org/wiki/Spin_glass) problem in physics.
# Finding the maximum cut is NP-Hard, where a maximum cut is a cut whose size is at least the size of any other cut,
# Let ``G=(V, E)`` be a graph, the [spin-glass](https://en.wikipedia.org/wiki/Spin_glass) problem in physics is characterized by the following energy function
# ```math
# H = - \sum_{ij \in E} J_{ij} s_i s_j + \sum_{i \in V} h_i s_i,
# ```
# where ``h_i`` is an onsite energy term associated with spin ``s_i \in \{0, 1\}``, and ``J_{ij}`` is the coupling strength between spins ``s_i`` and ``s_j``.
#
# The spin glass problem very close related to the cutting problem in graph theory.
# A [cut](https://en.wikipedia.org/wiki/Cut_(graph_theory)) is a partition of the vertices of a graph into two disjoint subsets.
# Finding the maximum cut (the spin glass maximum energy) is NP-Hard, where a maximum cut is a cut whose size is at least the size of any other cut,
# where the size of a cut is the number of edges (or the sum of weights on edges) crossing the cut.

using GenericTensorNetworks, Graphs

# In the following, we are going to defined an cutting problem for the Petersen graph.
# In the following, we are going to defined an spin glass problem for the Petersen graph.

graph = Graphs.smallgraph(:petersen)

Expand All @@ -23,52 +29,52 @@ locations = [[rot15(0.0, 2.0, i) for i=0:4]..., [rot15(0.0, 1.0, i) for i=0:4]..
show_graph(graph; locs=locations, format=:svg)

# ## Generic tensor network representation
# We define the cutting problem as
problem = MaxCut(graph);
# We define the spin glass problem as
problem = SpinGlass(graph);

# ### Theory (can skip)
#
# For a vertex ``v\in V``, we define a boolean degree of freedom ``s_v\in\{0, 1\}``.
# Then the maximum cutting problem can be encoded to tensor networks by mapping an edge ``(i,j)\in E`` to an edge matrix labelled by ``s_is_j``
# Then the spin glass problem can be encoded to tensor networks by mapping an edge ``(i,j)\in E`` to an edge matrix labelled by ``s_is_j``
# ```math
# B(x_{\langle i, j\rangle}) = \left(\begin{matrix}
# 1 & x_{\langle i, j\rangle}^{w_{\langle i,j \rangle}}\\
# x_{\langle i, j\rangle}^{w_{\langle i,j \rangle}} & 1
# \end{matrix}\right),
# ```
# If and only if there is a cut on edge ``(i, j)``,
# If and only if the spin configuration is anti-parallel on edge ``(i, j)``,
# this tensor contributes a factor ``x_{\langle i, j\rangle}^{w_{\langle i,j \rangle}}``,
# where ``w_{\langle i,j\rangle}`` is the weight of this edge.
# Similar to other problems, we can define a polynomial about edges variables by setting ``x_{\langle i, j\rangle} = x``,
# where its k-th coefficient is two times the number of configurations of cut size k.
# where its k-th coefficient is two times the number of configurations with energy (cut size) k.

# Its contraction time space complexity is ``2^{{\rm tw}(G)}``, where ``{\rm tw(G)}`` is the [tree-width](https://en.wikipedia.org/wiki/Treewidth) of ``G``.

# ## Solving properties
# ### Maximum cut size ``\gamma(G)``
max_cut_size = solve(problem, SizeMax())[]
# ### Maximum energy ``E^*(G)``
Emax = solve(problem, SizeMax())[]

# ### Counting properties
# ##### graph polynomial
# The graph polynomial defined for the cutting problem is
# The graph polynomial defined for the spin glass problem is
# ```math
# C(G, x) = \sum_{k=0}^{\gamma(G)} c_k x^k,
# C(G, x) = \sum_{k=0}^{E^*(G)} c_k x^k,
# ```
# where ``\alpha(G)`` is the maximum independent set size,
# ``c_k/2`` is the number of cuts of size ``k`` in graph ``G=(V,E)``.
# ``c_k/2`` is the number of anti-parallel edges (cuts) of size ``k`` in graph ``G=(V,E)``.
# Since the variable ``x`` is defined on edges,
# the coefficients of the polynomial is the number of configurations having different number of anti-parallel edges.
max_config = solve(problem, GraphPolynomial())[]

# ### Configuration properties
# ##### finding one max cut solution
# ##### finding one solution with highest energy
max_vertex_config = solve(problem, SingleConfigMax())[].c.data

max_cut_size_verify = cut_size(graph, max_vertex_config)
Emax_verify = spinglass_energy(graph, max_vertex_config)

# You should see a consistent result as above `max_cut_size`.
# You should see a consistent result as above `Emax`.

show_graph(graph; locs=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.
# where a red vertice and a white vertice correspond to a spin having value 1 and 0 respectively.
4 changes: 3 additions & 1 deletion src/GenericTensorNetworks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export GraphProblem, optimize_code, NoWeight
export flavors, labels, terms, nflavor, get_weights, fixedvertices
export IndependentSet, mis_compactify!, is_independent_set
export MaximalIS, is_maximal_independent_set
export MaxCut, cut_size
export cut_size, spinglass_energy, SpinGlass
export PaintShop, paintshop_from_pairs, num_paint_shop_color_switch, paint_shop_coloring_from_config
export Coloring, is_vertex_coloring
export Satisfiability, CNF, CNFClause, BoolVar, satisfiable, @bools, ∨, ¬, ∧
Expand Down Expand Up @@ -69,6 +69,8 @@ include("deprecate.jl")
include("multiprocessing.jl")
include("visualize.jl")

Base.@deprecate MaxCut(g::SimpleGraph; weights=NoWeight(), openvertices=(), fixedvertices=Dict{Int,Int}(), optimizer=GreedyMethod(), simplifier=nothing) SpinGlass(g; edge_weights=weights, openvertices, fixedvertices, optimizer, simplifier)

using Requires
function __init__()
@require CUDA="052768ef-5323-5732-b1bb-66c8b64840ba" include("cuda.jl")
Expand Down
62 changes: 0 additions & 62 deletions src/networks/MaxCut.jl

This file was deleted.

90 changes: 90 additions & 0 deletions src/networks/SpinGlass.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
"""
SpinGlass{CT<:AbstractEinsum,WT<:Union{NoWieght, Vector}} <: GraphProblem
SpinGlass(graph; edge_weights=NoWeight(), vertex_weights=NoWeight(), openvertices=(),
optimizer=GreedyMethod(), simplifier=nothing,
fixedvertices=Dict()
)

The [spin glass](https://psychic-meme-f4d866f8.pages.github.io/dev/generated/SpinGlass.html) problem (or cutting problem).

Positional arguments
-------------------------------
* `graph` is the problem graph.

Keyword arguments
-------------------------------
* `edge_weights` are associated with the edges of the `graph`, also known as the coupling strengths in spin glasses.
* `vertex_weights` are associated with the vertices of the `graph`, also known the onsite energy term in spin glasses.
* `optimizer` and `simplifier` are for tensor network optimization, check [`optimize_code`](@ref) for details.
* `fixedvertices` is a dict to specify the values of degree of freedoms, where a value can be `0` (in one side of the cut) or `1` (in the other side of the cut).
* `openvertices` is a tuple of labels to specify the output tensor. Theses degree of freedoms will not be contracted.
"""
struct SpinGlass{CT<:AbstractEinsum,WT1<:Union{NoWeight, Vector},WT2<:Union{ZeroWeight, Vector}} <: GraphProblem
code::CT
graph::SimpleGraph{Int}
edge_weights::WT1
vertex_weights::WT2
fixedvertices::Dict{Int,Int}
end
function SpinGlass(g::SimpleGraph; edge_weights=NoWeight(), vertex_weights=ZeroWeight(), openvertices=(), fixedvertices=Dict{Int,Int}(), optimizer=GreedyMethod(), simplifier=nothing)
@assert edge_weights isa NoWeight || length(edge_weights) == ne(g)
@assert vertex_weights isa ZeroWeight || length(vertex_weights) == nv(g)
rawcode = EinCode([
map(e->[minmax(e.src,e.dst)...], Graphs.edges(g))...,
map(v->[v], Graphs.vertices(g))...,
], collect(Int, openvertices)) # labels for edge tensors
SpinGlass(_optimize_code(rawcode, uniformsize_fix(rawcode, 2, fixedvertices), optimizer, simplifier), g, edge_weights, vertex_weights, Dict{Int,Int}(fixedvertices))
end

flavors(::Type{<:SpinGlass}) = [0, 1]
# first `ne` indices are for edge weights, last `nv` indices are for vertex weights.
get_weights(gp::SpinGlass, i::Int) = i <= ne(gp.graph) ? [0, gp.edge_weights[i]] : [0, gp.vertex_weights[i-ne(gp.graph)]]
terms(gp::SpinGlass) = getixsv(gp.code)
labels(gp::SpinGlass) = [1:nv(gp.graph)...]
fixedvertices(gp::SpinGlass) = gp.fixedvertices

function generate_tensors(x::T, gp::SpinGlass) where T
ixs = getixsv(gp.code)
l = ne(gp.graph)
tensors = [
Array{T}[spinglassb((Ref(x) .^ get_weights(gp, i)) ...) for i=1:l]...,
add_labels!(Array{T}[Ref(x) .^ get_weights(gp, i+l) for i=1:nv(gp.graph)], ixs[l+1:end], labels(gp))...
]
return select_dims(tensors, ixs, fixedvertices(gp))
end

function spinglassb(a, b)
return [a b; b a]
end

"""
spinglass_energy(g::SimpleGraph, config; edge_weights=NoWeight(), vertex_weights=ZeroWeight())

Compute the spin glass state energy for the vertex configuration `config` (an iterator).
"""
function spinglass_energy(g::SimpleGraph, config; edge_weights=NoWeight(), vertex_weights=ZeroWeight())
size = zero(eltype(edge_weights)) * false
# coupling terms
for (i, e) in enumerate(edges(g))
size += (config[e.src] != config[e.dst]) * edge_weights[i]
end
# onsite terms
for (i, v) in enumerate(vertices(g))
size += config[v] * vertex_weights[i]
end
return size
end


"""
cut_size(g::SimpleGraph, config; weights=NoWeight())

Compute the cut size for the vertex configuration `config` (an iterator).
"""
function cut_size(g::SimpleGraph, config; weights=NoWeight())
size = zero(eltype(weights)) * false
for (i, e) in enumerate(edges(g))
size += (config[e.src] != config[e.dst]) * weights[i]
end
return size
end
6 changes: 5 additions & 1 deletion src/networks/networks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ struct NoWeight end
Base.getindex(::NoWeight, i) = 1
Base.eltype(::NoWeight) = Int

struct ZeroWeight end
Base.getindex(::ZeroWeight, i) = 0
Base.eltype(::ZeroWeight) = Int

######## Interfaces for graph problems ##########
"""
get_weights(problem::GraphProblem, sym) -> Vector
Expand Down Expand Up @@ -109,7 +113,7 @@ generate_tensors(::Type{GT}) where GT = length(flavors(GT))

include("IndependentSet.jl")
include("MaximalIS.jl")
include("MaxCut.jl")
include("SpinGlass.jl")
include("Matching.jl")
include("Coloring.jl")
include("PaintShop.jl")
Expand Down
Loading