Calcular o XOR inverso

13

Let fSer a função que mapeia um bitfield ( {0 1}) de tamanho n+1para bitfield de tamanho naplicando XORao ith th e i+1th bit e gravando o resultado no novo bitfield.

Exemplo: f("0101") = "111"

Cálculo informal:

0 XOR 1 = 1

1 XOR 0 = 1

0 XOR 1 = 1

Let f_inverseSer a função inversa de f. Como o inverso não é exclusivo, f_inverseretorna uma solução válida.

Entrada: campo de bits como string (ou seja "0101111101011") e um número natural especificadok

Saída: campo de bits como sequência, para que a sequência contenha o resultado se f_inversefor aplicada kvezes ao campo de bits de entrada. (ie f_inverse(f_inverse(f_inverse(input))))

Critérios para ganhar: menos caracteres

Bônus:

-25Caracteres se f_inversenão é aplicada de forma recursiva / iterativa, em vez da cadeia de saída está diretamente calculado

Teste:

a = "011001"
k = 3

def f(a):
    k = len(a)
    r = ""
    for i in xrange(k-1):
        r += str(int(a[i]) ^ int(a[i+1]))
    return r

def iterate_f(a, k):
    print "Input ", a
    for i in xrange(k):
        a = f(a)
        print "Step " + str(i+1), a

iterate_f(a, k)

Você pode colá-lo, por exemplo, aqui e tentar.

nvidia
fonte
3
Você pode dar alguns casos de teste para verificar.
Optimizer
3
Você poderia parar de chamá-los de {0-1}-Bitfields? Também não entendo a definição de f, de onde ivem? Qual é o segundo argumento do XOR? como é que vamos 111partir 0101?
Mniip
Qual é um nome melhor? eu denota o índice
nvidia
Apenas um "campo de bits" serviria. Qual é o / value / of i? "0 XOR 1" = 1 "1 XOR 0" = 1 "0 XOR 1" = 1não explica nada: eu sei como o XOR funciona, mas o que exatamente nós estamos usando e onde estamos armazenando o resultado?
Mniip
9
Eu acho que ele significa: f([a,b,c,d]) = [a^b, b^c, c^d]. E ele quer o inverso dessa função, ou seja, f'([x,y,z]) = [a,b,c,d]de tal forma que a^b=x, b^c=y, c^d=z.
marinus

Respostas:

14

Pyth, 33 30 - 25 = 5 bytes

Jiz8K+lzQ%"%0*o",KuxG/G8rQ^2KJ

Execute-o com a entrada de stdin como (intérprete online: https://pyth.herokuapp.com/ ):

111
3

e o resultado será gravado em stdout.

Esta é uma tradução direta de:

Python 2, 127 118 79 - 25 = 54 bytes

def i(s,k):
 l=int(s,8);t=len(s)+k
 while k<1<<t:l^=l/8;k+=1
 print'%0*o'%(t,l)

Chame assim i("111", 3), e o resultado será gravado em stdout.

Observe que esperamos que k não seja muito grande, pois, para fins de golfe com código, o loop interno será executado por O (2 k ) vezes.


Eu acho que geralmente chamamos essa operação de "xorshift" ou algo assim. Se expressarmos a entrada como números inteiros big-endian, a função f é simplesmente:

  • f (x) = x ⊕ (x ≫ 1)

Se aplicarmos f duas vezes, obteremos:

  • f 2 (x) = x ⊕ (x »2)

No entanto, a aplicação de 3 vezes terá um padrão diferente:

  • f 3 (x) = x ⊕ (x »1) ⊕ (x» 2) ⊕ (x »3)

Ao aplicar 4 vezes, volte ao formulário básico:

  • f 4 (x) = x ⊕ (x »4)

E assim por diante:

  • f 2 k (x) = x ⊕ (x »2 k )

Observe que se escolhermos 2 k grandes o suficiente , então (x ≫ 2 k ) = 0, ou seja, f 2 k (x) = x, e o inverso é trivialmente a função de identidade!

Assim, a estratégia para encontrar f k (x) sem chamar f -1 (x) em tudo é:

  1. Encontre K tal que:

    • K ≥ k
    • K> log 2 x
    • K é uma potência de 2
  2. Expresse f -k (x) = f -K + (Kk) (x) = f -K (f K-k (x)) = f K-k (x)

  3. Assim, o resultado é fchamado Kk vezes

  4. Lucro de 25 caracteres: p


Atualização 1 : representação octal usada em vez de binária, para que pudéssemos usar a %formatação para economizar muitos bytes.

Atualização 2 : Explorar a estrutura periódica de f. A versão iterativa foi desativada, já que a não iterativa é mais curta, mesmo sem o bônus de -25 bytes.

Atualização 3 : Redução de 3 bytes do Pyth, obrigado isaacg!

kennytm
fonte
Conforme descrito nas dicas: codegolf.stackexchange.com/a/45280/20080, você pode substituir o loop for e as atribuições por uma redução, assim:Jiz8K+lzQ%"%0*o",KuxG/G8rQ^2KJ
isaacg
11

CJam, 15 14 bytes

l~{0\{1$^}/]}*

Toma entrada como

"111" 3

Teste aqui.

Explicação

l~{0\{1$^}/]}*
l~             "Read and evaluate input.";
  {         }* "Repeat k times.";
   0\          "Push a 0 and swap it with the string/array.";
     {   }/    "For each element in the string/array.";
      1$       "Copy the previous element.";
        ^      "XOR.";
           ]   "Wrap everything in a string/array again.";

O resultado é impresso automaticamente no final do programa.

Eu digo "string / array", porque começo com uma string (que é apenas uma matriz de caracteres), mas continuo tendo XORs entre eles e também entre números. Character Character ^fornece um número inteiro (com base no XOR dos pontos de código) Character Integer ^e Integer Character ^fornece um caractere (com base no XOR do número com o ponto de código - interpretado como um ponto de código). E, Integer Integer ^claro, apenas fornece um número inteiro.

Portanto, os tipos estão voando por todo o lado, mas, felizmente, sempre que eu tenho um número inteiro, é um 0ou outro 1e sempre que tenho um caractere, é um '0e '1e o resultado é sempre o desejado (em qualquer tipo). Como cadeias de caracteres são apenas matrizes de caracteres, misturar caracteres com números não é um problema. E no final, quando tudo é impresso, os caracteres não recebem delimitadores especiais; portanto, a saída não é afetada pelo bit que é representado como um número ou um caractere.

Martin Ender
fonte
Sua excelente explicação sobre o comportamento do tipo de caractere / número no CJam me permitiu extrair um byte da minha solução , atingindo 25 - 25 = 0 bytes. Obrigado e +1!
Ilmari Karonen
2
Esse tipo de comportamento é horrível (+1).
precisa saber é o seguinte
8

J, 17 caracteres

Sempre usando 0 como o dígito inicial.

   (~:/\@]^:[,~[$0:)

   3 (~:/\@]^:[,~[$0:) 1 1 1 
0 0 0 1 0 0

A partir do estado dos 128 1 da linha superior (esquerda) e de um estado aleatório (direita), mostrando os últimos 128 dígitos na primeira iteração 129.

   viewmat (~:/\)^:(<129) 128$1               viewmat (~:/\)^:(<129) ?128$2

enredo enredo

randomra
fonte
6

APL 11

((0,≠\)⍣⎕)⎕

Explicação:

≠\  compare increasing number of elements (1 1 1 ->1 0 1)
0,    add a starting zero
()⍣⎕  repeat the function in parenthesis ⎕ times, ⎕ is the second argument
()⎕   apply all to ⎕, that is first argument

Experimente em tryapl.org

Moris Zucca
fonte
Não foi possível executá-lo no tryapl (como você fornece as entradas?), Mas ≠\ não funcionaria em vez de 2|+\ ?
Aleatório
os ⎕ são as entradas; se você usar a mesma expressão que eu escrevi, o programa solicitará os números desejados, primeiro o vetor binário, depois uma segunda vez o número de iterações. Eu usei aeb no link para o tryapl, por isso é executado sem perguntar as coisas. Também obrigado pelo ≠ \ !!
Moris Zucca
Se eu copiar ((0,≠\)⍣⎕)⎕, recebo um token inválido. Tryapl não pode lidar com entradas?
Random #
1
Hmmmm ... você está certo, está acontecendo o mesmo comigo. Estou usando o Dyalog APL e, em seguida, tryapl apenas para postar aqui, então eu nunca notei, desculpe por isso.
Moris Zucca
5

CJam, 25 - 25 = 0 bytes

q~1,*_@{[\{1$^}/_](;)\}/;

Esta é apenas uma porta CJam direta da resposta GolfScript abaixo, pois, depois de ler a resposta de Martin Büttner , percebi que poderia salvar um byte devido ao manuseio de tipos inteiros e de caracteres por CJam. (Basicamente, o CJam não precisa do 1&usado para forçar caracteres ASCII em bits no código GolfScript, mas requer um prefixo qpara ler a entrada.) Normalmente, consideraria essa porta trivial um truque barato, mas atingir uma pontuação zero IMO vale a pena.

De qualquer forma, este programa funciona exatamente como o programa GolfScript original abaixo; portanto, consulte as instruções de descrição e uso. Como de costume, você pode testar a versão do CJam usando esse intérprete online .


GolfScript, 26 - 25 = 1 byte

~1,*.@{[1&\{1$^}/.](;)\}/;

Essa solução repete a string de entrada apenas uma vez, então acredito que se qualifica para o bônus de -25 bytes. Ele funciona mantendo internamente uma matriz de elementos k que armazena o bit atual de cada uma das k pré-iteradas.

A entrada deve ser fornecida via stdin, no formato "1111111" 3, ou seja, como uma seqüência de caracteres 0e citada 1, seguida do número k . A saída será stdout, como uma cadeia de bits sem aspas.

Teste este código online. (Se o programa atingir o tempo limite, tente executá-lo novamente; o servidor Web GolfScript é notório por intervalos aleatórios.)


Aqui está uma versão expandida deste programa, com comentários:

~             # eval the input, leaving a string and the number k on the stack

1,*           # turn the number k into an array of k zeros ("the state array")
.             # make a copy of the array; it will be left on the stack, making up the
              # first k bits of the output (which are always zeros)

@             # move the input string to the top of the stack, to be iterated over
{
  [           # place a start-of-array marker on the stack, for later use
  1&          # zero out all but the lowest bit of this input byte
  \           # move the state array to the top of the stack, to be iterated over

  { 1$^ } /   # iterate over each element of the state array, XORing each
              # element with the previous value on the stack, and leave
              # the results on the stack

  .           # duplicate the last value on the stack (which is the output bit we want)
  ]           # collect all values put on the stack since the last [ into an array
  (;          # remove the first element of the array (the input bit)
  )           # pop the last element (the duplicated output bit) off the array
  \           # move the popped bit below the new state array on the stack
}
/             # iterate the preceding code block over the bytes in the input string

;             # discard the state array, leaving just the output bits on the stack

Basicamente, como a maioria das soluções iterativas, esse código pode ser entendido como aplicando a recorrência

        b i , j : = b i , ( j −1)b ( i −1), ( j −1) ,

onde b 0, j é o j- ésimo bit de entrada (para j ≥ 1), b k , j é o j- ésimo bit de saída e b i , 0 = 0 por suposição. A diferença é que, enquanto as soluções iterativas, na verdade, calculam a recorrência "linha por linha" (ou seja, primeiro b 1, j para todos os j , depois b 2, j , etc.), essa solução a computa "coluna por coluna "(ou, mais precisamente," diagonal por diagonal "), primeiro calculando b i , i para 1 ≤ ik , então b i , i +1 , então b i , i +2 , etc.

Uma vantagem (teórica) dessa abordagem é que, em princípio, esse método pode processar uma sequência de entrada arbitrariamente longa usando apenas armazenamento O ( k ). Obviamente, o intérprete GolfScript lê automaticamente toda a entrada na memória antes de executar o programa, negando essa vantagem.

Ilmari Karonen
fonte
2

Python, 94 78

Será executado pelo menos uma vez e, portanto, fornece o mesmo resultado para n=0en=1

def f(x,n):
 c='0'
 for i in x:c+='10'[i==c[-1]]
 return f(c,n-1)if n>1 else c

Versão antiga que converte a string em uma matriz numérica e "integra" o módulo 2

from numpy import*
g=lambda x,n:g(''.join(map(str,cumsum(map(int,'0'+x))%2)),n-1)if n>0 else x
DenDenDo
fonte
2

Python 2, 68

g=lambda l,n,s=0:n and g(`s`+(l and g(l[1:],1,s^(l>='1'))),n-1)or l

Uma solução totalmente recusativa. É mais fácil entender se dividido em duas funções

f=lambda l,s=0:`s`+(l and f(l[1:],s^(l>='1')))
g=lambda l,n:n and g(f(l),n-1)or l

onde fcalcula diferenças sucessivas e gcompõe fconsigo mesmo n vezes.

A função fcalcula as somas XOR cumulativas de l, que é a operação inversa para diferenças XOR sucessivas. Como a entrada é fornecida como uma string, precisamos extrair int(l[0]), mas faça isso mais curto com a comparação de strings l>='1'.


Python 2, 69

Uma solução iterativa usando um execloop resultou em 1 caractere a mais.

l,n=input()
exec"r=l;l='0'\nfor x in r:l+='10'[l[-1]==x]\n"*n
print l

Talvez haja uma maneira mais curta de lidar com a corda. Se pudéssemos ter entradas / saídas como listas de números, economizaria 5 caracteres

l,n=input()
exec"r=l;l=[0]\nfor x in r:l+=[l[-1]^x]\n"*n
print l
xnor
fonte
1

Perl 5, 34

#!perl -p
s/ .*//;eval's/^|./$%^=$&/eg;'x$&

Parâmetros dados na entrada padrão separados por um espaço.

$ perl a.pl  <<<"1101 20"
101111011011011011010110
nutki
fonte
1

Javascript ES6, 47 caracteres

f=(s,k)=>k?f(0+s.replace(s=/./g,x=>s^=x),--k):s

By the way, não há efeitos colaterais :)

Qwertiy
fonte
Você precisa aceitar o parâmetro ak para o número de iterações. (O bônus -25 é para calcular o resultado das iterações sem realmente executar as iterações.) #
306156
Eu deveria ter especificação de ler atentamente (facepalm)
Qwertiy
1

C # - 178 161 115 caracteres

static string I(string a, int k){var s = "0";foreach(var c in a)s+=c==s[s.Length-1]?'0':'1';return k<2?s:I(s,--k);}

Ungolfed with harness

using System;
using System.Text;

namespace InverseXOR
{
    class Program
    {
        static string I(string a, int k)
        {
            var s = "0";
            foreach (var c in a)
                s += c == s[s.Length - 1] ? '0' : '1';
            return k < 2 ? s : I(s, --k);
        }

        static void Main(string[] args)
        {
            Console.WriteLine(I(args[0], Convert.ToInt32(args[1])));
        }
    }
}
RomSteady
fonte
0

CJam, 20 bytes

q~{:~0\{1$!_!?}/]s}*

Entrada é como "111" 3

Experimente online aqui

Optimizer
fonte
"011001" é o resultado do seu código para a sua entrada, mas não é correto se você verificar
nvidia
@ user3613886 Desculpe, copiou a versão anterior. Corrigido agora
Optimizer