Calculer l'inverse XOR

13

Soit fla fonction qui mappe un champ binaire ( {0 1}) de taille n+1sur un champ binaire de taille nen appliquant XORaux bits ith et i+1th et en écrivant le résultat dans le nouveau champ binaire.

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

Calcul informel:

0 XOR 1 = 1

1 XOR 0 = 1

0 XOR 1 = 1

Soit f_inversela fonction inverse de f. Étant donné que l'inverse n'est pas unique, f_inverserenvoie une solution valide.

Entrée: champ de bits sous forme de chaîne (c'est-à-dire "0101111101011") et un nombre naturel donnék

Sortie: champ de bits sous forme de chaîne, de sorte que la chaîne contienne le résultat si f_inverseest appliqué kfois au champ de bits d'entrée. (ie f_inverse(f_inverse(f_inverse(input))))

Critères gagnants: le moins de personnages

Prime:

-25Les caractères f_inversene sont pas appliqués de manière récursive / itérative, mais la chaîne de sortie est directement calculée

Script de test:

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)

Vous pouvez par exemple le coller ici puis l'essayer.

nvidia
la source
3
Pouvez-vous donner quelques cas de test pour vérifier.
Optimizer
3
Pourriez-vous s'il vous plaît arrêter de les appeler {0-1}-Bitfields? De plus, je ne comprends pas la définition de f, d'où ivient-il? Quel est le deuxième argument de XOR? comment pouvons-nous 111partir 0101?
mniip
Qu'est-ce qu'un meilleur nom? i désigne l'indice
nvidia
Un "champ de bits" suffirait. Quelle est la / valeur / de i? "0 XOR 1" = 1 "1 XOR 0" = 1 "0 XOR 1" = 1n'explique rien: je sais comment fonctionne XOR, mais que sommes-nous exactement XORing et où stockons-nous le résultat?
mniip
9
Je pense qu'il veut dire: f([a,b,c,d]) = [a^b, b^c, c^d]. Et il veut l'inverse de cette fonction, à savoir de f'([x,y,z]) = [a,b,c,d]telle sorte que a^b=x, b^c=y, c^d=z.
marinus

Réponses:

14

Pyth, 33 30 - 25 = 5 octets

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

Exécutez-le par entrée de stdin comme (interprète en ligne: https://pyth.herokuapp.com/ ):

111
3

et le résultat sera écrit sur stdout.

Il s'agit d'une traduction directe de:

Python 2, 127 118 79 - 25 = 54 octets

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)

Appelez-le comme i("111", 3)et le résultat sera écrit sur stdout.

Notez que nous nous attendons à ce que k ne soit pas trop grand, car à des fins de code-golf, la boucle intérieure fonctionnera pendant O (2 k ) fois.


Je pense que nous appelons généralement cette opération "xorshift" ou quelque chose. Si nous exprimons l'entrée sous forme d'entiers big-endian, alors la fonction f est simplement:

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

Si nous appliquons f deux fois, nous obtiendrons:

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

Cependant, appliquer 3 fois aura un schéma différent:

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

Appliquer 4 fois revient au formulaire de base:

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

Etc:

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

Notez que si nous choisissons un 2 k assez grand , alors (x ≫ 2 k ) = 0, signifiant f 2 k (x) = x, et l'inverse est trivialement la fonction d'identité!

Ainsi , la stratégie pour trouver f -k (x) sans appeler f -1 (x) tout est:

  1. Trouvez K tel que:

    • K ≥ k
    • K> log 2 x
    • K est une puissance de 2
  2. Express f -k (x) = f -K + (Kk) (x) = f -K (f K-k (x)) = f K-k (x)

  3. Ainsi, le résultat est fappelé Kk fois

  4. 25 caractères: p


Mise à jour 1 : représentation octale utilisée au lieu de binaire afin que nous puissions utiliser le %formatage pour enregistrer de nombreux octets.

Mise à jour 2 : exploiter la structure périodique de f. Retiré la version itérative car la version non itérative est plus courte même sans le bonus de -25 octets.

Mise à jour 3 : réduction de 3 octets de Pyth, merci isaacg!

kennytm
la source
Comme décrit dans les conseils: codegolf.stackexchange.com/a/45280/20080, vous pouvez remplacer la boucle for et les affectations par une réduction, comme ceci:Jiz8K+lzQ%"%0*o",KuxG/G8rQ^2KJ
isaacg
11

CJam, 15 14 octets

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

Prend l'entrée comme

"111" 3

Testez-le ici.

Explication

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.";

Le résultat est imprimé automatiquement à la fin du programme.

Je dis "chaîne / tableau", parce que je commence par une chaîne (qui n'est qu'un tableau de caractères), mais je continue de prendre des XOR entre eux et entre les nombres également. Character Character ^donne un entier (basé sur le XOR des points de code) Character Integer ^et Integer Character ^donne un caractère (basé sur le XOR du nombre avec le point de code - interprété comme un point de code). Et Integer Integer ^bien sûr, donne juste un entier.

Donc, les types volent partout, mais heureusement, chaque fois que j'ai un entier, c'est soit 0ou 1et chaque fois que j'ai un caractère, c'est soit '0et '1et le résultat est toujours celui souhaité (dans l'un ou l'autre type). Étant donné que les chaînes ne sont que des tableaux de caractères, le mélange de caractères avec des nombres n'est pas du tout un problème. Et à la fin, lorsque tout est imprimé, les caractères ne reçoivent aucun délimiteur spécial, de sorte que la sortie n'est pas affectée par le bit représenté sous la forme d'un nombre ou d'un caractère.

Martin Ender
la source
Votre excellente explication du comportement du type caractère / nombre dans CJam m'a permis de raser un octet de ma solution , atteignant 25 - 25 = 0 octet. Merci et +1!
Ilmari Karonen
2
Ce comportement de type est horrible (+1).
ballesta25
8

J, 17 caractères

Toujours en utilisant 0 comme premier chiffre.

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

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

À partir de l'état 128 1 de la ligne supérieure (à gauche) et d'un état aléatoire (à droite), montrant les 128 derniers chiffres jusqu'à la première 129 itération.

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

terrain terrain

randomra
la source
6

APL 11

((0,≠\)⍣⎕)⎕

Explication:

≠\  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

Essayez sur tryapl.org

Moris Zucca
la source
Impossible de l'exécuter sur tryapl (comment vous donnez les entrées?) Mais ≠\ ne fonctionnerait pas à la place de 2|+\ ?
randomra
les ⎕ sont les entrées, si vous utilisez la même expression que celle que j'ai écrite, le programme devrait vous demander les nombres que vous voulez, d'abord le vecteur binaire, puis une deuxième fois le nombre d'itérations. J'ai utilisé a et b dans le lien vers tryapl, il est donc exécuté sans rien demander. Merci aussi pour le ≠ \ !!
Moris Zucca
Si je copie, ((0,≠\)⍣⎕)⎕j'obtiens un jeton non valide. Tryapl ne peut pas gérer les entrées?
randomra
1
Hmmmm ... vous avez raison, ça m'arrive de la même façon. J'utilise Dyalog APL, puis j'essaie juste de poster ici, donc je ne l'ai jamais remarqué, désolé.
Moris Zucca
5

CJam, 25 - 25 = 0 octet

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

Ceci est juste un port CJam direct de la réponse GolfScript ci-dessous, car, après avoir lu la réponse de Martin Büttner , j'ai réalisé que je pouvais économiser un octet grâce à la gestion par CJam des types d'entiers et de caractères. (Fondamentalement, CJam n'a pas besoin de l' 1&utilisé pour forcer les caractères ASCII en bits dans le code GolfScript, mais nécessite un préfixe qpour lire l'entrée.) il vaut bien l'OMI.

Dans tous les cas, ce programme fonctionne exactement comme le programme GolfScript d'origine ci-dessous, veuillez donc vous référer à sa description et à ses instructions d'utilisation. Comme d'habitude, vous pouvez tester la version CJam à l'aide de cet interprète en ligne .


GolfScript, 26 - 25 = 1 octet

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

Cette solution n'itère la chaîne d'entrée qu'une seule fois, donc je pense qu'elle est admissible au bonus de -25 octets. Il fonctionne en maintenant en interne un tableau à k éléments qui stocke le bit actuel de chacun des k pré-itérations.

L'entrée doit être donnée via stdin, au format "1111111" 3, c'est-à-dire sous la forme d'une chaîne de caractères 0et de guillemets 1, suivie du nombre k . La sortie sera vers stdout, comme une chaîne de bits sans guillemets.

Testez ce code en ligne. (Si le programme arrive à expiration, essayez de le relancer; le serveur Web GolfScript est connu pour les délais d'expiration aléatoires.)


Voici une version étendue de ce programme, avec des commentaires:

~             # 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

Fondamentalement, comme la plupart des solutions itératives, ce code peut être compris comme appliquant la récurrence

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

b 0, j est le j- ème bit d'entrée (pour j ≥ 1), b k , j est le j- ème bit de sortie, et b i , 0 = 0 par hypothèse. La différence est que, alors que les solutions itératives, en fait, calculent la récurrence "ligne par ligne" (c'est-à-dire d'abord b 1, j pour tout j , puis b 2, j , etc.), cette solution la calcule plutôt "colonne par colonne "(ou, plus précisément," diagonale par diagonale "), calculant d'abord b i , i pour 1 ≤ ik , puis b i , i +1 , puis b i , i +2 , etc.

Un avantage (théorique) de cette approche est que, en principe, cette méthode peut traiter une chaîne d'entrée arbitrairement longue en utilisant uniquement le stockage O ( k ). Bien sûr, l'interpréteur GolfScript lit automatiquement toutes les entrées en mémoire avant d'exécuter le programme de toute façon, annulant principalement cet avantage.

Ilmari Karonen
la source
2

Python, 94 78

Sera exécuté au moins une fois et donne donc le même résultat pour n=0etn=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

Ancienne version qui convertit la chaîne en un tableau numérique et "intègre" le modulo 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
la source
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

Une solution totalement récusive. Il est plus facile à comprendre s'il est divisé en deux fonctions

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

fcalcule les différences successives et gcompose favec lui-même n fois.

La fonction fcalcule les sommes XOR cumulées de l, qui est l'opération inverse des différences XOR successives. Puisque l'entrée est donnée sous forme de chaîne, nous devons extraire int(l[0]), mais le faire plus court avec la comparaison de chaînes l>='1'.


Python 2, 69

Une solution itérative utilisant une execboucle s'est avérée 1 caractère plus longue.

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

Il existe peut-être un moyen plus court de gérer la chaîne. Si nous pouvions avoir des entrées / sorties sous forme de listes de nombres, cela économiserait 5 caractères

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

Perl 5, 34

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

Paramètres donnés sur l'entrée standard séparés par un espace.

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

Javascript ES6, 47 caractères

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

Au fait, il n'y a pas d'effets secondaires :)

Qwertiy
la source
Vous devez accepter un paramètre k pour le nombre d'itérations. (Le bonus de -25 sert à calculer le résultat des itérations sans réellement effectuer les itérations.)
Brilliand
J'aurais dû lire attentivement les spécifications (facepalm)
Qwertiy
1

C # - 178 161 115 caractères

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);}

Non golfé avec harnais

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
la source
0

CJam, 20 octets

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

L'entrée est comme "111" 3

Essayez-le en ligne ici

Optimiseur
la source
"011001" est le résultat de votre code pour votre entrée mais ce n'est pas correct si vous cochez
nvidia
@ user3613886 Désolé, ancienne version copiée. Corrigé maintenant
Optimizer