Skip to content

Commit

Permalink
Ad/docs (#9)
Browse files Browse the repository at this point in the history
* fix typos

* add docs

* WIP

* work in progress

* Work in Progress

* work in progress

* Almost done

* Finishing touches

---------

Co-authored-by: annamariadziubyna <[email protected]>
Co-authored-by: tomsmierz <[email protected]>
  • Loading branch information
3 people authored Mar 12, 2023
1 parent 8dc2443 commit 75227d9
Show file tree
Hide file tree
Showing 8 changed files with 304 additions and 16 deletions.
15 changes: 15 additions & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Documenter, SpinGlassNetworks

_pages = [
"Introduction" => "index.md",
"User guide" => "userguide.md",
"API Reference" => "api.md"
]

# ============================

makedocs(
sitename="SpinGlassNetworks",
modules = [SpinGlassNetworks],
pages = _pages
)
36 changes: 36 additions & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Library

---

```@meta
CurrentModule = SpinGlassNetworks
```

## Ising Graphs

```@docs
ising_graph
biases
couplings
cluster
prune
rank_vec
```

## Factor Graphs

```@docs
factor_graph
decode_factor_graph_state
```

## Auxiliary Functions

```@docs
brute_force
energy
full_spectrum
gibbs_tensor
rank_reveal
super_square_lattice
```
6 changes: 6 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# SpinGlassNetworks

A [Julia](http://julialang.org) package for building and interacting with Ising spin glass models in context of tensor networks. Part of [SpinGlassPEPS](https://github.com/euro-hpc-pl/SpinGlassPEPS.jl) package.



122 changes: 122 additions & 0 deletions docs/src/userguide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Introduction
This section provides examples of how to use the 'ising_graph' function to generate an Ising model graph and the 'factor_graph' function to convert the Ising graph into a factor graph.

# Ising Graph
The Ising model is a mathematical model used to describe the behavior of interacting particles, such as atoms or molecules, in a magnetic field. In the Ising model, each particle is represented as a binary variable $s_i$ that can take on the values of either +1 or -1. The total energy of the system is given by the Hamiltonian:

$$H = \sum_{(i,j) \in \mathcal{E}} J_{ij} s_i s_j + \sum_{i} h_i s_i$$

where $J_{ij}$ is the coupling constant between particles $i$ and $j$, $h_i$ is the external magnetic field at particle $i$, and the sum is taken over all pairs of particles and all particles in the system $\mathcal{E}$, respectively.


## simple examle
```@example
using SpinGlassNetworks
# Create Ising instance
instance = Dict((1, 1) => 1.0, (2, 2) => 0.5, (3, 3) => -0.25,
(1, 2) => -1.0, (2, 3) => 1.0)
# Generate Ising graph
ig = ising_graph(instance)
# View graph properties
@show biases(ig), couplings(ig)
```

## Generalisation

The 'ising_graph' function is quite general function. One can easly convert instance into another hamiltonian convention, ex.
```math
H = - \sum_{(i,j) \in \mathcal{E}} J_{ij} s_i s_j - \mu \sum_{i} h_i s_i
```
This conversion is directed by `sgn` parameter of `ising_graph`. It is wort doing, because then all `energy` functions will work as one intended.
```@example
using SpinGlassNetworks, LabelledGraphs
# lets define simple Ising system
instance = Dict((1,1) => 1.0, (2, 2) => -1.0, (1, 2) => -1.25)
ig = ising_graph(instance)
# use above convention
μ = 0.25
sgn = -1
# absorb μ into h and construct ising graph and
instance2 = Dict((1,1) => instance[(1,1)]*μ, (2, 2) => instance[(2,2)]*μ, (1, 2) => -1.25)
ig2 = ising_graph(instance2, sgn=sgn)
# select arbitrary state
σ = [1, 1]
println("energy without conversion: ", energy(σ, ig),
" energy after conversion: ", energy(σ, ig2))
```

'ising_graph' also allows for building other spin system, not only spin-``\frac{1}{2}`` system. For example one may build chain where sites allows for 3 spin values.

```@example
using SpinGlassNetworks
# Create spin chain instance
instance = Dict((1, 1) => 1.0, (2, 2) => 0.5, (3, 3) => -0.25,
(1, 2) => -1.0, (2, 3) => 1.0)
rank_override = Dict(1 => 3, 2 => 3, 3 => 3)
sg = ising_graph(instance, rank_override=rank_override)
# see ranks of each site
rank_vec(sg)
```

# factor graph

A factor graph is a graphical representation that allows for a convenient and intuitive way to describe the structure of a tensor network.

A factor graph consists of two types of nodes: variable nodes and factor nodes. Variable nodes represent the tensors in the tensor network, and factor nodes represent the operations that are applied to those tensors.

Each variable node in the factor graph corresponds to a tensor in the tensor network, and each factor node corresponds to a tensor contraction or operation that is applied to one or more of those tensors. The edges between the nodes in the factor graph represent the indices that are shared between the corresponding tensors in the tensor network.

## Simple example

```@example
using SpinGlassNetworks
# Prepare simple instance
instance = Dict((1, 1) => 1.0, (2, 2) => 0.5, (3, 3) => -0.25,
(1, 2) => -1.0, (2, 3) => 1.0)
ig = ising_graph(instance)
# Create factor graph.
fg = factor_graph(
ig,
cluster_assignment_rule = super_square_lattice((3, 1, 1))
)
```

## Chimera graphs
The Chimera graph is a type of graph architecture used in quantum computing systems, particularly in the quantum annealing machines developed by D-Wave Systems. It is a two-dimensional lattice of unit cells, each consisting of a bipartite graph of $K_{4,4}$ complete bipartite subgraphs. Futer details can be found [here](https://docs.dwavesys.com/docs/latest/c_gs_4.html#chimera-graph).


```@example
using SpinGlassEngine, SpinGlassNetworks, LabelledGraphs
# load Chimera instance and create Ising graph
instance = "$(@__DIR__)/../../src/instances/chimera_droplets/128power/001.txt"
ig = ising_graph(instance)
# Loaded instance is 4x4x8 chimera graph
m = 4
n = 4
t = 8
fg = fg = factor_graph(
ig,
cluster_assignment_rule = super_square_lattice((m, n, t))
)
println("Number of nodes in oryginal instance: ", length(LabelledGraphs.vertices(ig)), "\n",
" Number of nodes in factor graph: ", length(LabelledGraphs.vertices(fg)))
```
39 changes: 37 additions & 2 deletions src/factor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,28 @@ function factor_graph(
)
end

function factor_graph(
"""
factor_graph(
ig::IsingGraph,
num_states_cl::Dict;
spectrum::Function = full_spectrum,
cluster_assignment_rule::Dict) where {T}
Constructs a factor graph representation of the given `IsingGraph`.
# Arguments
- `ig::IsingGraph`: The Ising graph to convert to a factor graph.
- `num_states_cl::Dict` : A dictionary mapping each cluster to the number of states it can take on. If given empty dictionary
function will try to interfere number of states for each cluster. Can be also given as `Int`, then each cluster will have
specified number of states. If ommited completly, function will behave as if an empy directory was passed.
- `spectrum::Function`: A function that computes the spectrum (i.e., list of energies of all possible states) of
a given cluster. The default is `full_spectrum`, which computes the spectrum exactly.
- `cluster_assignment_rule::Dict`: A dictionary that assigns each vertex of the Ising graph to a cluster.
# Output
A `LabelledGraph` that represents the factor graph of the Ising graph.
"""
function factor_graph(
ig::IsingGraph,
num_states_cl::Dict{T,Int};
spectrum::Function = full_spectrum,
Expand Down Expand Up @@ -64,7 +85,8 @@ function factor_graph(
end
end
fg
end
end


function factor_graph(
ig::IsingGraph;
Expand All @@ -79,6 +101,15 @@ function factor_graph(
)
end

"""
rank_reveal(energy, order = :PE)
calculate the rank of the matrix represented by `energy`, and returns a tuple of two matrices `P` and `E`,
where `P` is a binary matrix that reveals the rank of `energy`, and `E` is the set of non-zero singular
values of `energy` in decreasing order. Argument `order=:PE` specifies the order of the output matrices.
The default is `:PE`, which means that the `P` matrix is returned first, followed by the `E` matrix.
If `order` is set to `:EP`, the order is reversed.
"""
function rank_reveal(energy, order = :PE)
@assert order (:PE, :EP)
dim = order == :PE ? 1 : 2
Expand All @@ -98,7 +129,11 @@ function rank_reveal(energy, order = :PE)
order == :PE ? (P, E) : (E, P)
end

"""
decode_factor_graph_state(fg, state::Vector{Int})
Convert factor graphs clusters states into state of the original Ising system.
"""
function decode_factor_graph_state(fg, state::Vector{Int})
ret = Dict{Int,Int}()
for (i, vert) zip(state, vertices(fg))
Expand Down
49 changes: 45 additions & 4 deletions src/ising.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,29 @@ const Instance = Union{String,Dict}
unique_nodes(ising_tuples) =
sort(collect(Set(Iterators.flatten((i, j) for (i, j, _) ising_tuples))))



const IsingGraph = LabelledGraph{MetaGraph{Int64,Float64},Int64}

"""
$(TYPEDSIGNATURES)
ising_graph(instance, sgn::Number = 1.0, rank_override::Dict{Int,Int} = Dict{Int,Int}())
Create an Ising model graph from an input `instance``.
Create the Ising spin glass model.
# Arguments
- `instance`: Instance of the Ising spin glass system. Can be given eiter as dictionary or a CSV file.
- `sgn::Number`: decides the used convention for the energy sum
- `rank_override`: Dict{Int,Int}
# Details
# Output
A `LabelledGraph` that represents inputed Ising instance.
Store extra information
# Example
```@example
instance = Dict((1, 1) => 0.5, (2, 2) => 0.75, (3, 3) => -0.25, (1, 2) => -1.0, (2, 3) => 1.0)
ig = ising_graph(instance)
```
"""
function ising_graph(
instance::Instance;
Expand Down Expand Up @@ -58,10 +71,27 @@ function ising_graph(
ig
end

"""
rank_vec(ising_graph)
Return vector of 'ranks' of nodes. In this context rank tels us how many spins values node can have.
"""
rank_vec(ig::IsingGraph) = Int[get_prop((ig), v, :rank) for v vertices(ig)]
basis_size(ig::IsingGraph) = prod(prod(rank_vec(ig)))

"""
biases(ising_graph)
Return vector of biases of ising model defined by given 'ising_graph'.
"""
biases(ig::IsingGraph) = get_prop.(Ref(ig), vertices(ig), :h)

"""
couplings(ising_graph)
Return couplings of ising model defined by given 'ising_graph'.
The couplings are presented as an uper-triangular matrix
"""
function couplings(ig::IsingGraph)
J = zeros(nv(ig), nv(ig))
for edge in edges(ig)
Expand All @@ -71,6 +101,11 @@ function couplings(ig::IsingGraph)
J
end

"""
cluster(ig::IsingGraph, verts)
Return cluster specified by `verts`
"""
cluster(ig::IsingGraph, verts) = induced_subgraph(ig, collect(verts))

function inter_cluster_edges(ig::IsingGraph, cl1::IsingGraph, cl2::IsingGraph)
Expand All @@ -85,6 +120,12 @@ function inter_cluster_edges(ig::IsingGraph, cl1::IsingGraph, cl2::IsingGraph)
outer_edges, J
end


"""
prune(ising_graph)
Return copy of 'ising_graph' with removed isolated vertices.
"""
function prune(ig::IsingGraph)
to_keep = vcat(
findall(!iszero, degree(ig)),
Expand Down
8 changes: 8 additions & 0 deletions src/lattice.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ function super_square_lattice(size::NTuple{5,Int})
Dict(old[k, uj, j, ui, i] => (i, j) for i = 1:m, ui = 1:um, j = 1:n, uj = 1:un, k = 1:t)
end

"""
super_square_lattice(size::NTuple{3,Int})
Create cluster assignment rule for Chimera architecture. The input is asumed to have form `(m, n, t)` where `m` is number of
columns, `n` number of rows and `t` is the size of the shore within each Chimera tile
([details](https://docs.ocean.dwavesys.com/en/stable/docs_dnx/reference/generated/dwave_networkx.chimera_graph.html)).
If `t=1` then this assigment rule can be used for square lattice, where every site will form its own unit cell.
"""
function super_square_lattice(size::NTuple{3,Int})
m, n, t = size
super_square_lattice((m, 1, n, 1, t))
Expand Down
Loading

0 comments on commit 75227d9

Please sign in to comment.