## `freeze, unfreeze` -- create an inactive or active copy of a function

#### Introduction

`freeze(f)` creates an inactive copy of the function `f`.

`unfreeze(object)` reactivates all inactive functions occurring in `object` and evaluates the result.

#### Call(s)

`freeze(f)`
`unfreeze(object)`

#### Parameters

`f` | - | a procedure or a function environment
`object` | - | any MuPAD object

#### Returns

`freeze` returns an object of the same type as `f`. `unfreeze` returns the evaluation of `object` after reactivating all inactive functions in it.

#### Related Functions

`eval`, `hold`, `MAXDEPTH`

#### Details

- `ff := freeze(f)` returns a function that is an ``inactive'' copy of the argument `f`. This means:
  1. `ff` only evaluates its arguments, but does not compute anything else,
  2. `ff` is printed in the same way as `f`,
  3. symbolic `ff` calls have the same type as symbolic `f` calls,
  4. if `f` is a function environment, then `ff` has all the slots of `f`.
  Note that `ff` evaluates its incoming parameters even if the function `f` has the procedure option `hold`.

- `freeze` can be used when many operations with `f` are to be performed that require `f` only in its symbolic form, but `f` need not be executed. See example 2.

- Neither `eval` nor `level` can enforce the evaluation of an inactive function; see example 2.

- `unfreeze(object)` reactivates all inactive functions occurring in `object`, proceeding recursively along the structure of `object`, and then evaluates the result.

- `unfreeze` uses `misc::maprec` to proceed recursively along the structure of `object`. This means that for `basic domains` such as arrays, tables, lists, or polynomials, the function `unfreeze` is applied to each operand of `object`.

  Note that if `object` is an element of a `library domain`, then the behavior of `unfreeze` is specified by the method `"maprec"` which overloads the function `misc::maprec`. If this method does not exist, then `unfreeze` has no effect on `object`. See example 5.

- `unfreeze` does not operate on the body of procedures, therefore it is recommended not to embed inactive functions inside procedures.

#### Example 1

We create an inactive form of the function environment `int`:

    >> _int := freeze(int): F := _int(x*exp(x^2), x = 0..1)

                                        2
                             int(x exp(x ), x = 0..1)

The inactive form of `int` keeps every information that is known about the function `int`, e.g., the output, the type, and the `"float"` slot for floating-point evaluation:

    >> F, type(F), float(F)

                              2
                   int(x exp(x ), x = 0..1), "int", 0.8591409142

The original function environment `int` is not modified by `freeze`:

    >> int(x*exp(x^2), x = 0..1)

                                   exp(1)
                                   ------ - 1/2
                                     2

Use `unfreeze` to reactivate the inactive function `_int` and evaluate the result:

    >> unfreeze(F), unfreeze(F + 1/2)

                               exp(1)        exp(1)
                               ------ - 1/2, ------
                                 2             2

#### Example 2

The function `student::riemann` makes use of `freeze` in order to return a result where the function `sum` is preserved in its symbolic form:

    >> a:= student::riemann(sin(x), x = 0..PI)

                           /    / PI (i3 + 1/2) \            \
                     PI sum| sin| ------------- |, i3 = 0..3 |
                           \    \       4       /            /
                     -----------------------------------------
                                         4

Only when applying `unfreeze` the sum is computed:

    >> unfreeze(a)

                              1/2     1/2         1/2 1/2
                        PI ((2    + 2)    + (2 - 2   )   )
                        ----------------------------------
                                        4

    >> float(%)

                                    2.052344306

#### Example 3

We demonstrate the difference between `hold` and `freeze`. The result of the command `S := hold(sum)(...)` does not contain an inactive version of `sum`, but the unevaluated identifier `sum`:

    >> S := hold(sum)(1/n^2, n = 1..infinity)

                               / 1                   \
                            sum| --, n = 1..infinity |
                               |  2                  |
                               \ n                   /

The next time `S` is evaluated, the identifier `sum` is replaced by its value, the function environment `sum`, and the procedure computing the value of the infinite sum is invoked:

    >> S

                                          2
                                        PI
                                        ---
                                         6

In contrast, evaluation of the result of `freeze` does not lead to an evaluation of the inactive function:

    >> S := freeze(sum)(1/n^2, n = 1..infinity)

                               / 1                   \
                            sum| --, n = 1..infinity |
                               |  2                  |
                               \ n                   /

    >> S

                               / 1                   \
                            sum| --, n = 1..infinity |
                               |  2                  |
                               \ n                   /

An inactive function does not even react to `eval`:

    >> eval(S)

                               / 1                   \
                            sum| --, n = 1..infinity |
                               |  2                  |
                               \ n                   /

The only way to undo a `freeze` is to use `unfreeze`, which reactivates the inactive function in `S` and then evaluates the result:

    >> unfreeze(S)

                                          2
                                        PI
                                        ---
                                         6

#### Example 4

Note that `freeze(f)` does not change the object `f` but returns a copy of `f` in an inactive form. This means that computations with the inactive version of `f` may contain the original function `f`.

For example, if we create an inactive version of the sine function:

    >> Sin := freeze(sin):

and expand the term `Sin(x+y)`, then the result is expressed in terms of the (original) sine function `sin`:

    >> expand(Sin(x + y))

                           cos(x) sin(y) + cos(y) sin(x)

#### Example 5

The function `unfreeze` uses `misc::maprec` to operate recursively along the structure of `object`. For example, if `object` is an array containing inactive functions, such as:

    >> a := array(1..2,
         [freeze(int)(sin(x), x = 0..2*PI), freeze(sum)(k^2, k = 1..n)]
       )

                  +-                               2           -+
                  | int(sin(x), x = 0..2 PI), sum(k , k = 1..n) |
                  +-                                           -+

then `unfreeze(a)` operates on the operands of `a`:

    >> unfreeze(a)

                               +-                -+
                               |          2    3  |
                               |     n   n    n   |
                               |  0, - + -- + --  |
                               |     6   2    3   |
                               +-                -+

This means that for library domains, the effect of `unfreeze` is specified by the method `"maprec"`. If the domain does not implement this method, then `unfreeze` does not operate on the objects of this domain. For example, we create a dummy domain and an object containing an inactive function as its operand:

    >> dummy := newDomain("dummy"):
       o := new(dummy, freeze(int)(sin(x), x = 0..2*PI))

                       new(dummy, int(sin(x), x = 0..2 PI))

The function `unfreeze` applied to the object `o` has no effect:

    >> unfreeze(o)

                       new(dummy, int(sin(x), x = 0..2 PI))

If we overload the function `misc::maprec` in order to operate on the first operand of objects of the domain `dummy`, then `unfreeze` operates on `o` as desired:

    >> dummy::maprec :=
         x -> extsubsop(x,
           1 = misc::maprec(extop(x,1), args(2..args(0)))
         ):
       unfreeze(o)

                                   new(dummy, 0)

#### Changes

- used to be called `[`
- freeze]misc::freeze
- used to be called `[`
- unfreeze]misc::unfreeze

Do you have questions or comments?
Copyright © SciFace Software GmbH & Co. KG 2000