Imprimer une valeur spécifique dans cette matrice binaire générée

14

Supposons que nous définissions une matrice infinie M, sur N^2 -> {0, 1}(où Ncommence à la 1place de 0) de cette manière:

  • M(1, 1)= 0.

  • Pour tout x > 1, M(x, 1)= 1if xest premier, et 0sinon.

  • Pour chaque y > 1, M(1, y)= le ye terme du Thue-Morse sequence.

  • Pour chaque x, y > 1, M(x, y)= M(x, y-1) + M(x-1, y) mod 2.

La section en haut à gauche 16x16de cette matrice ressemble (avec des xlignes et des ycolonnes):

0 1 1 0 1 0 0 1 1 0 0 1 0 1 1 0
1 0 1 1 0 0 0 1 0 0 0 1 1 0 1 1
1 1 0 1 1 1 1 0 0 0 0 1 0 0 1 0
0 1 1 0 1 0 1 1 1 1 1 0 0 0 1 1
1 0 1 1 0 0 1 0 1 0 1 1 1 1 0 1
0 0 1 0 0 0 1 1 0 0 1 0 1 0 0 1
1 1 0 0 0 0 1 0 0 0 1 1 0 0 0 1
0 1 1 1 1 1 0 0 0 0 1 0 0 0 0 1
0 1 0 1 0 1 1 1 1 1 0 0 0 0 0 1
0 1 1 0 0 1 0 1 0 1 1 1 1 1 1 0
1 0 1 1 1 0 0 1 1 0 1 0 1 0 1 1
0 0 1 0 1 1 1 0 1 1 0 0 1 1 0 1
1 1 0 0 1 0 1 1 0 1 1 1 0 1 1 0
0 1 1 1 0 0 1 0 0 1 0 1 1 0 1 1
0 1 0 1 1 1 0 0 0 1 1 0 1 1 0 1
0 1 1 0 1 0 0 0 0 1 0 0 1 0 0 1

Votre tâche consiste à créer un programme qui évaluera la valeur d'une entrée arbitraire dans cette matrice aussi précisément que possible.

Votre programme prendra deux entiers xet yen entrée, sous la forme que vous choisirez, et retournera M(x, y), qui sera soit 0ou 1.

Votre code peut être écrit dans n'importe quelle langue, mais ne doit pas dépasser 64 kilo-octets (65 536 octets) de taille de code source ou 2 Mo (2 097 152 octets) d'utilisation totale de la mémoire. Votre programme doit démarrer avec une mémoire vide (c'est-à-dire qu'il ne peut pas charger de données ailleurs) et s'exécuter indépendamment pour chaque entrée (c'est-à-dire qu'il ne peut pas stocker de données communes pour plusieurs exécutions). Votre programme doit également être en mesure d'évaluer toutes les entrées du 8192x8192carré supérieur gauche dans un délai raisonnable.

Le programme qui évalue correctement le plus d'entrées dans le 8192 x 8192carré supérieur gauche sera le gagnant, avec un code plus court faisant office de bris d'égalité.

Joe Z.
la source
Je vais probablement mettre à jour le cas de test pour quelque chose d'un peu plus élégant dans un instant, alors attendez le test jusqu'à ce que je retouche la question.
Joe Z.
@mbuettner Oui, c'est le cas.
Joe Z.
1
Je ne vois pas comment nous avons besoin d'une nouvelle balise pour «précision». Ce n'est qu'un [défi de code]. Veuillez d'abord lancer de nouvelles idées de genre de défi à travers la méta (il y a une chose que nous avons apprise de [code-trolling]).
Poignée de porte
^ Noté. Je vais supprimer cette balise.
Joe Z.
1
@TheDoctor Ce n'est pas trop rare. La réponse acceptée change avec le temps.
Joe Z.

Réponses:

9

J - 42 38 car

Assez rapide, 100% précis et bien dans les contraintes de mémoire.

([{+2&(~:/@#:@#@],~:/\,(p:>:)&#)0:)&<:

La stratégie est la suivante: nous allons calculer les antidiagonales successives de cette matrice, en effectuant un XOR par paire pour avancer et en ajoutant les bits Thue-Morse et Prime actuels aux extrémités. Nous retirons ensuite le chiffre requis de l'antidiagonale lorsque nous y arrivons.

Explication par explosion:

(                                 )&<:  NB. decrement each of x and y
     &(                        )        NB. apply the following function...
   +                                    NB. ... (x-1)+(y-1) times...
                                0:      NB. ... starting with a zero:
    2             ~:/\                  NB.   pairwise XOR on the argument
                      ,(p:>:)&#         NB.   append prime bit (is 1+length prime?)
       ~:/@#:@#@],                      NB.   prepend TM bit (XOR of binary)
 [{                                     NB. take the x-th bit (at index x-1)

L'utilisation de ce verbe est x m ypour M (x, y) comme spécifié dans la question, où mest le verbe.

   5 ([{+2&(~:/@#:@#@],~:/\,(p:>:)&#)0:)&<: 8
0
   m =: ([{+2&(~:/@#:@#@],~:/\,(p:>:)&#)0:)&<:
   1+i.16
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   m/~ 1+i.16
0 1 1 0 1 0 0 1 1 0 0 1 0 1 1 0
1 0 1 1 0 0 0 1 0 0 0 1 1 0 1 1
1 1 0 1 1 1 1 0 0 0 0 1 0 0 1 0
0 1 1 0 1 0 1 1 1 1 1 0 0 0 1 1
1 0 1 1 0 0 1 0 1 0 1 1 1 1 0 1
0 0 1 0 0 0 1 1 0 0 1 0 1 0 0 1
1 1 0 0 0 0 1 0 0 0 1 1 0 0 0 1
0 1 1 1 1 1 0 0 0 0 1 0 0 0 0 1
0 1 0 1 0 1 1 1 1 1 0 0 0 0 0 1
0 1 1 0 0 1 0 1 0 1 1 1 1 1 1 0
1 0 1 1 1 0 0 1 1 0 1 0 1 0 1 1
0 0 1 0 1 1 1 0 1 1 0 0 1 1 0 1
1 1 0 0 1 0 1 1 0 1 1 1 0 1 1 0
0 1 1 1 0 0 1 0 0 1 0 1 1 0 1 1
0 1 0 1 1 1 0 0 0 1 1 0 1 1 0 1
0 1 1 0 1 0 0 0 0 1 0 0 1 0 0 1

Pour enregistrer les frappes, nous n'essayons pas de dire si nous avons encore besoin de bits principaux ou Thue-Morse, nous calculons donc toute l'antidiagonale pour obtenir le bit que nous voulons. Cependant, 8192 m 8192fonctionne toujours en moins de 0,07 s et environ 100 Ko sur mon modeste ordinateur portable.

algorithmshark
la source
6

Mathematica - 100% de précision, 223 193 189 octets

f=(r=Array[0&,Max@##];For[s=2,s<=#+#2,++s,For[i=Max[1,s-#2],i<=Min[s-1,#],++i,j=s-i;r[[j]]=Which[i==1,PrimeQ@j,j==1,OddQ@Total@IntegerDigits[i-1,2],0<1,Xor@@r[[j-1;;j]]]]];If[r[[#2]],1,0])&

Voici une version lisible:

f[x_,y_] := (
   r = Array[0 &, Max[x,y]];
   For[s = 2, s <= x + y, ++s,
    For[
     i = Max[1, s - y],
     i <= Min[s - 1, x],
     ++i,

     j = s - i;
     r[[j]] = Which[
       i == 1,
       PrimeQ@j,
       j == 1,
       OddQ@Total@IntegerDigits[i - 1, 2],
       0 < 1,
       r[[j - 1]]~Xor~r[[j]]
       ]
     ]
    ];
   If[r[[y]], 1, 0]
   );

Je calcule essentiellement le long de diagonales de constante x+y.

Fonctionnalités:

  • C'est précis.
  • Ça marche O(x*y).
  • f[8192,8192]prend environ 400 secondes. Je suppose qu'il y a place à amélioration (peut RotateLeft- être pourrait remplacer la boucle intérieure).
  • Il utilise uniquement un tableau de max(x,y)résultats jusqu'à intermédiaires dans la mémoire. Il n'est donc pas nécessaire d'utiliser plus d'environ 32k (en supposant des entiers 32 bits) pour l'algorithme lui-même (plus, quoi que Mathematica utilise). En fait, Mathematica utilise 31M seul sur mon système, mais cela fonctionne sans problème:

    MemoryConstrained[f[8192, 8192], 2^21]
    
Martin Ender
la source
On dirait que tu l'as. Je vais en faire des plus difficiles à l'avenir, cependant: P
Joe Z.
Hm, dans l'un des changements, j'ai dû bousiller les performances d'exécution. La boucle interne est toujours appelée O(x*y)temps, mais le temps d'exécution total augmente plus rapidement que cela. Je ne sais pas trop ce qui se passe. Si certains Mathematica Guru pouvaient m'éclairer, quelle opération dans la boucle ne O(1)serait pas très utile! :) (eh bien, PrimeQet Total@IntegerDigitsne le sont pas, mais je les ai depuis le début, et ils n'ont appelé que O(y)et O(x)respectivement)
Martin Ender
3

Matlab: 100% de précision, 120 caractères, temps d'exécution déraisonnable

function z=M(x,y)
if y==1 z=(x>1)*isprime(x);elseif x==1 z=mod(sum(dec2bin(y-1)-48),2);else z=xor(M(x,y-1),M(x-1,y));end

Utiliser:

> M(4,4)
ans =
      0
> M(1, 9)
ans =
      1
intx13
la source
1
Maintenant, voici la question, pouvez-vous réellement exécuter ce programme et le tester?
Joe Z.
Si vous ne pouvez pas courir M(8192, 8192), je ne peux pas le supporter.
Joe Z.
@JoeZ C'est du code M, vous pouvez l'exécuter dans Matlab ou Octave.
intx13
@JoeZ Il calculera avec précision M (8192, 8192). Le défi n'a rien dit sur le temps à terminer;)
intx13
1
@JoeZ il semble que M (20,20) prenne plus de temps que je ne suis prêt à attendre. Mais bon, c'est "précis"! : P
intx13
2

Python, 192 caractères

100% de précision, calcule M (8192 8192) en ~ 10 secondes sur ma machine.

R=range
def M(X,Y):
 X+=1;c=[1]*X;r=[0]
 while len(r)<Y:r+=[i^1 for i in r]
 for i in R(2,X):
  if c[i]:
   for j in R(i+i,X,i):c[j]=0
  r[0]=c[i]
  for i in R(1,Y):r[i]^=r[i-1]
 return r[Y-1]
Aleksi Torhamo
la source
0

Haskell - 261 octets - 100% - 1 Mo - Je ne pense pas que ça va se terminer de sitôt

Prend environ 10 secondes pour m 16 16avec -O2, mais comme je l'ai écrit de toute façon, je peux le montrer malgré ce problème:

m x y=if n x y then 1 else 0 where n x 1=b x;n 1 y=(a!!13)!!(y-1);n x y=(n x (y-1))`f`(n(x-1)y)
f True False=True
f False True=True
f _ _=False
a=[False]:map step a where step a=a++map not a
b x=x`elem`takeWhile(<=x)e
e=c [2..]where c(p:s)=p:c[x|x<-s,x`mod`p>0]

Peut-être qu'un bon Haskeller est capable de l'optimiser?

m' x y = if m x y then 1 else 0
    where
        m x 1 = isPrime x
        m 1 y = morse' y
        m x y = (m x (y-1)) `xor` (m (x-1) y)

xor True False = True
xor False True = True
xor _ _ = False

morse' x = (morse !! 13) !! (x-1)
morse = [False] : map step morse where step a = a ++ map not a

isPrime x = x `elem` takeWhile (<=x) primes
primes :: [Integer]
primes = sieve [2..] where sieve (p:xs) = p : sieve [x|x <- xs, x `mod` p > 0]

main = putStrLn $ show $ m' 16 16
TimWolla
la source
je pense que l'algorithme lui-même est imparfait. de toute façon, il y a beaucoup de choses que vous pouvez faire pour jouer au golf. surtout des parenthèses supplémentaires, mais f p|p=not|0<1=iddevrait aussi être mieux. essayez également de l'utiliser morse = False : concat $ iterate [True] (\a -> a ++ map not a)pour augmenter la paresse. Je me demande comment cela affectera les performances.
fier haskeller
aussi, vous pouvez jouer Trueau golf vers 0<1et Falsevers 0>1.
fier haskeller
0

Perl, 137

Pas pour «gagner» :-), mais comme il n'y a pas encore de Perl ici et que le code a quand même été écrit, le voici.

sub f{($n,$m)=@_;@a=0;@a=(@a,map{0+!$_}@a)while@a<$n;for$k(2..$m){$p=0;O:{$k%$_?1:last O for 2..sqrt$k;$p=1}$p=$a[$_]^=$p for 1..$n-1}$p}

Prend plusieurs secondes s'il est appelé print f(8192,8192), stocke une seule ligne de matrice en mémoire (tableau de 8192 entiers (scalaires)), soit environ 3,5 Mo de processus Perl. J'ai essayé de le faire avec une chaîne au lieu d'un tableau (soit avec des expressions rationnelles ou en accédant avec substr), prend moins de mémoire et peut être joué plus loin, mais fonctionne beaucoup plus lentement.

Dentelé:

sub f{
    ($n,$m)=@_;
    @a=0;                                  # @a will be current line.
    @a=(@a,map{0+!$_}@a)while@a<$n;        # Fill it with Thue-Morse sequence.
    for$k(2..$m){                          # Repeat until required line number.
        $p=0;                              # Find out if current line number 
        O:{                                # is a prime.
            $k%$_?1:last O for 2..sqrt$k;
            $p=1                           # Store result (0 or 1) in $p.
        }
        $p=$a[$_]^=$p for 1..$n-1          # XOR previous value in current position
    }                                      # with $p and store in $p.
    $p                                     # Return $p.
}
user2846289
la source
0

Haskell, 223

g n=div(filter(>=n)(iterate(*2)1)!!0)2
1%1=0>1
1%n=not$1%(n-g n)
n%1=and[rem n x>0|x<-[2..n-1]]
a%b=g[0<1]where g s|foldr seq(0>1)s=0<1|n==a+b=s!!(b-1)|0<1=g$n%1:zipWith x s(tail s)++[1%n]where n=length s+1
x p|p=not|0<1=id

cela a un temps d'exécution rapide (5,7 secondes avec -O3). la mémoire n'a pas encore été vérifiée, bien qu'elle devrait être linéaire.

cela utilise l'algorithme diagonal vu précédemment.

en ce qui concerne la vitesse, les seules choses qui importent sont l'algorithme diagonal -O3, et le|foldr seq(0>1)s=0<1 garde, ce qui rend la liste stricte. tout le reste est implémenté de manière assez inefficace - la vérification principale est effectuée en vérifiant tous les nombres inférieurs pour la division, les éléments de la séquence Morse sont recalculés en permanence. mais c'est quand même assez rapide :-).

fier haskeller
la source