разница в скорости создания таблицы

Я читал полезный пост в блоге WRI о повышении скорости кода , и мне нужна помощь в понимании этого.

Сравните эти скорости

Timing[
 tbl = Table[i + j, {i, 1, 1000}, {j, 1, 1000}];     
]

{0.031, Null}

и

Timing[
 a = 1000;
 tbl = Table[i + j, {i, 1, a}, {j, 1, a}];
 ]

{0.422, Null}

. Так что гораздо быстрее помещать фактическое значение для ограничения внутри самой таблицы, а не снаружи. Объяснение этого, которое я уверен, что это правильно, но мне нужна помощь в понимании, заключается в том, что Таблица компилируется, если ее предел числовой, а не нет, это потому, что ее атрибуты равны HoldAll .

Но мой вопрос: как на самом деле будет работать вышеупомянутое, потому что пределы для таблицы должны в какой-то момент все равно стать числовыми? Я не могу писать

Clear[a]
tbl = Table[i + j, {i, 1, a}, {j, 1, a}]

Вышеупомянутое выдает ошибку.

Итак, для меня запись a = 1000 вне таблицы по сравнению с внутренней не имела никакого значения, поскольку без a , имеющего числовое значение, Таблица [] ничего не может сделать. Таким образом, замена a числом 1000 должна произойти в какой-то момент вычислителем, прежде чем Table [] сможет сделать что-нибудь полезное, не так ли?

Другими словами, в конечном итоге таблица должна увидеть {i, 1, 1000}, {j, 1, 1000} в обоих случаях.

Я думал, что это произойдет следующим образом:

  1. Evaluator заменяет a на 1000 в аргументах таблицы
  2. Evaluator вызывает Table с результатом, который теперь полностью числовой.
  3. Таблица компилируется и работает быстрее.

Но, кажется, происходит кое-что еще. (из-за HoldAll ?)

  1. Таблица принимает свои аргументы, как есть. Поскольку у него есть HoldAll, он видит a , а не 1000.
  2. Он не вызывает Compile, поскольку не все его аргументы являются числами.
  3. Теперь он генерирует таблицу с пределом a , Evaluator оценивает a до 1000
  4. Таблица создается теперь все ограничения числовые, но теперь медленнее, так как код не компилируется .

Вопрос: происходит ли подобное? Может ли кто-нибудь объяснить шаги, которые могли бы произойти, чтобы объяснить эту разницу во времени?

Кроме того, как можно гарантировать, что таблица скомпилирована в обоих случаях в приведенном выше примере, даже если используется переменная для Лимит? Не всегда возможно жестко запрограммировать числа для пределов таблицы, но иногда необходимо использовать для них переменные. Следует ли явно использовать команду Compile ? (Я не использую Compile напрямую, поскольку предполагал, что это выполняется автоматически, когда это необходимо).

редактировать (1)

В ответ на сообщение Майка ниже о том, что не было разницы во времени при использовании вызова.

ClearAll[tblFunc];
Timing[a = 1000;
 tblFunc[a_] := Table[i + j, {i, 1, a}, {j, 1, a}];
 Developer`PackedArrayQ[tblFunc[a]]
 ]

дает

{0.031, True}

Но это потому, что a теперь является числом 1000 ВНУТРИ функции после ее вызова. Поскольку M передает вещи на VALUE.

Если мы заставим вызов быть по ссылке, так что a останется невычисленным, тогда мы получим

ClearAll[tblFunc];
Timing[a = 1000;
 tblFunc[a_] := Table[i + j, {i, 1, a}, {j, 1, a}];
 Developer`PackedArrayQ[tblFunc[Unevaluated@a]]
 ]

, теперь мы видим ожидаемый результат, так как теперь a все еще символический ВНУТРИ функции, мы вернулись к исходной точке, и теперь она медленная, так как не упакована. И так как он не запакован, Compile не используется.

{0.437, False}

редактировать (2) Спасибо всем за ответы, думаю, я многому научился у них.

Вот краткое изложение, просто чтобы убедиться, что у меня все в порядке.

enter image description here

edit (3)

Вот ссылки, которые у меня есть специально для советов по ускорению работы кода Mathematica.

  1. http://library.wolfram.com/howtos/faster/
  2. http://blog.wolfram.com/2011/12/07/10-tips-for-writing-fast-mathematica-code/
  3. https://stackoverflow.com/questions/4721171/performance-tuning-in-mathematica
  4. Использование функций массивов и таблиц в системе Mathematica. Что лучше всего, когда

14
задан Community 23 May 2017 в 12:16
поделиться