MuPAD and MuPAD-Combinat Programming Tips And Tricks

Note: the tips and tricks are being moved from the end of the README file to here.

Tips and tricks for users

  1. How to define the field of expressions in factored form?

    K := Dom::ExpressionField(expr@factor);
    K(x^2-1);

    Note that it is safer to use expr@factor as normalizing function. Indeed, for efficiency reason, polynomials over fields of expressions use syntactical equality to decide for equality to zero; in some cases, the kernel may not detect, and delete, zero terms.

    See http://www.mupad.de/BUGS/?bug=1402 for details

Tips and tricks for developers

  1. Adding a new domain / category to MuPAD-Combinat

    You may want to use the script createDomain at the top level of the MuPAD-Combinat distribution. See the documentation inside the script for details. Basic usage:

    createDomain combinat::myCombinatorialClass "the combinatorial class of ..."

Tests

  1. Writing tests

    A very practical way to create new tests is to use prog::makeTest interactively, and to copy paste the result (after double checking it!) into the test file (say lib/COMBINAT/DOC/words.tst). Example:

          >> prog::makeTest(combinat::partitions::count(4),
                            combinat::partitions::list(3)):
          prog::test(combinat::partitions::count(4),
                      5):
          prog::test(combinat::partitions::list(3),
                      [[3], [2, 1], [1, 1, 1]]):
  2. Running the test suite of a particular package (say combinat::words)

          cd test
          make COMBINAT/words.res
  3. Running the test suite under a temporary different version of MuPAD

          cd test
          make check MUPAD=mupad252 MUPAD_VERSION=2.5.2

Debbugging

Learn to use the MuPAD debugger. It is very powerful, quite easy to

use, and it will save you tons of time. In short
      debug(theFunctionToDebug(bla, bli))

And then you can go through the function step by step, continue until the next error, check and set variables, etc ... (like in any standard source code debugger like gdb). See ?debug for details.

For a nice graphical interface which shows you the source code while you run through it, I recommend using the debugger inside emacs (see http://mupacs.sf.net), or inside xmupad.

Breakpoints are not very practical to use with the MuPAD command line debugger. However, they can be conveniently emulated with the

following little trick
    f:=proc()
    begin
        bla:=1;
        ble:=2;
        warning("STOP HERE");
        bli:=3;
    end:
    debug(f())

Now, just press c, and the execution will continue until the line with the warning is reached.

evaluation voodoo

  1. Learn option hold

    Most functions want their arguments nicely evaluated. If for some reason yours is a function that does not (say, you really want "1+2" instead of "3" or the user should be able to give a sequence as one of the parameters), think again and if this is still the case, use option hold in the definition of the function, as in the following:
      twolists := proc(l1, l2)
                    option hold;
                  begin
                    [[context(l1)], [context(l2)]];
                  end:
      twolists((1,2,3), 4); // returns [[1,2,3], 4]

    Note that almost any access to the parameters in such a procedure requires a call to the function context.

  2. Passing options when using option hold

    If your function has option hold and wants to call another function, which might have this option, too, the following are safe ways of doing that, if the function you want to call is visible to your caller:
       context(hold(f)(x))
       context(hold(a::b)(x))

    If the function is not visible, or you need to use dom to name it, better use

       context(subsop(hold(f)(x), 0 = dom::something))

    with any f -- it's just a placeholder anyway.

Documentation

  1. Where to find documentation on how to write documentation for MuPAD-Combinat

    Badly enough, there is no up-to-date documentation on the LaTeX style files for MuPAD documentation. However, our documentation files have a fairly systematic layout and chances are that you can learn everything you need just by browsing through the source of the existing ones. The documentation of combinat::partitions is one of the

    oldest and most polished that we have, so that's a good place to start with

    lib/COMBINAT/DOC/partitions.tex

    You may also browse through the documentation of combinat::permutations which

    is a more developped one, with several subsections by theme

    lib/COMBINAT/DOC/permutations.tex

    See also DocumentationTipsAndTricks

  2. Updating the documentation

          cd doc
          make
Sur les distributions Debian Woody/Sarge, il faut modifier (en tant que root) le fichier /usr/share/texmf/web2c/texmf.cnf en changeant les champs suivants
      hash_extra.context = 40000
      hash_extra = 300000
      pool_size.context = 750000
      pool_size = 300000
  1. Compiling just one of the documentation files with just one latex run

          cd doc/dvi    (or doc/dvia4!)
          make combinat.mdvi LATEXRUNS=1
  2. Testing the examples in the documentation

          cd doc/dvi
          make check
  3. Testing the examples of a particular documentation file

          cd doc/dvi
          make combinat.res

Tips and tricks to ensure backward compatibility with former versions of MuPAD

  1. prog::getOptions

    We strongly support the use of prog::getOptions for parsing procedure options. However, this function only appeared (undocumented) in MuPAD 2.5.0, and was changed incompatibly in MuPAD 3.0.0. To ensure compatibility with all versions of MuPAD, it should be called as combinat::getOptions, which is a patched backport of the prog::getOptions of MuPAD 3.0.0.

  2. MuPAD 2.0.0's option remember bug for methods

    Try this code with MuPAD 2.0.0:

          domain bla
              x:=
              proc()
              option remember;
              begin
                  print(coucou);
              end_proc;
          end_proc:
          bla::x();
          bla::x();
          bla::x();

    The first time bla::x is called, the result is not inserted in the remember table. This is fixed in MuPAD >= 2.5.0. Standard workaround: force the evaluation of bla::x before calling it:

          domain bla
              x:=
              proc()
                  option remember;
              begin
                  print(coucou);
              end_proc;
          end_proc:
          bla::x;
          bla::x();
          bla::x();
  3. MuPAD 2.0.0's prog::check bug

          prog::check(proc(typeOfObjects)
                          local rank;
                      begin
                          proc() : typeOfObjects
                          begin
                          end_proc;
                      end_proc, 3)
  4. Type::Boolean:

    Beware that Type::Boolean is not defined in MuPAD < 2.5.0. Furthermore, if you just want to test for TRUE/FALSE/UNKNOWN, it's preferable to use DOM_BOOL (Type::Boolean is for boolean expressions in general).

  5. Deleting list entries

    Better use delete(l[3]) than l[3]:=null() to delete an element of a list (with MuPAD 2.0.0, the list needs to be evaluated for the element to be actually deleted).

  6. min/max

    Beware that min([1,2,3]) returns [1,2,3] with MuPAD <= 2.5 and 1 with MuPAD 3.0.0. So, always use the form min(op([1,2,3])) to get the minimal element of a list.

  7. Strings indexed access

Since MuPAD 3.0.0 strings are indexed by 1..length(s) to be more coherent with other MuPAD objects (lists, ...); beforehand, they were indexed by 0..length(s)-1. This is a good thing in se, but this means that we need to be careful when writing code for all versions of MuPAD. We already encoutered this problem in several of the MuPAD-Combinat libraries (see e.g. combinat::dyckWords). The standard

idiom for this is

%if "12"?1="1" then // work around a change in strings indexed

// access from MuPAD 3.0.0 on

// Code when strings are indexed by 1..length(s)

else

// Code when strings are indexed by 0..length(s)-1

end_if;

Mind the %if: it means that the test is resolved at parse-time. So there is no overhead during execution. Note also that the test does not rely on the MuPAD version, but on the feature itself. This makes it more robust (some old mupad devel versions before the string already had version number 3.0.0, ...).

Dynamic modules

  1. Compiling dynamic modules on MacOS 9

    Note from Christopher: Compiling modules for this MuPAD version requires ?MetroWerks ?CodeWarrior, if I remember correctly. The "Modules" directory of the installation contains a directory "Dynamic Module SDK" in which you should find all that is needed.

  2. Recompiling the dynamic modules for another MuPAD version

          rm config.cache
          rm `\ls src/*/*.mcc | sed 's/\.mcc$/.cc/'`
          ./configure MUPAD=mupad2.5.1
          make
  3. Compiling programs/dynamic modules with another compiler

          rm config.cache
          cd src; make clean
          ./configure CXX=g++3
          make
  4. Using dynamic module functions when time is critical

    (Christopher) Using:

          f := external("module", "function")
          f(a, b)

    may be faster than

          module::function(a, b)

    There is still a non-negligible overhead compared to standard function calls in C.