Bijective işlevi ℤ → ℤⁿ


23

Z'den (tüm tamsayılar kümesinden) Z'ye (örneğin, kimlik işlevi) kadar bir sıfat işlevi oluşturmak mümkündür .ZZ

Bir örten işlev oluşturmak da mümkündür için Z 2 (, 2 tamsayılar çiftleri grubu Kartezyen ürün bir Z ve Z ). Örneğin, 2B düzlemde tamsayı noktalarını temsil eden kafesi alabilir, 0'dan dışa doğru bir spiral çizebilir ve daha sonra tam sayı çiftlerini bu noktayla kesiştiğinde spiral boyunca olan mesafe olarak kodlayabiliriz.ZZ2ZZ

Spiral

(Bunu doğal sayılarla yapan bir işlev , eşleştirme işlevi olarak bilinir .)

Aslında, bu sıfat fonksiyonlarının bir ailesi var:

fk(x):ZZk

Meydan okuma

fonksiyonlarının bir ailesini tanımlayın ( k k pozitif bir tamsayıdır), f k ( x ) tamsayılarını k- tamsayılarına k- tuples ile eşzamanlı olarak eşler.fk(x)kfk(x)k

Gönderiminiz, ve x girdileri verildiğinde , f k ( x ) değerini döndürmelidir .kxfk(x)

Bu , bu yüzden en kısa geçerli cevap (bayt cinsinden ölçülen) kazanır.

Özellikler

  • Herhangi bir aile olduğu sürece yukarıdaki kriterleri karşılayan olarak kullanılabilir.fk(x)
  • İşlev ailesinin nasıl çalıştığının bir açıklamasını ve işlevin tersini hesaplamak için bir pasajı eklemeniz önerilir (bu, bayt sayınıza dahil değildir).
  • Ters fonksiyonun hesaplanamaz olması durumunda, fonksiyonun sakıncalı olduğunu kanıtlayabildiğiniz sürece sorun yoktur.
  • Diliniz için imzalı tamsayılar ve imzalı tamsayıların listesi için uygun olan herhangi bir gösterimi kullanabilirsiniz, ancak işlevinize girdilerin sınırsız kalmasına izin vermelisiniz.
  • Sadece kadar k değerlerini desteklemeniz gerekir .k

Dize sürümlerini almak tamam mı k ve xyerine tamsayılar?
JungHwan Min

@JungHwanMin Giriş numaralarını temsil eden dizeler iyi.
Esolanging Fruit

Yanıtlar:


19

Alice , 14 12 bayt

/O
\i@/t&Yd&

Çevrimiçi deneyin!

Ters fonksiyon (golf oynamayan):

/o     Q
\i@/~~\ /dt&Z

Çevrimiçi deneyin!

açıklama

Alice, un ve 2 arasında Y(paketten çıkarma ) ve bunun tersi Z (paket) ile hesaplanabilen yerleşik bir önyargıya sahiptir . İşte itiraz açıklayan docs bir alıntı:

İtirazın detayları çoğu kullanım durumuyla ilgili değildir. Ana nokta, kullanıcının iki tam sayıyı bir arada kodlamasını ve daha sonra iki tam sayıyı çıkarmasını sağlamasıdır. Paket komutunu tekrar tekrar uygulamak suretiyle, tam listelerin veya ağaçların tamamı tek bir numarada saklanabilir (özellikle hafıza açısından verimli olmasa da). Paketleme işlemi tarafından hesaplanan eşleme 2 → ℤ (yani bire bir eşleme) gibi bir önyükleme işlevidir . İlk olarak, {..., -2, -1, 0, 1, 2, ...} tamsayıları {... , 3, 1, 0, 2, 4 gibi doğal sayılarla (sıfır dahil) eşlenir , ...}(Başka bir deyişle, negatif tamsayılar garip doğaya eşlenir ve negatif olmayan tamsayılar bile doğaya eşlenir). İki doğal sayı, daha sonra , doğalları tamsayı ızgarasının ilk çeyreğinin köşegenleri boyunca yazan Cantor eşleştirme işlevi eşleştirilir . Özellikle, {(0,0), (1,0), (0,1), (2,0), (1,1), (0,2), (3,0), ...} olan {0, 1, 2, 3, 4, 5, 6, ...} ile eşlendi . Sonuçta ortaya çıkan doğal sayı daha önceki önyüklemenin tersini kullanarak tamsayılarla eşleştirilir. Unpack komutu, tam olarak bu eşlemenin tersini hesaplar.

Yukarıda belirtildiği gibi, bu paket açma işlemini - k eşlemesinde kullanabiliriz . de kullanabiliriz. İlk tamsayıya uyguladıktan sonra, sonucun ikinci tamsayısını tekrar açabiliriz, bu da bize üç tamsayının bir listesini verir. Böylece k-1 uygulamaları Ybize sonuç olarak k tamsayıları verir .

Listeyi en Zbaştan paketleyerek tersini de hesaplayabiliriz .

Yani programın kendisi bu yapıya sahiptir:

/O
\i@/...d&

Bu, değişken olarak ondalık sayıları girdi olarak okuyan ve sonuç olarak değişken sayı yazdıran bir program için yalnızca temel bir şablondur. Yani gerçek kod gerçekten sadece:

t   Decrement k.
&   Repeat the next command k-1 times.
Y   Unpack.

Ele almak istediğim bir şey "neden Alice’in bir ℤ → ℤ 2 ki, bu golf sahası değil mi?" Alice'in garibini yerleşik ins çoğunda olduğu gibi, temel nedeni Alice'in tasarım prensibi her komut edilmelidir iki anlamı Cardinal (tamsayı) modu için bir ve Ordinal (string) modu için bir tane ve bu iki anlamı var olmasıdır nasılsa vermek ilişkin Kardinal ve Ordinal mod, olayların aynı, aynı zamanda farklı olduğu ayna evrenleri olduğu hissini verir. Sıklıkla eklemek istediğim iki moddan birine komut verdim ve sonra hangi komutla eşleştirileceğini bulmak zorunda kaldım.

Bu durumuda Y ve ZSıra modunda birinci oldu: İki dizeleri (zip) serpiştirilmesi ve tekrar (unzip) bunları ayırmak için bir işlevi olmasını istedik. Kardinal modda yakalamak istediğim şeyin kalitesi, ikiden bir tam sayı oluşturmak ve iki tam sayıyı daha sonra tekrar çıkarabilmekti;

Ayrıca bunun golf oynama dışında da çok faydalı olacağını düşündüm, çünkü tek bir bellek biriminde (yığın elemanı, teyp hücresi veya ızgara hücresi) tüm bir listeyi veya hatta tamsayılar ağacını saklamanıza izin veriyor.


Her zamanki gibi harika bir açıklama
Luis Mendo

Alice belgelerinde bulmak Yve bulmak Zaslında bu zorluğu atmam için beni yönlendirdi (bir süredir bunu düşünüyordum ama bu bana hatırlattı).
Esolanging Fruit

11

Python, 96 93 bayt

def f(k,x):
 c=[0]*k;i=0
 while x:v=(x+1)%3-1;x=x//3+(v<0);c[i%k]+=v*3**(i//k);i+=1
 return c

Giriş numarasını dönüştürerek ilke olarak bu çalışmalar xiçin dengeli bir üçlü ve daha sonra ilk yuvarlak masa oturumu tarzında farklı koordinatlar arasındaki en küçük anlamlı Trits (üçlü sayı) dağıtmak. Bu nedenle, k=2örneğin, her konumlandırılmış her trit xkoordinatlara katkıda bulunacak ve her sıralı pozisyon trit ykoordinatına katkıda bulunacaktır . Çünkü k=3sizlere katkıda bulunan ilk, dördüncü ve yedinci tritler (vb.) Olurken x, ikinci, beşinci ve sekizinciy ve üçüncü, altıncı ve dokuzuncu katkısı var z.

Örneğin, k=2şuna bir bakalım x=35. Dengeli üçlü olarak, 35bir 110T(Vikipedi makalenin gösterimi kullanılarak Tbir temsil -1rakamı). Tritleri bölmek 1T( xkoordinat için birinci ve üçüncü basamaklar, sağdan sayılır) ve koordinat için 10(ikinci ve dördüncü basamaklar) verir y. Her bir koordinatı ondalık basamağa geri dönüştürebiliriz 2, 3.

Tabii ki, aslında tam sayıyı bir kerede golf kodunda dengeli bir üçlüye dönüştürmüyorum. Her seferinde bir vdeğişkeni hesaplıyorum ( değişkende) ve değerini doğrudan uygun koordinatlara ekliyorum.

İşte koordinatların bir listesini alır ve bir sayı döndüren yıpranmış bir ters fonksiyon:

def inverse_f(coords):
    x = 0
    i = 0
    while any(coords):
        v = (coords[i%3]+1) % 3 - 1
        coords[i%3] = coords[i%3] // 3 + (v==-1)
        x += v * 3**i
        i += 1
    return x

Benim fişlevim belki de performansı ile dikkat çekiyor. Yalnızca O(k)bellek kullanır ve O(k) + O(log(x))sonuçları bulmak için zaman alır , böylece çok büyük giriş değerleriyle çalışabilir. Deneyin f(10000, 10**10000)mesela ve siz (böylece üs için ekstra bir sıfır ekleyerek hemen hemen anında bir cevap alırsınız xolduğunu 10**100000benim eski PC'de 30 saniye kadar sürebilir markaları). Ters fonksiyon hızlı değildir, çünkü ne zaman yapıldığını söylemesi zordur (her değişiklikten sonra tüm koordinatları tarar, bu yüzden zaman alır O(k*log(x))). Muhtemelen daha hızlı olacak şekilde optimize edilmiş olabilir, ancak zaten normal parametreler için muhtemelen yeterince hızlıdır.


While döngüsü içindeki boşlukları (newlines) kaldırabilirsiniz
Bay Xcoder

Teşekkürler, yanlışlıkla bir döngü ile ;ifadeleri tek bir satırda zincirleme kullanmak arasında bir çeşit çatışma olduğunu düşünmüştüm .
Blckknght

9

Kabuğu , 10 bayt

§~!oΠR€Θݱ

Çevrimiçi deneyin!

Ters fonksiyon da 10 bayttır.

§o!ȯ€ΠRΘݱ

Çevrimiçi deneyin!

açıklama

İleri yönde:

§~!oΠR€Θݱ  Implicit inputs, say k=3 and x=-48
        ݱ  The infinite list [1,-1,2,-2,3,-3,4,-4,..
       Θ    Prepend 0: [0,1,-1,2,-2,3,-3,4,-4,..
 ~    €     Index of x in this sequence: 97
§    R      Repeat the sequence k times: [[0,1,-1,..],[0,1,-1,..],[0,1,-1,..]]
   oΠ       Cartesian product: [[0,0,0],[1,0,0],[0,1,0],[1,1,0],[-1,0,0],[0,0,1],..
  !         Index into this list using the index computed from x: [-6,1,0]

Ters yön:

§o!ȯ€ΠRΘݱ  Implicit inputs, say k=3 and y=[-6,1,0]
     ΠRΘݱ  As above, k-wise Cartesian product of [0,1,-1,2,-2,..
   ȯ€       Index of y in this sequence: 97
§o!         Index into the sequence [0,1,-1,2,-2,.. : -48

Yerleşik Kartezyen ürünü Π, her bir k- parçasını tam olarak bir kez numaralandıran sonsuz listeler için güzel davranır .


[[0,1,-1,..],[[0,1,-1,..],[[0,1,-1,..]]bu kısım mı olmalı [[0,1,-1,..],[0,1,-1,..],[0,1,-1,..]]?
Outgolfer Erik,

@EriktheOutgolfer Umm evet, şimdi düzeltildi.
Zgarb

Bu güzel. Bir J programcısı olarak, bu gibi tembel bir liste çözümünü J'ye dönüştürmenin iyi bir yolu olup olmadığını biliyor musunuz? ^:^:_tip çözümler genellikle çok daha hantal olur ...
Jonah

@Jonah Emin değilim. Tüm k -tuples dizilerini girdilerle hesaplayabilir ve i: xmutlak değerlerin toplamına göre sıralayabilir, daha sonra buna indeksleyebilirsiniz. Fikir bu dizilerin tüm k -tuples içeren bir "sonsuz dizi" nin önekleri olmasıdır.
Zgarb

7

Wolfram Dili (Mathematica) , 61 bayt

SortBy[Range[-(x=2Abs@#+Boole[#>=0]),x]~Tuples~#2,#.#&][[x]]&

Çevrimiçi deneyin!

(Tamsayıyı ve ardından girişin uzunluğunu girdi olarak alır.)

Ters:

If[OddQ[#],#-1,-#]/2&@Tr@Position[SortBy[Range[-(x=Ceiling@Norm@#),x]~Tuples~Length@#,#.#&],#]&

Çevrimiçi deneyin!

Nasıl çalışır

Fikir açıktır: tamsayı girişini pozitif bir tamsayıya dönüştürürüz (0,1,2,3, ... ila 1,3,5,7, ... ve -1, -2, -3 ... 2,4,6, ...) ve sonra tüm k dizinine orijinden uzaklığa ve ardından Mathematica'nın varsayılan bağlayıcılığına göre sıralanan başlıklarına indeksleyin.

Ama biz aradığımızı bu yüzden zaman, sonsuz bir liste kullanamaz n inci k -tuple, sadece üretmek k -tuples aralığında tamsayılar {- n , ..., n }. Bunun nedeni, yeterli olması sağlanır n inci en küçük k norm tarafından -tuple az norma sahip n ve norm tüm tuples n veya daha az bu listeye dahil edilmiştir.

Tersine , biz sadece yeterince uzun bir k- tller listesi hazırlıyoruz, bu k- tupleın o listedeki pozisyonunu bulup , "katlamayı pozitif bir tamsayı" işlemine çeviriyoruz.


2
Girişlerle [15, 5]
çalışmak PC'mi çökertdi

2
Bu olacak. Prensipte, algoritma her şey için çalışır, ancak sizin durumunuzda {-31, .., 31} aralığında 5 tuple oluşturarak ve sonra da 31'inden birini alarak çalışır, bu yüzden oldukça hafızalıdır.
Misha Lavrov

3

J, 7 Bayt

#.,|:#:

Bu utanç verici basitleştirmek için J kodu

Çok basit bir eşleştirme işlevi (veya, kayma işlevi), sayıların her birinin ikili genişlemesinin basamaklarını basitçe harmanlamaktır. Dolayısıyla, örneğin (47, 79)şu şekilde eşleştirilecektir:

1_0_0_1_1_1_1
 1_0_1_1_1_1
-------------
1100011111111

veya, 6399. Açıkçası, herhangi bir n-demetine önemsiz bir şekilde genellenebiliriz.

Bu fiil tarafından fiil nasıl çalıştığını inceleyelim.

#:anti-baz iki, monadik olarak kullanıldığında bir sayının ikili genişlemesini döndürür. #: 47 79sonuç verir:

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

|:bir diziyi basitçe döndüren transpoze operatörüdür. Aşağıdaki sonucu #: 47 79döndürür:

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

Monodik olarak kullanıldığında ,, ravel operatörüdür, bir tablodan 1 boyutlu bir liste oluşturur:

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

Son olarak, #.ikili sonucu genişletmeyi geri dönüştürerek sonucu bize verir 6339.

Bu çözüm herhangi bir tamsayı dizisi için çalışacaktır.


7
Negatif sayılar için bu nasıl çalışır?
Neil

2

Perl 6 , 148 bayt

my@s=map ->\n{|grep {n==abs any |$_},(-n..n X -n..n)},^Inf;my&f={$_==1??+*!!do {my&g=f $_-1;my@v=map {.[0],|g .[1]},@s;->\n{@v[n>=0??2*n!!-1-2*n]}}}

Çevrimiçi deneyin!

Ungolfed:

sub rect($n) {
    grep ->[$x,$y] { abs($x|$y) == $n }, (-$n..$n X -$n..$n);
}

my @spiral = map { |rect($_) }, ^Inf;

sub f($k) {
    if ($k == 1) {
        -> $_ { $_ }
    } else {
        my &g = f($k-1);
        my @v = map -> [$x, $y] { $x, |g($y) }, @spiral;
        -> $_ { $_ >= 0 ?? @v[2*$_] !! @v[-1-2*$_] }
    }
}

Açıklama:

  • rect($n)koordinatlardan bir dikdörtgen kenarına yekpare noktalarının koordinatları üreten bir yardımcı fonksiyonudur (-$n,$n)için ($n, $n).

  • @spiral 0'dan başlayarak, artan boyuttaki dikdörtgenlerin kenarlarındaki integral noktalarının tembel, sonsuz bir listesidir.

  • f($k)tamsayılardan tamsayılara kadar bir $könyükleme olan bir işlev döndürür .

Eğer $kbir 1, fkimlik eşlemesi döndürür -> $_ { $_ }.

Aksi halde, &gtamsayılardan tamsayılara kadar $k-1tekrarlı olarak elde edilen haritalamadır .

Sonra @spiralorijinden çıktık ve her noktada $kX koordinatını ve gY koordinatını çağırmanın düzleştirilmiş sonucunu alarak bir -tuple oluştururuz . Bu tembel olarak oluşturulan haritalama dizide saklanır @v.

@v$k0 dizini ile başlayan tüm -trupları içerir , böylece dizini negatif tam sayılara genişletmek için, pozitif girişleri çift sayılarla ve negatif girişleri tek sayılarla eşleştiririz. @vBu şekilde elemanları arayan bir işlev (kapatma) döndürülür .


2

JavaScript, 155 bayt

f=k=>x=>(t=x<0?1+2*~x:2*x,h=y=>(g=(v,p=[])=>1/p[k-1]?v||t--?0:p.map(v=>v&1?~(v/2):v/2):[...Array(1+v)].map((_,i)=>g(v-i,[...p,i])).find(u=>u))(y)||h(y+1))(0)

Güzel sürüm:

k => x => {
  // Map input to non-negative integer
  if (x > 0) t = 2 * x; else t = 2 * -x - 1;
  // we try to generate all triples with sum of v
  g = (v, p = []) => {
    if (p.length === k) {
      if (v) return null;
      if (t--) return null;
      // if this is the t-th one we generate then we got it
      return p;
    }
    for (var i = 0; i <= v; i++) {
      var r = g(v-i, [...p, i]);
      if (r) return r;
    }
  }
  // try sum from 0 to infinity
  h = x => g(x) || h(x + 1);
  // map tuple of non-negative integers back
  return h(0).map(v => {
    if (v % 2) return -(v + 1) / 2
    else return v / 2;
  });
}
  • Öncelikle, tüm tam sayıları negatif olmayan tüm tam sayılara tek tek eşleriz:
    • eğer n> 0 ise sonuç = n * 2
    • aksi halde sonuç = -n * 2 - 1
  • İkincisi, k-uzunluğu negatif olmayan tamsayılara sahip tüm gruplara bir emir veririz:
    • tüm elemanların toplamını hesaplar, küçük olan önce gelir
    • eğer toplam eşitse, soldan sağa doğru karşılaştırın, daha küçük olanı önce gelir
    • Sonuç olarak, negatif olmayan tamsayıların negatif olmayan tamsayılarla tupl'lerin haritasını çıkardık.
  • Son olarak, ikinci adımda verilen negatif olmayan tamsayıları, ilk adımdaki benzer formüle sahip tüm tamsayılarla eşleştirin

Sanırım x<0?~x-x:x+x2 bayt kurtarıyor.
Neil

2

Wolfram Dili (Mathematica) , 107 bayt

(-1)^#⌈#/2⌉&@Nest[{w=⌊(√(8#+1)-1)/2⌋;x=#-w(w+1)/2,w-x}~Join~{##2}&@@#&,{2Abs@#-Boole[#<0]},#2-1]&

Çevrimiçi deneyin!

Ters, 60 bayt

(-1)^#⌈#/2⌉&@Fold[+##(1+##)/2+#&,2Abs@#-Boole[#<0]&/@#]&

Çevrimiçi deneyin!

Açıklama:

Z -> N0 üzerinden f(n) = 2n if n>=0 and -2n-1 if n<0

N0 -> N0 ^ 2 eşleştirme işlevinin tersi yoluyla

N0 -> N0 ^ k Uzunluğa kadar yukarıdakileri en soldaki sayıya tekrar tekrar uygulayın k

N0 ^ k -> Z ^ k üzerinden f(n) = (-1)^n * ceil(n/2), element-bilge


Mathematica, 101 bayt

(-1)^#⌈#/2⌉&@Nest[{a=#~IntegerExponent~2+1,#/2^a+1/2}~Join~{##2}&@@#&,{2Abs@#+Boole[#<=0]},#2-1]&

Yukarıdakine benzer (N0 yerine N kullanır), ancak f: N ^ 2 -> N f(a, b) = 2^(a - 1)(2b - 1)


Yani ... bunun için yerleşik bir Mathematica yok (Alice'te bir tane varsa)? Ben suskunum.
JayCe

1

JavaScript, 112 bayt

k=>x=>(r=Array(k).fill(''),[...`${x<0?2*~x+1:2*x}`].map((c,i,s)=>r[(s.length-i)%k]+=c),r.map(v=>v&1?~(v/2):v/2))
  1. negatif olmayana dönüştür
  2. (n * k + i) inci hane i-inci sayı
  3. geri dön

@HermanLauenstein'ın geri dönmesine gerek yok mu?
tsh

x<0?~x-x:x+x2 bayt kurtardığını düşünüyorum .
Neil

-5 bayt kullanarak [...BT${x<0?~x-x:x+x}BT].reverse().map((c,i)=>r[i%k]+=c),(kredi için @Neil x<0?~x-x:x+x). .reverse()yerine kullanılan (s.length-i)ekstra parametrenin ihtiyacını ortadan kaldırır çünkü silkine .map. Geçici dizi tekrar kullanılmadığı için geri dönmeye gerek yoktur. (Test etmedim ama muhtemelen çalışması gerekiyor)
Herman L

Başka bir bayt yerine kaydedilebilir .fill('')olan .fill(0)lider sıfır (en az Safari'deki test zaman) herhangi bir fark etmez, çünkü
Herman L

@HermanLauenstein Denedin mi .fill`` ? Başka bir kaç bayt kurtarabilir.
Neil


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.