Как я могу сгенерировать простую последовательность Роуленда в J? - PullRequest
1 голос
/ 10 июня 2010

Если вы не знакомы с простой последовательностью Роуленда, вы можете узнать об этом здесь . Я создал уродливый процедурный монадический глагол в J, чтобы сгенерировать первые n членов в этой последовательности следующим образом:

rowland =: monad define
    result =. 0 $ 0
    t =. 1 $ 7
    while. (# result) < y do.
        a =. {: t
        n =. 1 + # t
        t =. t , a + n +. a
        d =. | -/ _2 {. t
        if. d > 1 do.
            result =. ~. result , d
        end.
    end.
    result
)

Это работает отлично, и действительно генерирует первые n членов в последовательности. (Под n терминами я подразумеваю первые n отдельные простые числа.)

Вот вывод rowland 20:

5 3 11 23 47 101 7 13 233 467 941 1889 3779 7559 15131 53 30323 60647 121403 242807

У меня вопрос, как я могу написать это более идиоматическим J? Понятия не имею, хотя я написал следующую функцию, чтобы найти различия между каждым последующим числом в списке номера, что является одним из обязательных шагов. Вот оно, хотя он, вероятно, мог бы быть подвергнут рефакторингу более опытным программистом J, чем я:

diffs =: monad : '}: (|@-/@(2&{.) , $:@}.) ^: (1 < #) y'

Ответы [ 2 ]

3 голосов
/ 20 февраля 2012

Хотя я уже пометил ответ Эстанфорда как правильный, я проделал длинный, долгий путь с J, так как я задал этот вопрос.Вот гораздо более идиоматический способ генерации простой последовательности строк в J:

~. (#~ 1&<) | 2 -/\ (, ({: + ({: +. >:@#)))^:(1000 - #) 7

Выражение (, ({: + ({: +. >:@#)))^:(1000 - #) 7 генерирует так называемую оригинальную последовательность до 1000 членов.Первые различия этой последовательности могут быть сгенерированы как | 2 -/\, то есть абсолютные значения разностей каждых двух элементов.(Сравните это с моим оригинальным длинным глаголом diffs из исходного вопроса.)

Наконец, мы удаляем единицы и дубликаты простых чисел ~. (#~ 1&<), чтобы получить последовательность простых чисел.

Это намного лучше, чем я делал это раньше.Его можно легко превратить в глагол для генерации n числа простых чисел с небольшой рекурсией.

2 голосов
/ 12 июня 2010

У меня пока нет полного ответа, но это эссе Роджера Хуэя имеет молчаливую конструкцию, которую можно использовать для замены явных циклов while.Другой (связанный) способ - сделать внутреннюю логику блока неявным выражением, например:

FUNWITHTACIT =: ] , {: + {: +. 1 + #
rowland =: monad define
    result =. >a:
    t =. 7x
    while. (# result) < y do.
      t =. FUNWITHTACIT t
      d =.  | -/ _2 {. t
      result =. ~.result,((d>1)#d)
    end.
    result
)

(хотя вы можете сохранить блок if для эффективности, так как я написал кодтаким образом, что result изменяется независимо от того, было ли выполнено условие - если это не так, изменение не имеет никакого эффекта. Логика if может быть даже записана обратно в молчаливое выражение, используяОператор повестки дня.)

Полное решение будет состоять в том, чтобы выяснить, как представить всю логику внутри цикла while в виде единой функции, а затем использовать трюк Роджера для реализации логики while в качестве неявного выражения.Я посмотрю, что у меня получится.

Кроме того, я заставил J собрать для меня FUNWITHTACIT, взяв первые несколько строк вашего кода, подставив вручную функции, которые вы объявили для переменнойзначения (что я мог сделать, потому что все они работали с одним аргументом по-разному), заменил каждый экземпляр t на y и велел J построить неявный эквивалент полученного выражения:

]FUNWITHTACIT =: 13 : 'y,({:y)+(1+#y)+.({:y)'
   ] , {: + {: +. 1 + #

Использование 13 для объявления монады - это то, как J знает, как взять монаду (иначе явно объявленную с помощью 3 : 0 или monad define, как вы написали в своей программе) и преобразовать явное выражение в неявное выражение.

EDIT:

Вот функции, которые я написал для avenue (2), о которых я упоминал в комментарии:

candfun =: 3 : '(] , {: + {: +. 1 + #)^:(y) 7'
firstdiff =: [: | 2 -/\ ]
triage =: [: /:~ [: ~. 1&~: # ]
rowland2 =: triage @firstdiff @candfun

Эта функция генерирует первые n-много номеров кандидатов, используяОтношение повторяемости Роуленда оценивает их первые различия, отбрасывает все первые различия, равные 1, отбрасывает все дубликаты и сортирует их в порядке возрастания.Я не думаю, что это пока полностью удовлетворительно, так как аргумент задает количество кандидатов, а не количество результатов.Но это все еще прогресс.

Пример:

   rowland2 1000
3 5 7 11 13 23 47 101 233 467 941

Вот версия первой функции, которую я опубликовал, с минимальным размером каждого аргумента:

NB. rowrec takes y=(n,an) where n is the index and a(n) is the
NB. nth member of the rowland candidate sequence. The base case
NB. is rowrec 1 7. The output is (n+1,a(n+1)).
rowrec =: (1 + {.) , }. + [: +./ 1 0 + ]

rowland3 =: 3 : 0
 result =. >a:
 t =. 1 7
 while. y > #result do.
  ts =. (<"1)2 2 $ t,rowrec t
  fdiff =. |2-/\,>(}.&.>) ts
  if. 1~:fdiff do.
   result =. ~. result,fdiff
  end.
  t =. ,>}.ts
 end.
 /:~ result
) 

, который находит первые y-много различных простых чисел Роуленда и представляет их в порядке возрастания:

   rowland3 20
3 5 7 11 13 23 47 53 101 233 467 941 1889 3779 7559 15131 30323 60647 121403 242807

Большая часть сложности этой функции связана с моей обработкой коробочных массивов.Это не очень красивый код, но он только хранит 4+#result многих элементов данных (которые растут в масштабе журнала) в памяти во время вычислений.Исходная функция rowland сохраняет (#t)+(#result) элементов в памяти (которая растет в линейном масштабе).rowland2 y создает массив из y -много элементов, что делает его профиль памяти почти таким же, как rowland, даже если он никогда не выходит за пределы указанной границы.Мне нравится rowland2 за его компактность, но без формулы для прогнозирования точного размера y, необходимого для генерации n-многих различных простых чисел, эту задачу необходимо будет выполнить методом проб и ошибок и, следовательно, потенциально использоватьнамного больше циклов, чем rowland или rowland3 при избыточных вычислениях.rowland3, вероятно, более эффективен, чем моя версия rowland, поскольку FUNWITHTACIT пересчитывает #t на каждую итерацию цикла - rowland3 просто увеличивает счетчик, который требует меньше вычислений.

Тем не менееЯ не доволен явными управляющими структурами rowland3.Кажется, должен быть способ выполнить это поведение, используя рекурсию или что-то в этом роде.

...