Вывести определенное значение в этой сгенерированной двоичной матрице

14

Предположим, мы определяем бесконечную матрицу Mна N^2 -> {0, 1}(откуда Nначинается 1вместо 0) следующим образом:

  • M(1, 1)= 0.

  • Для каждого x > 1, M(x, 1)= 1если xпростой, и в 0противном случае.

  • Для каждого y > 1, M(1, y)= yй член в Thue-Morse sequence.

  • Для каждого x, y > 1, M(x, y)= M(x, y-1) + M(x-1, y) mod 2.

Верхний левый 16x16раздел этой матрицы выглядит следующим образом (со xстроками и со yстолбцами):

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

Ваша задача - построить программу, которая будет оценивать значение произвольной записи в этой матрице с максимально возможной точностью.

Ваша программа будет принимать два целых числа xи в yкачестве входных данных, в любой выбранной вами форме, и возвращать M(x, y), что будет либо либо, 0либо 1.

Ваш код может быть написан на любом языке, но не должен превышать 64 килобайт (65 536 байт) размера исходного кода или 2 МБ (2 097 152 байт) общего использования памяти. Ваша программа должна начинаться с пустой памяти (то есть она не может загружать данные откуда-то еще) и запускаться независимо для каждого входа (то есть она может не хранить общие данные для нескольких запусков). Ваша программа также должна быть в состоянии оценить все записи в верхнем левом 8192x8192квадрате за разумное время.

Программа, которая оценивает большинство записей правильно в верхнем левом 8192 x 8192квадрате, будет победителем, с более коротким кодом, действующим как тай-брейк.

Джо З.
источник
Вероятно, я собираюсь обновить тестовый пример до чего-то более элегантного, поэтому продолжайте тестирование, пока я не отредактирую вопрос снова.
Джо З.
@mbuettner Да, это так.
Джо З.
1
Я не вижу, как нам нужен новый тег для «точности». Это просто [вызов кода]. Пожалуйста, сначала ознакомьтесь с новыми идеями жанра испытаний через мета (есть одна вещь, которую мы узнали из [код-троллинга]).
Дверная ручка
^ Отметил. Я удалю этот тег.
Джо З.
1
@TheDoctor Это не так уж редко. Принятый ответ меняется со временем.
Джо З.

Ответы:

9

J - 42 38 символов

Довольно быстрый, точный на 100% и хорошо вписывается в ограничения памяти.

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

Стратегия заключается в следующем: мы рассчитаем последовательные антидиагоналы этой матрицы, выполняя попарно XOR для движения вперед и добавляя текущие числа Ту-Морса и простые биты к концам. Затем мы вытаскиваем нужную цифру из антидиагонали, когда попадаем туда.

Объяснение взрывом:

(                                 )&<:  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)

Использование этого глагола x m yдля M (x, y), как указано в вопросе, где mглагол.

   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

Чтобы сохранить нажатия клавиш, мы не пытаемся определить, нужны ли нам еще простые биты или биты Тью-Морса, поэтому мы вычисляем всю антидиагональность, чтобы получить нужный бит. Тем не менее, 8192 m 8192все еще работает менее чем за 0,07 с и около 100 КиБ на моем скромном ноутбуке.

algorithmshark
источник
6

Mathematica - точность 100%, 223 193 189 байт

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

Вот разборчивая версия:

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

Я в основном заранее вычисляю по диагонали константы x+y.

Функции:

  • Это точно.
  • Это работает в O(x*y).
  • f[8192,8192]занимает около 400 секунд. Я полагаю, что есть возможности для улучшения (возможно, RotateLeftможет заменить внутренний цикл).
  • Он использует только один массив до max(x,y)промежуточных результатов в памяти. Таким образом, нет необходимости использовать более 32 тыс. (При условии 32-разрядных целых чисел) для самого алгоритма (плюс все, что использует Mathematica). Фактически, Mathematica использует 31M в моей системе, но это работает без проблем:

    MemoryConstrained[f[8192, 8192], 2^21]
    
Мартин Эндер
источник
Ну, похоже, ты понял. Но в будущем я буду делать все сложнее: P
Джо З.
Хм, в одном из изменений я, должно быть, испортил производительность во время выполнения. Внутренний цикл по-прежнему называется O(x*y)временем, но общее время выполнения увеличивается быстрее. Я не совсем уверен, что происходит. Если бы какой-нибудь Гуру Математики мог просветить меня, какая операция в цикле не O(1)была бы очень полезной! :) (ну, PrimeQи Total@IntegerDigitsнет, но у меня они были там с самого начала, и они только звонили O(y)и O(x)время соответственно)
Мартин Эндер
3

Matlab: точность 100%, 120 символов, необоснованное время выполнения

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

Использовать:

> M(4,4)
ans =
      0
> M(1, 9)
ans =
      1
intx13
источник
1
Теперь вот вопрос, можете ли вы на самом деле запустить эту программу и протестировать ее?
Джо З.
Если ты не умеешь бегать M(8192, 8192), я не выдержу.
Джо З.
@JoeZ Это М-код, вы можете запустить его в Matlab или Octave.
intx13
@JoeZ Он точно вычислит M (8192, 8192). Задача ничего не сказала о времени для завершения;)
intx13
1
@JoeZ ну, похоже, М (20,20) занимает больше времени, чем я готов ждать. Но эй, это "точно"! : P
intx13
2

Python, 192 символа

Точность 100%, вычисляет M (8192,8192) за ~ 10 секунд на моей машине.

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]
Алекси Торхамо
источник
0

Haskell - 261 байт - 100% - 1MB - я не думаю, что это скоро закончится

Требуется около 10 секунд для m 16 16с -O2, но, как я уже написал, я могу показать это, несмотря на эту проблему:

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]

Может быть, какой-то хороший Хаскеллер сможет это оптимизировать?

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
источник
Я думаю, что сам алгоритм имеет недостатки. во всяком случае, есть много вещей, которые вы можете сделать, чтобы играть в гольф. в основном лишние скобки, но также f p|p=not|0<1=idдолжны быть лучше. Кроме того, попробуйте использовать morse = False : concat $ iterate [True] (\a -> a ++ map not a)для увеличения лени. Интересно, как это повлияет на производительность?
гордый haskeller
Кроме того , вы можете играть в гольф , Trueчтобы 0<1и Falseв 0>1.
гордый haskeller
0

Perl, 137

Не для «победы» :-), но поскольку здесь еще нет Perl и код был написан в любом случае, вот он.

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}

Занимает несколько секунд, если вызывается print f(8192,8192), сохраняет одну строку матрицы в памяти (массив из 8192 целых чисел (скаляров)), около 3,5 Мб всего процесса Perl. Я попытался сделать это с помощью строки вместо массива (либо с помощью регулярных выражений, либо с помощью substr), занимал меньше памяти и в дальнейшем мог играть в гольф, но работает намного медленнее.

Отступ:

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
источник
0

Хаскелл, 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

это имеет быстрое время выполнения (5,7 секунд с -O3). память еще не проверена, хотя она должна быть линейной.

здесь используется алгоритм диагонали, который мы видели раньше.

Что касается скорости, то важны только диагональный алгоритм -O3и |foldr seq(0>1)s=0<1защита, которая делает список строгим. все остальное реализовано довольно неэффективно - первичная проверка выполняется путем проверки всех меньших чисел на деление, элементы последовательности Морса пересчитываются постоянно. но это все еще достаточно быстро :-).

гордый хаскеллер
источник