Две странные проблемы эффективности в Mathematica - PullRequest
5 голосов
/ 01 мая 2010

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

Я рассчитал, сколько времени потребуется для вычисления следующих операторов (где 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;

Алиса, Боб и Крис - идентичные матрицы, вычисленные 3 слегка разными способами. Я считаю, что Крис вычисляется в 1000 раз быстрее, чем Алиса и Боб.

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

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


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

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

f(x)=x+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?


EDIT:

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

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

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

Ответы [ 3 ]

5 голосов
/ 01 мая 2010

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

Проблема одна

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

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:

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

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

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

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

2 голосов
/ 24 декабря 2011

Ваша первая проблема уже была объяснена, но я хочу отметить, что ConstantArray был введен в Mathematica 6 для решения этой проблемы. До этого времени Table[expr, {50}] использовалось как для фиксированных, так и для изменяющихся выражений.

С момента введения ConstantArray существует четкое разделение между итерацией с переоценкой и простым дублированием выражения. Вы можете увидеть поведение, используя это:

ConstantArray[Table[Pause[1]; i, {i, 5}], {50}] ~Monitor~ i

Из-за Pause[1] прохождение цикла Table занимает пять секунд, но после того, как этот цикл завершен, он не переоценивается, и 50 копий сразу же печатаются.

1 голос
/ 01 мая 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...