Projetar uma função injetiva comutativa entre qualquer conjunto infinito (restrito) e seus pares não ordenados


18

Relacionado, mas isso requer apenas números inteiros positivos e não precisa ser comutativo

A função de emparelhamento Cantor é descrita neste artigo da Wikipedia . Essencialmente, é uma operação que, quando aplicada a dois valores X e Y, é possível obter os valores originais X e Y, considerando o resultado.

Sua tarefa é projetar duas funções: uma que executa X, Y -> Ze a outra que executa Z -> X, Y. Aqui está o problema: X, Y -> Zdeve ser comutativo. Isso significa que Z -> X, Ynão será possível determinar se a entrada foi X, You Y, X.

A definição formal desse desafio seria:

Escolha um conjunto infinito contável de números.
Projete duas funções que executam as seguintes tarefas:

  • Dado um par não ordenado de valores em S, retorne um valor em S
  • Dado um valor de retorno da função inicial, retorne o par não ordenado de valores que é avaliado para o número inteiro de entrada quando passado pela primeira função. Não me importo com o comportamento dessa função inversa se a entrada não for um valor de retorno da primeira função.

Exigências

  • O resultado deve ser idêntico entre as execuções.
  • {a, a} é um par não ordenado

Nota: é mais provável que a sua resposta receba um voto positivo se você fornecer uma prova, mas testarei as respostas quando chegar a ela e a votarei assim que tiver certeza de que funciona.


Isso não se encaixa melhor no puzzling.stackexchange.com ?
Jakube 11/11

2
@Jakube Não necessariamente, pois você precisa escrever um código.
Mr. Xcoder

Estou assumindo que os pares são únicos, mas os números usados ​​nesses pares não são? Então, quando 1,2é um dos pares, 1,3também pode ser um par em potencial (ambos usam 1)?
Kevin Cruijssen

@KevinCruijssen Eu não tenho certeza do que você quer dizer
HyperNeutrino

@ Giuseppe O inverso não precisa ser capaz de retornar a ordem correta; é só que, para função fe seu inverso g, sorted((x, y))deve ser o mesmo quesorted(g(f(x, y)))
HyperNeutrino 11/17/17

Respostas:


13

Haskell , 65 + 30 = 95 bytes

a#b=length.fst$span(<(max a b,min a b))[(a,b)|a<-[1..],b<-[1..a]]

Experimente online!

([(a,b)|a<-[1..],b<-[1..a]]!!)

Experimente online!


Nota: Quando as duas funções podem compartilhar código, são apenas 75 bytes:

(l!!)
a#b=length.fst$span(<(max a b,min a b))l
l=[(a,b)|a<-[1..],b<-[1..a]]

Experimente online! O domínio são os números inteiros positivos. A função (#)realiza o emparelhamento, a função (l!!)é inversa. Exemplo de uso: Ambos (#) 5 3e (#) 3 5rendimento 12, e (l!!) 12rendimentos (5,3).

Isso funciona listando explicitamente todos os pares classificados em uma lista infinita l:

l = [(1,1),(2,1),(2,2),(3,1),(3,2),(3,3),(4,1),(4,2),(4,3),(4,4),(5,1),(5,2),(5,3),(5,4),(5,5),(6,1), ...`

A codificação é então apenas o índice nesta lista.


pelo OP, código compartilhado deve ser contado duas vezes
haskeller orgulhoso

5

Pitão , 8 + 6 = 14 bytes

ij\aSQ16

    SQ   # Sort the input
 j\a     # join with "a"
i     16 # convert from base 16 to base 10

Experimente online!

c.HQ\a

 .HQ     # convert from base 10 to 16
c   \a   # split on "a"

Experimente online!
Domínio: números inteiros positivos.


boa abordagem! +1
HyperNeutrino

4
Não funciona para um monte de números como 2e 10por exemplo (que são de domínio)
Emigna


A 2ª função deve funcionar para qualquer valor em S, não apenas um que foi gerado com a primeira função (eu cometi o mesmo erro).
precisa saber é o seguinte


4

JavaScript (ES7), 44 bytes

(x,y)=>x>y?x*x+y:y*y+x
z=>[x=z**.5|0,y=z-x*x]

Mapeia de números inteiros não negativos para um subconjunto deles.


4

C (gcc) , 36 + 39 = 75 bytes

Obrigado a @tsh por salvar dois bytes.

O domínio é números inteiros não negativos.

p(x,y){return y>x?p(y,x):-~x*x/2+y;}

Toma xe yretorna z.

u(int*r){for(*r=0;r[1]>*r;r[1]-=++*r);}

Toma uma intmatriz de dois elementos . O segundo elemento deve ser definido como zantes da chamada. Após a chamada rconter xe y.

Experimente online!


(x+1)->-~x
TSH

3

Geléia , 13 11 bytes

par de números inteiros positivos para número inteiro positivo, 5 bytes

Ṁc2+Ṃ

Experimente online!

número inteiro positivo para par de números inteiros positivos, 6 bytes

ŒċṀÞị@

Experimente online!

Algoritmo

Se ordenarmos o conjunto de todos os pares não ordenados de números inteiros positivos pelo seu máximo e depois pela sua soma, obteremos a seguinte sequência.

{1,1}, {1,2}, {2,2}, {1,3}, {2,3}, {3,3}, {1,4}, {2,4}, {3 , 4}, {4,4}, {1,5}, {2,5}, {3,5}, {4,5}, {5,5},…

A primeira função pega um par {x, y} e encontra seu índice nessa sequência.

A segunda função leva um número inteiro positivo z e retorna o z th produto da sequência.

Observe que esse mapeamento é o mesmo da resposta Jelly do @ EriktheOutgolfer .

Como funciona

Ṁc2+Ṃ   Main link. Argument: [x, y]
        Let m = max(x, y) and n = min(x, y).

Ṁ       Maximum; yield m.
 c2     2-combinations; yield mC2 = m(m-1)/2.
        Note that there's one pair with maximum 1 ({1,1}), two pairs with maximum 2
        ({1,2}, {2,2}), etc., so there are 1 + 2 + … + (m-1) = m(m-1)/2 pairs with
        maximum less than m.
    Ṃ   Minimum; yield n.
        Note that {x,y} is the n-th pair with maximum m.
   +    Add; yield mC2 + n.
        This finds {x,y}'s index in the sequence.
ŒċṀÞị@  Main link. Argument: z

Œċ      2-combinations w/replacement; yield all pairs [x, y] such that x ≤ y ≤ z.
  ṀÞ    Sort by maximum.
    ị@  Retrieve the pair at index z (1-based).

2
Explicação, por favor. Não estou confiante de que isso seja válido ...
Erik the Outgolfer

Eu adicionei o algoritmo.
Dennis

Alguma coisa não grude comigo ... embora eu também não tenha certeza se isso é inválido. Basicamente, não é bem assim que você usa os dois ce Œċ... embora eu possa estar errado. BTW, que foi a minha resposta que você superou> _>
Erik the Outgolfer

A diferença é mínima para pares. Se C calcula combinações sem substituição e Ƈ calcula combinações com, nƇ2 = nC2 + n .
Dennis

2

Mathematica (35 + 53) = 78 bytes

((x=Min[#])+(y=Max[#]))(x+y+1)/2+y&

(i=Floor[(-1+Sqrt[1+8#])/2];{#-i(1+i)/2,i(3+i)/2-#})&

Essa é a única função de emparelhamento quadrático conhecida para Z <--> ZxZ combinada com Min e Max para torná-la sem ordem.


2

Ruby, 66 bytes

f=->x,y{2**~-x|2**~-y}
g=->n{x,y=(1..n).select{|i|n[i-1]>0};[x,y||x]}

Estou tentando encontrar uma maneira de selecionar astuciosamente um conjunto infinito para tornar isso mais fácil, este é o melhor que tenho até agora.

Definimos f (x, y) = 2 x-1 bit a bit ou 2 y-1 . O domínio consiste no conjunto definido recursivamente como contendo 1,2 e todos os números que podem ser produzidos chamando f nos números do conjunto (observe que f (1,1) = 1 ef (2,2) = 2, então 1 e 2 têm inversos). Todos os números resultantes têm um ou dois 1s em sua expansão binária, com os índices dos 1s correspondentes aos números no conjunto. Podemos obter o par não ordenado original retirando os índices. Se houver apenas um 1, isso significa que os elementos do par são iguais.

Por exemplo, f (3,5) é 20, porque 20 é 10100 na base 2, que possui 1s nos 3º e 5º lugares menos significativos.



Graças, S é, na verdade, um subconjunto dessa sequência OEIS embora porque inclui apenas números cujos 1s têm índices em S.
histocrat

ah sim, claro. Bem, nenhuma outra sequência corresponde aos primeiros termos (até 32).
Giuseppe

Adicione 0 a S e você poderá salvar alguns decrementos.
Nwellnhof 11/09

2

Java 8, 153 146 141 137 + 268 224 216 205 bytes

Função de par

a->{String f="";for(int i=(f+a[0]).length(),c=0,j;i>0;i-=c,f+=c,c=0)for(j=1;j<10;c+=i-j++<0?0:1);return new Integer(a[0]+""+a[1]+"0"+f);}

Experimente online!

Função Depair

r->{String a=r+"",t=a.substring(a.lastIndexOf('0')+1);int l=0,i=l,o=t.length();for(;i<o;l+=r.decode(t.charAt(i++)+""));return new int[]{r.decode(a.substring(0,l)),r.decode(a.substring(l,a.length()-o-1))};}

Experimente online!


11
Você pode jogar golfe em algumas partes. Na função de par: int i=(""+a[0]).length()pode ser int i=(f+a[0]).length(); o espaço entre eles c=0,j;i>0;pode ser removido; a[0].parseIntpode ser new Integer. Na função de desespero: todos os três r.parseIntpodem ser r.decode; e você pode fazer uma variável int para t.length(), desde que você a use duas vezes.
Kevin Cruijssen 12/09


1

JavaScript, 72 bytes

f=a=>eval('0x'+a.sort().join`a`)
g=n=>n.toString(16).split`a`.map(x=>+x)

Funciona para números inteiros positivos (em teoria). Idéia bastante simples: classifique dois números em alguma ordem (mágica), conecte-os como string por uma letra "a", analise-o como número inteiro hexadecimal.


1

MATL, 6 + 8 = 14 bytes

Função de codificação, aceita duas entradas n, m. Produz o produto de enésimo primo e enésimo primo.

,iYq]*

Passos:

  • , - faça duas vezes
  • i - Entrada push
  • Yq - Entrada pop, entrada push'th prime
  • ]* - Finalize duas vezes, coloque os dois primos e empurre o produto

Função de decodificação, leva uma entrada m. Emite o número de primos abaixo de cada um dos fatores primos de n.

iYf"@Zqn

Passos:

  • i - Entrada push
  • Yf - Entrada pop, push array de fatores principais
  • " - Para n na matriz
  • @Zq - Empurre a matriz de números primos abaixo de n
  • n - Pop array, comprimento do push do array

Isso é comutativo porque a multiplicação é comutativa e injetável porque as fatorações primárias são únicas. Não que isso não esteja nos números inteiros.


0

Casca , 5 + 3 = 8 bytes

Eu realmente espero ter acertado o desafio, vejo algumas respostas excluídas que parecem válidas para mim ...

Pares de números inteiros positivos para um único número inteiro positivo:

¤*!İp

Experimente online!

Ele funciona pegando os números nos índices fornecidos (indexados em 1) da lista de números primos e multiplicando-os.

Resultado da primeira função para pares de números inteiros positivos:

mṗp

Experimente online!

Nós fatoramos o número de entrada e retornamos o índice na lista de números primos de todos (ambos) de seus fatores.

Exemplo trabalhado

Dado (4,1)como um casal inicial, pegamos o quarto e o primeiro números primos (7,2)e os multiplicamos → 14. Essa multiplicação é o que torna a função independente da ordem dos dois elementos.

Começando por 14, nós o fatoramos (2,7)e retornamos os índices de 2e 7na lista de números primos → (1,4).


Na verdade, olhando para a resposta excluída de Arnauld, seu algoritmo é ainda melhor, e a transferência para Husk resultaria em 6 bytes ... Alguém poderia confirmar se sua solução (e a minha também) é válida ou não?
Leo

Não funciona para números primos (que estão no domínio de inteiros positivos)
Emigna

@Emigna a segunda função não faz, mas primos nunca são retornados pelo primeiro ...
Leo

Seu domínio é números inteiros positivos, portanto, os dois métodos precisam trabalhar com números inteiros positivos. EDIT: ou pelo menos isso costumava ser um requisito. As regras atuais parecem permitir um subconjunto do domínio.
Emigna

0

C # , 80 bytes (38 + 42)


Dados

Codificador

  • Int32 lNúmero de entrada A
  • Int32 rNúmero de entrada A
  • Saída Int64 As duas entradas se fundiram

Decodificador

  • Entrada Int32 v O valor
  • Saída Int32[] Uma matriz com as duas entradas originais.

Golfe

// Encoder
e=(l,r)=>{return(long)l<<32|(uint)r;};

// Decoder
d=v=>{return new[]{v>>32,v&0xFFFFFFFFL};};

Ungolfed

// Encoder
e = ( l, r ) => {
    return (long) l << 32 | (uint) r;
};

// Decoder
d = v => {
    return new[] {
        v >> 32,
        v & 0xFFFFFFFFL };
};

Ungolfed legible

// Encoder
// Takes a pair of ints
e = ( l, r ) => {

    // Returns the ints fused together in a long where the first 32 bits are the first int
    // and the last 32 bits the second int
    return (long) l << 32 | (uint) r;
};

// Decoder
// Takes a long
d = v => {

    // Returns an array with the ints decoded where...
    return new[] {

        // ... the first 32 bits are the first int...
        v >> 32,

        // ... and the last 32 bits the second int
        v & 0xFFFFFFFFL };
};

Código completo

using System;
using System.Collections.Generic;

namespace TestBench {
    public class Program {
        // Methods
        static void Main( string[] args ) {
            Func<Int32, Int32, Int64> e = ( l, r ) => {
                return(long) l << 32 | (uint) r;
            };
            Func<Int64, Int64[]> d = v => {
                return new[] { v >> 32, v & 0xFFFFFFFFL };
            };

            List<KeyValuePair<Int32, Int32>>
                testCases = new List<KeyValuePair<Int32, Int32>>() {
                    new KeyValuePair<Int32, Int32>( 13, 897 ),
                    new KeyValuePair<Int32, Int32>( 54234, 0 ),
                    new KeyValuePair<Int32, Int32>( 0, 0 ),
                    new KeyValuePair<Int32, Int32>( 1, 1 ),
                    new KeyValuePair<Int32, Int32>( 615234, 1223343 ),
                };

            foreach( KeyValuePair<Int32, Int32> testCase in testCases ) {
                Console.WriteLine( $" ENCODER: {testCase.Key}, {testCase.Value} = {e( testCase.Key, testCase.Value )}" );
                Console.Write( $"DECODING: {e( testCase.Key, testCase.Value )} = " );
                PrintArray( d( e( testCase.Key, testCase.Value ) ) );

                Console.WriteLine();
            }

            Console.ReadLine();
        }

        public static void PrintArray<TSource>( TSource[] array ) {
            PrintArray( array, o => o.ToString() );
        }
        public static void PrintArray<TSource>( TSource[] array, Func<TSource, String> valueFetcher ) {
            List<String>
                output = new List<String>();

            for( Int32 index = 0; index < array.Length; index++ ) {
                output.Add( valueFetcher( array[ index ] ) );
            }

            Console.WriteLine( $"[ {String.Join( ", ", output )} ]" );
        }
    }
}

Lançamentos

  • v1.0 - 80 bytes- Solução inicial.

Notas

  • Nenhum

0

Python: 41 + 45 = 86

codificador: 41

e=lambda*x:int('1'*max(x)+'0'+'1'*min(x))
e(4, 3), e(3,4)

(11110111, 11110111)

decodificador: 45

d=lambda z:[len(i)for i in str(z).split('0')]
d(11110111)

[4, 3]

Tentativa anterior:

Python: 114: 30 + 84

codificador: 30

aceita 2 inteiros, retorna uma string

e=lambda*x:2**max(x)*3**min(x)
e(3, 4), e(4, 3)

(432, 432)

decodificador: 86

def d(z):
 x=y=0
 while 1-z%2:
  x+=1
  z/=2
 while 1-z%3:
  y+=1
  z/=3
 return x,y
d(432)

4, 3

decoder2: 120

outra tentativa com compreensão e soma de geradores

def d(z):
 x=sum(1 for i in range(z)if not z%(2**i))-1
 z/=2**x
 return x,sum(1 for i in range(int(z))if not z%(3**i))-1

11
com base na segunda tentativa: e=lambda*x:10**sum(x)-10**min(x);d=lambda z:map(z .count,'09'); TIO
tsh

@tsh muito bom. Vou adaptá-lo mais tarde, ou você pode enviar sua própria resposta #
Maarten Fabré
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.