prog:: remember

Расширенный помнят механизм за процедуры

Блокноты MuPAD® будут демонтированы в будущем релизе. Используйте live скрипты MATLAB® вместо этого.

Live скрипты MATLAB поддерживают большую часть функциональности MuPAD, хотя существуют некоторые различия. Для получения дополнительной информации смотрите, Преобразовывают Notebook MuPAD в Live скрипты MATLAB.

Синтаксис

prog::remember(f, <depends>, <PreventRecursion, <predef>>)

Описание

prog::remember(f) возвращает измененную копию процедуры f, который хранит ранее вычисленные результаты и дополнительную информацию в помнить таблице. Когда вы вызываете f с аргументами, которые вы уже использовали в предыдущих вызовах, f находит результаты в помнить таблицу и сразу возвращает их.

Если вы присваиваете f идентификатору или доменному слоту, также необходимо присвоить копию, возвращенную prog::remember в тот же идентификатор или слот, например, f := prog::remember(f).

f := prog::remember(f) помнит результаты без контекстной информации, такие как свойства или значение DIGITS. В первый раз, когда вы вызываете f с любой новой комбинацией входных параметров, помнить таблица f хранит `input`->`f(input)`. После этого, когда вы вызываете f с теми же входными параметрами, он берет результату f(input) из помнить таблицы вместо того, чтобы повторно вычислить его. Смотрите Пример 1.

f := prog::remember(f, depends) помнит результаты и дополнительную контекстную информацию. Функция зависимости depends позволяет вам задать контекстную информацию, чтобы сохранить наряду с вычисленными результатами в помнить таблице и проверить в каждом вызове функции. Смотрите Пример 2.

Как правило, полезно сохранить и проверить свойства входа и значения DIGITS и ORDER. К свойствам доступа входа используйте property::depends. Эта функция зависимости проверяет все три значения:

() -> [property::depends(args()), DIGITS, ORDER]

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

() -> [property::depends, slotAssignCounter("foo")]

Чтобы объединить все три задачи, используйте эту функцию зависимости:

() -> [property::depends(args()),
			DIGITS, ORDER, slotAssignCounter("foo")]

В первый раз, когда вы вызываете f с любой новой комбинацией входных параметров, помнить таблица f хранит `[input, depends(input)]`->`f(input)`. После этого, когда вы вызываете f с теми же входными параметрами, он проверяет, возвращает ли depends(input) то же значение как прежде. Если это делает, то f берет результат f(input) из помнить таблицы. В противном случае это вычисляет f(input) и добавляет новые значения `[input, depends(input)]`->`f(input)` в помнить таблицу. Единственным исключением к этому правилу являются результаты, вычисленные с различными значениями MAXEFFORT. Если в предыдущих вызовах f(input) был вычислен с более низким MAXEFFORT, то новый вызов с более высоким MAXEFFORT оценен и помнил, что результаты заменяются новыми единицами.

Если функция зависимости является постоянной или возвращает значение, которое не зависит от входа, то помнить механизм игнорирует контекстную информацию.

Можно вызвать измененную процедуру с опцией Remember в качестве первого аргумента и одной из этих специальных опций в качестве второго аргумента:

  • Clear очищает помнить таблицу процедуры.

  • ClearPrevent очищает помнить таблицу, которая предотвращает бесконечные рекурсии в процедуре. Для получения дополнительной информации о предотвращении бесконечных рекурсий, см. описание опции PreventRecursion.

  • Print возвращает помнить таблицу процедуры.

Например, вызов f(Remember, Clear) очищает помнить таблицу f. Также смотрите Пример 3.

Примеры

Пример 1

Создайте эту функцию:

f := X -> if X > 1 then f(X - 1)*f(X - 2) - f(X - 2) else 1 end_if:

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

f(20), time(f(20))

Используя помнить механизм устраняет эти переоценки. Чтобы включить помнить механизм, используйте prog::remember:

f := prog::remember(f):
f(200), time(f(200))

Пример 2

Создайте процедуру pos, который проверяет, положителен ли его параметр:

pos := proc(x)
       begin
         is(x > 0)
       end_proc:

Включите помнить механизм для pos:

pos := prog::remember(pos):

pos возвращает UNKNOWN для переменной a:

pos(a)

Теперь используйте assume, чтобы указать, что переменная a положительна:

assume(a > 0):

Когда вы вызываете pos для переменной a, он находит значение pos(a) в помнить таблице. В этом случае помнить таблица не хранит контекстную информацию, и поэтому не проверяет на новые предположения на переменной a. Это возвращает помнивший результат, который является неправильным из-за нового предположения:

pos(a)

Вызов pos для a^3 возвращает правильный результат, потому что pos(a^3) еще не находится в помнить таблице:

pos(a^3)

Примите, что a отрицателен:

assume(a < 0):

Теперь оба вызова возвращают неправильные значения, потому что результаты взяты из помнить таблиц:

pos(a), pos(a^3)

Чтобы сделать помнить механизм, знающий об изменениях в предположениях, используйте prog::remember со вторым аргументом property::depends как функция зависимости:

unassume(a):
pos := proc(x)
       begin
         is(x > 0)
       end_proc:
pos := prog::remember(pos, property::depends):
pos(a)

Теперь pos реагирует правильно на новое предположение:

assume(a > 0):
pos(a)

pos также возвращает правильный результат после того, как вы очистите предположение:

unassume(a):
pos(a)

Пример 3

Создайте процедуру pos и включите помнить механизм для него:

pos := proc(x)
       begin
         is(x > 0)
       end_proc:
pos := prog::remember(pos, getprop):

Вызовите pos для этих параметров:

pos(a):
assume(b > a, _and):
pos(b):

После того, как вы вызовете процедуру, по крайней мере, однажды, она составляет помнить таблицу. Чтобы видеть помнить таблицу процедуры, используйте специальную опцию Print. Значение 106 во втором столбце является значением MAXEFFORT, используемого во время вычислений.

pos(Remember, Print)

Чтобы очистить помнить таблицу процедуры и таким образом обеспечить функцию, чтобы переоценить все результаты, используйте специальную опцию Clear:

pos(Remember, Clear):
pos(b)

Пример 4

Создайте процедуру deps, который собирает все операнды свойств данного выражения, включая идентификаторы принятых свойств:

deps := proc(x)
        begin
          if domtype(x) <> DOM_IDENT then
            op(map(indets(x), deps))
          else
            x, deps(getprop(x))
          end_if
        end_proc:

Установите следующее предположение. Обратите внимание на то, что теперь deps содержит потенциально бесконечные рекурсии, потому что свойство x относится к y, и свойство y вернулось к x:

assume(x > y):
deps(x)
Error: Recursive definition [See ?MAXDEPTH]

Чтобы предотвратить бесконечные рекурсии, используйте prog::remember с опцией PreventRecursion:

deps := prog::remember(deps, PreventRecursion):
deps(x)

Чтобы упростить возвращаемое значение deps, перепишите функцию так, чтобы это возвратило набор всех идентификаторов:

deps := proc(x)
        begin
          if domtype(x) <> DOM_IDENT then
            _union(op(map(indets(x), deps)))
          else
            {x} union deps(getprop(x))
          end_if
        end_proc:
deps := prog::remember(deps, PreventRecursion):
deps(x)

Теперь deps ожидает, что возвращаемое значение будет набором. По умолчанию, когда рекурсия обнаруживается, процедура возвращает значение своего входа (который не является набором в этом примере). При предотвращении рекурсии в процедуре, где тип входа отличается от типа возвращаемого значения, задайте значение predef, который возвращает процедура, когда рекурсия обнаруживается:

deps := proc(x)
        begin
          if domtype(x) <> DOM_IDENT then
            _union(op(map(indets(x), deps)))
          else
            {x} union deps(getprop(x))
          end_if
        end_proc:
deps := prog::remember(deps, PreventRecursion, () -> {args()}):

Здесь predef возвращает набор с входом как операнд:

deps(x)

Параметры

f

Процедура или функциональная среда

depends

Процедура или выражение

predef

Процедура или выражение

Опции

PreventRecursion

При использовании этой опции процедура, возвращенная prog::remember, использует помнившую информацию, чтобы предотвратить бесконечную рекурсию в процедуре.

f := prog::remember(f, PreventRecursion, predef ) хранит входные параметры только во время вызова функции. Этот подход позволяет вам постараться не переоценивать тот же вызов функции когда вызовы функции сам рекурсивно. Вместо этого это возвращает вход (по умолчанию) или результат вызова predef(input) (если вы задаете predef). Если возврат входа не является соответствующим результатом для вызова функции (например, если возвращаемое значение f и входа имеет различные типы), то необходимо задать значение predef. Смотрите Пример 4.

В конце вызова функции отбрасываются все помнившие значения. Если вы вызываете функцию с теми же входными параметрами снова, вызов функции оценен с теми же затратами как прежде.

Можно предотвратить рекурсию в вызове функции и одновременно использовать помнить механизм вне вызова функции при помощи этого синтаксиса: f := prog::remember(f, depends, PreventRecursion, predef ). Если вы хотите использовать помнить механизм с контекстной информацией, задайте функцию зависимости depends, как обычно. Если вы хотите использовать помнить механизм без контекстной информации и предотвратить рекурсии в процедуре, задать depends как константу (или любая функция, возвращаемое значение которой не зависит от входа). Обратите внимание на то, что, если вы не используете функцию depends и только используете синтаксис f := prog::remember(f, PreventRecursion, predef ), затем помнить механизм не работает вне вызова функции. В этом случае вы только предотвращаете рекурсии.

Возвращаемые значения

Измененная процедура или функциональная среда

Смотрите также

Функции MuPAD