Skip to content

Instantly share code, notes, and snippets.

@esquinas
Created September 29, 2021 12:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save esquinas/6242aa7ccdea3debb51a22559e42b340 to your computer and use it in GitHub Desktop.
Save esquinas/6242aa7ccdea3debb51a22559e42b340 to your computer and use it in GitHub Desktop.
Ruby implementation of the Cantor pairing function to uniquely encode two natural numbers into a single natural number while being order sensitive.
# LINK: https://en.wikipedia.org/wiki/Pairing_function#Cantor_pairing_function
# LINK: https://www.cantorsparadise.com/cantor-pairing-function-e213a8a89c2b
def inv_cantor(z)
w = ((Math.sqrt(8.0*z.to_f + 1.0) - 1.0) / 2.0).floor
t = (w**2 + w) / 2
y = (z - t)
x = (w - y)
[x, y]
end
def cantor(x, y)
(x + y) * (x + y + 1) / 2 + y
end
def test(n = 25)
assert_equal = ->(a, b, msg) {
raise "TEST FAILED!\n#{msg}" unless a == b
}
assert_not_equal = ->(a, b, msg) {
raise "TEST FAILED!\n#{msg}" if a == b
}
assert_not_equal.(cantor(2, 1), cantor(1, 2), 'Pairing function should be order sensitive')
n.times do |i|
randx = rand(0...10**rand(1..8)).to_i
randy = rand(0...10**rand(1..8)).to_i
cantorxy = cantor(randx, randy)
expected = [randx, randy]
actual = inv_cantor(cantorxy)
assert_equal.(expected, actual, "CHECK cantor(#{randx}, #{randy}) = #{cantorxy} BUT inv_cantor(#{cantorxy}) = #{actual.join(', ')}")
puts "#{(i+1).to_s.rjust(n.to_s.size)}: cantor(#{randx.to_s.rjust(8)}, #{randy.to_s.rjust(8)}) => #{cantorxy.to_s.rjust(17)} => inv_cantor(_) => [#{actual.join(', ')}]"
end
end
test
# Example test output:
# --------------------
# 1: cantor( 56, 6) => 1959 => inv_cantor(_) => [56, 6]
# 2: cantor(27137933, 304794) => 376551646624422 => inv_cantor(_) => [27137933, 304794]
# 3: cantor( 282455, 310234) => 175640731939 => inv_cantor(_) => [282455, 310234]
# 4: cantor( 7, 45625) => 1041208153 => inv_cantor(_) => [7, 45625]
# 5: cantor( 4437, 95) => 10271873 => inv_cantor(_) => [4437, 95]
# 6: cantor( 22, 339478) => 57630634228 => inv_cantor(_) => [22, 339478]
# 7: cantor( 903, 201) => 610161 => inv_cantor(_) => [903, 201]
# 8: cantor( 740444, 5706) => 278370290031 => inv_cantor(_) => [740444, 5706]
# 9: cantor( 60, 449042) => 100846976795 => inv_cantor(_) => [60, 449042]
# 10: cantor( 79247, 89) => 3147140205 => inv_cantor(_) => [79247, 89]
# 11: cantor( 2832, 244406) => 30563682347 => inv_cantor(_) => [2832, 244406]
# 12: cantor( 71620, 935068) => 506711803084 => inv_cantor(_) => [71620, 935068]
# 13: cantor( 858819, 34) => 368814667265 => inv_cantor(_) => [858819, 34]
# 14: cantor(83665641, 28021) => 3502314571359974 => inv_cantor(_) => [83665641, 28021]
# 15: cantor( 360425, 778875) => 649003593525 => inv_cantor(_) => [360425, 778875]
# 16: cantor( 252, 6841) => 25165712 => inv_cantor(_) => [252, 6841]
# 17: cantor( 2260581, 503158) => 3819128515088 => inv_cantor(_) => [2260581, 503158]
# 18: cantor(20701431, 40089741) => 1847783367052119 => inv_cantor(_) => [20701431, 40089741]
# 19: cantor( 56097, 23942) => 3203184722 => inv_cantor(_) => [56097, 23942]
# 20: cantor( 151949, 97) => 11559069178 => inv_cantor(_) => [151949, 97]
# 21: cantor( 51, 269) => 51629 => inv_cantor(_) => [51, 269]
# 22: cantor( 429, 974484) => 475229140725 => inv_cantor(_) => [429, 974484]
# 23: cantor( 786, 37944927) => 719938624456968 => inv_cantor(_) => [786, 37944927]
# 24: cantor( 211, 71199) => 2549800954 => inv_cantor(_) => [211, 71199]
# 25: cantor( 2867234, 56484) => 4274064990105 => inv_cantor(_) => [2867234, 56484]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment