Imagine que você tem duas caixas B(x)
e B(y)
, cada uma contendo um bit desconhecido - 0 ou 1, e uma máquina F
que pode radiografá-las e produzir uma terceira caixa para B(x^y)
( xor ). F
também pode calcular B(x*y)
( e ). De fato, esses são apenas casos especiais da operação única que a máquina pode executar - produto interno cada , indicado F()
abaixo.
Para duas matrizes do mesmo comprimento
[B(x[0]), B(x[1]), ..., B(x[n-1])]
[B(y[0]), B(y[1]), ..., B(y[n-1])]
produto interno é definido como
B(x[0]*y[0] ^ x[1]*y[1] ^ ... ^ x[n-1]*y[n-1])
" Cada " meios F()
pode processar vários pares de x[]
, y[]
de uma só vez. O x[]
e y[]
de um par deve ter o mesmo comprimento; x[]
-s e y[]
-s de pares diferentes não precisam necessariamente.
As caixas são representadas por IDs inteiros exclusivos.
Uma implementação de produto interno, cada uma em JavaScript, pode parecer
var H=[0,1]; // hidden values, indexed by boxId
function B(x) { // seal x in a new box and return the box id
return H.push(x)-1;
}
function F(pairs) { // "inner product each"
return pairs.map(function (pair) {
var r = 0, x = pair[0], y = pair[1];
for (var i = 0; i < x.length; i++) r ^= H[x[i]] * H[y[i]];
return B(r);
})
}
(Traduza o texto acima para o seu idioma preferido.)
Dado o acesso a uma F()
implementação conforme apropriado para o seu idioma (mas sem acesso a H
ou B()
) e duas matrizes de IDs de caixa que constituem as representações binárias de 16 bits de dois números inteiros a
e b
, sua tarefa é produzir IDs de caixa para a representação binária de 16 bits de a+b
(descartando estouro) com o número mínimo de F()
chamadas.
A solução que chama F()
menos vezes vence. Os laços serão quebrados contando o número total de x[],y[]
pares que F()
foram chamados - menos é melhor. Se ainda estiver empatado, o tamanho do seu código (excluindo a implementação F()
e seus auxiliares) determina o vencedor da maneira tradicional do código de golfe. Por favor, use um título como "MyLang, 123 chamadas, 456 pares, 789 bytes" para sua resposta.
Escreva uma função ou um programa completo. Entrada / saída / argumentos / resultado são matrizes int em qualquer formato razoável. A representação binária pode ser pequena ou grande endian - escolha uma.
Apêndice 1: Para facilitar um pouco o desafio, você pode assumir que as caixas com os IDs 0 e 1 contêm os valores 0 e 1. Isso fornece constantes, úteis, por exemplo, para negação ( x^1
não é ")". Havia maneiras de contornar a falta de constantes, é claro, mas o resto do desafio já é difícil o suficiente, então vamos eliminar essa distração.
Apêndice 2: Para ganhar a recompensa, siga um destes procedimentos:
publique sua pontuação (chamadas, pares, bytes) e seu código antes do prazo
publique sua pontuação e um hash sha256 do seu código antes do prazo; depois publique o código real dentro de 23 horas após o prazo
F
apenas uma vez. Certamente isso seria trapaça, mas não tenho certeza se seria uma boa trapaça ou má trapaça.y=f(x)
e deixareix
dependery
.data Box = B Int deriving (Show); f :: [[[Box]]] -> [Box]
Vou precisar de mais tempo para descobrir como implementarf
(Haskell força minúsculas aqui) - tentarei amanhã.Respostas:
Python 3 , 5 chamadas, 92 pares, 922 bytes
Python 3 , 5 chamadas, 134 pares, 3120 bytesPython 3 , 6 chamadas, 106 pares, 2405 bytes[JavaScript (Node.js)], 9 chamadas, 91 pares, 1405 bytesJavaScript (Node.js), 16 chamadas, 31 pares, 378 bytesExperimente online!
PRIMEIRA VERSÃO Ok, isso não é golfe. É apenas uma adaptação do código do @ ngn.
A única idéia aqui é que você não precisa calcular o último transporte, pois descarta o estouro. Além disso, as chamadas de
F
são agrupadas por dois. Talvez eles possam ser agrupados de outra maneira, mas duvido que você possa reduzir significativamente o número de pares, devido à natureza do algoritmo de adição básico.EDIT : Ainda não jogou golfe. O número de pares certamente poderia ser reduzido, e provavelmente o número de ligações também. Consulte https://gist.github.com/jferard/864f4be6e4b63979da176bff380e6c62 para obter uma "prova" com sympy.
EDIT 2 Mudei para Python porque é mais legível para mim. Agora que tenho a fórmula geral, acho que posso atingir o limite de 5 (talvez 4) chamadas.
EDIT 3 Aqui estão os tijolos básicos:
A fórmula geral é:
A versão expandida é:
5 chamadas parece o limite para mim. Agora tenho um pouco de trabalho para remover pares e jogar golfe!
EDIT 4 Joguei este aqui.
Versão não destruída:
Experimente online!
fonte
F()
. Garanto que existe uma maneira de reduzi-los significativamente (essa é a parte mais difícil deste desafio) e, em seguida, haverá espaço para otimizar o número de pares e, finalmente, é claro, jogar o código (mas esse é o critério menos importante).... + x * y * z + ...
. Não podemosF
avaliar isso, mas se tivermos calculadox * y
com aF
chamada anterior , basta fazer o seguinte:... + (x * y) * z + ...
(corresponde ao formato deF
). Jogando com o sympy, consegui poupar uma chamada (passo1: calcular r0, c0, r1; passo2: calcular c1 e alguns valores auxiliares; passo3: calcular r2, c2, r3, c3) e agora estou procurando um general solução.Haskell, 1 chamada (trapaça ???), 32 pares (poderia ser melhorado), 283 bytes (o mesmo)
Por favor, não fique com raiva de mim, não quero vencer com isso, mas fui encorajado nas observações ao desafio de explicar o que estava falando.
Tentei usar a mônada do estado para lidar com a adição de caixas e a contagem de chamadas e pares, e isso funcionou, mas não consegui fazer minha solução funcionar nessa configuração. Então fiz o que também foi sugerido nos comentários: apenas oculte os dados atrás de um construtor de dados e não espreite. (A maneira mais limpa seria usar um módulo separado e não exportar o construtor.) Esta versão tem a vantagem de ser muito mais simples.
Já que estamos falando de caixas de bits, eu coloco
Bool
valores nelas. Eu definozero
como a caixa fornecida com o bit zero - aone
não é necessário.Estamos usando a função de depuração
trace
para ver com que frequênciaf
foi chamado e com quantos pares.&&&
olha para as caixas pela correspondência de padrões, a desigualdade/=
usada nosBool
valores éxor
.A
test
função pega um somador binário cego como primeiro argumento e, em seguida, dois números para os quais a adição é testada. RetornaBool
indicando se o teste foi bem-sucedido. Primeiro, as caixas de entrada são criadas e, em seguida, o somador é chamado, o resultado descompactado (comunB
) e comparado com o resultado esperado.Eu implementei dois adicionadores, a solução de amostra
simple
, para que possamos ver que a saída de depuração funciona corretamente e minha solução usando recursão de valorvalrec
.Veja como eu estou definindo
res
em termos de si mesmo? Isso também é conhecido como amarrar o nó .Agora podemos ver como
f
é chamado apenas uma vez:Ou substitua
valrec
porsimple
paraf
ser chamado 32 vezes.Experimente online! (a saída de rastreamento aparece em "Debug")
fonte
f
é uma lista preguiçosa e potencialmente infinita que se materializa à medida que você itera nela? Receio que isso seja contrário ao espírito do desafio - ele permite que você adie a decisão sobre o que passar como oi+1
-st argumento até depois de obter o resultado correspondente aoi
-th. É muito mais interessante descobrir quantas chamadas paraf
você precisará com totalmente materializado, argumentos imutáveis :)f
possa receber entrada infinita (adicione fluxos de bits infinitos, yay!), Esse não é o ponto. Ah, e na verdade atrace
mensagem garante que o comprimento seja finito e conhecido no início. Além disso, eu não diria que há uma decisão adiada: tudo foi planejado com antecedência, como exigido, estou apenas remexendo cegamente as caixas. E observe que não se trata de ordem dos argumentos: eu poderia alterá-lo para queres
primeiro contenha o resultado e depois os bits de transporte.f
; você alimenta essa caixa como outro argumento na mesma chamada paraf
?JavaScript, 32 chamadas, 32 pares, 388 bytes
Dyalog APL, 32 chamadas, 32 pares, 270 bytes
Esta é uma solução de amostra ingênua que pode servir como modelo.
Observe que a contagem de bytes deve incluir apenas a seção cercada com "BEGIN / END SOLUTION".
Explicação:
Eu escolhi a ordem de bits little-endian (
x[0]
é o bit menos significativo).Observe que a adição de bit único mod 2 pode ser realizada como
F([[[x,y],[x,y]]])
(isto é:x*x ^ y*y
- multiplicação mod 2 é idempotente) e multiplicação binária comoF([[[x],[y]]])
.Atravessamos os bits do menos significativo para o mais significativo e, a cada passo, calculamos um bit de resultado e um carry.
O mesmo no Dyalog APL (mas usando IDs de caixa aleatórios):
fonte