{"id":13869962,"url":"https://github.com/galtay/hilbertcurve","last_synced_at":"2025-04-04T10:04:20.270Z","repository":{"id":45375493,"uuid":"44505058","full_name":"galtay/hilbertcurve","owner":"galtay","description":"maps between 1-D space filling hilbert curve and N-D coordinates","archived":false,"fork":false,"pushed_at":"2024-04-28T16:08:23.000Z","size":823,"stargazers_count":257,"open_issues_count":2,"forks_count":38,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-03-28T09:02:16.259Z","etag":null,"topics":["fractal","hilbert-curve","python","python3","space-filling-curves"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/galtay.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-10-19T01:47:37.000Z","updated_at":"2025-03-19T10:29:21.000Z","dependencies_parsed_at":"2024-06-18T18:11:38.763Z","dependency_job_id":"3f94151b-2af0-4753-b184-c38a4a891575","html_url":"https://github.com/galtay/hilbertcurve","commit_stats":{"total_commits":88,"total_committers":3,"mean_commits":"29.333333333333332","dds":0.4772727272727273,"last_synced_commit":"58c59c4979a9e8f2882f369821e63a34e6ac4efb"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/galtay%2Fhilbertcurve","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/galtay%2Fhilbertcurve/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/galtay%2Fhilbertcurve/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/galtay%2Fhilbertcurve/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/galtay","download_url":"https://codeload.github.com/galtay/hilbertcurve/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247149489,"owners_count":20891954,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fractal","hilbert-curve","python","python3","space-filling-curves"],"created_at":"2024-08-05T20:01:23.537Z","updated_at":"2025-04-04T10:04:20.247Z","avatar_url":"https://github.com/galtay.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":".. image:: https://travis-ci.com/galtay/hilbertcurve.svg?branch=develop\n    :target: https://travis-ci.com/galtay/hilbertcurve\n\n.. contents:: Table of Contents\n   :depth: 2\n\n\n============\nIntroduction\n============\n\nThis is a package to convert between one dimensional distance along a\n`Hilbert curve`_, ``h``, and ``n``-dimensional points,\n``(x_0, x_1, ... x_n-1)``.  There are two important parameters,\n\n* ``n`` -- the number of dimensions (must be \u003e 0)\n* ``p`` -- the number of iterations used in constructing the Hilbert curve (must be \u003e 0)\n\nWe consider an ``n``-dimensional `hypercube`_ of side length ``2^p``.\nThis hypercube contains ``2^{n p}`` unit hypercubes (``2^p`` along\neach dimension).  The number of unit hypercubes determine the possible\ndiscrete distances along the Hilbert curve (indexed from 0 to\n``2^{n p} - 1``).\n\n\n==========\nQuickstart\n==========\n\nInstall the package with pip,\n\n.. code-block:: bash\n\n  pip install hilbertcurve\n\nYou can calculate points given distances along a hilbert curve,\n\n.. code-block:: python\n\n  \u003e\u003e\u003e from hilbertcurve.hilbertcurve import HilbertCurve\n  \u003e\u003e\u003e p=1; n=2\n  \u003e\u003e\u003e hilbert_curve = HilbertCurve(p, n)\n  \u003e\u003e\u003e distances = list(range(4))\n  \u003e\u003e\u003e points = hilbert_curve.points_from_distances(distances)\n  \u003e\u003e\u003e for point, dist in zip(points, distances):\n  \u003e\u003e\u003e     print(f'point(h={dist}) = {point}')\n\n  point(h=0) = [0, 0]\n  point(h=1) = [0, 1]\n  point(h=2) = [1, 1]\n  point(h=3) = [1, 0]\n\nYou can also calculate distances along a hilbert curve given points,\n\n.. code-block:: python\n\n  \u003e\u003e\u003e points = [[0,0], [0,1], [1,1], [1,0]]\n  \u003e\u003e\u003e distances = hilbert_curve.distances_from_points(points)\n  \u003e\u003e\u003e for point, dist in zip(points, distances):\n  \u003e\u003e\u003e     print(f'distance(x={point}) = {dist}')\n\n  distance(x=[0, 0]) = 0\n  distance(x=[0, 1]) = 1\n  distance(x=[1, 1]) = 2\n  distance(x=[1, 0]) = 3\n\n=========================\nInputs and Outputs\n=========================\n\nThe ``HilbertCurve`` class has four main public methods.\n\n* ``point_from_distance(distance: int) -\u003e Iterable[int]``\n* ``points_from_distances(distances: Iterable[int], match_type: bool=False) -\u003e Iterable[Iterable[int]]``\n* ``distance_from_point(point: Iterable[int]) -\u003e int``\n* ``distances_from_points(points: Iterable[Iterable[int]], match_type: bool=False) -\u003e Iterable[int]``\n\nArguments that are type hinted with ``Iterable[int]`` have been tested with lists, tuples, and 1-d numpy arrays.\nArguments that are type hinted with ``Iterable[Iterable[int]]`` have been tested with list of lists, tuples of tuples, and 2-d numpy arrays with shape (num_points, num_dimensions). The ``match_type`` key word argument forces the output iterable to match the type of the input iterable. \n\nThe ``HilbertCurve`` class also contains some useful metadata derived from the inputs ``p`` and ``n``. For instance, you can construct a numpy array of random points on the hilbert curve and calculate their distances in the following way,\n\n.. code-block:: python\n\n  \u003e\u003e\u003e from hilbertcurve.hilbertcurve import HilbertCurve\n  \u003e\u003e\u003e p=1; n=2\n  \u003e\u003e\u003e hilbert_curve = HilbertCurve(p, n)\n  \u003e\u003e\u003e num_points = 10_000                                                                                              \n  \u003e\u003e\u003e points = np.random.randint(                                                                                   \n          low=0,                                                                                                    \n          high=hilbert_curve.max_x + 1,                                                                                 \n          size=(num_points, hilbert_curve.n)                                                                        \n      )\n  \u003e\u003e\u003e distances = hilbert_curve.distances_from_points(points)\n  \u003e\u003e\u003e type(distances)\n  \n  list\n\n  \u003e\u003e\u003e distances = hilbert_curve.distances_from_points(points, match_type=True)\n  \u003e\u003e\u003e type(distances)\n  \n  numpy.ndarray\n  \n=========================\nMultiprocessing\n=========================\n\nYou can now take advantage of multiple processes to speed up calculations by using the ``n_procs`` keyword argument when creating an instance of ``HilbertCurve``. \n\n.. code-block:: bash\n\n  n_procs (int): number of processes to use\n      0 = dont use multiprocessing\n     -1 = use all available processes\n      any other positive integer = number of processes to use\n\nA value of 0 will completely avoid using the multiprocessing module while a value of 1 will use the multiprocessing module but with a single process. If you want to take advantage of every thread on your computer use the value -1 and if you want something in the middle use a value between 1 and the number of threads on your computer.  A concrete example starting with the code block above is,\n\n.. code-block:: python\n\n  \u003e\u003e\u003e from hilbertcurve.hilbertcurve import HilbertCurve\n  \u003e\u003e\u003e p=1; n=2\n  \u003e\u003e\u003e hilbert_curve = HilbertCurve(p, n, n_procs=-1)\n  \u003e\u003e\u003e num_points = 100_000                                                                                              \n  \u003e\u003e\u003e points = np.random.randint(                                                                                   \n          low=0,                                                                                                    \n          high=hilbert_curve.max_x + 1,                                                                                 \n          size=(num_points, hilbert_curve.n)                                                                        \n      )\n  \u003e\u003e\u003e distances = hilbert_curve.distances_from_points(points)\n\nThe following methods are able to use multiple cores. \n\n* ``points_from_distances(distances: Iterable[int], match_type: bool=False) -\u003e Iterable[Iterable[int]]``\n* ``distances_from_points(points: Iterable[Iterable[int]], match_type: bool=False) -\u003e Iterable[int]``\n\n\n=========================\n(Absurdly) Large Integers\n=========================\n\nDue to the magic of `arbitrarily large integers in Python`_,\nthese calculations can be done with ... well ... arbitrarily large integers!\n\n.. code-block:: python\n\n  \u003e\u003e\u003e p = 512; n = 10\n  \u003e\u003e\u003e hilbert_curve = HilbertCurve(p, n)\n  \u003e\u003e\u003e ii = 123456789101112131415161718192021222324252627282930\n  \u003e\u003e\u003e point = hilbert_curve.points_from_distances([ii])[0]\n  \u003e\u003e\u003e print(f'point = {point}')\n\n  point = [121075, 67332, 67326, 108879, 26637, 43346, 23848, 1551, 68130, 84004]\n\nThe calculations above represent the 512th iteration of the Hilbert curve in 10 dimensions.\nThe maximum value along any coordinate axis is an integer with 155 digits and the maximum\ndistance along the curve is an integer with 1542 digits.  For comparison,\n`an estimate of the number of atoms in the observable universe`_\nis ``10^{82}`` (i.e. an integer with 83 digits).\n\n=======\nVisuals\n=======\n\n\n.. figure:: https://raw.githubusercontent.com/galtay/hilbertcurve/main/n2_p3.png\n\n   The figure above shows the first three iterations of the Hilbert\n   curve in two (``n=2``) dimensions.  The ``p=1`` iteration is shown\n   in red, ``p=2`` in blue, and ``p=3`` in black.\n   For the ``p=3`` iteration, distances, ``h``, along the curve are\n   labeled from 0 to 63 (i.e. from 0 to ``2^{n p}-1``).  This package\n   provides methods to translate between ``n``-dimensional points and one\n   dimensional distance.  For example, between (``x_0=4, x_1=6``) and\n   ``h=36``.  Note that the ``p=1`` and ``p=2`` iterations have been\n   scaled and translated to the coordinate system of the ``p=3`` iteration.\n\n\nAn animation of the same case in 3-D is available on YouTube.  To watch the video,\nclick the link below.  Once the YouTube video loads, you can right click on it and\nturn \"Loop\" on to watch the curve rotate continuously.\n\n.. figure:: https://img.youtube.com/vi/TfJEJidwkBQ/0.jpg\n\n   3-D Hilbert Curve Animation https://www.youtube.com/watch?v=TfJEJidwkBQ\n\n=========\nReference\n=========\n\nThis module is based on the C code provided in the 2004 article\n\"Programming the Hilbert Curve\" by John Skilling,\n\n* http://adsabs.harvard.edu/abs/2004AIPC..707..381S\n\nI was also helped by the discussion in the following stackoverflow post,\n\n* `mapping-n-dimensional-value-to-a-point-on-hilbert-curve`_\n\nwhich points out a typo in the source code of the paper.  The Skilling code\nprovides two functions ``TransposetoAxes`` and ``AxestoTranspose``.  In this\ncase, Transpose refers to a specific packing of the integer that represents\ndistance along the Hilbert curve (see below for details) and\nAxes refer to the n-dimensional coordinates.  Below is an excerpt from the\ndocumentation of Skilling's code,\n\n::\n\n    //+++++++++++++++++++++++++++ PUBLIC-DOMAIN SOFTWARE ++++++++++++++++++++++++++\n    // Functions: TransposetoAxes  AxestoTranspose\n    // Purpose:   Transform in-place between Hilbert transpose and geometrical axes\n    // Example:   b=5 bits for each of n=3 coordinates.\n    //            15-bit Hilbert integer = A B C D E F G H I J K L M N O is stored\n    //            as its Transpose\n    //                   X[0] = A D G J M                X[2]|\n    //                   X[1] = B E H K N    \u003c-------\u003e       | /X[1]\n    //                   X[2] = C F I L O               axes |/\n    //                          high  low                    0------ X[0]\n    //            Axes are stored conveniently as b-bit integers.\n    // Author:    John Skilling  20 Apr 2001 to 11 Oct 2003\n\n============\nChange Log\n============\n\nVersion 2.0\n===========\n\nVersion 2.0 introduces some breaking changes.\n\nAPI Changes\n-----------\n\nPrevious versions transformed a single distance to a vector or a single vector to a distance.\n\n* ``coordinates_from_distance(self, h: int) -\u003e List[int]``\n* ``distance_from_coordinates(self, x_in: List[int]) -\u003e int``\n\nIn version 2.0 coordinates -\u003e point(s) and we add methods to handle multiple distances or multiple points.\nThe `match_type` kwarg forces the output type to match the input type and all functions can handle tuples,\nlists, and ndarrays.\n\n* ``point_from_distance(self, distance: int) -\u003e Iterable[int]``\n* ``points_from_distances(self, distances: Iterable[int], match_type: bool=False) -\u003e Iterable[Iterable[int]]``\n* ``distance_from_point(self, point: Iterable[int]) -\u003e int``\n* ``distances_from_points(self, points: Iterable[Iterable[int]], match_type: bool=False) -\u003e Iterable[int]``\n\n\nMultiprocessing\n---------------\n\nThe methods that handle multiple distances or multiple points can take advantage of multiple cores.\nYou can control this behavior using the `n_procs` kwarg when you create an instance of `HilbertCurve`.\n\n\n\n.. _Hilbert curve: https://en.wikipedia.org/wiki/Hilbert_curve\n.. _hypercube: https://en.wikipedia.org/wiki/Hypercube\n.. _arbitrarily large integers in Python: https://docs.python.org/3.3/library/stdtypes.html#numeric-types-int-float-complex\n.. _an estimate of the number of atoms in the observable universe: https://www.universetoday.com/36302/atoms-in-the-universe\n.. _mapping-n-dimensional-value-to-a-point-on-hilbert-curve: http://stackoverflow.com/questions/499166/mapping-n-dimensional-value-to-a-point-on-hilbert-curve\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgaltay%2Fhilbertcurve","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgaltay%2Fhilbertcurve","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgaltay%2Fhilbertcurve/lists"}