## `package` -- load a package of new library functions

#### Introduction

`package``(dirname)` loads a new library package.

#### Call(s)

`package(dirname <, Quiet> <, Forced>)`

#### Parameters

`dirname` | - | a valid directory path: a character string

#### Options

`Quiet` | - | suppresses screen output while loading the library
`Forced` | - | enforces reloading of libraries that are already loaded

#### Returns

the value of the last statement in the initialization file `init.mu` of the package.

#### Side Effects

The path `dirname/lib` is prepended to the search path `LIBPATH`. The path `dirname/modules/OSName` is prepended to the search path `READPATH` (`OSName` is the name of the operating system; cf. `sysname`). This way, library functions are first searched for in the package. Modules contained in the package are found automatically. In case of a naming conflict, a package function overrides a function of the system's main library.

#### Related Functions

`export`, `LIBPATH`, `loadmod`, `loadproc`, `newDomain`, `read`, `READPATH`

#### Details

- In MuPAD, procedures implementing algorithms from a specific mathematical area are organized as libraries. E.g., `numlib` is the library for number theory, `numeric` is the library for numerical algorithms etc. Also the user should organize collections of related functions as a library package. With a suitable structure of the folder containing the files with the source code, the whole library can be loaded into the MuPAD session via a call to `package`.
- Formally, a library is a domain. The functions in the library are its slots and are accessed by the ``slot operator'' `::` as in `numlib::fibonacci`, `numeric::int` etc.
- Typically, either a new library domain is to be created and its functions are to be loaded by `package`, or new functions are to be added to an existing library domain of MuPAD's standard installation. The detailed example 1 below is devoted to the former case, whereas example 2 covers the latter case. Special care should be taken, when existing libraries are modified: the user should make sure that existing functionality is not overwritten or destroyed by the modification.
- The folder `mypack`, say, containing the library package to be loaded can be placed anywhere in the filesystem. The pathname specified in a `package` call may be an absolut path (from the root to `mypack`). Alternatively, a path relative to the ``working directory'' may be specified.

  Note that the ``working directory'' is different on different operating systems. On Windows systems, for example, the ``working directory'' is the folder, where MuPAD is installed. On UNIX or Linux systems, it is the directory in which the current MuPAD session was started.

- The folder `mypack` must have the same hierarchical structure as the standard MuPAD library. In particular, it must have a subfolder `lib` containing the source files of the package. Inside the `lib` folder, an initialization file `init.mu` must exist.

  For example, on a UNIX or Linux system, the folder `mypack` should have the following structure (up to different path separators, the same holds for other operating systems as well):

  > `mypack/lib/init.mu
  > mypack/lib/LIBFILES/mylib.mu
  > mypack/lib/MYLIB/stuff.mu
  > mypack/lib/MYLIB/...
  > mypack/lib/MYLIB/SUBDIR/morestuff.mu
  > mypack/lib/MYLIB/SUBDIR/...`

  Typically, the initialization file `init.mu` uses `loadproc` commands to define the objects (new library domains and/or functions) of the package.

  If a new library domain is to be created, the `lib` folder should contain a subfolder `LIBFILES` with a file `LIBFILES/mylib.mu`. The `loadproc` commands inside `init.mu` should refer to the file `mylib.mu`. Inside this file, the new library domain should be created via `newDomain`. The functions (slots) of this new library domain should again be declared via `loadproc` commands that refer to the actual location of the files containing the source code of these functions. The code files should be organized in folders such as `lib/MYLIB`, `lib/MYLIB/SUBDIR` etc.

  This structure and the loading mechanism corresponds to the organization of MuPAD's main library. It uses the initialization file `MuPAD_ROOT_PATH/lib/sysinit.mu`.

- If a new library domain `mylib`, say, is to be generated by the package, the initialization file `mypack/lib/init.mu` should refer to the file `LIBFILES/mylib.mu` where the library is actually created:

        // -------- file mypack/lib/init.mu --------
        // load the library domain 'mylib'
        alias(path = pathname("LIBFILES")):
        mylib := loadproc(mylib, path, "mylib"):
        unalias(path):
        stdlib::LIBRARIES := stdlib::LIBRARIES union {"mylib"}:
        // The return value of the package call:
        null():
        // ---------- end of file init.mu ----------

  By adding the new library domain `mylib` to the set `stdlib::LIBRARIES`, a call to `package` will automatically launch the `info` function to print information about the new package. The information includes the string `mylib::info` that should be defined in `LIBFILES/mylib.mu`.

  The value of the last statement in the file `init.mu` is the return value of a `package` call. Typically, this is the `null()` object to avoid any unwanted screen output when loading the package. Alternatively, some useful information such as the string `"package 'mylib' successfully loaded"` may be returned.

  Cf. example 1 for further details.

- The file `LIBFILES/mylib.mu` should generate the new library domain via `newDomain`. Some standard entries such as `mylib::Name`, `mylib::info`, and `mylib::interface` should be defined. The functions `mylib::function1` etc. of the new library should refer to the actual code files via `loadproc`:

        // ---- file mypack/lib/LIBFILES/mylib.mu ----
        // mylib -- a library containing my functions
        mylib := newDomain("mylib"):
        mylib::Name := "mylib":
        mylib::info := "Library 'mylib': a library with my functions":
        mylib::interface := {hold(function1), hold(function2), ...}:
        // define the functions implemented in ../MYLIB/function1.mu etc:
        alias(path = pathname("MYLIB")):
        mylib::function1 := loadproc(mylib::function1, path, "function1"):
        mylib::function2 := loadproc(mylib::function2, path, "function2"):
        ...
        unalias(path):
        // define the functions implemented in ../MYLIB/SUBDIR/more1.mu etc:
        alias(path = pathname("MYLIB", ßUBDIR")):
        mylib::more1 := loadproc(mylib::more1, path, "more1"):
        mylib::more2 := loadproc(mylib::more2, path, "more2"):
        ...
        unalias(path):
        null():
        // -------- end of file mylib.mu ------------

  Cf. example 1 for further details.

#### Option: Quiet

- This option suppresses printing of information about the package during loading.

#### Option: Forced

- Usually, a package is loaded only once; a further attempt to reload the package causes an error. This option allows to enforce reloading of packages that are already loaded.

#### Example 1

In the following, we demonstrate how a package should be organized that generates a new library domain containing user-defined functions. In example 2, we load the same functions, but include them in one of MuPAD's standard libraries rather than create a new library domain.

Suppose we have implemented some functions operating on integers such as a factorial function and a new function for computing powers of integers. It is a good idea to combine these functions into one package. The new library domain is to be called `numfuncs` (for elementary number theoretic functions). It is organized as a package stored in the folder `demoPack1`. This folder has the following structure:

          demoPack1/lib/init.mu
          demoPack1/lib/LIBFILES/numfuncs.mu
          demoPack1/lib/NUMFUNCS/factorial.mu
          demoPack1/lib/NUMFUNCS/russian.mu

The initialization file `init.mu` may be implemented as follows:

          // ----- file demoPack1/lib/init.mu -----
          // loads the library 'numfuncs'
          alias(path = pathname("LIBFILES")):
          numfuncs := loadproc(numfuncs, path, "numfuncs"):
          stdlib::LIBRARIES := stdlib::LIBRARIES union {"numfuncs"}:
          unalias(path):
          // return value of package:
          "library 'numfuncs' successfully loaded":
          // -------- end of file init.mu ---------

The function `pathname` is used to create the pathname in a form that is appropriate for the currently used operating system. The `loadproc` call refers to the actual definition of the new library domain in the file `LIBFILES/numfuncs.mu`:

          // --- file demoPack1/lib/LIBFILES/numfuncs.mu ---
          // numfuncs -- the library for elementary number theory
          numfuncs := newDomain("numfuncs"):
          numfuncs::Name := "numfuncs":
          numfuncs::info := "Library 'numfuncs': the library of ".
                            "functions for elementary number theory":
          numfuncs::interface := {hold(factorial), hold(russianPower)}:
          // define the functions implemented in ../NUMFUNCS/factorial.mu etc:
          alias(path = pathname("NUMFUNCS")):
          numfuncs::factorial :=
                 loadproc(numfuncs::factorial, path, "factorial"):
          numfuncs::odd :=
                 loadproc(numfuncs::odd, path, "russian"):
          numfuncs::russianPower :=
                 loadproc(numfuncs::russianPower, path, "russian"):
          unalias(path):
          null():
          // --------- end of file numfuncs.mu ---------

Here, the new library domain is created via `newDomain`. Any library domain should have the entries `Name` and `info`. One may also define an `interface` entry, which is to contain all the functions a user should be aware of.

This file also contains the definitions of the functions `factorial`, `odd`, and `russianPower` which are implemented in the subfolder `demoPack1/lib/NUMFUNCS`. (See example 2 for details of the implementation; just replace `numlib` by `numfuncs`.)

The function `numfuncs::factorial` is implemented in a separate file. The functions `numfuncs::odd` and `numfuncs::russianPower` are both installed in the file `russian.mu`.

Note that `numfuncs::odd` is not added to the interface slot, because it is a utility function that should not be seen and used by the user.

Finally, we demonstrate the loading of the library package. Suppose that we have several packages, installed in the folder `myMuPADFolder`:

          /home/myLoginName/myMuPADFolder/demoPack1
          /home/myLoginName/myMuPADFolder/demoPack2
          ...

The library `numfuncs` installed in `demoPack1` is loaded by a call to the `package` function:

    >> package("/home/myLoginName/myMuPADFolder/demoPack1")

          Library 'numfuncs': the library of functions for elementary \
          number theory

          -- Interface:
          numfuncs::factorial, numfuncs::russianPower

                    "library 'numfuncs' successfully loaded"

In the initialization file `init.mu`, the new library was added to `stdlib::LIBRARIES`. For the reason, loading causes the above information about the library to be printed. By default, a library package can be loaded only once:

    >> package("/home/myLoginName/myMuPADFolder/demoPack1")

          Warning: Package already defined. For redefinition use option \
          Forced [package]

Following the warning, we overwrite the existing library `numfuncs` by another call to `package` using the option Forced:

    >> package("/home/myLoginName/myMuPADFolder/demoPack1",
               Forced)

          Warning: Package redefined [package]

                     "library 'numfuncs' successfully loaded"

After loading, the new library `numfuncs` is fully integrated into the system. Its functions can be called like any other function of MuPAD's main library:

    >> numfuncs::factorial(41)

                33452526613163807108170062053440751665152000000000

    >> numfuncs::russianPower(123, 12)

                            11991163848716906297072721

#### Example 2

We demonstrate how a package should be organized that adds new functions to an existing library domain.

We consider the same functions as in example 1. However, instead of creating a new library domain, we wish to add these functions to the existing library domain `numlib` of MuPAD's main library. In particular, the package is to install the new functions `numlib::factorial` and `numlib::russianPower`. Before loading such functions, we should make sure that they do not overwrite existing functions of the standard `numlib` installation. As a simple test to check that the standard installation does not provide a function `numlib::factorial`, one may simply try to call this function:

    >> numlib::factorial

                                       FAIL

Indeed, this function does not exist yet and shall now be provided by an extension installed in a folder `demoPack2`:

          demoPack2/lib/init.mu
          demoPack2/lib/NUMLIB/factorial.mu
          demoPack2/lib/NUMLIB/russian.mu

In this case, no new library domain is to be created. Hence, in contrast to example 1, no file `demoPack2/lib/LIBFILES/numlib.mu` needs to be installed (which would be in conflict with the corresponding file defining the `numlib` library domain of the standard installation). Instead, the new functions may be declared directly in the initialization file `init.mu` as follows:

          // ------ file demoPack2/lib/init.mu -------
          // loads additional functions for the existing library 'numlib'
          numlib::interface := numlib::interface
                union {hold(factorial), hold(russianPower)}:
          // define the functions implemented in ../NUMLIB/factorial.mu etc:
          alias(path = pathname ("NUMLIB")):
          numlib::factorial :=
                loadproc(numlib::factorial, path, "factorial"):
          numlib::odd :=
                loadproc(numlib::odd, path, "russian"):
          numlib::russianPower :=
                loadproc(numlib::russianPower, path, "russian"):
          unalias(path):
          // return value of package:
          "new numlib functions successfully loaded":
          // ---------- end of file init.mu ----------

Similar to example 1, we added the main functions to the existing `interface` slot of `numlib`.

We now have a look into the files `factorial.mu` and `russian.mu` containing the source code of the functions:

          // ---- file demoPack2/lib/NUMLIB/factorial.mu ----
          numlib::factorial :=
            proc(n : Type::NonNegInt) : Type::PosInt
              // factorial(n) computes n!
            begin
              if n = 0 then 1
              else n*numlib::factorial(n - 1)
              end_if
            end_proc:
          // -------- end of file factorial.mu ---------

The routine `numlib::odd` is a utility function for `numlib::russianPower`. Bothe functions are coded in one file:

          // ---- file demoPack2/lib/NUMLIB/russian.mu ----
          numlib::odd := m -> not(iszero(m mod 2)):

          numlib::russianPower :=
            proc(m : DOM_INT, n : Type::NonNegInt) : DOM_INT
              // computes the n-th power of m using the
              // russian peasant method of multiplication
              local d;
            begin
              d := 1;
              while n>0 do
                if numlib::odd(n) then
                  d := d*m;
                  n := n - 1;
                else
                  m := m*m;
                  n := n div 2;
                end_if
              end_while;
              d
            end_proc:
          // ----------- end of file russian.mu ------------

Finally, we demonstrate the loading of the functions. Suppose that we have several packages, installed in the folder `myMuPADFolder`:

          /home/myLoginName/myMuPADFolder/demoPack1
          /home/myLoginName/myMuPADFolder/demoPack2
          ...

The functions installed in `demoPack2` are loaded by a call to the `package` function:

    >> package("/home/myLoginName/myMuPADFolder/demoPack2")

                    "new numlib functions successfully loaded"

The new functions added to the `interface` slot of `numlib` are listed by an `info` call:

    >> info(numlib)

          Library 'numlib': the package for elementary number theory

          -- Interface:
          numlib::Lambda,           numlib::Omega,
          ...
          numlib::factorial,        numlib::fibonacci,
          ...
          numlib::proveprime,       numlib::russianPower,
          ...

After loading, the new functions are fully integrated into the library and can be called like any other function of MuPAD's library:

    >> numlib::factorial(41)

                33452526613163807108170062053440751665152000000000

    >> numlib::russianPower(123, 12)

                            11991163848716906297072721

#### Changes

- new function

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