def test_from_parameters(self): """Test from_parameters.""" coupling_matrix = np.array([[1.0, 1.0 + 1.0j, 2.0 - 2.0j], [1.0 - 1.0j, 0.0, 0.0], [2.0 + 2.0j, 0.0, 1.0]]) ism = cast(IsingModel, IsingModel.from_parameters(coupling_matrix)) with self.subTest("Check the graph."): target_graph = PyGraph(multigraph=False) target_graph.add_nodes_from(range(3)) target_weight = [(0, 0, 1.0), (0, 1, 1.0 + 1.0j), (0, 2, 2.0 - 2.0j), (2, 2, 1.0)] target_graph.add_edges_from(target_weight) self.assertTrue( is_isomorphic(ism.lattice.graph, target_graph, edge_matcher=lambda x, y: x == y)) with self.subTest("Check the coupling matrix."): assert_array_equal(ism.coupling_matrix(), coupling_matrix) with self.subTest("Check the second q op representation."): coupling = [ ("Z_0 Z_1", 1.0 + 1.0j), ("Z_0 Z_2", 2.0 - 2.0j), ("X_0", 1.0), ("X_2", 1.0), ] ham = coupling self.assertSetEqual(set(ham), set(ism.second_q_ops().to_list()))
def test_from_nodes_and_edges(self): """Test from_nodes_edges.""" graph = PyGraph(multigraph=False) graph.add_nodes_from(range(6)) weighted_edge_list = [ (0, 1, 1.0 + 1.0j), (0, 2, -1.0), (2, 3, 2.0), (4, 2, -1.0), (4, 4, 3.0), (2, 5, -1.0), ] graph.add_edges_from(weighted_edge_list) lattice = Lattice(graph) target_num_nodes = 6 target_weighted_edge_list = [ (2, 5, -1.0), (4, 4, 3), (4, 2, -1.0), (2, 3, 2.0), (0, 2, -1.0), (0, 1, 1.0 + 1.0j), ] target_lattice = Lattice.from_nodes_and_edges( target_num_nodes, target_weighted_edge_list) self.assertTrue( is_isomorphic(lattice.graph, target_lattice.graph, edge_matcher=lambda x, y: x == y))
def test_nonnumeric_weight_raises(self): """Test the initialization with a graph with non-numeric edge weights raises.""" graph = PyGraph(multigraph=False) graph.add_nodes_from(range(3)) graph.add_edges_from([(0, 1, 1), (1, 2, "banana")]) with self.assertRaises(ValueError): _ = Lattice(graph)
def test_uniform_parameters(self): """Test uniform_parameters.""" graph = PyGraph(multigraph=False) graph.add_nodes_from(range(3)) weighted_edge_list = [ (0, 1, 1.0 + 1.0j), (0, 2, -1.0), (1, 1, 2.0), ] graph.add_edges_from(weighted_edge_list) lattice = Lattice(graph) uniform_ism = cast( IsingModel, IsingModel.uniform_parameters( lattice, uniform_interaction=1.0 + 1.0j, uniform_onsite_potential=0.0, ), ) with self.subTest("Check the graph."): target_graph = PyGraph(multigraph=False) target_graph.add_nodes_from(range(3)) target_weight = [ (0, 1, 1.0 + 1.0j), (0, 2, 1.0 + 1.0j), (0, 0, 0.0), (1, 1, 0.0), (2, 2, 0.0), ] target_graph.add_edges_from(target_weight) self.assertTrue( is_isomorphic(uniform_ism.lattice.graph, target_graph, edge_matcher=lambda x, y: x == y)) with self.subTest("Check the coupling matrix."): coupling_matrix = uniform_ism.coupling_matrix() target_matrix = np.array([[0.0, 1.0 + 1.0j, 1.0 + 1.0j], [1.0 - 1.0j, 0.0, 0.0], [1.0 - 1.0j, 0.0, 0.0]]) assert_array_equal(coupling_matrix, target_matrix) with self.subTest("Check the second q op representation."): coupling = [ ("Z_0 Z_1", 1.0 + 1.0j), ("Z_0 Z_2", 1.0 + 1.0j), ("X_0", 0.0), ("X_1", 0.0), ("X_2", 0.0), ] ham = coupling self.assertSetEqual(set(ham), set(uniform_ism.second_q_ops().to_list()))
def test_init(self): """Test init.""" graph = PyGraph(multigraph=False) graph.add_nodes_from(range(6)) weighted_edge_list = [ (0, 1, 1.0 + 1.0j), (0, 2, -1.0), (2, 3, 2.0), (2, 4, -1.0), (4, 4, 3.0), (2, 5, -1.0), ] graph.add_edges_from(weighted_edge_list) lattice = Lattice(graph) with self.subTest("Check the type of lattice."): self.assertIsInstance(lattice, Lattice) with self.subTest("Check graph."): target_graph = PyGraph(multigraph=False) target_graph.add_nodes_from(range(6)) target_weighted_edge_list = [ (4, 4, 3.0), (0, 1, 1 + 1j), (2, 3, 2.0), (2, 4, -1.0), (2, 5, -1.0), (0, 2, -1), ] target_graph.add_edges_from(target_weighted_edge_list) self.assertTrue( is_isomorphic(lattice.graph, target_graph, edge_matcher=lambda x, y: x == y)) with self.subTest("Check the number of nodes."): self.assertEqual(lattice.num_nodes, 6) with self.subTest("Check the set of nodes."): self.assertSetEqual(set(lattice.node_indexes), set(range(6))) with self.subTest("Check the set of weights."): target_set = { (0, 1, 1 + 1j), (4, 4, 3), (2, 5, -1.0), (0, 2, -1.0), (2, 3, 2.0), (2, 4, -1.0), } self.assertEqual(set(lattice.weighted_edge_list), target_set)
def test_init(self): """Test init.""" graph = PyGraph(multigraph=False) graph.add_nodes_from(range(3)) weighted_edge_list = [ (0, 1, 1.0 + 1.0j), (0, 2, -1.0), (1, 1, 2.0), ] graph.add_edges_from(weighted_edge_list) lattice = Lattice(graph) fhm = FermiHubbardModel(lattice, onsite_interaction=10.0) with self.subTest("Check the graph."): self.assertTrue( is_isomorphic(fhm.lattice.graph, lattice.graph, edge_matcher=lambda x, y: x == y)) with self.subTest("Check the hopping matrix"): hopping_matrix = fhm.hopping_matrix() target_matrix = np.array([[0.0, 1.0 + 1.0j, -1.0], [1.0 - 1.0j, 2.0, 0.0], [-1.0, 0.0, 0.0]]) assert_array_equal(hopping_matrix, target_matrix) with self.subTest("Check the second q op representation."): hopping = [ ("+_0 -_2", 1.0 + 1.0j), ("-_0 +_2", -(1.0 - 1.0j)), ("+_0 -_4", -1.0), ("-_0 +_4", 1.0), ("+_1 -_3", 1.0 + 1.0j), ("-_1 +_3", -(1.0 - 1.0j)), ("+_1 -_5", -1.0), ("-_1 +_5", 1.0), ("+_2 -_2", 2.0), ("+_3 -_3", 2.0), ] interaction = [ ("+_0 -_0 +_1 -_1", 10.0), ("+_2 -_2 +_3 -_3", 10.0), ("+_4 -_4 +_5 -_5", 10.0), ] ham = hopping + interaction self.assertSetEqual( set(ham), set(fhm.second_q_ops(display_format="sparse").to_list()))
def test_from_parameters(self): """Test from_parameters.""" hopping_matrix = np.array([[1.0, 1.0 + 1.0j, 2.0 + 2.0j], [1.0 - 1.0j, 0.0, 0.0], [2.0 - 2.0j, 0.0, 1.0]]) onsite_interaction = 10.0 fhm = FermiHubbardModel.from_parameters(hopping_matrix, onsite_interaction) with self.subTest("Check the graph."): target_graph = PyGraph(multigraph=False) target_graph.add_nodes_from(range(3)) target_weight = [(0, 0, 1.0), (0, 1, 1.0 + 1.0j), (0, 2, 2.0 + 2.0j), (2, 2, 1.0)] target_graph.add_edges_from(target_weight) self.assertTrue( is_isomorphic(fhm.lattice.graph, target_graph, edge_matcher=lambda x, y: x == y)) with self.subTest("Check the hopping matrix."): assert_array_equal(fhm.hopping_matrix(), hopping_matrix) with self.subTest("Check the second q op representation."): hopping = [ ("+_0 -_2", 1.0 + 1.0j), ("-_0 +_2", -(1.0 - 1.0j)), ("+_0 -_4", 2.0 + 2.0j), ("-_0 +_4", -(2.0 - 2.0j)), ("+_1 -_3", 1.0 + 1.0j), ("-_1 +_3", -(1.0 - 1.0j)), ("+_1 -_5", 2.0 + 2.0j), ("-_1 +_5", -(2.0 - 2.0j)), ("+_0 -_0", 1.0), ("+_1 -_1", 1.0), ("+_4 -_4", 1.0), ("+_5 -_5", 1.0), ] interaction = [ ("+_0 -_0 +_1 -_1", onsite_interaction), ("+_2 -_2 +_3 -_3", onsite_interaction), ("+_4 -_4 +_5 -_5", onsite_interaction), ] ham = hopping + interaction self.assertSetEqual( set(ham), set(fhm.second_q_ops(display_format="sparse").to_list()))
def from_nodes_and_edges( cls, num_nodes: int, weighted_edges: List[Tuple[int, int, complex]] ) -> "Lattice": """Return an instance of Lattice from the number of nodes and the list of edges. Args: num_nodes: The number of nodes. weighted_edges: A list of tuples consisting of two nodes and the weight between them. Returns: Lattice generated from lists of nodes and edges. """ graph = PyGraph(multigraph=False) graph.add_nodes_from(range(num_nodes)) graph.add_edges_from(weighted_edges) return cls(graph)
def test_from_networkx(self): """Test initialization from a networkx graph.""" graph = nx.Graph() graph.add_nodes_from(range(5)) graph.add_edges_from([(i, i + 1) for i in range(4)]) lattice = Lattice(graph) target_graph = PyGraph() target_graph.add_nodes_from(range(5)) target_graph.add_edges_from([(i, i + 1, 1) for i in range(4)]) self.assertTrue( is_isomorphic(lattice.graph, target_graph, edge_matcher=lambda x, y: x == y))
def test_to_adjacency_matrix(self): """Test to_adjacency_matrix.""" graph = PyGraph(multigraph=False) graph.add_nodes_from(range(3)) weighted_edge_list = [(0, 1, 1.0 + 1.0j), (0, 2, -1.0), (2, 2, 3)] graph.add_edges_from(weighted_edge_list) lattice = Lattice(graph) target_matrix = np.array([[0, 1 + 1j, -1.0], [1 - 1j, 0, 0], [-1.0, 0, 3.0]]) assert_array_equal(lattice.to_adjacency_matrix(weighted=True), target_matrix) target_matrix = np.array([[0, 1, 1], [1, 0, 0], [1, 0, 1]]) assert_array_equal(lattice.to_adjacency_matrix(), target_matrix)
def _generate_lattice_from_parameters(interaction_matrix: np.ndarray): # make a graph from the interaction matrix. # This should be replaced by from_adjacency_matrix of retworkx. shape = interaction_matrix.shape if len(shape) != 2 or shape[0] != shape[1]: raise ValueError( f"Invalid shape of `interaction_matrix`, {shape}, is given." "It must be a square matrix.") graph = PyGraph(multigraph=False) graph.add_nodes_from(range(shape[0])) for source_index in range(shape[0]): for target_index in range(source_index, shape[0]): weight = interaction_matrix[source_index, target_index] if not weight == 0.0: graph.add_edge(source_index, target_index, weight) return Lattice(graph)
def test_edges_removed(self): """Test the initialization with a graph where edges have been removed.""" graph = PyGraph(multigraph=False) graph.add_nodes_from(range(3)) graph.add_edges_from([(0, 1, 1), (1, 2, 1)]) graph.remove_edge_from_index(0) lattice = Lattice(graph) target_graph = PyGraph(multigraph=False) target_graph.add_nodes_from(range(3)) target_graph.add_edges_from([(1, 2, 1)]) self.assertTrue( is_isomorphic(lattice.graph, target_graph, edge_matcher=lambda x, y: x == y))
def test_copy(self): """Test test_copy.""" graph = PyGraph(multigraph=False) graph.add_nodes_from(range(6)) weighted_edge_list = [ (0, 1, 1.0 + 1.0j), (0, 2, -1.0), (2, 3, 2.0), (2, 4, -1.0), (4, 4, 3.0), (2, 5, -1.0), ] graph.add_edges_from(weighted_edge_list) lattice = Lattice(graph) lattice_copy = lattice.copy() self.assertTrue( is_isomorphic(lattice_copy.graph, graph, edge_matcher=lambda x, y: x == y))
def test_init(self): """Test init.""" graph = PyGraph(multigraph=False) graph.add_nodes_from(range(3)) weighted_edge_list = [ (0, 1, 1.0 + 1.0j), (0, 2, -1.0), (1, 1, 2.0), ] graph.add_edges_from(weighted_edge_list) lattice = Lattice(graph) ism = IsingModel(lattice) with self.subTest("Check the graph."): self.assertTrue( is_isomorphic(ism.lattice.graph, lattice.graph, edge_matcher=lambda x, y: x == y)) with self.subTest("Check the coupling matrix"): coupling_matrix = ism.coupling_matrix() target_matrix = np.array([[0.0, 1.0 + 1.0j, -1.0], [1.0 - 1.0j, 2.0, 0.0], [-1.0, 0.0, 0.0]]) assert_array_equal(coupling_matrix, target_matrix) with self.subTest("Check the second q op representation."): coupling = [ ("Z_0 Z_1", 1.0 + 1.0j), ("Z_0 Z_2", -1.0), ("X_1", 2.0), ] ham = coupling self.assertSetEqual(set(ham), set(ism.second_q_ops().to_list()))
def test_init(self): """Test init.""" rows = 3 cols = 2 edge_parameter = (1.0 + 1.0j, 2.0 + 2.0j) onsite_parameter = 1.0 boundary_condition = (BoundaryCondition.PERIODIC, BoundaryCondition.OPEN) square = SquareLattice(rows, cols, edge_parameter, onsite_parameter, boundary_condition) with self.subTest("Check the graph."): target_graph = PyGraph(multigraph=False) target_graph.add_nodes_from(range(6)) weighted_edge_list = [ (0, 1, 1.0 + 1.0j), (1, 2, 1.0 + 1.0j), (0, 2, 1.0 - 1.0j), (3, 4, 1.0 + 1.0j), (4, 5, 1.0 + 1.0j), (3, 5, 1.0 - 1.0j), (0, 3, 2.0 + 2.0j), (1, 4, 2.0 + 2.0j), (2, 5, 2.0 + 2.0j), (0, 0, 1.0), (1, 1, 1.0), (2, 2, 1.0), (3, 3, 1.0), (4, 4, 1.0), (5, 5, 1.0), ] target_graph.add_edges_from(weighted_edge_list) self.assertTrue( is_isomorphic(square.graph, target_graph, edge_matcher=lambda x, y: x == y)) with self.subTest("Check the number of nodes."): self.assertEqual(square.num_nodes, 6) with self.subTest("Check the set of nodes."): self.assertSetEqual(set(square.node_indexes), set(range(6))) with self.subTest("Check the set of weights."): target_set = { (0, 1, 1.0 + 1.0j), (1, 2, 1.0 + 1.0j), (0, 2, 1.0 - 1.0j), (3, 4, 1.0 + 1.0j), (4, 5, 1.0 + 1.0j), (3, 5, 1.0 - 1.0j), (0, 3, 2.0 + 2.0j), (1, 4, 2.0 + 2.0j), (2, 5, 2.0 + 2.0j), (0, 0, 1.0), (1, 1, 1.0), (2, 2, 1.0), (3, 3, 1.0), (4, 4, 1.0), (5, 5, 1.0), } self.assertSetEqual(set(square.weighted_edge_list), target_set) with self.subTest("Check the adjacency matrix."): target_matrix = np.array([ [1.0, 1.0 + 1.0j, 1.0 - 1.0j, 2.0 + 2.0j, 0.0, 0.0], [1.0 - 1.0j, 1.0, 1.0 + 1.0j, 0.0, 2.0 + 2.0j, 0.0], [1.0 + 1.0j, 1.0 - 1.0j, 1.0, 0.0, 0.0, 2.0 + 2.0j], [2.0 - 2.0j, 0.0, 0.0, 1.0, 1.0 + 1.0j, 1.0 - 1.0j], [0.0, 2.0 - 2.0j, 0.0, 1.0 - 1.0j, 1.0, 1.0 + 1.0j], [0.0, 0.0, 2.0 - 2.0j, 1.0 + 1.0j, 1.0 - 1.0j, 1.0], ]) assert_array_equal(square.to_adjacency_matrix(weighted=True), target_matrix)
def __init__( self, rows: int, cols: int, edge_parameter: Union[complex, Tuple[complex, complex, complex]] = 1.0, onsite_parameter: complex = 0.0, boundary_condition: BoundaryCondition = BoundaryCondition.OPEN, ) -> None: """ Args: rows: Length of the x direction. cols: Length of the y direction. edge_parameter: Weights on the edges in x, y and diagonal directions. This is specified as a tuple of length 3 or a single value. When it is a single value, it is interpreted as a tuple of length 3 consisting of the same values. Defaults to 1.0, onsite_parameter: Weight on the self-loops, which are edges connecting a node to itself. Defaults to 0.0. boundary_condition: Boundary condition for the lattice. The available boundary conditions are: BoundaryCondition.OPEN, BoundaryCondition.PERIODIC. Defaults to BoundaryCondition.OPEN. Raises: ValueError: Given size, edge parameter or boundary condition are invalid values. """ self.rows = rows self.cols = cols self.size = (rows, cols) self.dim = 2 self.boundary_condition = boundary_condition if rows < 2 or cols < 2 or (rows, cols) == (2, 2): # If it's True, triangular lattice can't be well defined. raise ValueError("Both of `rows` and `cols` must not be (2, 2)" "and must be greater than or equal to 2.") if isinstance(edge_parameter, (int, float, complex)): edge_parameter = (edge_parameter, edge_parameter, edge_parameter) elif isinstance(edge_parameter, tuple): if len(edge_parameter) != 3: raise ValueError( f"The length of `edge_parameter` must be 3, not {len(edge_parameter)}." ) self.edge_parameter = edge_parameter self.onsite_parameter = onsite_parameter graph = PyGraph(multigraph=False) graph.add_nodes_from(range(np.prod(self.size))) # add edges excluding the boundary edges bulk_edges = self._bulk_edges() graph.add_edges_from(bulk_edges) # add self-loops self_loop_list = self._self_loops() graph.add_edges_from(self_loop_list) # add edges that cross the boundaries boundary_edge_list = self._boundary_edges() graph.add_edges_from(boundary_edge_list) # a list of edges that depend on the boundary condition self.boundary_edges = [(edge[0], edge[1]) for edge in boundary_edge_list] super().__init__(graph) # default position self.pos = self._default_position()
def test_init(self): """Test init.""" size = (2, 2, 2) edge_parameter = (1.0 + 1.0j, 0.0, -2.0 - 2.0j) onsite_parameter = 5.0 boundary_condition = ( BoundaryCondition.OPEN, BoundaryCondition.PERIODIC, BoundaryCondition.OPEN, ) hyper_cubic = HyperCubicLattice(size, edge_parameter, onsite_parameter, boundary_condition) with self.subTest("Check the graph."): target_graph = PyGraph(multigraph=False) target_graph.add_nodes_from(range(8)) weighted_edge_list = [ (0, 1, 1.0 + 1.0j), (2, 3, 1.0 + 1.0j), (4, 5, 1.0 + 1.0j), (6, 7, 1.0 + 1.0j), (0, 2, 0.0), (1, 3, 0.0), (4, 6, 0.0), (5, 7, 0.0), (0, 4, -2.0 - 2.0j), (1, 5, -2.0 - 2.0j), (2, 6, -2.0 - 2.0j), (3, 7, -2.0 - 2.0j), (0, 0, 5.0), (1, 1, 5.0), (2, 2, 5.0), (3, 3, 5.0), (4, 4, 5.0), (5, 5, 5.0), (6, 6, 5.0), (7, 7, 5.0), ] target_graph.add_edges_from(weighted_edge_list) self.assertTrue( is_isomorphic(hyper_cubic.graph, target_graph, edge_matcher=lambda x, y: x == y)) with self.subTest("Check the number of nodes."): self.assertEqual(hyper_cubic.num_nodes, 8) with self.subTest("Check the set of nodes."): self.assertSetEqual(set(hyper_cubic.node_indexes), set(range(8))) with self.subTest("Check the set of weights."): target_set = { (0, 1, 1.0 + 1.0j), (2, 3, 1.0 + 1.0j), (4, 5, 1.0 + 1.0j), (6, 7, 1.0 + 1.0j), (0, 2, 0.0), (1, 3, 0.0), (4, 6, 0.0), (5, 7, 0.0), (0, 4, -2.0 - 2.0j), (1, 5, -2.0 - 2.0j), (2, 6, -2.0 - 2.0j), (3, 7, -2.0 - 2.0j), (0, 0, 5.0), (1, 1, 5.0), (2, 2, 5.0), (3, 3, 5.0), (4, 4, 5.0), (5, 5, 5.0), (6, 6, 5.0), (7, 7, 5.0), } self.assertSetEqual(set(hyper_cubic.weighted_edge_list), target_set) with self.subTest("Check the adjacency matrix."): target_matrix = np.array([ [5.0, 1.0 + 1.0j, 0.0, 0.0, -2.0 - 2.0j, 0.0, 0.0, 0.0], [1.0 - 1.0j, 5.0, 0.0, 0.0, 0.0, -2.0 - 2.0j, 0.0, 0.0], [0.0, 0.0, 5.0, 1.0 + 1.0j, 0.0, 0.0, -2.0 - 2.0j, 0.0], [0.0, 0.0, 1.0 - 1.0j, 5.0, 0.0, 0.0, 0.0, -2.0 - 2.0j], [-2.0 + 2.0j, 0.0, 0.0, 0.0, 5.0, 1.0 + 1.0j, 0.0, 0.0], [0.0, -2.0 + 2.0j, 0.0, 0.0, 1.0 - 1.0j, 5.0, 0.0, 0.0], [0.0, 0.0, -2.0 + 2.0j, 0.0, 0.0, 0.0, 5.0, 1.0 + 1.0j], [0.0, 0.0, 0.0, -2.0 + 2.0j, 0.0, 0.0, 1.0 - 1.0j, 5.0], ]) assert_array_equal(hyper_cubic.to_adjacency_matrix(weighted=True), target_matrix)
def __init__( self, size: Tuple[int, ...], edge_parameter: Union[complex, Tuple[complex, ...]] = 1.0, onsite_parameter: complex = 0.0, boundary_condition: Union[ BoundaryCondition, Tuple[BoundaryCondition, ...] ] = BoundaryCondition.OPEN, ) -> None: """ Args: size: Lengths of each dimension. edge_parameter: Weights on the edges in each direction. When it is a single value, it is interpreted as a tuple of the same length as `size` consisting of the same values. Defaults to 1.0. onsite_parameter: Weight on the self-loops, which are edges connecting a node to itself. This is uniform over the lattice points. Defaults to 0.0. boundary_condition: Boundary condition for each dimension. The available boundary conditions are: BoundaryCondition.OPEN, BoundaryCondition.PERIODIC. When it is a single value, it is interpreted as a tuple of the same length as `size` consisting of the same values. Defaults to BoundaryCondition.OPEN. Raises: ValueError: When edge parameter or boundary condition is a tuple, the length of that is not the same as that of size. """ self._dim = len(size) self._size = size # edge parameter if isinstance(edge_parameter, (int, float, complex)): edge_parameter = (edge_parameter,) * self._dim elif isinstance(edge_parameter, tuple): if len(edge_parameter) != self._dim: raise ValueError( "size mismatch, " f"`edge_parameter`: {len(edge_parameter)}, `size`: {self._dim}." "The length of `edge_parameter` must be the same as that of size." ) self._edge_parameter = edge_parameter self._onsite_parameter = onsite_parameter # boundary condition if isinstance(boundary_condition, BoundaryCondition): boundary_condition = (boundary_condition,) * self._dim elif isinstance(boundary_condition, tuple): if len(boundary_condition) != self._dim: raise ValueError( "size mismatch, " f"`boundary_condition`: {len(boundary_condition)}, `size`: {self._dim}." "The length of `boundary_condition` must be the same as that of size." ) self._boundary_condition = boundary_condition graph = PyGraph(multigraph=False) graph.add_nodes_from(range(np.prod(size))) # add edges excluding the boundary edges bulk_edge_list = self._bulk_edges() graph.add_edges_from(bulk_edge_list) # add self-loops. self_loop_list = self._self_loops() graph.add_edges_from(self_loop_list) # add edges that cross the boundaries boundary_edge_list = self._create_boundary_edges() graph.add_edges_from(boundary_edge_list) # a list of edges that depend on the boundary condition self._boundary_edges = [(edge[0], edge[1]) for edge in boundary_edge_list] super().__init__(graph) # default position for one and two-dimensional cases. self.pos = self._default_position()