diff --git a/Project.toml b/Project.toml index f69a008..06f8bd0 100644 --- a/Project.toml +++ b/Project.toml @@ -1,8 +1,10 @@ name = "SpinGlassPEPS" uuid = "2c514f87-1261-494e-8566-326879aaf4fe" -version = "1.3.0" +version = "1.4.0" [deps] +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +DocumenterTools = "35a29f4d-8980-5a13-9543-d66fff28ecb8" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" SpinGlassEngine = "0563570f-ea1b-4080-8a64-041ac6565a4e" SpinGlassExhaustive = "a894d7c4-7f54-4100-9d77-d00d924adeb3" @@ -11,9 +13,9 @@ SpinGlassTensors = "7584fc6a-5a23-4eeb-8277-827aab0146ea" [compat] Reexport = "1.0" -SpinGlassEngine = "1.4.0" +SpinGlassEngine = "1.5.0" SpinGlassExhaustive = "1.0.0" -SpinGlassNetworks = "1.2.0" +SpinGlassNetworks = "1.3.0" SpinGlassTensors = "1.1.3" julia = "1.10" diff --git a/docs/src/algorithm.md b/docs/src/algorithm.md index e9cc3d2..e712551 100644 --- a/docs/src/algorithm.md +++ b/docs/src/algorithm.md @@ -16,7 +16,7 @@ We assume that graph $\mathcal{E}$ forms a quasi-2D lattice. In real life applic ```@raw html ``` -In order to adress this three types of geometries using tensor networks, we represent the problem as a clustered Hamiltonian. To that end we group together sets of variables. In this framework Ising problem translates to: +In order to adress this three types of geometries using tensor networks, we represent the problem as a Potts Hamiltonian. To that end we group together sets of variables. In this framework Ising problem translates to: ```math H(\underline{x}_{\bar{N}}) = \sum_{\langle m,n\rangle \in \mathcal{F}} E_{x_m x_n} + \sum_{n=1}^{\bar{N}} E_{x_n} ``` diff --git a/docs/src/images/algorithm.png b/docs/src/images/algorithm.png index 65907de..6ed71f8 100644 Binary files a/docs/src/images/algorithm.png and b/docs/src/images/algorithm.png differ diff --git a/docs/src/images/clustering.png b/docs/src/images/clustering.png index 999f783..454e0b1 100644 Binary files a/docs/src/images/clustering.png and b/docs/src/images/clustering.png differ diff --git a/docs/src/images/lattice.png b/docs/src/images/lattice.png index 5ece9f0..3685161 100644 Binary files a/docs/src/images/lattice.png and b/docs/src/images/lattice.png differ diff --git a/docs/src/index.md b/docs/src/index.md index 2918912..a0d5ce3 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,5 +1,5 @@ ```@meta -Author = "Krzysztof Domino, Bartłomiej Gardas, Konrad Jałowiecki, Łukasz Pawela, Marek Rams, Anna Dziubyna, Tomasz Śmierzchalski" +Author = "Tomasz Śmierzchalski, Anna M. Dziubyna, Konrad Jałowiecki, Zakaria Mzaouali, Łukasz Pawela, Bartłomiej Gardas and Marek M. Rams" ``` # Welcome to SpinGlassPEPS.jl documentation! @@ -19,16 +19,17 @@ using Pkg; Pkg.add("SpinGlassPEPS") ``` The package `SpinGlassPEPS.jl` includes: +* `SpinGlassEngine.jl` - Package containing the solver itself and tools focused on finding and operating on excitations. +* `SpinGlassNetworks.jl` - Package containing all tools needed to construct an Ising graph from a given instance and create Potts Hamiltonian. * `SpinGlassTensors.jl` - Package containing all necessary functionalities for creating and operating on tensors. It allows the use of both CPU and GPU. -* `SpinGlassNetworks.jl` - Package containing all tools needed to construct a tensor network from a given instance. -* `SpinGlassEngine.jl` - Package containing the solver itself and tools focused on finding and operating on droplets. + ```@raw html ``` ## Our goals -`SpinGlassPEPS.jl` was created to heuristically solve Ising-type optimization problems defined on quasi-2D lattices or Random Markov Fields (RMF) on 2D rectangular lattices. This package combines advanced heuristics to address optimization challenges and employs tensor network contractions to compute conditional probabilities to identify the most probable states according to the Gibbs distribution. `SpinGlassPEPS.jl` is a tool for reconstructing the low-energy spectrum of Ising spin glass Hamiltonians and RMF Hamiltonians. Beyond energy computations, the package offers insights into spin configurations, associated probabilities, and retains the largest discarded probability during the branch and bound optimization procedure. Notably, `SpinGlassPEPS.jl` goes beyond ground states, introducing a unique feature for identifying and analyzing spin glass droplets — collective excitations crucial for understanding system dynamics beyond the fundamental ground state configurations. +`SpinGlassPEPS.jl` was created to heuristically solve Ising-type optimization problems defined on quasi-2D lattices or Random Markov Fields (RMF) on 2D rectangular lattices. This package combines advanced heuristics to address optimization challenges and employs tensor network contractions to compute conditional probabilities to identify the most probable states according to the Gibbs distribution. `SpinGlassPEPS.jl` is a tool for reconstructing the low-energy spectrum of Ising spin glass Hamiltonians and RMF Hamiltonians. Beyond energy computations, the package offers insights into spin configurations, associated probabilities, and retains the largest discarded probability during the branch and bound optimization procedure. Notably, `SpinGlassPEPS.jl` goes beyond ground states, introducing a feature for identifying and analyzing spin glass droplets — collective excitations crucial for understanding system dynamics beyond the fundamental ground state configurations. ```@raw html ``` @@ -36,7 +37,8 @@ The package `SpinGlassPEPS.jl` includes: ## Citing SpinGlassPEPS.jl If you use `SpinGlassPEPS.jl` for academic research and wish to cite it, please use the following paper: -K. Jałowiecki, K. Domino, A. M. Dziubyna, M. M. Rams, B. Gardas and Ł. Pawela, *“SpinGlassPEPS.jl: software to emulate quantum annealing processors”* +Tomasz Śmierzchalski, Anna M. Dziubyna, Konrad Jałowiecki, Zakaria Mzaouali, Łukasz Pawela, Bartłomiej Gardas and Marek M. Rams, +*“SpinGlassPEPS.jl: low-energy solutions for near-term quantum annealers"* ## Contributing Contributions are always welcome: diff --git a/docs/src/intro.md b/docs/src/intro.md index 56e1e82..eb281bc 100644 --- a/docs/src/intro.md +++ b/docs/src/intro.md @@ -1,161 +1,167 @@ # Getting started -Before providing the documentation of the offered functionality, it is good to demonstrate exactly what the package does. +Before diving into the documentation for the provided functionalities, let's demonstrate the core capabilities of this package through a practical example. ## Basic example -In this example, we demonstrate how to use the `SpinGlassPEPS.jl` package to obtain a low-energy spectrum for a spin glass Hamiltonian defined on a square lattice with diagonal interactions on 100 spins. Let's discuss the main steps of the code. +In this example, we demonstrate how to use the `SpinGlassPEPS.jl` package to calculate a low-energy spectrum for a spin glass Hamiltonian defined on a square lattice with diagonal interactions. -The first line ```@julia -instance = "$(@__DIR__)/../src/instances/square_diagonal/5x5/diagonal.txt" -``` -reads instance that is provided in txt format. +using SpinGlassEngine +using SpinGlassNetworks -Next line defines the problem size -```@julia -m, n, t = 5, 5, 4 -``` -In this example, number of columns and row, `m` and `n` respectively, is equal 5. Parameter `t` tells how many spins are creating a cluster. +function get_instance(topology::NTuple{3, Int}) + m, n, t = topology + "$(@__DIR__)/instances/square_diagonal/$(m)x$(n)x$(t).txt" +end -`SpinGlassPEPS.jl` enables to perform calculations not only on CPU, but also on GPU. If you want to switch on GPU mode, then type -```@julia -onGPU = true -``` +function run_square_diag_bench(::Type{T}; topology::NTuple{3, Int}) where {T} + m, n, _ = topology + instance = get_instance(topology) + lattice = super_square_lattice(topology) -The next part of the code contains parmeters which user should provide before starting the calculations. -The main parameter is temperature, given as the inverse of temperature. -```@julia -β = 1.0 -``` -A higher `β` lets us focus more on low-energy states, but it might make the numerical stability of tensor network contraction a bit shaky. Figuring out the best β depends on the problem, and we might need to try different values in experiments for various instances. + hamming_dist = 5 + eng = 10 -Subsequently, the user can input parameters that will be utilized in exploring the state space, such as the cutoff probability for terminating the search `δp` and the maximum number of states considered during the search (`num_states`). -```@julia -# Search parameters -δp = 0 # The cutoff probability for terminating the search -num_states = 20 # The maximum number of states to be considered during the search -``` + best_energies = T[] -Another group of parameters describes the method of contracting the network using the boundary MPS-MPO approach. -```@julia -bond_dim = 12 # Bond dimension -max_num_sweeps = 10 # Maximal number of sweeps during variational compression -tol_var = 1E-16 # The tolerance for the variational solver used in MPS optimization -tol_svd = 1E-16 # The tolerance used in singular value decomposition (SVD) -iters_svd = 2 # The number of iterations to perform in SVD computations -iters_var = 1 # The number of iterations for variational optimization -dtemp_mult = 2 # A multiplier for the bond dimension -method = :psvd_sparse # The SVD method to use -``` + potts_h = potts_hamiltonian( + ising_graph(instance), + spectrum = full_spectrum, + cluster_assignment_rule = lattice, + ) -We can also choose the arrangement of tensors forming the MPO (`Layout`) and the strategy to optimize boundary MPS (`Strategy`). The user also has the decision-making authority on whether the MPS will be truncated in a gradual manner (`graduate_truncation`). We can initiate our algorithm from various starting points. The parameter responsible for this choice is `transform`, which allows for the rotation and reflection of the tensor network, consequently altering the starting point for the exploration. Last, but not least, the user can also choose whether to use the `Sparse` or `Dense` mode. This choice should depend on the size of the unit cell in the specific problem at hand. -```@julia -Layout = GaugesEnergy # Way of decomposition of the network into MPO -Strategy = Zipper # Strategy to optimize MPS -graduate_truncation = :graduate_truncate # Gradually truncates MPS -transform = rotation(0) # Transformation of the lattice -Sparsity = Sparse # Use sparse mode, when tensors are large -``` + params = MpsParameters{T}(; bond_dim = 16, num_sweeps = 1) + search_params = SearchParameters(; max_states = 2^8, cut_off_prob = 1E-4) -The parameters provided by the user are then stored in data structures `MpsParameters` and `SearchParameters`. -```@julia -params = MpsParameters(bond_dim, tol_var, max_num_sweeps, - tol_svd, iters_svd, iters_var, dtemp_mult, method) -search_params = SearchParameters(num_states, δp) -``` + for transform ∈ all_lattice_transformations + net = PEPSNetwork{KingSingleNode{GaugesEnergy}, Dense, T}( + m, n, potts_h, transform, + ) -User can not only calculate the ground state of the given problem, but also find exitations in the system. To achieve this, the user must specify the energy range `eng` above the ground state within which the solver should search for low-energy excitations. The `SpinGlassPEPS.jl` algorithm seeks large independent excitations, meaning states that are far from each other in a Hamming sense, so states that differ from each other by at least a `hamming_dist` distance – this distance is provided by the user. -```@julia -eng = 10 -hamming_dist = 10 -``` + ctr = MpsContractor(SVDTruncate, net, params; + onGPU = false, beta = T(2), graduate_truncation = true, + ) -With this prepared set of parameters, we are ready for the actual computations. The first step is to create the Ising graph. In the Ising graph, nodes are formed by the spin positions, and interactions between them are represented by the edges. -```@julia -ig = ising_graph(instance) -``` + single = SingleLayerDroplets(eng, hamming_dist, :hamming) + merge_strategy = merge_branches( + ctr; merge_type = :nofit, update_droplets = single, + ) -Next, we need to translate our problem into a clustered problem, where several spins form an unit cell. This is achieved through the use of the `clustered_hamiltonian` function. -```@julia -cl_h = clustered_hamiltonian( - ig, - spectrum = full_spectrum, - cluster_assignment_rule=super_square_lattice((m, n, t)) -) -``` + sol, _ = low_energy_spectrum(ctr, search_params, merge_strategy) -The next part of the code builds the PEPS tensor network compatible with previously defined clustered Hamiltonian. -```@julia -net = PEPSNetwork{SquareCrossSingleNode{Layout}, Sparsity}(m, n, cl_h, transform) -``` + push!(best_energies, sol.energies[1]) + clear_memoize_cache() + end -In order to start calculating conditional probabilities we need to define `MpsContractor` structure which stores the elements and information necessary for contracting the tensor network and, consequently, calculating the probability of a given configuration. -```@julia -ctr = MpsContractor{Strategy, NoUpdate}(net, [β], graduate_truncation, params; onGPU=onGPU) -``` + ground = best_energies[1] + @assert all(ground .≈ best_energies) -Finally the call -```@julia -sol_peps, schmidts = low_energy_spectrum(ctr, search_params, merge_branches(ctr, :fit, SingleLayerDroplets(eng, hamming_dist, :hamming))) + println("Best energy found: $(ground)") +end +T = Float64 +@time run_square_diag_bench(T; topology = (3, 3, 2)) ``` -which runs branch and bound algorithm included in `SpinGlassPEPS.jl` It is actual solver, which iteratively explores the state space in search of the most probable states. The probabilities of a given configuration are calculated approximately through the contractions of the tensor network. -## Expected output -The function `low_energy_spectrum`, as its output, provides a wealth of information, which we will briefly discuss now. -```@julia -sol_peps, schmidt_val = low_energy_spectrum(ctr, search_params, merge_branches(ctr)) -``` -It returns a Solution-type structure (`sol_peps`) and Schmidt values `schmidt_val`. In the `Solution` structure, the following information is recorded: -* energies - a vector containing the energies of the discovered states -If you want to display it, you can type: +### Main steps +Let’s walk through the key steps of the code. + +#### Defining the lattice +The first line of the code above loads the problem instance using the `get_instance` function: ```@julia -println(sol_peps.energies) +instance = get_instance(topology) ``` -In this case, you should obtain: +Here, `topology` is a tuple `(m, n, t)` representing the dimensions of the lattice `m`, `n` and the cluster size `t`. The `get_instance` function constructs the file path to the corresponding problem instance, based on the provided topology. + +The topology of the lattice is specified: ```@julia -[-215.23679958927175] +topology = (3, 3, 2) +m, n, _ = topology ``` -* states - a vector of cluster state configurations corresponding to the energies +This defines a 3x3 grid with clusters of size 2. + +#### Defining the Hamiltonian +Then we map the Ising problem to a Potts Hamiltonian defined on a king’s graph (`super_square_lattice`): ```@julia -println(sol_peps.states) +potts_h = potts_hamiltonian( +ising_graph(instance), +spectrum = full_spectrum, +cluster_assignment_rule = super_square_lattice(topology), +) ``` +Here, `ising_graph(instance)` reads the Ising graph from the file and the spins are grouped into clusters based on the `super_square_lattice rule`. + +#### Setting parameters +To control the complexity and accuracy of the simulation, we define several parameters: ```@julia -println([[4, 4, 2, 16, 9, 8, 8, 2, 3, 8, 7, 1, 4, 10, 9, 2, 11, 2, 1, 2, 11, 3, 11, 8, 3]]) +params = MpsParameters{T}(; bond_dim = 16, num_sweeps = 1) +search_params = SearchParameters(; max_states = 2^8, cut_off_prob = 1E-4) ``` -* probabilities - the probabilities associated with each discovered state +* `bond_dim = 16`: The bond dimension for the tensor network. +* `num_sweeps = 1`: Number of sweeps during variational compression. +* `max_states = 2^8`: Maximum number of states considered during the search. +* `cut_off_prob = 1E-4`: The cutoff probability specifies the probability below which states are discarded from further consideration. + +#### Tensor network construction and contraction +The tensor network representation of the system is created using the `PEPSNetwork` structure: ```@julia -println(sol_peps.probabilities) +net = PEPSNetwork{KingSingleNode{GaugesEnergy}, Dense, T}(m, n, potts_h, transform) ``` +This constructs a PEPS network based on the `KingSingleNode`, which specifies the type of the node used within the tensor networks. The layout `GaugesEnergy` defines how the tensor network is divided into boundary Matrix Product States (MPSs). +Other control parameter includes `Sparsity` which determines whether dense or sparse tensors should be used. In this example, as we apply small clusters containing two spins, we can use `Dense` mode. The parameter `T` represents the data type used for numerical calculations. In this example, we set: ```@julia -[-5.637640487579043] +T = Float64 ``` -* degeneracy +Here, `Float64` specifies that the computations will be performed using 64-bit floating-point numbers, which is a common choice in scientific computing for balancing precision and performance. One can also use `Float32`. +The contraction of the tensor network is handled by the `MpsContractor`: ```@julia -println(sol_peps.degeneracy) +ctr = MpsContractor(SVDTruncate, net, params; + onGPU = false, beta = T(2), graduate_truncation = true, +) ``` +The parameters for the `MpsContractor` include: +* `Strategy` refers to the method used for approximating boundary Matrix Product States. Here `Strategy` is set to `SVDTruncate`. +* `onGPU = false`: Here computations are done on the CPU. If you want to switch on GPU mode, then type ```@julia -[2] -``` -* largest discarded probability - largest probability below which states are considered to be discarded +onGPU = true +``` +* `beta = T(2)`: Inverse temperature, here set to 2. Higher value (lower temperature) allows us to focus on low-energy states. +* `graduate_truncation = true`: Enabling gradual truncation of the MPS. + +#### Searching for excitations +The branch-and-bound search algorithm is used to find low-energy excitations: ```@julia -println(sol_peps.largest_discarded_probability) +single = SingleLayerDroplets(eng, hamming_dist, :hamming) +merge_strategy = merge_branches(ctr; merge_type = :nofit, update_droplets = single) ``` -```@julia --4.70579014404923 +Here, the parameter `eng` sets the energy range within which we look for excitations above the ground state. The `hamming_dist` parameter enforces a minimum Hamming distance between excitations, ensuring that the algorithm searches for distinct, independent excitations. +The optional `merge_branches` function allows us to identify spin glass droplets. + +#### Multiple lattice transformations +We apply different lattice transformations to the problem, iterating over all possible transformations: +```@julia +for transform ∈ all_lattice_transformations + ... +end ``` -* Schmidt values - a dictionary containing Schmidt spectra for each MPS +This loop applies all possible transformations (rotations and reflections) to the 2D lattice. By exploring all eight transformations, the algorithm can start the contraction process from different points on the lattice, improving stability and increasing the chances of finding the global minimum energy state. + +#### Low-energy spectrum calculation +Finally, the low-energy spectrum is calculated with: ```@julia -println(schmidt_val) +sol, _ = low_energy_spectrum(ctr, search_params, merge_strategy) ``` -which are +This function returns the low-energy states found during the search. + +### Expected output +The output of this example should print the best energy found during the optimization: + ```@julia -Dict{Any, Any}(5 => Any[1.0, 1.0, 0.0035931343796194565, 0.0015050888555964259, 0.0007184752751868924, 5.2741877514519126e-5, 4.137035816131772e-5, 0.00040017490729592366, 0.00021874495320028077, 6.827849766898342e-5], 4 => Any[1.0, 1.0, 1.704951518711975e-5, 0.00037890798675182353, 0.00011310427642297989, 0.001014257142680146, 0.0012672631937840461, 0.0005487312667512858, 0.0006741839581781018, 0.00012017531445170455], 6 => Any[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], 2 => Any[1.0, 1.0, 0.0001405854472578707, 0.0012280075890260514, 0.001177462193268373, 0.0029570115655969827, 0.002997829968910592, 0.0011163442379909382, 0.0010056280784881478, 0.00026431187613365595], 3 => Any[1.0, 1.0, 1.864183962070951e-5, 0.006059161388679921, 0.006793028602573968, 0.012337242616802302, 0.011721497080177857, 0.013791830543357657, 0.020430181282353188, 0.014653186648427675]) +println("Best energy found: $(ground)") ``` -* statistics - a possible warning sign, with values ranging from [0, 2]. A nonzero value signifies that certain conditional probabilities derived from tensor network contraction were negative, suggesting a lack of numerical stability during contraction. Here we display the worst-case scenario. +This output confirms that the ground state energies found under different lattice transformations are consistent. + +The full function is executed as: ```@julia -println(minimum(values(ctr.statistics))) +T = Float64 +@time run_square_diag_bench(T; topology = (3, 3, 2)) ``` -The output should give you -```@julia -0.0 -``` \ No newline at end of file diff --git a/docs/src/sge/guide.md b/docs/src/sge/guide.md index e2429dc..15bbac6 100755 --- a/docs/src/sge/guide.md +++ b/docs/src/sge/guide.md @@ -1,5 +1,5 @@ # Introduction A [Julia](http://julialang.org) package for finding low energy spectrum of Ising spin systems. Part of [SpinGlassPEPS](https://github.com/euro-hpc-pl/SpinGlassPEPS.jl) package. -This part of the documentation is dedicated to describing the `SpinGlassEngine.jl` package, which serves as the actual solver. First, we will demonstrate how to construct a tensor network using the clustered Hamiltonian obtained with the `SpinGlassNetworks.jl` package. Next, we discuss the parameters necessary for conducting calculations, which the user should provide. Finally, we present functions that enable the discovery of low-energy spectra. +This part of the documentation is dedicated to describing the `SpinGlassEngine.jl` package, which serves as the actual solver. First, we will demonstrate how to construct a tensor network using the Potts Hamiltonian obtained with the `SpinGlassNetworks.jl` package. Next, we discuss the parameters necessary for conducting calculations, which the user should provide. Finally, we present functions that enable the discovery of low-energy spectra. diff --git a/docs/src/sge/search.md b/docs/src/sge/search.md index 8392d9d..e7a14e4 100755 --- a/docs/src/sge/search.md +++ b/docs/src/sge/search.md @@ -12,7 +12,14 @@ Solution ``` # Droplet search -`SpinGlassPEPS.jl` offers the possibility not only finding low lying energy states, but also droplet excitations. In order to search for droplets, one need to choose the option `SingleLayerDroplets` in `merge_branches`. +`SpinGlassPEPS.jl` provides the capability to find not only low-energy states but also droplet excitations. To search for droplets, the `SingleLayerDroplets` option must be selected in the `merge_branches` function. + +Droplets are identified during the optional `merge_branches` step, which can be invoked within the `low_energy_spectrum` function that runs the branch-and-bound algorithm. This search focuses on finding diverse excitations within a specific energy range above the ground state. An excitation is accepted only if its Hamming distance from any previously identified excitation exceeds a predefined threshold. + +This behavior is controlled by two key parameters: +* `energy_cutoff`: Defines the maximum allowed energy above the ground state for considering an excitation. +* `hamming_cutoff`: Sets the minimum Hamming distance required between excitations for them to be classified as distinct. +By adjusting these parameters, users can search for different excitations while ensuring that only sufficiently distinct ones are included. ```@docs SingleLayerDroplets ``` \ No newline at end of file diff --git a/docs/src/sgn/api.md b/docs/src/sgn/api.md index cf987b7..6e09308 100755 --- a/docs/src/sgn/api.md +++ b/docs/src/sgn/api.md @@ -11,17 +11,17 @@ prune couplings ``` -## Clustered Hamiltonian +## Potts Hamiltonian ```@docs split_into_clusters -decode_clustered_hamiltonian_state +decode_potts_hamiltonian_state rank_reveal energy energy_2site cluster_size bond_energy exact_cond_prob -truncate_clustered_hamiltonian +truncate_potts_hamiltonian ``` ## Belief propagation @@ -31,7 +31,7 @@ interaction_energy get_neighbors MergedEnergy update_message -merge_vertices_cl_h +merge_vertices_potts_h projector SparseCSC ``` @@ -54,8 +54,8 @@ brute_force ## Truncate ```@docs -truncate_clustered_hamiltonian_1site_BP -truncate_clustered_hamiltonian_2site_energy +truncate_potts_hamiltonian_1site_BP +truncate_potts_hamiltonian_2site_energy select_numstate_best ```