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)
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))
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())
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
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)