Golf a bijection \ $\mathbb{N}^n\to\mathbb{N}\$

Oct 26 2020

Twoim zadaniem jest napisanie programu, który implementuje bijection \$\mathbb{N}^n\to\mathbb{N}\$dla \$n \ge 1\$. Twój program powinien zająć \$n\$liczby naturalne jako dane wejściowe, w dowolnej akceptowalnej metodzie (w tym biorąc je jako pojedyncze, \$n\$ lista elementów / tablica) i wyprowadzić unikalną liczbę naturalną dla wszystkich możliwych danych wejściowych.

Mówiąc prościej, bijekcja \$\mathbb{N}^n\to\mathbb{N}\$ znaczy:

  • Weź \$n\$ liczby naturalne jako dane wejściowe
  • Zmapuj te \$n\$ liczby naturalne na pojedynczą liczbę naturalną
  • Dla każdego możliwego wejścia wyjście jest niepowtarzalne
  • Dla każdego możliwego wyjścia istnieje wejście, które da to wyjście

Na przykład funkcja parowania Cantora \$\pi : \mathbb{N}^2\to\mathbb{N}\$ jest bijekcją, która przyjmuje dwie liczby naturalne i odwzorowuje każdą parę na unikalną liczbę naturalną.

Możesz zaimplementować dowolną funkcję bijektywną, o ile zostanie udowodnione, że jest ona bijektywna dla wszystkich możliwych danych wejściowych. Prosimy o dołączenie tego dowodu (bezpośrednio lub poprzez łącze) do odpowiedzi. To jest code-golf, więc wygrywa najkrótszy kod w bajtach.

Możesz zdecydować, czy chcesz użyć \$\mathbb{N} = \{1, 2, 3, \dots\}\$lub \$\mathbb{N} = \{0, 1, 2, \dots\}\$, o ile jest to spójne dla wszystkich \$n\$.

Odpowiedzi

5 ovs Oct 26 2020 at 02:47

APL (Dyalog Unicode) , 13 10 bajtów

(⊢+1⊥∘⍳+)/

Wypróbuj online!

Podobnie jak w przypadku innych odpowiedzi, ponieważ parowanie Cantora jest bijektywne, kompozycja \$n-1\$ Pary Cantor są również bijektywne.

(       )/  ⍝ reduce the input with following function
       +    ⍝ left argument + right argument
      ⍳     ⍝ the first left+right positive integers
   1⊥       ⍝ convert those from base 1 (sum)
 ⊢+         ⍝ + right argument
5 xash Oct 26 2020 at 06:17

J , 8 bajtów

,@|:&.#:

Wypróbuj online! (wyświetla macierz 10x10 dla f (A, B) i kilka kolejnych liczb dla n = 3.)

Zasadniczo wykorzystuje początkowy pomysł Neila, przeplatając bity poprzez ich równomierne rozłożenie (więc dla n = 3, maska ​​bitowa wyjścia to … 1 2 3 1 2 3 1 2 3.). Ale zamiast przesuwania bitów, możemy skorzystać z kształtów: Konwersja każdego numeru do podstawy 2 i list pad z zerami, fe #: 2 3 8jest

0 0 1 0
0 0 1 1
1 0 0 0

Transponuj macierz za pomocą |::

0 0 1
0 0 0
1 1 0
0 1 0

I „deshape” za pomocą ,, czyli połącz wiersze w listę: 0 0 1 0 0 0 1 1 0 0 1 0i zamień ją z powrotem z podstawy 2 &.#:na liczbę: 562.

4 JonathanAllan Oct 26 2020 at 02:48

Galaretka , 6 bajtów

Prawdopodobnie caird's 6 byter ...

+RS+ʋ/

Wypróbuj online!

W jaki sposób?

Implementuje wielokrotne zastosowanie funkcji parowania Cantora.

Pojedyncza aplikacja to \$f(a,b)=\frac{1}{2}(a+b)(a+b+1)+b\$

Ale pamiętaj, że \$\frac{1}{2}(a+b)(a+b+1)=\sum_{i=1}^{a+b}i\$

Więc \$f(a,b)=b+\sum_{i=1}^{a+b}i\$

+RS+ʋ/ - Link: list of non-negative integers
     / - reduce by:
    ʋ  -   last four links as a dyad - f(a,b)
+      -     add     -> a+b
 R     -     range   -> [1,2,3,...,a+b]
  S    -     sum     -> (a+b)(a+b+1)/2
   +   -     add (b) -> b+(a+b)(a+b+1)/2
4 xnor Oct 26 2020 at 04:59

Python 2 , 38 bajtów

f=lambda a,*l:l and(a-~a<<f(*l))-1or a

Wypróbuj online!

Przyjmuje dane wejściowe jak f(1,2,3).

Wykorzystuje funkcję parowania \$p(a,b)=(2a+1)2^b\$. Używamy przesunięcia bitowego, <<baby skrócić *2**bi piszemy, a-~aaby zaoszczędzić bajt 2*a+1.

41 bajtów

lambda l:reduce(lambda a,b:(a-~a<<b)-1,l)

Wypróbuj online!

4 Neil Oct 26 2020 at 01:30

Węgiel drzewny , 21 18 bajtów

W⊖Lθ⊞θ⊖×⊕⊗⊟θX²⊟θIθ

Wypróbuj online! Teraz używa funkcji parowania @ xnor. Poprzednia 21-bajtowa odpowiedź:

W⊖Lθ⊞θΣE²×⊕κ↨↨⊟貦⁴Iθ

Wypróbuj online! Link prowadzi do pełnej wersji kodu. Wyjaśnienie:

W⊖Lθ

Powtarzaj, aż pozostanie tylko jeden element (tj. Zmniejsz w prawo) ...

⊞θΣE²×⊕κ↨↨⊟貦⁴

Zamień ostatnie dwa elementy na podstawę 2, a następnie z powrotem z podstawy 4, podwoj jeden z nich i weź sumę, wypychając wynik z powrotem na listę. Jest to równoważne przeplataniu ich bitów. Używam tego bijekcji zamiast funkcji parowania Cantora, ponieważ wymaga ona odczytania każdej wartości tylko raz, dzięki czemu jest bardziej golfowa w Charcoal.

Iθ

Podaj wynik końcowy.

3 xnor Oct 26 2020 at 04:38

Haskell , 27 bajtów

foldr1(\a b->2^a*(2*b+1)-1)

Wypróbuj online!

Używa innego typu bijekcji niż funkcja parowania Cantora. Każdą dodatnią liczbę całkowitą można jednoznacznie podzielić na potęgę 2 razy liczbę nieparzystą, czyli \$2^a(2b+1)\$dla nieujemnych liczb całkowitych \$a,b\$. Odejmowanie 1 oznacza, że ​​otrzymujemy wszystkie nieujemne liczby całkowite, w tym 0.

Oto tabela bijekcji dla \$a,b\$ od 0 do 6:

  0   2   4   6   8  10  12 ...
  1   5   9  13  17  21  25
  3  11  19  27  35  43  51
  7  23  39  55  71  87 103
 15  47  79 111 143 175 207
 31  95 159 223 287 351 415
 63 191 319 447 575 703 831
 ...                        ...
3 HyperNeutrino Oct 26 2020 at 00:50

Galaretka , 7 bajtów

+‘c2+µ/

Wypróbuj online!

0 to liczba naturalna.

Implementuje parowanie Cantora i redukuje listę.

(Najwyraźniej jest 6-bajtowe rozwiązanie, więc jestem smutny)

Parowanie Cantora jest bijektywne (nie jestem pewien dowodu, ale myślę, że jest to dobrze znane), więc ponieważ kompozycje bijektywne są bijektywne, jest to bijektywne. W skrajnym przypadku, gdy n = 1, to jest tożsamość, więc nadal jest bijektywna.

Przynajmniej tak myślę, że to działa. Daj mi znać, jeśli znajdziesz niezamapowaną wartość lub kolizję.

2 Arnauld Oct 26 2020 at 02:32

JavaScript (ES6), 33 bajty

Parowanie Cantora w tablicy wejściowej a[].

a=>a.reduce((x,y)=>y-(x+=y)*~x/2)

Wypróbuj online!

2 KevinCruijssen Oct 26 2020 at 17:00

05AB1E , 10 9 bajtów

Å«+LOy+}н

Wypróbuj online lub zweryfikuj wszystkie przypadki testowe .

Port odpowiedzi APL @ovs , więc nie zapomnij go zagłosować!
-1 bajt dzięki @ovs .

Alternatywa 9 bajtów :

ćsvy+LOy+

Wypróbuj online lub sprawdź więcej przypadków testowych .

Wyjaśnienie:

Å«         # Cumulative right-reduce by (unfortunately keeping all intermediate steps):
  +        #  Add them together: a+b
   L       #  Pop and push a list in the range [a+b]
    O      #  Sum this list
     y+    #  Add a to it
 }н        # After the reduce-by, pop the list and leave just the first item
           # (after which it is output implicitly as result)

ć          # Extract head of the (implicit) input-list; pushing the remainder-list
           # and first item separated to the stack
 s         # Swap so the remainder-list is at the top
  v        # Loop over each integer `y` in this list:
   y+      #  Add the current integer `y` to the top value
     L     #  Pop and push a list in the range [1,n]
      O    #  Sum this list
       y+  #  And add `y` to it
           # (after the loop, the integer is output implicitly as result)
1 corvus_192 Oct 26 2020 at 02:23

Haskell, 31 bajtów

foldl1(\x y->(x+y)*(x+y+1)/2+y)

Wypróbuj online!

1 corvus_192 Oct 26 2020 at 02:13

Scala, 34 bajty

_.reduce((x,y)=>(x+y)*(x+y+1)/2+y)

Wypróbuj online

Anonimowa funkcja typu Seq[Int] => Int. Stosuje parowanie kantorów do dwóch elementów, aż wynikiem będzie pojedyncza liczba całkowita.

1 Noodle9 Oct 26 2020 at 04:35

C (gcc) , 62 \$\cdots\$ 56 55 bajtów

Zapisano bajt dzięki Ceilingcat !!!

f(a,l)int*a;{l=l?*++a=*a-(*a+=a[1])*~*a/2,f(a,l-1):*a;}

Wypróbuj online!

Wprowadza tablicę liczb naturalnych i jej długość minus \$1\$i zwraca unikalną liczbę naturalną przy użyciu parowania Cantora .

1 DominicvanEssen Oct 26 2020 at 18:53

Łuska , 7 bajtów

FS+ȯΣḣ+

Wypróbuj online!

Rekurencyjne parowanie Cantora (to samo podejście, co odpowiedź HyperNeutrino ).

FS+ȯΣḣ+
F           # Fold over list (=recursively apply to pairs):
 S+ȯΣḣ+     # Cantor-pairing bijection:
 S          # Hook: combine 2 functions using same (first) argument
  +         # add first argument to
   ȯ        # combination of 2 3 functions:
    Σ       # sum of
     ḣ      # series from 1 up to
      +     # sum of first & second arguments
1 Neil Oct 27 2020 at 19:39

Retina , 59 bajtów

.+
*
+`(_+)\1
$1@ @_ _ ^'@P`.+ N$`.
$.%`
¶

_
@_
+`_@
@__
_

Wypróbuj online! Wyjaśnienie:

.+
*
+`(_+)\1
$1@
@_
_

Konwertuj dane wejściowe na binarne, używając @for 0i _for 1.

^'@P`.+

W lewo wszystkie linie o @tej samej długości.

N$`. $.%`
¶

Transponuj i połącz linie.

_
@_
+`_@
@__
_

Konwertuj z dwójkowego na dziesiętny.