English
Languages
English
Bengali
Japanese
Spanish

# Source code for qiskit_optimization.applications.sk_model

# This code is part of Qiskit.
#
#
# obtain a copy of this license in the LICENSE.txt file in the root directory
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""An application class for the Sherrington Kirkpatrick (SK) model."""

from typing import Union, List, Optional

import networkx as nx
import numpy as np
from docplex.mp.model import Model

from .graph_optimization_application import OptimizationApplication
from ..algorithms import OptimizationResult
from ..translators import from_docplex_mp

[docs]class SKModel(OptimizationApplication):
r"""Optimization application of the "Sherrington Kirkpatrick (SK) model" [1].

The SK Hamiltonian over n spins is given as:
:math:H(x)=-1/\sqrt{n} \sum_{i<j} w_{i,j}x_ix_j,
where :math:x_i\in\{\pm 1\} is the configuration of spins and
:math:w_{i,j}\in\{\pm 1\} is a disorder chosen independently and uniformly at random.
Notice that there are other variants of disorders e.g., with :math:w_{i,j} chosen from
the normal distribution with mean 0 and variance 1.

References:
[1]: Dmitry Panchenko. "The Sherrington-Kirkpatrick model: an overview",
https://arxiv.org/abs/1211.1094
"""

def __init__(
self, num_sites: int, rng_or_seed: Optional[Union[np.random.Generator, int]] = None
):
"""
Args:
num_sites: number of sites
rng_or_seed: NumPy pseudo-random number generator or seed for np.random.default_rng(<seed>)
or None. None results in usage of np.random.default_rng().
"""
if isinstance(rng_or_seed, np.random.Generator):
self._rng = rng_or_seed
else:
self._rng = np.random.default_rng(rng_or_seed)

self._num_sites = num_sites
self._graph = nx.complete_graph(self._num_sites)

self.disorder()

[docs]    def disorder(self) -> None:
"""Generate a new disorder of the SK model."""
for _, _, edge_data in self._graph.edges(data=True):
edge_data["weight"] = self._rng.choice([-1, 1])

"""Convert an SK model problem instance into a
:class:~qiskit_optimization.problems.QuadraticProgram.

Returns:
The :class:~qiskit_optimization.problems.QuadraticProgram created
from the SK problem instance.
"""
mdl = Model(name="SK-model")
x = mdl.binary_var_list(self._graph.number_of_nodes())

objective = mdl.sum(
-1
/ np.sqrt(self._num_sites)
* self._graph.edges[i, j]["weight"]
* (2 * x[i] - 1)
* (2 * x[j] - 1)
for i, j in self._graph.edges
)
# we converted the standard H(x)=-1/\sqrt{n} \sum w_{ij}x_ix_j, where x_i\in\pm 1 to binary.

mdl.minimize(objective)
return from_docplex_mp(mdl)

[docs]    def interpret(self, result: Union[OptimizationResult, np.ndarray]) -> List[int]:
"""Interpret a result as configuration of spins.

Args:
result : The calculated result of the problem.

Returns:
configuration of spins
"""
configuration = [2 * x - 1 for x in self._result_to_x(result)]
return configuration

@property
def graph(self) -> nx.Graph:
"""Getter of the graph representation.
Returns:
A graph for a problem.
"""
return self._graph

@property
def num_sites(self) -> int:
"""Getter of the number of sites.
Returns:
Number of sites.
"""
return self._num_sites