Две странных проблемы эффективности в Mathematica

ПЕРВАЯ ПРОБЛЕМА

Я синхронизировал, сколько времени это берет для вычислений следующих утверждений (где V [x] интенсивный временем вызов функции):

Alice     = Table[V[i],{i,1,300},{1000}];
Bob       = Table[Table[V[i],{i,1,300}],{1000}]^tr;
Chris_pre = Table[V[i],{i,1,300}];
Chris     = Table[Chris_pre,{1000}]^tr;

Alice, Bob и Chris являются идентичным matricies, вычисленным 3 немного отличающихся пути. Я нахожу, что Chris вычисляется в 1000 раз быстрее, чем Alice и Bob.

Не удивительно, что Alice вычисляется в 1000 раз медленнее, потому что, наивно, функция V должна быть вызвана еще 1000 раз чем тогда, когда Chris вычисляется. Но очень удивительно, что Bob является настолько медленным, так как он вычисляется тождественно Chris за исключением того, что Chris хранит промежуточный шаг Chris_pre.

Почему Bob оценивает так медленно?


ВТОРАЯ ПРОБЛЕМА

Предположим, что я хочу скомпилировать функцию в Mathematica формы

f(x)=x+y

где "y" является константой, зафиксированной во время компиляции (но который я предпочитаю не непосредственно заменять в коде его числовым, потому что я хочу смочь легко изменить его). Если фактическое значение y является y=7.3, и я определяю

f1=Compile[{x},x+y]
f2=Compile[{x},x+7.3]

затем f1 работает на 50% медленнее, чем f2. Как я заставляю Mathematica заменить "y" "7,3", когда f1 компилируется, так, чтобы f1 работал с такой скоростью, как f2?


Править:

Я нашел ужасное обходное решение для второй проблемы:

f1=ReleaseHold[Hold[Compile[{x},x+z]]/.{z->y}]

Должен быть лучший путь...

5
задан Brian Tompsett - 汤莱恩 25 January 2017 в 19:40
поделиться

2 ответа

Вам, наверное, стоило опубликовать их как отдельные вопросы, но не беспокойтесь!

Проблема первая

Проблема с Алисой, конечно же, соответствует вашим ожиданиям. Проблема с Бобом заключается в том, что внутренняя таблица вычисляется один раз за итерацию внешней таблицы . Это хорошо видно с Trace:

Trace[Table[Table[i, {i, 1, 3}], {3}]]

{
Table[Table[i,{i,1,2}],{2}],
{Table[i,{i,1,2}],{i,1},{i,2},{1,2}},{Table[i,{i,1,2}],{i,1},{i,2},{1,2}},
{{1,2},{1,2}}
}

Разрывы строк добавлены для акцента, и да, вывод Trace on Table немного странный, но вы можете это увидеть. Очевидно, что Mathematica могла бы оптимизировать это лучше, зная, что внешняя таблица не имеет итератора, но по какой-то причине она не принимает это во внимание.Только Крис делает то, что вы хотите, хотя вы можете изменить Боба:

Transpose[Table[Evaluate[Table[V[i],{i,1,300}]],{1000}]]

Похоже, что он на самом деле превосходит Криса примерно в два раза, потому что ему не нужно сохранять промежуточный результат.

Проблема вторая

Есть более простое решение с Evaluate, хотя я ожидаю, что оно не будет работать со всеми возможными функциями, подлежащими компиляции (то есть с теми, которые действительно должны быть отложены):

f1 = Compile[{x}, Evaluate[x + y]];

Вы также можете использовать ] С помощью :

With[{y=7.3},
    f1 = Compile[{x}, x + y];
]

Или, если y определено где-то еще, используйте временное значение:

y = 7.3;
With[{z = y},
    f1 = Compile[{x}, x + z];
]

Я не эксперт по механизмам определения объема и оценки Mathematica, так что легко мог бы быть гораздо лучший способ, но, надеюсь, один из они делают это за вас!

5
ответ дан 14 December 2019 в 04:32
поделиться

Первая проблема Вы проверили результат вычисления Chris_pre? Вы обнаружите, что это совсем не большая матрица, поскольку вы пытаетесь сохранить промежуточный результат в шаблоне, а не в переменной. Вместо этого попробуйте ChrisPre. Тогда все тайминги сопоставимы.

Вторая проблема Компиляция имеет ряд хитрых ограничений на ее использование. Одна проблема заключается в том, что вы не можете ссылаться на глобальные переменные.Конструкция With, которая уже была предложена, является предлагаемым способом решения этой проблемы. Если вы хотите узнать больше о компиляции, ознакомьтесь с уловками Теда Эрсека: http://www.verbeia.com/mathematica/tips/Tricks.html

1
ответ дан 14 December 2019 в 04:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: