Skip to content

Commit 4693f15

Browse files
author
iantonopoulos
committed
[feat]: developed szudzik's pair and unpair methods
1 parent 6caa8de commit 4693f15

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

pairing_functions/__init__.py

Whitespace-only changes.

pairing_functions/__version__.py

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
__title__ = 'pairing-functions'
3+
__description__ = 'A collection of pairing functions'
4+
__url__ = 'https://github.com/ConvertGroupLabs/pairing-functions'
5+
__version__ = '0.1.0'
6+
__author__ = 'Convert Group Labs'
7+
__author_email__ = 'tools@convertgroup.com'
8+
__license__ = 'MIT License'
9+
__copyright__ = 'Copyright 2019 Convert Group'

pairing_functions/szudzik.py

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from collections import deque
4+
from math import pow, floor, sqrt
5+
from typing import Union
6+
7+
8+
def pair(numbers: Union[list, tuple, deque]) -> int:
9+
"""
10+
Maps a pair of non-negative integers to a
11+
uniquely associated single non-negative integer.
12+
Pairing also generalizes for `n` non-negative integers,
13+
by recursively mapping the first pair.
14+
For example, to map the following tuple:
15+
(n_1, n_2, n_3)
16+
the n_1, n_2 pair is mapped accordingly to a number n_p,
17+
and then the n_p, n3 pair is mapped to produce the final association.
18+
"""
19+
if len(numbers) < 2:
20+
raise ValueError('Szudzik pairing function needs at least 2 numbers as input')
21+
22+
elif any((n < 0) or (not isinstance(n, int)) for n in numbers):
23+
raise ValueError('Szudzik pairing function maps only non-negative integers')
24+
25+
numbers = deque(numbers)
26+
27+
n1 = numbers.popleft()
28+
n2 = numbers.popleft()
29+
30+
if n1 != max(n1, n2):
31+
mapping = pow(n2, 2) + n1
32+
else:
33+
mapping = pow(n1, 2) + n1 + n2
34+
35+
mapping = int(mapping)
36+
37+
if not numbers:
38+
return mapping
39+
else:
40+
numbers.appendleft(mapping)
41+
return pair(numbers)
42+
43+
44+
def unpair(number: int, n: int = 2) -> tuple:
45+
"""
46+
The inverse function outputs the pair
47+
associated with a non-negative integer.
48+
Unpairing also generalizes by recursively unpairing
49+
a non-negative integer to `n` non-negative integers.
50+
For example, to associate a `number` with three non-negative
51+
integers n_1, n_2, n_3, such that:
52+
53+
pairing((n_1, n_2, n_3)) = `number`
54+
55+
the `number` will first be unpaired to n_p, n_3, then
56+
the n_p will be unpaired to n_1, n_2 - thus producing
57+
the desired n_1, n_2 and n_3.
58+
"""
59+
if (number < 0) or (not isinstance(number, int)):
60+
raise ValueError('Szudzik unpairing function requires a non-negative integer')
61+
62+
if number - pow(floor(sqrt(number)), 2) < floor(sqrt(number)):
63+
64+
n1 = number - pow(floor(sqrt(number)), 2)
65+
n2 = floor(sqrt(number))
66+
67+
else:
68+
n1 = floor(sqrt(number))
69+
n2 = number - pow(floor(sqrt(number)), 2) - floor(sqrt(number))
70+
71+
n1, n2 = int(n1), int(n2)
72+
73+
if n > 2:
74+
return unpair(n1, n - 1) + (n2,)
75+
else:
76+
return n1, n2

0 commit comments

Comments
 (0)