Table of Contents

polymake Extensions

What is an extension

A polymake extension is a collection of various bits and pieces of software that can be used together with the core stuff obtained from the distribution. An extension may enhance existing applications and/or define fully new, independent applications. In detail, an extension may contain any mix of:

Starting an own extension

  1. Choose a location on your computer (or a network share) where you have write permissions; let's name it my_ext in the examples below.
    If you are working with a git working copy of polymake, please make sure that your new directory is outside the source tree.
  2. In an interactive polymake session, execute the commands:
    found_extension "~/my_ext";
    extend_application "~/my_ext", "APP_NAME";
    where APP_NAME is the name of an existing application you are going to enhance.

What has happened? polymake has created a folder my_ext (if it did not exist before) and within it a whole hierarchy of subfolders, having the same structure as the core applications:
apps/APP_NAME/rules
apps/APP_NAME/scripts
apps/APP_NAME/src
and so on. Now it's upon you to populate it with new stuff. polymake has also created two directories
include and
build.<architecture>
in my_ext. The first contains links to the header directories in apps/polytope/include, the second will later contain the compiled libraries. You should not put any stuff there yourself. The absolute path to the top directory my_ext is stored in your custom variable @extensions, so that from now on everything you put in this extension is automatically available as if it were defined in the core distribution.

If you are going to define new rules, please remember that one of the rule files should be called main.rules, which will be loaded by polymake at the very start of the session. For instance, if you want to use a new rule file called my_rules.rules, the file my_ext/apps/APP_NAME/rules/main.rules should contain the following lines:

INCLUDE
   my_rules.rules

If you have written some C++ clients, they will be automatically compiled at the beginning of the next interactive session; however, later changes must be compiled manually by invoking
make -C ~/my_ext.

Adding more applications to the same extension

You repeat the same command extend_application as described above, specifying the same extension directory.

To create a really new application from scratch, execute the command
found_application "~/my_ext", "APP_NAME";
Again, it will create a folder hierarchy rooting at my_ext/apps/APP_NAME. After having composed the rules and/or clients, you may add the APP_NAME to the custom variable @start_applications, so that you'll have your new application at hand in every interactive session.

Configuring an extension

If your extension depends on third-party software packages which need to be installed separately, you'll have to provide some auto-configuration routines in the rules. To resolve dependencies on autonomous programs, you can use all the fancy tools available in the “standard” rules: custom variables, CONFIGURE clauses, utilities like find_location, find_program, etc.

In the case your extension needs a third-party library to build the C++ clients, you should provide a pre-build configuration procedure performing some preparations and sanity checks like adding compiler and linker flags necessary to find this library, asserting that its version is not too old for you, etc.

All this is done in a script configure.pl located in the support directory of your extension. For this purpose, every extension gets at its birth a personal copy of a script template configure.pl.template. You should edit it, filling the stubs of the functions with appropriate actions, introduce configuration options, if needed, and finally rename the script into configure.pl. Then this script will be executed immediately during the extension import as well as each time one runs the interactive command reconfigure_extension. All clients in the extension are recompiled after each reconfiguration, at the latest at the beginning of the next polymake session.

The script template contains comments describing the purpose and signature of each mandatory function; you may also want to look for the examples into the configuration scripts of extensions bundled with polymake. At your disposal are all utilities from the module perllib/Polymake/Configure.pm and all core configuration variables, both defined in the package Polymake::Configure. The extension configuration script is interpreted in a separate package; please, don't change into other package within the script. Also be aware that the extended perl syntax (like namespace mode) is not allowed for the configure script.

The outcome of a successful run of the configuration script is a list of variable assignments, which are stored in the file build.ARCH/conf.make in your extension which is included at each subsequent build. These variables can be referred to in custom make rules placed in Makefile.inc next to your clients; besides this, the script may directly add values to standard variables like CXXflags or Libs. If your extension has prerequisites with their own configuration scripts, all their make variables are available in your extension build as well.

In a complex scenario when the build process and the rules share some configurable paths or options, a rulefile can access the configured make variables of the own extension and all prerequisites by calling a special function load_extension_config_vars in its CONFIGURE clause. It is advisable to copy all necessary values into custom variables, as to avoid expensive parsing of makefiles in each polymake session.

Example

custom $path_to_something;

CONFIGURE {
  my $vars=load_extension_config_vars();
  $path_to_something=$vars->{SOME_DIR};
  1   # signal success
}

where the script configure.pl is supposed to contain (among others) the following fragments:

@make_vars=qw( SOME_DIR );

sub proceed {
  $SOME_DIR=find_something() or die "can't find an important thing!\n";
}

Sharing an extension with other people

There are three possible ways to make your extension available to other people, which may also be arbitrarily combined:

  1. If you have writing access to the polymake core installation (or can ask your sysadmin for assistance), that is available to other users on your computer or local network, you may install your extension right there:
    make -C ~/my_ext install ExtensionName=EXTNAME
    This will create a subdirectory ext/EXTNAME under the top installation directory of polymake (which is stored in the variable $InstallTop, by the way). Omitting the ExtensionName argument in the make command will install your extension under ext/my_ext.
  2. If you have collaborators developing your extension, you may keep it in a version-controlled repository. If you choose subversion, polymake will even automatically commit all automatically generated files and create svn:ignore attributes whenever needed. To fully enjoy the polymake support for subversion, you should register the top directory ~/my_ext prior to calling any found_extension or extend_application commands.
  3. If you want to bring your extension to broader audience, you may create a tarball starting at ~/my_dir (but excluding the Makefile and any build.* folders) and make it available for download.

In any case, people using your extension will eventually produce data files depending on it. Especially if you introduce new properties, object types, or applications, anybody not having access to your extension won't even be able to load a data file containing any of your specific features. To clearly distinguish them from the core features, each publicly available extension must have a unique identifier, also called URI. Although the form of the URI can't be strictly prescribed, we recommend a URL-like string roughly pointing in the direction of your website. e.g.:
"http://www.your.domain/polymake/extension/EXTNAME"

The URI of your choice must be stored in the description file ~/my_ext/polymake.ext. This file is created by found_extension command and already contains a tentative URI starting with file:///. Please replace it with an URI of your choice. Don't forget to submit the description file into the repository if you are using any. From now on each XML data file containing any of the extension-specific features will bear an additional ext attribute showing your URI.

Documentation

As your extension keeps growing, you'll want to create the documentation HTML pages to have a better overview of all the new features at hand. This can be done very easily with the script generate_docs shipped with polymake. Just call it from the interactive session like this: script("generate_docs", "OUT_DIR"); Then you'll obtain the complete set of documentation pages describing the standard system and all loaded extensions, rooted at the given directory OUT_DIR, which you can load directly into your web browser or deploy to your local webserver.

Please note that the extensions are not described on separate pages; instead, the properties, functions, etc. introduced in extensions are listed together with the corresponding standard features, as usual arranged by applications and object types. This behavior is implemented purposely, as it fully matches the seamless style of integrating extensions in the standard system.

How to make other people aware of your work

Uncomment the CREDIT section in the description file my_ext/polymake.ext and put few lines there, including your name, your homepage URL, as well as copyright notice, a short description of the features implemented in your extension, a citation of your main article about it, or whatever else you'll find appropriate to mention. Then this text will be displayed in each session as soon as a rule or function from your extension is called; the abbreviated form of your credit note will be also stored in each XML data file containing some of extension-specific object properties.

In the case of a large team working together on an extension individual contributions may still be distinguished by usual credit notes embedded in the rulefiles; then the credit note of the entire extension will be assigned by default to all rules and functions lacking individual credit notes.

Managing changes in data model

In the course of time you may change the data representation or rename properties introduced in your extension. These changes may render your old data files useless, as polymake won't be able to load them any more. To be able to recover the old files automatically, you should make use of versioning. To this end, you adopt some numbering scheme and append the current version number to the URI of your extension, like this: http://www.your.domain/polymake/extension/EXTNAME#1.0 (recall that this is stored in the description file polymake.ext in the top folder of your extension). Then, each time you are introducing an incompatible change in your extension, you bump the version number (for example up to 1.1) and create a transformation stylesheet (XSLT) xml/upgrade-1.1 . There are some lines that need to be present in any transformation sheet. Here is an example

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                             xmlns:p="http://www.math.tu-berlin.de/polymake/#3">
<xsl:output method="xml" encoding="utf-8" cdata-section-elements="p:description" indent="yes" />

[...]

<xsl:include href="trivial-copy.xslt" />
</xsl:transform>

Replace […] with transformation rules for your extension. A simple transformation rule could be the following:

<xsl:template match="p:property[@name='OLD_PROPERTY']">
  <xsl:element name="property" namespace="{namespace-uri()}">
    <xsl:attribute name="name">NEW_PROPERTY</xsl:attribute>
    <xsl:attribute name="value">
      <xsl:value-of select="@value" />
    </xsl:attribute>
  </xsl:element>
</xsl:template>

This code just renames the property OLD_PROPERTY to NEW_PROPERTY, leaving everything else invariant. Note, however, that this would apply to any occurrence of OLD_PROPERTY, so if this property name also occurs somewhere else (e.g. in another application, or as a property of some other object) then those will be changed as well. So in this case make sure that your rule only matches the occurrence in your extension.

The standard polymake distribution already contains several transformation stylesheets which can be used as a source of inspiration.

When polymake loads a very old data file lying behind several version bumps, all transformations between its version and the current version are applied in the proper (ascending) order; thus each transformation stylesheet should only contain converting operations specific for a single version bump.

Writing testcases

It is always a good idea - especially if your extension is large - to write unit tests for your code. Those are essentially small examples which test individual rules and functions. One advantage of this is that you will quickly notice if a change in your code (or in a new polymake release) breaks something in your extension. Polymake offers a convenient set of tools for this, you can find a full description here.

Using other people's extensions

Depending on the way of distribution (as described above), you may have to check out the extension from a repository or download a tarball and unpack it. In any case the concluding step will be
import_extension "~/my_ext";
called in a interactive session.

Some extensions may ask for prerequisite libraries provided by third parties, necessary to compile the client functions. Such an extension will provide a configuration script which tries to automatically locate the required libraries and prepare the compilation process to use them. If the automatic recognition fails, the extension will be put in a disabled (unconfigured) state. You will see a (hopefully intelligible) error message explaining what exactly has been missing and how you can remedy the problem. When you have installed the required third-party libraries, or decided to turn down some optional part of the extension functionality, you can try to reactivate it using the command reconfigure_extension. Depending on the style in which the extension configuration script is written, you might have to supply some options as string arguments to this command, or it will try to ask you some questions interactively. You can investigate the behavior calling
reconfigure_extension "~/my_ext", "--help";
as well as trying the TAB completion or context-sensitive help (F1) when typing in this command. If nothing helps, you are invited to complain by the authors of the extension and asking them for assistance. Note that all configuration options can also be passed immediately to import_extension in the first place, as far as you can guess them up front. An active extension can also be reconfigured any time later, if needed.

An extension can also be imported on demand, in the course of loading a data file containing an unknown extension URI. As soon as polymake encounters such a URI in the data file, it stops the loading procedure and asks you for the location where the extension resides. If you have no idea where to obtain the extension right now or simply don't want to bother installing it, you should type in stop (thus interrupting the loading process) or skip (loading only standard properties). In the latter case a backup copy of the data file is created. Your decision to despise this particular extension is remembered until the end of the interactive session; should you change your mind later, you'll have to restart polymake.

You can stocktake your imported and configured extensions at any time using the interactive shell command
show_extensions;

Relations between extensions

Extensions may build upon each other, establishing dependence relations similar to software packages installed on your computer. The relations between extensions are described in dedicated sections of description files polymake.ext. Every section contains one or more URIs of related extensions, separated with white spaces or distributed over several lines. An empty line marks the end of a section, similar to rulefiles.

REQUIRE URI URI#version …

List of prerequisite extensions. In order to be able to import this extension, you must have imported all prerequisites up front. An optional version number expresses an additional requirement to have the specified extension in the given version or newer.

A prerequisite bundled extension is specified using its short URI bundled:NAME.

REPLACE URI

List of obsolete URIs assigned earlier to this extension as well as to other old extensions merged with this one. You may also invent an abstract URI designating a feature provided by this extension and some alternatives. Then other extensions depending on this feature can list this abstract URI among their prerequisites. Any extension providing this URI as REPLACEment will successfully fulfill the role of that prerequisite.

Bundled extensions may also have a REPLACE section if they were initially born as independent extensions and only later became part of polymake distribution.

CONFLICT URI

List of extensions which can't be imported together with this one.

Additional remarks about prerequisite extensions:

Getting rid of an extension

One nice day you might suddenly want to get rid of an extension. The reason may be that you aren't interested in it any more, or that its functionality has silently moved into the standard distribution or another extension. The most comfortable way is to use the command obliterate_extension . It deletes all traces of the extension in your polymake settings. Be aware, however, that in the current interactive session you still have the pieces from the discarded extension loaded and ready-to-use. Thus, to avoid confusion, you should quit the session as soon as possible after using this command. Note also that you can't obliterate an extension as long as other registered extensions depend on it as a prerequisite.

If you later try to load a data file referring to the URI of the obliterated extension, polymake will ask you, as usual, to enter its installation directory. If you are sure that in the meanwhile all the stuff has migrated into the standard distribution and/or other (already loaded) extensions, you should respond with the magic word ignore .