Source code for hiperwalk.graph.hypercube

from .multigraph import Multigraph
from .weighted_graph import WeightedGraph

def __adjacent(self, u, v):
    x = u ^ v #bitwise xor
    return x != 0 and x & (x - 1) == 0

    # TODO: check if the following strategy is faster
    # try:
    #     # python >= 3.10
    #     count = x.bit_count()
    # except:
    #     count = bin(x).count('1')
    # return count == 1

def __neighbor_index(self, vertex, neigh):
    # TODO: how to use __debug__?
    # how to unable __debug__ when uploading to pip?
    # TODO: throw value error if not adjacent
    if __debug__:
        assert self.adjacent(vertex, neigh)

    # it is supposed that vertex and neigh are adjacent
    x = vertex ^ neigh

    # numpy integers do not have bit_length
    # TODO: check if it is faster fo convert or to calculate
    # np.ceil(np.log2(x + 1)).astype(int)
    x = int(x)
    return x.bit_length() - 1

def __degree(self, vertex):
    return self._dimension

def __number_of_vertices(self):
    return 1 << self._dim

def __number_of_edges(self):
    return (1 << (self._dim - 1)) * self._dim

def __degree(self, vertex):
    return self._dim

[docs] def dimension(self): r""" The dimension of the Hypercube. Returns ------- int Examples -------- .. testsetup:: from sys import path path.append('..') import hiperwalk as hpw .. doctest:: >>> n = 10 >>> g = hpw.Hypercube(10) >>> g.dimension() == n True """ return self._dim
# graph constructor import numpy as np from scipy.sparse import csr_array from types import MethodType from .graph import Graph
[docs] def Hypercube(dim, multiedges=None, weights=None, copy=False): r""" Hypercube graph constructor. The hypercube graph consists of ``2**dim`` vertices. The numerical labels of these vertices are ``0``, ``1``, ..., ``2**dim - 1``. Two vertices are adjacent if and only if the corresponding binary tuples differ by only one bit, indicating a Hamming distance of 1. Parameters ---------- dim : int The dimension of the hypercube. multiedges, weights: matrix or dict, default=None See :ref:`graph_constructors`. copy : bool, default=False See :ref:`graph_constructors`. Returns ------- :class:`hiperwalk.Graph` See :ref:`graph_constructors` for details. See Also -------- :ref:`graph_constructors`. Notes ----- A vertex :math:`v` in the hypercube is adjacent to all other vertices that have a Hamming distance of 1. To put it differently, :math:`v` is adjacent to :math:`v \oplus 2^0`, :math:`v \oplus 2^1`, :math:`\ldots`, :math:`v \oplus 2^{n - 2}`, and :math:`v \oplus 2^{n - 1}`. Here, :math:`\oplus` represents the bitwise XOR operation, and :math:`n` signifies the dimension of the hypercube. The **order of neighbors** is determined by the XOR operation. The neighbors of vertex :math:`u` are given in the following order: :math:`u \oplus 2^0`, :math:`u \oplus 2^1, \ldots,` :math:`u \oplus 2^{n - 1}`. For example, .. testsetup:: import hiperwalk as hpw .. doctest:: >>> g = hpw.Hypercube(4) >>> u = 10 >>> bin(u) '0b1010' >>> neigh = g.neighbors(u) >>> neigh array([11, 8, 14, 2]) >>> [bin(v) for v in neigh] ['0b1011', '0b1000', '0b1110', '0b10'] >>> [u^v for v in neigh] [1, 2, 4, 8] """ if weights is not None and multiedges is not None: raise ValueError( "Both `weights` and `multiedges` arguments were set. " + "Cannot decide whether to create a weighted graph or " + "a multigraph." ) # adjacency matrix num_vert = 1 << dim num_arcs = dim*num_vert data = np.ones(num_arcs, dtype=np.int64) indptr = np.arange(0, num_arcs + 1, dim) indices = np.array([v ^ 1 << shift for v in range(num_vert) for shift in range(dim)]) adj_matrix = csr_array((data, indices, indptr), shape=(num_vert, num_vert)) g = Graph(adj_matrix, copy=False) data = weights if weights is not None else multiedges if data is not None: if hasattr(data, 'keys'): data = g._dict_to_adj_matrix(data) copy = False else: g._rearrange_matrix_indices(data) del g if weights is not None: g = WeightedGraph(data, copy=copy) elif multiedges is not None: g = Multigraph(data, copy=copy) if multiedges is None: # bind specific simple/weighted graph methods g.degree = MethodType(__degree, g) g.number_of_edges = MethodType(__number_of_edges, g) # Binding common attributes and methods g._dim = int(dim) g._num_loops = 0 g.adjacent = MethodType(__adjacent, g) g._neighbor_index = MethodType(__neighbor_index, g) g.number_of_vertices = MethodType(__number_of_vertices, g) g.dimension = MethodType(dimension, g) return g