Print a specific value in this generated binary matrix

14

0

Suppose we define an infinite matrix M, on N^2 -> {0, 1} (where N starts from 1 instead of 0) in this manner:

  • M(1, 1) = 0.

  • For every x > 1, M(x, 1) = 1 if x is prime, and 0 otherwise.

  • For every y > 1, M(1, y) = the yth term in the Thue-Morse sequence.

  • For every x, y > 1, M(x, y) = M(x, y-1) + M(x-1, y) mod 2.

The top-left 16x16 section of this matrix looks like (with x being rows and y being columns):

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

Your task is to build a program that will evaluate the value of an arbitrary entry in this matrix as accurately as possible.

Your program will take two integers x and y as input, in any form you choose, and return M(x, y), which will be either 0 or 1.

Your code may be written in any language, but must not exceed 64 kilobytes (65,536 bytes) of source code size or 2 MB (2,097,152 bytes) of total memory usage. Your program must start with empty memory (i.e. it cannot load data from somewhere else) and run independently for each input (that is, it may not store common data for multiple runs). Your program must also be able to evaluate all the entries in the top-left 8192x8192 square in a reasonable amount of time.

The program that evaluates the most entries correctly in the top-left 8192 x 8192 square will be the winner, with shorter code acting as a tie-breaker.

Joe Z.

Posted 2014-03-19T21:20:33.657

Reputation: 30 589

I'm probably going to update the testing case to something slightly more elegant in a moment, so hang on with the testing until I edit the question again. – Joe Z. – 2014-03-19T21:25:25.343

@mbuettner Yes, it does. – Joe Z. – 2014-03-19T21:27:34.393

1I fail to see how we need a new tag for "accuracy." This is just a [code-challenge]. Please run new challenge genre ideas through meta first (there's one thing we learned from [code-trolling]). – Doorknob – 2014-03-19T21:31:58.190

^ Noted. I'll remove that tag. – Joe Z. – 2014-03-19T21:34:11.120

You posted a comment on a now deleted answer saying "You need to create a function that computes the value of that matrix with two coordinates without computing the entire matrix." I can't find in your question the "without computing the entire matrix" part. Perhaps you think that the memory constraints enforce that, but perhaps it isn't so. – Dr. belisarius – 2014-03-19T21:59:45.733

Since any valid answer will be "accurate" (or it's buggy), isn't this just code golf? – intx13 – 2014-03-19T22:01:50.117

@intx13: The point is that an answer may produce incorrect results but still be considered valid. An answer that simply says print 1 would still be right about 50% of the time, but would be beaten by an answer that gave the correct answer 90% of the time. – Joe Z. – 2014-03-19T22:09:44.330

@belisarius It would also be prohibitively expensive time-wise to actually test it if you computed the entire matrix at once. The point I was trying to make was that Kaya had created a literal matrix, and not a function that evaluates values in that matrix. – Joe Z. – 2014-03-19T22:11:23.583

@JoeZ I guess. But since I have a solution that is 100% accurate and the challenge goes first by who is most accurate, it's now code golf. – intx13 – 2014-03-19T22:13:23.630

That being said, if you can find a way to encode the entire matrix in just 2 MB of memory, go right ahead. That would count as a 100% accurate answer. – Joe Z. – 2014-03-19T22:13:25.000

I presume that you're of the school of thought that N doesn't include 0, but since there are two schools of thought it's worth making that clear. It's also worth making it clear when you first mention them rather than three lines later that for some reason you've chosen to use x for the row and y for the column, confusing anyone who's used to Cartesian coordinates. – Peter Taylor – 2014-03-19T23:42:57.100

Actually, usually to me N does include 0, but for the purposes of this question it didn't work out. And I already put in the latter clarifier about x and y. Perhaps it would be better to use a and b so they're not confused with Cartesian coordinates? – Joe Z. – 2014-03-19T23:46:19.530

1@TheDoctor It's not too uncommon. The accepted answer changes over time. – Joe Z. – 2014-03-19T23:47:13.283

@JoeZ. - I usually wait till the interest on the question has declined – TheDoctor – 2014-03-19T23:52:34.033

I believe the memory restriction unnecessarily complicates this. It's also hard to ensure accuracy. – qwr – 2014-03-20T00:09:52.207

@qwr to be honest, I think the memory restriction is the most interesting thing about this problem. just computing the entire table in rows or columns seems quite trivial. – Martin Ender – 2014-03-20T00:25:53.057

r and c for row and column? I edited my comment when I saw that you had put in a clarification, but I didn't see it immediately because I read the bullet points and then went straight to the table. – Peter Taylor – 2014-03-20T08:33:31.230

Answers

9

J - 42 38 char

Pretty fast, 100% accurate, and well within the memory constraints.

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

The strategy is as follows: we will calculate successive antidiagonals of this matrix, performing a pairwise XOR to move along and adding the current Thue-Morse and prime bits to the ends. We then pull the required digit out of the antidiagonal when we get there.

Explanation by 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)

Usage of this verb is x m y for M(x, y) as specified in the question, where m is the verb.

   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

To save keystrokes we don't try to tell if we still need more prime or Thue-Morse bits, so we compute the entire antidiagonal to get the bit we want. However, 8192 m 8192 still runs in less than 0.07 s and about 100 KiB on my modest laptop.

algorithmshark

Posted 2014-03-19T21:20:33.657

Reputation: 8 144

6

Mathematica – 100% accuracy, 223 193 189 bytes

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])&

Here is a legible version:

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

I basically precompute along diagonals of constant x+y.

Features:

  • It's accurate.
  • It runs in O(x*y).
  • f[8192,8192] takes about 400 seconds. I suppose there is room for improvement (maybe RotateLeft could replace the inner loop).
  • It only uses one array of up to max(x,y) intermediate results in memory. So there is no necessity to use more than about 32k (assuming 32-bit integers) for the algorithm itself (plus, whatever Mathematica uses). In fact, Mathematica uses 31M by itself on my system, but this works without an issue:

    MemoryConstrained[f[8192, 8192], 2^21]
    

Martin Ender

Posted 2014-03-19T21:20:33.657

Reputation: 184 808

Well, looks like you got it. I'll be making harder ones in the future, though :P – Joe Z. – 2014-03-19T23:09:56.290

Hm, in one of the changes I must have screwed up the runtime performance. The inner loop is still called O(x*y) times, but the total execution time increases faster than that. I'm not quite sure what's happening. If some Mathematica Guru could enlighten me, which operation in the loop is not O(1) that would be very helpful! :) (well, PrimeQ and Total@IntegerDigits aren't, but I've had them in there from the beginning, and they only called O(y) and O(x) times respectively) – Martin Ender – 2014-03-20T00:01:27.980

3

Matlab: 100% accuracy, 120 characters, unreasonable execution time

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

To use:

> M(4,4)
ans =
      0
> M(1, 9)
ans =
      1

intx13

Posted 2014-03-19T21:20:33.657

Reputation: 1 517

1Now here's the question, can you actually run this program and test it? – Joe Z. – 2014-03-19T22:14:01.803

If you can't run M(8192, 8192), I can't take it. – Joe Z. – 2014-03-19T22:17:12.587

@JoeZ It's M-code, you can run it in Matlab or Octave. – intx13 – 2014-03-19T22:17:34.047

@JoeZ It will accurately compute M(8192, 8192). The challenge didn't say anything about time to complete ;) – intx13 – 2014-03-19T22:18:26.930

That was my bad; I had originally intended to put that into the specification, but couldn't find a way to make it concrete. It's in there now for some definition of "reasonable", for better or for worse. – Joe Z. – 2014-03-19T22:18:48.123

The memory constraint is also difficult to test... do you count Matlab itself? Is it memory at startup? The full thing? What about dynamic libraries? – intx13 – 2014-03-19T22:20:46.517

1@JoeZ well it looks like M(20,20) takes longer than I'm willing to wait. But hey, it's "accurate"! :P – intx13 – 2014-03-19T22:21:21.143

Generally I go by memory that the program uses after all the initial libraries have been loaded. Dynamic libraries don't count if they're loaded at startup before the actual algorithm kicks in. But really what the memory constraints are trying to avoid is solutions that use some sort of huge precomputation to get their "accuracy", which isn't really in the spirit of the type of question I'm trying to make the "binary matrix" genre into. – Joe Z. – 2014-03-19T22:22:53.117

2

Python, 192 characters

100% accuracy, calculates M(8192,8192) in ~10 seconds on my 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

Posted 2014-03-19T21:20:33.657

Reputation: 1 871

0

Haskell - 261 bytes - 100% - 1MB - I don't think it is going to end anytime soon

Takes about 10 seconds for m 16 16 with -O2, but as I have written it anyway I can show it despite this problem:

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]

Maybe some good Haskeller is able to optimize it?

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

Posted 2014-03-19T21:20:33.657

Reputation: 1 878

i think the algorithm itself is flawed. anyway, there are many things you can do to golf this. mostly extra parentheses , but also f p|p=not|0<1=id should be better. also, try using morse = False : concat $ iterate [True] (\a -> a ++ map not a) for increased laziness. I wonder how it will affect performance. – proud haskeller – 2015-01-01T22:15:23.840

also, you can golf True to 0<1 and False to 0>1. – proud haskeller – 2015-01-01T22:15:46.727

0

Perl, 137

Not to 'win' :-), but since there's no Perl here yet and code was written anyway, here it is.

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}

Takes several seconds if called print f(8192,8192), stores single line of matrix in memory (array of 8192 integers (scalars)), about 3.5 Mb whole Perl process. I tried to do it with string instead of array (either with regexps or accessing with substr), takes less memory and can be golfed further, but runs much slower.

Indented:

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

Posted 2014-03-19T21:20:33.657

Reputation: 1 541

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

this has fast runtime (5.7 seconds with -O3). memory wasn't checked yet, though it should be linear.

this uses the diagonal algorithm seen here before.

as far as speed is concerned, the only things that matter are the diagonal algorithm, -O3 , and the |foldr seq(0>1)s=0<1 guard, which makes the list strict. everything else is implemented rather inefficiently - prime checking is done by checking all the lesser numbers for division, the Morse sequence's elements are recomputed constantly. but it is still fast enough :-).

proud haskeller

Posted 2014-03-19T21:20:33.657

Reputation: 5 866