Exemplo n.º 1
0
 def test_invalid_adjacency_complex(self, adj, monkeypatch):
     """Test if function raises a ``ValueError`` for a complex symmetric matrix"""
     adj = adj * 1j
     with monkeypatch.context() as m:
         m.setattr(utils, "is_undirected", lambda _: True)
         with pytest.raises(
                 Exception,
                 match="Input NumPy arrays must be real and symmetric"):
             utils.validate_graph(adj)
Exemplo n.º 2
0
 def test_valid_adjacency(self, adj, monkeypatch):
     """Test if function returns the NetworkX Graph class corresponding to the input adjacency
     matrix """
     with monkeypatch.context() as m:
         m.setattr(utils, "is_undirected", lambda _: True)
         graph = utils.validate_graph(adj)
     assert np.allclose(adj, nx.to_numpy_array(graph))
Exemplo n.º 3
0
 def test_invalid_type(self, adj):
     """Test if function raises a ``TypeError`` when the input is not a NumPy array or
     NetworkX graph """
     with pytest.raises(TypeError, match="Graph is not of valid type"):
         utils.validate_graph(adj.tolist())
Exemplo n.º 4
0
 def test_valid_graph(self, adj):
     """Test if function returns the same as input when a NetworkX Graph class is the input"""
     nx_graph = nx.Graph(adj)
     graph = utils.validate_graph(nx_graph)
     assert graph is nx_graph
Exemplo n.º 5
0
def search(graph: graph_type,
           nodes: int,
           iterations: int = 1,
           options: Optional[dict] = None) -> Tuple[float, list]:
    """Find a dense subgraph of a given size.

    This function returns the densest `node-induced subgraph
    <http://mathworld.wolfram.com/Vertex-InducedSubgraph.html>`__ of size ``nodes`` after
    multiple repetitions. It uses heuristic optimization that combines search space exploration
    with local searching. The heuristic method can be set with the ``options`` argument. Methods
    can contain stochastic elements, where randomness can come from distributions including GBS.

    All elements of the heuristic can be controlled with the ``options`` argument, which should be a
    dict-of-dicts where the first level specifies the option type as a string-based key,
    with corresponding value being a dictionary of options for that type. The option types are:

    - ``"heuristic"``: specifying options used by optimization heuristic; corresponding
      dictionary of options explained further :ref:`below <heuristic>`
    - ``"backend"``: specifying options used by backend quantum samplers; corresponding
      dictionary of options explained further in :mod:`~strawberryfields.gbs.sample`
    - ``"resize"``: specifying options used by resizing method; corresponding dictionary of
      options explained further in :mod:`~strawberryfields.gbs.resize`
    - ``"sample"``: specifying options used in sampling; corresponding dictionary of options
      explained further in :mod:`~strawberryfields.gbs.sample`

    If unspecified, a default set of options is adopted for a given option type.

    .. _heuristic:

    The options dictionary corresponding to ``"heuristic"`` can contain any of the following:

    .. glossary::

        key: ``"method"``, value: *str* or *callable*
            Value can be either a string selecting from a range of available methods or a
            customized callable function. Options include:

            - ``"random-search"``: a simple random search algorithm where many subgraphs are
              selected and the densest one is chosen (default)
            - *callable*: accepting ``(graph: nx.Graph, nodes: int, iterations: int, options:
              dict)`` as arguments and returning ``Tuple[float, list]`` corresponding to the
              density and list of nodes of the densest subgraph found, see :func:`random_search`
              for an example

    Args:
        graph (graph_type): the input graph
        nodes (int): the size of desired dense subgraph
        iterations (int): number of iterations to use in algorithm
        options (dict[str, dict[str, Any]]): dict-of-dicts specifying options in different parts
            of heuristic search algorithm; defaults to :const:`OPTIONS_DEFAULTS`

    Returns:
        tuple[float, list]: the density and list of nodes corresponding to the densest subgraph
        found
    """
    options = {**OPTIONS_DEFAULTS, **(options or {})}

    method = options["heuristic"]["method"]

    if not callable(method):
        method = METHOD_DICT[method]

    return method(graph=utils.validate_graph(graph),
                  nodes=nodes,
                  iterations=iterations,
                  options=options)