Skip to content

Commit d83a5d6

Browse files
authored
Switch from Requires to extensions (#81)
* Create CUDA and GenericTensorNetworks extensions * update project version * fix document * fix documentation * prevent long vector * fix the energy mode
1 parent 849a28b commit d83a5d6

File tree

13 files changed

+123
-96
lines changed

13 files changed

+123
-96
lines changed

Project.toml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,32 @@ version = "0.4.2"
55

66
[deps]
77
Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
8-
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
98
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
10-
GenericTensorNetworks = "3521c873-ad32-4bb4-b63d-f4f178f42b49"
119
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1210
OMEinsum = "ebe7aa44-baf0-506c-a96f-8464559b3922"
1311
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
1412
PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
1513
PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
16-
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
14+
ProblemReductions = "899c297d-f7d2-4ebf-8815-a35996def416"
1715
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
1816
TropicalNumbers = "b3a74e9c-7526-4576-a4eb-79c0d4c32334"
1917

18+
[weakdeps]
19+
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
20+
21+
[extensions]
22+
TensorInferenceCUDAExt = "CUDA"
23+
2024
[compat]
2125
Artifacts = "1"
2226
CUDA = "4, 5"
2327
DocStringExtensions = "0.8.6, 0.9"
24-
GenericTensorNetworks = "2"
2528
LinearAlgebra = "1"
2629
OMEinsum = "0.8"
2730
Pkg = "1"
2831
PrecompileTools = "1"
2932
PrettyTables = "2"
30-
Requires = "1"
33+
ProblemReductions = "0.3"
3134
StatsBase = "0.34"
3235
TropicalNumbers = "0.5.4, 0.6"
33-
julia = "1.3"
36+
julia = "1.9"

benchmark/bench_map.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ using Artifacts
66

77
const SUITE = BenchmarkGroup()
88

9-
problem = problem_from_artifact("uai2014", "MAR" "Promedus", 14)
9+
problem = problem_from_artifact("uai2014", "MAR", "Promedus", 14)
1010

1111
optimizer = TreeSA(ntrials = 1, niters = 2, βs = 1:0.1:40)
1212
tn = TensorNetworkModel(read_model(problem); optimizer, evidence=get_evidence(problem))

docs/Project.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
[deps]
22
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
3-
GenericTensorNetworks = "3521c873-ad32-4bb4-b63d-f4f178f42b49"
3+
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
44
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
55
LiveServer = "16fef848-5104-11e9-1b77-fb7a48bbb589"
6+
LuxorGraphPlot = "1f49bdf2-22a7-4bc4-978b-948dc219fbbc"
7+
ProblemReductions = "899c297d-f7d2-4ebf-8815-a35996def416"
68
TensorInference = "c2297e78-99bd-40ad-871d-f50e56b81012"
79
TikzPictures = "37f6aa50-8035-52d0-81c2-5a1d08754b2d"

examples/hard-core-lattice-gas/main.jl

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,17 @@
1515

1616
a, b = (1, 0), (0.5, 0.5*sqrt(3))
1717
Na, Nb = 10, 10
18-
sites = vec([50 .* (a .* i .+ b .* j) for i=1:Na, j=1:Nb])
18+
sites = vec([50 .* (a .* i .+ b .* j) for i=1:Na, j=1:Nb]);
1919

2020
# There exists blockade interactions between hard-core particles.
2121
# We connect two lattice sites within blockade radius by an edge.
2222
# Two ends of an edge can not both be occupied by particles.
23-
blockade_radius = 55
24-
using GenericTensorNetworks: show_graph, unit_disk_graph
25-
using GenericTensorNetworks.Graphs: edges, nv
26-
graph = unit_disk_graph(vec(sites), blockade_radius)
27-
show_graph(graph, sites; texts=fill("", length(sites)))
23+
blockade_radius = 55.0
24+
using LuxorGraphPlot: show_graph, GraphDisplayConfig
25+
using Graphs: edges, nv, SimpleGraph
26+
using TensorInference.ProblemReductions: UnitDiskGraph, IndependentSet
27+
graph = UnitDiskGraph(vec(sites), blockade_radius)
28+
show_graph(SimpleGraph(graph), sites; texts=fill("", length(sites)))
2829

2930
# These constraints defines an independent set problem that characterized by the following energy based model.
3031
# Let $G = (V, E)$ be a graph, where $V$ is the set of vertices and $E$ is the set of edges.
@@ -38,7 +39,6 @@ show_graph(graph, sites; texts=fill("", length(sites)))
3839
# The solution space hard-core lattice gas is equivalent to that of an independent set problem.
3940
# The independent set problem involves finding a set of vertices in a graph such that no two vertices in the set are adjacent (i.e., there is no edge connecting them).
4041
# One can create a tensor network based modeling of an independent set problem with package [`GenericTensorNetworks.jl`](https://github.com/QuEraComputing/GenericTensorNetworks.jl).
41-
using GenericTensorNetworks
4242
problem = IndependentSet(graph)
4343

4444
# There are plenty of discussions related to solution space properties in the `GenericTensorNetworks` [documentaion page](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/IndependentSet/).
@@ -59,14 +59,14 @@ partition_func[]
5959

6060
# The marginal probabilities can be computed with the [`marginals`](@ref) function, which measures how likely a site is occupied.
6161
mars = marginals(pmodel)
62-
show_graph(graph, sites; vertex_colors=[(b = mars[[i]][2]; (1-b, 1-b, 1-b)) for i in 1:nv(graph)], texts=fill("", nv(graph)))
62+
show_graph(SimpleGraph(graph), sites; vertex_colors=[(b = mars[[i]][2]; (1-b, 1-b, 1-b)) for i in 1:nv(graph)], texts=fill("", nv(graph)))
6363
# The can see the sites at the corner is more likely to be occupied.
6464
# To obtain two-site correlations, one can set the variables to query marginal probabilities manually.
6565
pmodel2 = TensorNetworkModel(problem, β; mars=[[e.src, e.dst] for e in edges(graph)])
6666
mars = marginals(pmodel2);
6767

6868
# We show the probability that both sites on an edge are not occupied
69-
show_graph(graph, sites; edge_colors=[(b = mars[[e.src, e.dst]][1, 1]; (1-b, 1-b, 1-b)) for e in edges(graph)], texts=fill("", nv(graph)), config=GraphDisplayConfig(; edge_line_width=5))
69+
show_graph(SimpleGraph(graph), sites; edge_colors=[(b = mars[[e.src, e.dst]][1, 1]; (1-b, 1-b, 1-b)) for e in edges(graph)], texts=fill("", nv(graph)), config=GraphDisplayConfig(; edge_line_width=5))
7070

7171
# ## The most likely configuration
7272
# The MAP and MMAP can be used to get the most likely configuration given an evidence.
@@ -77,7 +77,7 @@ mars = marginals(pmodel3)
7777
logp, config = most_probable_config(pmodel3)
7878

7979
# The log probability is 102. Let us visualize the configuration.
80-
show_graph(graph, sites; vertex_colors=[(1-b, 1-b, 1-b) for b in config], texts=fill("", nv(graph)))
80+
show_graph(SimpleGraph(graph), sites; vertex_colors=[(1-b, 1-b, 1-b) for b in config], texts=fill("", nv(graph)))
8181
# The number of particles is
8282
sum(config)
8383

@@ -86,7 +86,7 @@ pmodel3 = TensorNetworkModel(problem, β; evidence=Dict(1=>0))
8686
logp2, config2 = most_probable_config(pmodel)
8787

8888
# The log probability is 99, which is much smaller.
89-
show_graph(graph, sites; vertex_colors=[(1-b, 1-b, 1-b) for b in config2], texts=fill("", nv(graph)))
89+
show_graph(SimpleGraph(graph), sites; vertex_colors=[(1-b, 1-b, 1-b) for b in config2], texts=fill("", nv(graph)))
9090
# The number of particles is
9191
sum(config2)
9292

src/cuda.jl renamed to ext/TensorInferenceCUDAExt.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
using .CUDA: CuArray
1+
module TensorInferenceCUDAExt
2+
using CUDA: CuArray
3+
import CUDA
4+
import TensorInference: match_arraytype, keep_only!, onehot_like, togpu
25

36
function onehot_like(A::CuArray, j)
47
mask = zero(A)
@@ -15,3 +18,7 @@ function keep_only!(x::CuArray{T}, j) where T
1518
CUDA.@allowscalar x[j] = hotvalue
1619
return x
1720
end
21+
22+
togpu(x::AbstractArray) = CuArray(x)
23+
24+
end

src/TensorInference.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ using DocStringExtensions, TropicalNumbers
1212
# The Tropical GEMM support
1313
using StatsBase
1414
using PrettyTables
15+
using ProblemReductions
16+
1517
import Pkg
1618

1719
# reexport OMEinsum functions
@@ -35,6 +37,9 @@ export sample
3537
# MMAP
3638
export MMAPModel
3739

40+
# for ProblemReductions
41+
export update_temperature
42+
3843
# utils
3944
export random_matrix_product_state
4045

@@ -45,12 +50,7 @@ include("mar.jl")
4550
include("map.jl")
4651
include("mmap.jl")
4752
include("sampling.jl")
48-
49-
using Requires
50-
function __init__()
51-
@require CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" include("cuda.jl")
52-
@require GenericTensorNetworks = "3521c873-ad32-4bb4-b63d-f4f178f42b49" include("generictensornetworks.jl")
53-
end
53+
include("cspmodels.jl")
5454

5555
# import PrecompileTools
5656
# PrecompileTools.@setup_workload begin

src/cspmodels.jl

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# generate the tensors for the constraint satisfaction problem
2+
function generate_tensors::T, problem::ConstraintSatisfactionProblem) where T <: Real
3+
cons = ProblemReductions.constraints(problem)
4+
objs = ProblemReductions.objectives(problem)
5+
ixs = vcat([t.variables for t in cons], [t.variables for t in objs])
6+
# generate tensors for x = e^β
7+
x = energy_mode(problem) === LargerSizeIsBetter() ? exp(β) : exp(-β)
8+
tensors = vcat(
9+
Array{T}[reshape(map(s -> s ? one(x) : zero(x), t.specification), ntuple(i->num_flavors(problem), length(t.variables))) for t in cons],
10+
Array{T}[reshape(map(s -> x^s, t.specification), ntuple(i->num_flavors(problem), length(t.variables))) for t in objs]
11+
)
12+
return tensors, ixs
13+
end
14+
15+
"""
16+
$TYPEDSIGNATURES
17+
18+
Convert a constraint satisfiability problem (or energy model) to a probabilistic model.
19+
20+
### Arguments
21+
* `problem` is a `ConstraintSatisfactionProblem` instance in [`ProblemReductions`](https://github.com/GiggleLiu/ProblemReductions.jl).
22+
* `β` is the inverse temperature.
23+
24+
### Keyword Arguments
25+
* `evidence` is a dictionary mapping variables to their values.
26+
* `optimizer` is the optimizer used to optimize the tensor network.
27+
* `openvars` is the list of variables to be marginalized.
28+
* `mars` is the list of variables to be marginalized.
29+
"""
30+
function TensorNetworkModel(problem::ConstraintSatisfactionProblem, β::T; evidence::Dict=Dict{Int,Int}(),
31+
optimizer=GreedyMethod(), openvars=Int[], simplifier=nothing, mars=[[l] for l in variables(problem)]) where T <: Real
32+
tensors, ixs = generate_tensors(β, problem)
33+
factors = [Factor((ix...,), t) for (ix, t) in zip(ixs, tensors)]
34+
return TensorNetworkModel(variables(problem), fill(num_flavors(problem), num_variables(problem)), factors; openvars, evidence, optimizer, simplifier, mars)
35+
end
36+
37+
"""
38+
$TYPEDSIGNATURES
39+
40+
Update the temperature of a tensor network model.
41+
The program will regenerate tensors from the problem, without repeated optimizing the contraction order.
42+
43+
### Arguments
44+
- `tnet` is the [`TensorNetworkModel`](@ref) instance.
45+
- `problem` is the target constraint satisfiability problem.
46+
- `β` is the inverse temperature.
47+
"""
48+
function update_temperature(tnet::TensorNetworkModel, problem::ConstraintSatisfactionProblem, β::Real)
49+
tensors, ixs = generate_tensors(β, problem)
50+
alltensors = [tnet.tensors[1:length(tnet.mars)]..., tensors...]
51+
return TensorNetworkModel(tnet.vars, tnet.code, alltensors, tnet.evidence, tnet.mars)
52+
end
53+
54+
function MMAPModel(problem::ConstraintSatisfactionProblem, β::Real;
55+
queryvars,
56+
openvars = Int[],
57+
evidence = Dict{Int, Int}(),
58+
optimizer = GreedyMethod(), simplifier = nothing,
59+
marginalize_optimizer = GreedyMethod(), marginalize_simplifier = nothing
60+
)::MMAPModel
61+
# generate tensors for x = e^β
62+
tensors, ixs = generate_tensors(β, problem)
63+
factors = [Factor((ix...,), t) for (ix, t) in zip(ixs, tensors)]
64+
return MMAPModel(variables(problem), fill(num_flavors(problem), num_variables(problem)), factors; queryvars, openvars, evidence,
65+
optimizer, simplifier,
66+
marginalize_optimizer, marginalize_simplifier)
67+
end
68+
function update_temperature(tnet::MMAPModel, problem::ConstraintSatisfactionProblem, β::Real)
69+
error("We haven't got time to implement setting temperatures for `MMAPModel`.
70+
It is about one or two hours of works. If you need it, please file an issue to let us know: https://github.com/TensorBFS/TensorInference.jl/issues")
71+
end

src/generictensornetworks.jl

Lines changed: 0 additions & 66 deletions
This file was deleted.

src/mar.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ function adapt_tensors(code, tensors, evidence; usecuda, rescale)
77
map(tensors, ixs) do t, ix
88
dims = map(ixi -> ixi keys(evidence) ? Colon() : ((evidence[ixi] + 1):(evidence[ixi] + 1)), ix)
99
t2 = t[dims...]
10-
t3 = usecuda ? CuArray(t2) : t2
10+
t3 = usecuda ? togpu(t2) : t2
1111
rescale ? rescale_array(t3) : t3
1212
end
1313
end

src/utils.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ function get_artifact_path(artifact_name::String)
306306
return Pkg.Artifacts.artifact_path(artifact_hash)
307307
end
308308

309+
togpu(x) = error("You must import CUDA with `using CUDA` before using GPU!")
310+
309311
"""
310312
$TYPEDSIGNATURES
311313

test/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ KaHyPar = "2a6221f6-aa48-11e9-3542-2d9e0ef01880"
66
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
77
OMEinsum = "ebe7aa44-baf0-506c-a96f-8464559b3922"
88
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
9+
ProblemReductions = "899c297d-f7d2-4ebf-8815-a35996def416"
910
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1011
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
1112
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

test/generictensornetworks.jl renamed to test/cspmodels.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Test
2-
using GenericTensorNetworks, TensorInference
2+
using TensorInference, ProblemReductions.Graphs
3+
using GenericTensorNetworks
34

45
@testset "marginals" begin
56
# compute the probability
@@ -24,4 +25,10 @@ using GenericTensorNetworks, TensorInference
2425
model = MMAPModel(problem, β; queryvars=[1,4])
2526
logp, config = most_probable_config(model)
2627
@test config == [0, 0]
28+
29+
β = 1.0
30+
problem = SpinGlass(g, -ones(Int, ne(g)), zeros(Int, nv(g)))
31+
model = TensorNetworkModel(problem, β; mars=[[2, 3]])
32+
samples = sample(model, 100)
33+
@test sum(energy.(Ref(problem), samples))/100 <= -14
2734
end

test/runtests.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ end
2020
include("sampling.jl")
2121
end
2222

23-
@testset "generic tensor networks" begin
24-
include("generictensornetworks.jl")
23+
@testset "cspmodels" begin
24+
include("cspmodels.jl")
2525
end
2626

2727
using CUDA

0 commit comments

Comments
 (0)