Skip to content

Commit

Permalink
Add HexagonalLattice Class (#1027)
Browse files Browse the repository at this point in the history
* First attempt at hex lattice class

* Added hexagonal Lattice class

* Update qiskit_nature/second_q/hamiltonians/lattices/hexagonal_lattice.py

Co-authored-by: Matthew Treinish <[email protected]>

* added tests

* simplified test

* fixed copyright

* use more performant rustworkx functions

* Apply suggestions from code review

Co-authored-by: Max Rossmannek <[email protected]>

* Make changes requested in review

* Added default positions

* ✨ lint! ✨

* remove heavy hex arg

* fix mypy issues

* Fix typing

* increased rustworkx

* fixed mypy again?

* lint: fix mypy

* lint: update headers

* docs: Add reno

---------

Co-authored-by: Matthew Treinish <[email protected]>
Co-authored-by: Max Rossmannek <[email protected]>
Co-authored-by: Max Rossmannek <[email protected]>
  • Loading branch information
4 people authored Sep 4, 2023
1 parent 0f73ea7 commit 9b48d54
Show file tree
Hide file tree
Showing 5 changed files with 233 additions and 1 deletion.
3 changes: 3 additions & 0 deletions qiskit_nature/second_q/hamiltonians/lattices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
SquareLattice
TriangularLattice
HyperCubicLattice
HexagonalLattice
KagomeLattice
"""
Expand All @@ -34,6 +35,7 @@
from .line_lattice import LineLattice
from .square_lattice import SquareLattice
from .triangular_lattice import TriangularLattice
from .hexagonal_lattice import HexagonalLattice
from .kagome_lattice import KagomeLattice

__all__ = [
Expand All @@ -44,5 +46,6 @@
"SquareLattice",
"TriangularLattice",
"HyperCubicLattice",
"HexagonalLattice",
"KagomeLattice",
]
122 changes: 122 additions & 0 deletions qiskit_nature/second_q/hamiltonians/lattices/hexagonal_lattice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# This code is part of a Qiskit project.
#
# (C) Copyright IBM 2021, 2023.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# 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.

"""The hexagonal lattice"""

from __future__ import annotations

from rustworkx import generators # type: ignore[attr-defined]

from .lattice import Lattice


class HexagonalLattice(Lattice):
"""Hexagonal lattice."""

def __init__(
self,
rows: int,
cols: int,
edge_parameter: complex = 1.0,
onsite_parameter: complex = 0.0,
) -> None:
"""
Args:
rows: Number of hexagons in the x direction.
cols: Number of hexagons in the y direction.
edge_parameter: Weight on all the edges, specified as a single value.
Defaults to 1.0.
onsite_parameter: Weight on the self-loops, which are edges connecting a node to itself.
Defaults to 0.0.
"""
self._rows = rows
self._cols = cols
self._edge_parameter = edge_parameter
self._onsite_parameter = onsite_parameter

graph = generators.hexagonal_lattice_graph(rows, cols, multigraph=False)

# Add edge weights
for idx in range(graph.num_edges()):
graph.update_edge_by_index(idx, self._edge_parameter)

# Add self loops
for node in range(graph.num_nodes()):
graph.add_edges_from([(node, node, self._onsite_parameter)])

super().__init__(graph)

self.pos = self._default_position()

@property
def edge_parameter(self) -> complex:
"""Weights on all edges.
Returns:
the parameter for the edges.
"""
return self._edge_parameter

@property
def onsite_parameter(self) -> complex:
"""Weight on the self-loops (edges connecting a node to itself).
Returns:
the parameter for the self-loops.
"""
return self._onsite_parameter

def _default_position(self) -> dict[int, tuple[int, int]]:
"""Return a dictionary of default positions for visualization of
a one- or two-dimensional lattice.
Returns:
A dictionary where the keys are the labels of lattice points, and the values are
two-dimensional coordinates.
"""
pos = {}
rowlen = 2 * self._rows + 2
collen = self._cols + 1
x_adjust = 0

for i in range(collen):
x_adjust += 1
for j in range(rowlen):
idx = i * rowlen + j - 1
x = i

# plot the y coords to form heavy hex shape
if i == 0:
y = j - 1
elif (self._cols % 2 == 0) and (i == self._cols):
y = j + 1
else:
y = j

# even numbered nodes in the first, last and odd numbered columns need to be
# shifted to the right
if i == 0 or (i == self._cols) or (i % 2 != 0):
if idx % 2 == 0:
x = i + x_adjust
else:
x = i + i
# odd numbered nodes that aren't in the first, last or odd numbered columns
# need to be shifted to the right
else:
if idx % 2 == 0:
x = i + i
else:
x = i + x_adjust

pos[idx] = (x, y)

return pos
21 changes: 21 additions & 0 deletions releasenotes/notes/add-hexagonal-lattice-a981f1b5c832a154.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
features:
- |
Adds a new lattice class, :class:`~qiskit_nature.second_q.hamiltonians.lattices.HexagonalLattice`
for the generation of hexagonal lattices.
You construct a hexagonal lattice by specifying the number of rows and columns of hexagons.
You can also specify the edge- and on-site-parameters.
Below is a simple example to illustrate this:
.. code-block:: python
from qiskit_nature.second_q.hamiltonians.lattices import HexagonalLattice
lattice = HexagonalLattice(
2,
3,
edge_parameter=1.0,
onsite_parameter=1.5,
)
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ psutil>=5
setuptools>=40.1.0
typing_extensions
h5py
rustworkx
rustworkx>=0.12
86 changes: 86 additions & 0 deletions test/second_q/hamiltonians/lattices/test_hexagonal_lattice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# This code is part of a Qiskit project.
#
# (C) Copyright IBM 2021, 2023.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# 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.

"""Test for HexgonalLattice."""
from test import QiskitNatureTestCase
import numpy as np
from numpy.testing import assert_array_equal
from rustworkx import PyGraph, is_isomorphic # type: ignore[attr-defined]
from qiskit_nature.second_q.hamiltonians.lattices import HexagonalLattice


class TestHexagonalLattice(QiskitNatureTestCase):
"""Test HexagonalLattice"""

def test_init(self):
"""Test init."""
rows = 1
cols = 2
edge_parameter = 0 + 1.42j
onsite_parameter = 1.0
weighted_edge_list = [
(0, 1, 1.42j),
(1, 2, 1.42j),
(3, 4, 1.42j),
(4, 5, 1.42j),
(5, 6, 1.42j),
(7, 8, 1.42j),
(8, 9, 1.42j),
(0, 3, 1.42j),
(2, 5, 1.42j),
(4, 7, 1.42j),
(6, 9, 1.42j),
(0, 0, 1.0),
(1, 1, 1.0),
(2, 2, 1.0),
(3, 3, 1.0),
(4, 4, 1.0),
(5, 5, 1.0),
(6, 6, 1.0),
(7, 7, 1.0),
(8, 8, 1.0),
(9, 9, 1.0),
]

hexa = HexagonalLattice(rows, cols, edge_parameter, onsite_parameter)

with self.subTest("Check the graph."):
target_graph = PyGraph(multigraph=False)
target_graph.add_nodes_from(range(10))
target_graph.add_edges_from(weighted_edge_list)
self.assertTrue(
is_isomorphic(hexa.graph, target_graph, edge_matcher=lambda x, y: x == y)
)

with self.subTest("Check the number of nodes."):
self.assertEqual(hexa.num_nodes, 10)

with self.subTest("Check the set of nodes."):
self.assertSetEqual(set(hexa.node_indexes), set(range(10)))

with self.subTest("Check the set of weights."):
target_set = set(weighted_edge_list)
self.assertSetEqual(set(hexa.weighted_edge_list), target_set)

with self.subTest("Check the adjacency matrix."):
target_matrix = np.zeros((10, 10), dtype=complex)

indices = [(a, b) for a, b, _ in weighted_edge_list]

for idx1, idx2 in indices:
target_matrix[idx1, idx2] = 0 + 1.42j

target_matrix -= target_matrix.T

np.fill_diagonal(target_matrix, 1.0)

assert_array_equal(hexa.to_adjacency_matrix(weighted=True), target_matrix)

0 comments on commit 9b48d54

Please sign in to comment.