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.