The Petri Net Kernel (PNK) version 2.0 provides an infrastrucure for building Petri net tools.

Copyright (C) 2001 Petri Net Kernel Team (Humboldt-University Berlin, Germany)

pnk@informatik.hu-berlin.de

PNK User's Manual


Table of Contents


License Agreement

The PNK version 2.0 is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License (see file LICENSE.GNU-LGPL) as published by the Free Software Foundation; version 2 of the license. (Note, that some PNK applications are developed under GNU General Public License---see file http://www.gnu.org/copyleft/gpl.html ) The PNK is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY.

You are NOT ALLOWED to CHANGE THE ORIGINAL COPYRIGHT NOTICE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the PNK; if not see http://www.gnu.org/. An application using the Petri Net Kernel MUST GIVE NOTICE OF THIS USE. Please contact pnk@informatik.hu-berlin.de to notify this application.

Quick Start


This is just a crash course to get the Petrinet Kernel running. It should give you an overview how to use the Petrinet Kernel. I'm leaving out some important details which will be added soon ...

NOTE: It is important that you have installed the jdk1.2.2 to use the Petrinet Kernel. Otherwise download it from java.sun.com. If you don't know which jdk version is installed on your system, you may check this by calling the Java interpreter's -version option.

java -version

Download and Run

Download the latest PNK2alpha.jar file. Extract the archive on the command line by typing

jar xvf PNK2alpha.jar

This creates a new directory PNK2/ containing the source and class files of the Petrinet Kernel. Now you may change to PNK2/ directory

cd PNK2

and take a look at it's contents. You should find something like this ...

Then start up Petrinet Kernel using the -jar option of the java interpreter.

java -jar PNK2.jar

You may also compile sources by hand. Therefore you possibly have to extract a source file archive.

jar xvf PNK2sources.jar

This command installs a directory tree of source files. Now take notice of the makefile in the PNK2/ root directory. Modify it to your requirements and enter

make run

This command should compile all files and run the Petrinet Kernel. If it does not, please check the path to your java2 interpreter and java2 compiler. You may edit the path in the headline of the makefile. Verify also the correctness of the CLASSPATH variable. It should at least point to the crimson.jar and jaxp.jar archives distributed with the pnk.jar archive. These two file archives are necessary for loading and writing xml and pnml files.

At first change into the directory where you placed the downloaded PNK2alpha.jar file. Extract the file and examine the contents of the new directory. Finally run the Petrinet Kernel using the -jar option supported by the java2 interpreter.

If the makefile doesn't work you may generally start the Petrinet Kernel by typing a commandline like this:

java -classpath .:jaxp.jar:crimson.jar de.huberlin.informatik.pnk.appControl.ApplicationControl

In this case it is important that you are currently in the root directory of the Petrinet Kernel. First steps - Open, Edit and Save Nets

First steps - Open, Edit and Save Nets

Now I will give you a short tutorial how you can play around with the Petrinet Kernel. In this section I tell you how you may open or edit nets and how you may invoke applications to work on your net. When launching the Petrinet Kernel the ApplicationControl's window should appear.

In the ApplicationControl's menubar you find a File menu for opening existing nets, creating new nets and saving nets. There should also be a Net menu to launch applications related to a specific net and switch between them. At first you have to choose your nettype. You may open the File menu. If you select the File -> new Net menuentry a submenu with a list of different nettypes appears. Click on one of these menuitems. You can also select the File -> Open menuentry to open an existing net. Some interesting netexamples are stored in the sampleNets/ directory.

By default a editor start's to display the net. Everytime you invoke an application it's menu is shown in the ApplicationControl's menubar. So now you should find there the editor's menu. Alternatively you may use the popupmenu of the editor.

Probable you ask: 'How can I add objects like places, transitions and arcs to the net?' In the editor's menu you select the Place checkbox or the Transition checkbox. Then click on an open editorpage. Every mouseclick should create a new object. Then choose the Arc checkbox and mouseclick on a place. The place should change it's color indicating that it is selected as an arc's initialnode. Now mouseclick a transition and a new arc appears. You may want to drag around some places and transitions to make your net look lovely. You achieve this by mouseclicking in an object and hold the mousebutton pressed while moving your mouse. After this you usually want edit the extensions of some objects. For example set the name and marking of places, the inscriptions of several arcs or the guards of transition. Which of these extensions exists depends on the nettype. To edit an extension you choose the Edit checkbox in editor's popupmenu. Now a mouseclick on a place, transition or arc will open a dialog frame where you may set new values for the objects extensions.

You can open a second page using the editor's menu in the ApplicationControl's menubar. If you enable the join checkbox you may join two different nodes as one node. That's the way you merge the pages. Therefore you click in a place and it should change it's color than click into another place. Now these places represent both the same place of the net. You can undo this with the help of the split operation. Then it is recommended that you save your net with the File -> save or File -> save as menu and choose ApplicationControl's Net menu to start a further application for example a simulator.

Start a first Simulator Session

Choose Net -> Start Application -> Simulator. This creates a new instance of the simulator. Now the simulator's menu should appear in the ApplicationControl's menubar. Please pay attention to the fact that some applications (for example the simulator) are not automatically launched when they were invoked. To run the simulator choose the Simulator -> Start menu from ApplicationControl's menubar. You should now see a dialog frame with a CANCEL button, pushing this button will abort the simulator application. If there is any concessioned transition in the net the simulator will emphasize it in the editor. You may fire a concessioned transition by mouseclicking into it. Continue these steps until you are tired or there is no concessioned transition anymore. In the first case press the CANCEL button in the simulator's dialog frame. (It is recommended that you don't choose Simulator -> Stop from ApplicationControl's menubar, because it's not yet correctly implemented.) In the last case the simulator stops automatically.

Some Basics


Now I want to introduce you in some details so that you are able to develop your own petrinet application using the Petrinet Kernel. The Petrinet Kernel's sources are a bunch of packages. These are ...

The idea of the Petrinet Kernel project is to make a petrinet data structure available for developers and scientists. We decided to add an editor to the project to remove this task from developers. And finally we created the ApplicationControl with should make it easy to compose nets and applications to one large application.

In the following I will say something about the mainpackages and mainclasses.

The Kernel

The de.huberlin.informatik.pnk.kernel's package contains especially the following important classes:

A petrinet is a bipartitioned, directed graph with nodes called places and transitions.

For the beginning I list the methods of these classes and try to explain their meaning. Then I will discuss their use by an example.

The Net class describes a petrinet. It has methods to access their arcs, places and transitions. Or you may ask a net for it's FiringRule object that describes when a transition is concessioned and how you does it fire. How do you may profite from these methods you will see in the Example Simulator chapter.

 
public final class Net extends Graph {

        public Vector getArcs()
 
        public Vector getPlaces() 

        public Vector getTransitions()
 
        public FiringRule getFiringRule() 
     
} // class Net
    

The Place class describes a place of a petrinet. You create a place using the class constructor. The place registers itself in the net which must be passed as a constructor's parameter. You can remove a place by calling it's delete() method. You may request the current marking and so on ...


public final class Place extends Node

        public Place(Net net, String name, Object initiator)

        public void delete(Object initiator)

        public Marking getMarking()

        public void setMarkingAsInitial()

} // class Place
    

The Transition class describes a transition of a petrinet. You create a transition using the class constructor. The transition registers itself in the net which must be passed as a constructor's parameter. You delete it using it's delete() method. You can also request the mode of a transition.


public final class Transition extends Node {
     
        public Transition(Net net, String name, Object initiator)
  
        public void delete(Object initiator)
  
        public Mode getMode() 

} // class Transition 
    

The Arc class describes an arc of a petrinet. You create a new arc using the class constructor. The arc registers itself in the net passed as constructor parameter. You may ask an arc for it's initialnode, it's targetnode, it's inscription and so on ...


public class Arc extends Edge {

       public Arc(Net net, Node source, Node target, Object initiator)

       public Inscription getInscription()

       public Place getPlace()

       public Transition getTransition()

       /// METHODS INHERITED FROM class Edge: 

          public Node getSource()

          public Node getTarget()

} // class Arc 
    

The ApplicationControl

As you already notice the ApplicationControl in the de.huberlin.informatik.pnk.appControl package plays an very important role. This class manages all nets and applications of the Petrinet Kernel. The ApplicationControl parses some XML files for configuration. These are for example the specification of all nettypes in the netTypeSpecification directory or a list of valid applications to each nettype in toolSpecification.xml file. Furthermore it is responsible for loading and writing nets as PNML files. It also offers useful interfaces that lets different applications cooperate with each other. Using the main main() method of the ApplicationControl you launch the Petrinet Kernel on commandline.

java -classpath .:crimson.jar:jaxp.jar \
    de.huberlin.informatik.pnk.appControl.ApplicationControl \
    toolSpecifications/toolSpecification.xml
    

Of course you have to specify the classpath correctly. Optional you may give the location of an toolSpecification.xml file as argument. If you don't the ApplicationControl uses toolSpecifications/toolSpecification.xml as default. With the toolSpecification.xml file you inform the ApplicationControl of known nettypes and applications. The idea is to give you the possibility to compose your own toolsets. This for example could be the content of toolSpecifications/toolSpecification.xml :


< ?xml version="1.0" encoding="UTF-8"? >
< !DOCTYPE toolSpecification SYSTEM "toolSpecification.dtd" >
< toolSpecification >
  < !-- Nettypes -- >
  < nettype id="n1" typeSpecification="file:netTypeSpecifications/simpleHLNet.xml"/ >
  < nettype id="n2" typeSpecification="file:netTypeSpecifications/dawnNet.xml"/ >
  < nettype id="n3" typeSpecification="file:netTypeSpecifications/Echo.xml"/ >
  < !-- Applications -- >
  < application id="a1" mainClass="de.huberlin.informatik.pnk.editor.Editor" maxinstances="inf" >
    < allowedNettypes >
      < ntref ref="n1"/ >
      < ntref ref="n2"/ >
      < ntref ref="n3"/ >
    < /allowedNettypes >
  < /application >
  < !-- Input / Output -- >
    < format id="pnml" ioClass="de.huberlin.informatik.pnk.appControl.PnmlInOut" >
      < allowedNettypes >
        < ntref ref="n1"/ >
        < ntref ref="n2"/ >
      < /allowedNettypes >
    < /format >
    < format id="io" ioClass="de.huberlin.informatik.pnk.appControl.InOut" >
    < /format >
  < !-- default settings -- >
  < standardNettype ref="n1"/ >
  < standardApplication ref="a1"/ >
  < standardFormat ref="pnml"/ >
< /toolSpecification >                                                                            
    

You see that the toolspecificationfile is structured in three parts. The first part declares the nettypes, the second part lists the applications with references to nettypes and the third part defines Input/Output formats (in this case PNML). For each application you may list the allowed nettypes. If you drop the < allowedNettypes > tag, it is supposed that all nettypes are tolerated. If the < allowedNettypes > tag is found but it's empty, it is supposed that no nettype is allowed.

The Editor

If you open a net it is by default displayed in an editor. The editor application resists in the de.huberlin.informatik.pnk.editor package. I presume that you never need to access it directly. To let your application work with an editor it is recommended to use the offered interface ApplicationNetDialog. Nevertheless you may look at the editor's implementation to learn how to combine complex applications and the ApplicationControl.

Write Applications


Now I will give you a short introduction how to write an application by discussing the implementation of a simulator.

Example Simulator

Now let's take a look at the Simulator application in the de.huberlin.informatik.pnk.app package. This example should show how easy it is to write an application.

 
package de.huberlin.informatik.pnk.app;
 
import de.huberlin.informatik.pnk.app.base.MetaApplication;
import de.huberlin.informatik.pnk.appControl.ApplicationControl;
import de.huberlin.informatik.pnk.netElementExtensions.llNet.SimpleRule;
 
/**
 * Simulator.java
 *
 * Created: Wed Jan 24 08:51:50 2001
 *
 * @author hohberg
 * @version
 */
public class Simulator extends MetaApplication {

    // this application's name
    public static String staticAppName = "Simulator";  

    // class constructor
    public Simulator(ApplicationControl ac) { 
        super(ac);
    }

    public void run() {
        SimpleRule rule =
            (SimpleRule) net.getExtension("firingRule");
        rule.simulateWithUserInteraction(this);
    }

} // Simulator

    

The Simulator extends the MetaApplication class.


public class Simulator extends MetaApplication

    

Every application has to extend this class to inherit important base functionality. The class constructor has to take an ApplicationControl object as parameter and propagate it with the super() call to the MetaApplication's class constructor.


public Simulator(ApplicationControl ac) {
    super(ac);
}

    

The application may define it's name in a static class field staticAppName so the ApplicationControl can display the application's name in it's menubar.


public static String staticAppName = "Simulator";

    

The application then implements a run() method. This method is called by the ApplicationControl to start the application.


public void run() {

    

After this the Simulator requests a net's extension using the net field inherited from the MetaApplication class.


SimpleRule rule = (SimpleRule) net.getExtension("firingRule");
rule.simulateWithUserInteraction(this);

    

The FiringRule interface

The SimpleRule class implements the interface de.huberlin.informatik.pnk.netElementExtensions.base.FiringRule. This interface defines methods like:

The SimpleRule object is nettype specific and has to be implemented with the nettype. How to create new nettypes will be discussed in a later section. Furthermore the method simulateWithUserInteraction(MetaApplication app) is declared in the SimpleRule class. It is implemented as:



public class SimpleRule extends FiringRule {

   ...

   public void simulateWithUserInteraction(MetaApplication app) {

       checkContextAndParseExtensions();
       ApplicationControl ac = app.getApplicationControl();
       Net net = (Net) getGraph();

       Vector concessioned = getAllConcessioned( ); //all concessioned transitions

       if(conc == null || conc.isEmpty()) 
           return;

       Transition transition = (Transition) 
           (new SelectObjectAction(ac, net, app, concessioned)).invokeAction();

       while(transition != null) {
           fire(transition);
           concessioned = getAllConcessioned();
           if(concessioned == null || concessioned.isEmpty()) 
               return;
           transition = (Transition) 
               (new SelectObjectAction(ac, net, app, concessioned)).invokeAction();
       }
   }

   ...
  
} // class SimpleRule

    

The implementation of this simulateWithUserInteraction() method is interesting in many aspects. Especially you see the use of the FiringRule interface. Farther you see how applications communicate with each other.

Communication between applications

For short I want to introduce the Petrinet Kernel's concept of communication between applications. The Editor for example implements the ApplicationNetDialog interface in de.huberlin.informatik.pnk.app.base package. This interface serves a couple of nice methods. With the help of these methods an application may request the editor to emphasize, select or annotate a place, transition or arc.

package de.huberlin.informatik.pnk.app.base;
 
import de.huberlin.informatik.pnk.kernel.*;
import java.util.*;

/*
 * If an application want's to request the editor
 * to emphasize, annotate or select (one object | some objects),
 * it may use the methods of this interface.
 */
public interface ApplicationNetDialog {

   // The application requests the editor to annotate some objects.
  public void anotateObjects(Hashtable annotations);  

   // The application requests the editor to emphasize some objects.
  public void emphasizeObjects(Vector objects);  

   // The application requests the editor to reset all annotations.
  public void resetAnnotations();  

   // The application requests the editor to unemphasize all objects.
  public void resetEmphasize();  

   // The application requests the editor to select an object.
  public Member selectObject(Vector objects);  

   // The application requests the editor to select some objects...
  public Vector selectObjects(Vector objects);  

   // The application requests the editor to unannotate the objects.
  public void unAnotateObjects(Vector objects);  

   // The application requests the editor to unEmphasize the objects.
  public void unEmphasizeObjects(Vector objects);  

} //interface ApplicationNetDialog 

    

Communication is realized with the help of ActionObjects. The following examples of ActionObjects reside in de.huberlin.informatik.pnk.app.base

An application can initialize an ActionObject giving a reference of the ApplicationControl that should find a suitable request executer application and a reference of the net this application currently processes and calls the ActionObject's invokeAction() method.

/**
 * I presume that an MetaApplication 'app' requests the ApplicationControl 'ac'
 * to instruct another MetaApplication (that implements the 'ApplicationNetDialog' interface) 
 * to select a transition from the java.util.Vector 'concessioned'. 
 */

Net net;                     // net the transitions belong to
Vector concessioned;         // one of these transitions should be selected
MetaApplication app;         // application that initiates the request
ApplicationControl ac;       // applicationcontrol that routes the request

Transition transition = (Transition) 
    (new SelectObjectAction(ac, net, app, concessioned)).invokeAction();

    

This example starts a SelectObject request. It returns a transition of the list of concessioned transitions passed as argument to the constructor. The ApplicationControl now searches for an application that handles this request. The request executer application is supposed to be an editor which asks the user to select a transition. Then the editor returns a transition chosen by the user. For a better understanding we discuss the implementation of the EmphasizeObjectsAction which request to emphasize some netobjects like Arcs, Places or Transitions.


package de.huberlin.informatik.pnk.app.base;
 
import java.util.Vector;
import de.huberlin.informatik.pnk.kernel.*;
import de.huberlin.informatik.pnk.appControl.*;
 
/**
 * EmphasizeObjectsAction.java
 *
 * An application working on a net may emphasize
 * some netobjects (for example Places or Transitions)
 * using this ActionObject. The application specifies an
 * ApplicationControl. This tries to find another application as target
 * to perform the emphasize request. Therefore the ApplciationControl
 * checks if the targetapplication works on the same net and
 * implements the necessary interface.
 *
 * @author: gruenewa
 */
public class EmphasizeObjectsAction extends MetaActionObject {
 
    /*
     * A list of objects that should be emphasized by
     * an application for example an editor
     */
    Vector emphasizeObjects = null;
 
    /**
     * Creates a new EmphasizeObjectsAction instance.
     *
     * @param ac an ApplicationControl the AC which should find a targetapplication
     * @param net a Graph the graph/net the targetapplication currently processes
     * @param initiator a MetaApplication initiator of this request
     * @param emphasizeObjects a Vector parameters for the request
     */
    public EmphasizeObjectsAction(ApplicationControl ac,
                                  Graph net,
                                  MetaApplication initiator,
                                  Vector emphasizeObjects) {
        super(ac, net, initiator);
        this.emphasizeObjects = emphasizeObjects;
    }
 
    /**
     * method checkInterface
     *
     * The ApplicationControl uses this method to check all
     * available applications if they implement the necessary
     * interface to achieve this request.
     *
     * @param target an Object an application candidate
     * @return a boolean true if candidate is fine
     */
    public boolean checkInterface(Object appCandidate) {
        return appCandidate instanceof ApplicationNetDialog;
    }
 
    /**
     * method performAction
     *
     * After the ApplicationControl has extracted a suitable application
     * it call's this method to execute the request.
     *
     * @param target a MetaApplication application for the request
     * @return an Object result of the request will always be null
     */
    public Object performAction(MetaApplication target) {
        ((ApplicationNetDialog) target).emphasizeObjects(emphasizeObjects);
        return null; // this request is one-way, no return value necessary
    }
 
} // class EmphasizeObjectsAction

    

Take this example to design your own ActionObjects.

Application with Menu

Possibly you intend to write a more complex application with buttons and frames for example an editor. You want the application to set a menu in the ApplicationControl's menubar and to show this menu ever when an application's window got the focus. If your application implements an getMenus() method:


     public JMenu[] getMenus()
 
    

the ApplicationControl uses this method to request an java.lang.Array of javax.swing.JMenus's and sets these menus in it's menubar. If your application uses frames we recommend to use the de.huberlin.informatik.pnk.app.base.MetaJFrame class. This class implements some base functionality. It informs the ApplicationControl when the frame has got focus or it notifies the ApplicationControl when a window was closed. So the ApplicationControl knows which application currently works.

Load Applications

Presumed you have written a new application you have to announce it to the Petrinet Kernel's ApplicationControl. You do this by invoking the Petrinet Kernel's ToolSpecification mechanism. Edit the related toolSpecification.xml file by inserting an entry for your application. For the simulator application this entry would look something like this:

< !-- Simulator Application -- >
< !-- Embedding a simulator application using a reference to it's class file -- >
< !-- Maximum 5 instances, you could also choose 'inf' for infinity  -- >
< application id="a5" mainClass="de.huberlin.informatik.pnk.app.Simulator" maxinstances="5" >
  < allowedNettypes >
    < !-- Here you have to enter references -- >
    < !-- of nettypes the simulator can work with -- >
    < ntref ref="n1"/ >
    < ntref ref="n6"/ >
  < /allowedNettypes >
< /application >
    

Use a TOOLspecificationfile to unite some nettypes and applications to one tool. For example the EchoSimulator tool has a specificationfile toolSpecifications/EchoSimulator.xml. You launch the EchoSimulator tool on commandline by initiating the ApplicationControl with the specificationfile as first argument.

java -classpath .:crimson.jar:jaxp.jar \
  de.huberlin.informatik.pnk.appControl.ApplicationControl \
  toolSpecifications/EchoSimulator.xml
    

The EchoSimulator tool consists of two nettypes, a Echo Net that represents the algorithm and a graph, used by the algorithm. It also inheres an editor application for animation, a simulator application that performs the algorithm and a MarkingsToInitial application to set the initial marking before you continue the simulation. All these components are enumerated in the specificationfile.

< ?xml version="1.0" encoding="UTF-8"? >
< !DOCTYPE toolSpecification SYSTEM "toolSpecification.dtd" >
< toolSpecification >

  < !-- Nettypes -- >
    < nettype id="n3" typeSpecification="file:netTypeSpecifications/Echo.xml"/ >  
    < nettype id="n4" typeSpecification="file:netTypeSpecifications/graph.xml"/ >  

  < !-- Applications -- >
    < application id="a1" mainClass="de.huberlin.informatik.pnk.editor.Editor" maxinstances="inf" >
    < /application >
    < application id="a3" mainClass="de.huberlin.informatik.pnk.app.MarkingsToInitial" maxinstances="inf" >
    < /application >
    < application id="a5" mainClass="de.huberlin.informatik.pnk.app.EchoSimulator" maxinstances="inf" >
      < allowedNettypes >
        < ntref ref="n4"/ >
      < /allowedNettypes >
    < /application >
	
  < !-- Input / Output Format Filters-- >
    < format id="pnml" ioClass="de.huberlin.informatik.pnk.appControl.PnmlInOut" >
    < /format >

  < !-- default settings -- > 
    < standardNettype ref="n4"/ >
    < standardApplication ref="a1"/ >
    < standardFormat ref="pnml"/ >

< /toolSpecification >
    

You can write a specificationfile per tool, or you put all your nettypes, applications and fileformatfilters into one specificationfile. So you will construct an universal monster tool. I favor the first variant.

Write Nettypes


There exists much petrinet theorie in the world and a lot of different petrinet formalism. You can find Place-Transition Net's, Algebraic Net's or Timed Net's and many others. The idea of the Petrinet Kernel is that you may create your own nettype using our concept of netextensions. Therefore you have to write a nettype specification. Then you have to notify the corresponding toolspecificationfile, that a new nettype exists and where it can be found. For instance a file toolSpecifications/PTNetTool.xml would contain something like this:

< !DOCTYPE toolSpecification SYSTEM "toolSpecification.dtd" >
< toolSpecification >
  < !-- Nettypes -- >
    < nettype id="n1" typeSpecification="file:netTypeSpecifications/PTNet.xml"/ >
  < !-- Applications -- >
    < !-- Here comes a list of applications ... -- >
  < !-- Input / Output -- >
    < !-- Here comes a list of Input / Output filters ... -- >
< /toolSpecification >
    

Let's take a closer look at netTypeSpecifications/PTNet.xml.


< ?xml version="1.0" encoding="UTF-8"? >
< !DOCTYPE netTypeSpecification SYSTEM "netTypeSpecification.dtd" >
< netTypeSpecification name="PTNet" >
  < extendable class="de.huberlin.informatik.pnk.kernel.Net" >
    < extension name="firingRule" class="de.huberlin.informatik.pnk.netElementExtensions.llNet.SimpleRule"/ >
  < /extendable >
  < extendable class="de.huberlin.informatik.pnk.kernel.Place" >
    < extension name="marking" class="de.huberlin.informatik.pnk.netElementExtensions.llNet.NaturalNumber"/ >
    < extension name="initialMarking" class="de.huberlin.informatik.pnk.netElementExtensions.llNet.NaturalNumber"/ >
  < /extendable >
  < extendable class="de.huberlin.informatik.pnk.kernel.Transition" >
  < /extendable >
  < extendable class="de.huberlin.informatik.pnk.kernel.Arc" >
    < extension name="inscription" class="de.huberlin.informatik.pnk.netElementExtensions.llNet.NaturalNumber1"/ >
  < /extendable >
< /netTypeSpecification >
    

The < netTypeSpecification name="PTNet" > tells us the name of the nettype. The same name will be shown in the ApplicationControl's new Net menu or stored in a pnml file. Then a list of extendables and it's extensions follows. The extendable implements the de.huberlin.informatik.pnk.kernel.Extendable interface. Extendables for example are:

The interface serves methods like:

For the extandable de.huberlin.informatik.pnk.kernel.Place an imaginable extension could be marking. The extensions implementation could be the class de.huberlin.informatik.pnk.netElementExtensions.llNet.NaturalNumber. So that's the code you have to put into the nettype-specificationfile:

  < extendable class="de.huberlin.informatik.pnk.kernel.Place" >
    < extension name="marking" class="de.huberlin.informatik.pnk.netElementExtensions.llNet.NaturalNumber"/ >
    

As you can see an extension entry is formed by a name and a reference to a java class. In this case the extension's name is marking and the extensions's implementation is de.huberlin.informatik.pnk.netElementExtensions.llNet.NaturalNumber. When an extendable is generated (in this case a place) the extensions where build from the specification (an instance of de.huberlin.informatik.pnk.netElementExtensions.llNet.NaturalNumber will be initialized).

NOTE: The name of an extendable is a standard extension, so You have not to refer it in the nettype-specificationfile!

Now it's time to say something about the [ abstract classes | interfaces ] Marking, Inscription, Mode and FiringRule. These are very important to affect the behaviour of your nettype. To make your nettype work you have to implement these or you use one of our default implementations.

Marking

Let's start with the Marking extension. It is an abstact class. It serves methods like:


public abstract class Marking 
  extends Extension implements Inscription {

  //************************************************************
  // These are the methods you have to implement to make the
  // Marking work.
  //************************************************************

  /**
   * Returns true if marking is contained in this marking.
   */
  abstract public boolean contains(Marking marking);

  /** 
   * Adds the markings. This method is called by
   * the add(Marking marking) method
   * of this marking.
   */
  abstract protected void localAdd(Marking marking);

  /** 
   * Subtracts the markings. This method is called by
   * the add(Marking marking) method
   * of this marking.
   */
  abstract protected void localSub(Marking marking);

  //************************p************************************
  // These are the methods you may use.
  //************************************************************

  public Marking evaluate() { return this; }

  /**
   * Add operation of an Marking.
   * Uses the localAdd(Marking marking) method
   * and updates the new value of the marking in kernel.
   */
  final public void add(Marking marking) { ... }

  /**
   * Subtract operation of an Marking.
   * Uses the localSub(Marking marking) method
   * and updates the new value of the marking in kernel.
   */
  final public void sub(Marking marking) { ... }

  /**
   * Returns true if this marking is empty.
   */
  final public boolean isEmpty( ){ ... }

} // public interface Marking
    

As you can see it is expected that you implement the methods:

Inscription

The inscription extension of an arc is an interface.

/**
  * The template for the implementation of an  inscription  of an
  *  {@link Arc arc}.
  * The  "inscription"  of an
  * arc is a standard {@link Extension  extension}. Whenever you design
  * your own {@link Net Petri Net} type you either need to implement a
  * custom inscription class (derived from class Extension and
  * implementing Inscription) or you use one of the
  * standard implementations (e.g. {@link Arc arc} multiplicities for
  * Place/Transition-Nets).
*/
public interface Inscription
{
        Marking evaluate();
}
    

It declares an evaluate() method that returns an object of a Marking class. For example you want to subtract tokens from a place using the inscription of an arc. You could program something like

     // get sourcenode of arc
     Place sourceNode = (Place) arc.getSource();
     // get marking of sourcenode
     Marking marking = sourceNode.getMarking();
     // get inscription of arc
     Inscription inscription = arc.getInscription();
     // subtract the value of arc's inscription from sourcenode's marking
     marking.sub(inscription.evaluate());  
    

I hope this clears the idea of the Inscription interface and the Marking class. You need both to implement the firingRule extension of a net.

FiringRule

A de.huberlin.informatik.pnk.kernel.Net is recommended to have a firingRule. This extension should implement the de.huberlin.informatik.pnk.netElementExtensions.base.FiringRule interface. This interface demands as previously mentioned the methods:


/**
  * Is the template for implementing the  firing rule  of a
  * {@link de.huberlin.informatik.pnk.kernel.Net Petri Net}.
  *
  * The firing rule of a net is a
  * standard {@link de.huberlin.informatik.pnk.kernel.Extension extension}. 
  * Whenever you design your own
  * Petri Net type you either need to implement a custom
  * firing rule class (derived from class 
  * {@link de.huberlin.informatik.pnk.kernel.Extension Extension} and implementing
  *  FiringRule ) or you use one of the standard
  * implementations (e.g. the 'Hamburg' rule for Place/Transition-Nets).
  */
public interface FiringRule
{
  /**
   * Parses all Extensions with an internal value depending on
   * (possibly edited) other extensions.
   */      
  void  checkContextAndParseExtensions();  

  /**
   * Fires the set of {@link Transition transitions} given by
   * transitions. 
   * The  transitions are fired simultaneously. Usually 
   * an order is practically introduced due to the sequential nature of 
   * the implementation of fire, but no assumptions should me 
   * made about this order. 
   */
  void fire(Vector transitions);  

  /**
   * Returns the set of all {@link #isConcessioned concessioned} {@link 
   * Transition transitions}. 
   */
  Vector getAllConcessioned();  

  /**
   * Returns the set of all {@link #isConcessioned concessioned}
   * {@link Transition transitions}, which are in the  
   *  set inclTrans and not in  exclTrans. 
   * The returned set contains  each {@link #isConcessioned 
   * concessioned} transition meeting the additional 
   * criteria.
   * Both sets may possibly be empty. Set inclTrans is empty 
   * or set exclTrans  equals the set of all transitions 
   * implies that an empty set will be returned. If exclTrans 
   * is empty, no  transition is a priori excluded from 
   * the eventually returned set. 
   */
  Vector getAllConcessioned(Vector inclTrans, Vector exclTrans);  

  /**
   * Returns the set of all simultaneously fireable sets ({@link #isStep 
   * steps}) of {@link Transition transitions}. 
   * @see #getStep()
   */
  Vector getAllSteps();  

  /**
   * Returns the set of all sets ({@link #isStep steps}) of 
   * simultaneously fireable {@link Transition transitions}. 
   * Each returned {@link #isStep step} has at least one 
   *  transition in common with inclTrans and the 
   * intersection with exclTrans is empty. 
   */
  Vector getAllSteps(Vector inclTrans, Vector exclTrans);  

  /**
   * Returns a reference to a {@link #isConcessioned concessioned} 
   *  transition. 
   */
  Transition getConcessioned();  

  /**
   * Returns a reference to a {@link #isConcessioned concessioned} 
   * transition, which is in the  transition 
   * set inclTrans and not in exclTrans. 
   * Both sets may possibly be empty. An empty set inclTrans 
   * or a set exclTrans equal to the set of all
   * transitions always causes an exception. If 
   * exclTrans is empty, no  transition is 
   * a priori excluded from the set of possible return values. 
   */
  Transition getConcessioned(Vector inclTrans, Vector exclTrans);  

  /**
   * Returns a simultaneously fireable set ({@link #isStep step}) of 
   * {@link Transition transitions}. 
   * The step is simultaneously fireable according to 
   * the implemented firing rule. Naturally all  
   * transitions in a  step are {@link #isConcessioned 
   * concessioned}. 
   * The returned {@link #isStep step} may serve as input for {@link 
   * #fire fire(step)}. 
   */
  Vector getStep();  

  /**
   * Returns a simultaneously fireable subset ({@link #isStep step}) of 
   * set  transitions. 
   * The {@link #isStep step} has at least one  
   * transition in common with inclTrans and the 
   * intersection with exclTrans is empty. 
   * The  step is fireable according to the implemented 
   * firing rule. Naturally all transitions in the 
   * step are {@link #isConcessioned concessioned}. 
   */
  Vector getStep(Vector transitions);  

  /**
   * Returns whether the given  transition is 
   * concessioned. 
   * The definition of concessioned varies even among the same class of 
   * {@link de.huberlin.informatik.pnk.kernel.Net Petri Nets}. The most commonly used definition for
   * P/T-Nets simply demands that each {@link de.huberlin.informatik.pnk.kernel.Place place} in the preset
   * of a {@link Transition transition} must carry at least as many tokens 
   * as the multiplicity of the {@link de.huberlin.informatik.pnk.kernel.Arc arc} from the
   * place to the  transition. 
   */
  boolean isConcessioned( Transition transition);  

  /**
   * Returns whether a set of {@link Transition transitions} is 
   * simultaneously fireable. 
   * Be aware of the difference between simultaneously fireable 
   * and fireable in an arbitrary order under certain 
   * circumstances. 
   * The maximal step firing rule for P/T-Nets is an example for the 
   * importance of that difference. In that case a step is defined as an 
   * inclusion-maximal set of simultaneously fireable {@link Transition 
   * transitions}. Under the normal firing rule for P/T-Nets the {@link 
   * Transition transitions} in this set could be {@link #fire fired} in 
   * an arbitrary order. One can imagine a situation where a  
   * transition t, which is not member of the step, can only 
   * be {@link #isConcessioned concessioned} during the {@link 
   * #fire firing} of the  transitions in the step in 
   * an appropriate order. The freedom of choosing the order is taken away 
   * by the maximal step firing rule, since there is no 'during'. It all 
   * happens in the very same moment. Consequently  
   * transition t can never become {@link #isConcessioned concessioned}. 
   * 
   * What is even more astonishing: because of that feature of P/T-Nets 
   * with the maximal step firing rule it is possible to simulate the 
   * decrement if not zero and goto i, otherwise goto j operation 
   * of a counter automata, which is as expressive as and as hard to 
   * analyze as a Turing machine. 
   */
  boolean isStep( Vector transitions);  

} // public interface FiringRule
    

As showed in the simulator example, you use the firingrule extension to request concessioned transitions and fire them. For an sample implementation you might see the de.huberlin.informatik.pnk.netElementExtensions.llNet.SimpleRule. You can use this implementation as default. It profits by methods of the de.huberlin.informatik.pnk.netElementExtensions.base.Marking class and the de.huberlin.informatik.pnk.netElementExtensions.base.Inscription interface. An possible implementation of the fire() methode in a FiringRule object could be:

/**
 * A sample implementation of methode fire() in FiringRule.
 * Fires the given transition by subtracting
 * markings from all places in preset of transition and 
 * adding markings to all places in postset of transition.
 */
public void fire(Transition transition) {

  Vector edges;

  /*
   * subtract markings from places in preset of transition
   */

  edges = transition.getIncomingEdges();
  for(int i = 0; i < edges.size(); i++) {
    Edge edge = (Edge) edges.get(i);
    Inscription inscription = (Inscription) edge.getExtension("inscription");
    Marking marking = ((Place) edge.getSource()).getMarking();
    marking.sub(inscription.evaluate());
  } // end for
 
  /*
   * add markings to places in postset of transition
   */

  edges = transition.getOutgoingEdges();
  for(int i = 0; i < edges.size(); i++) {
    Edge edge = (Edge) edges.get(i);
    Inscription inscription = (Inscription) edge.getExtension("inscription");
    Marking marking = ((Place) edge.getTarget()).getMarking();
    marking.add(inscription.evaluate());
  } // end for

} // public void fire   
    

A second example shows a practicable implementation of the isConcessioned() method in a FiringRule object:

/**
 * Returns whether the given
 * transition is concessioned. 
*/ public boolean isConcessioned(Transition transition) { boolean to_return = true; // indicates that transition is concessioned // enumerate on all incoming edges, // check if there is one place as edge sourcenode // that doesn't activate the transition Vector edges = transition.getIncomingEdges(); for(int i = 0; i < edges.size(); i++) { Edge edge = (Edge) edges.get(i); Inscription inscription = (Inscription) edge.getExtension("inscription"); Marking marking = ((Place)edge.getSource()).getMarking(); if( ! marking.contains(inscription.evaluate())) to_return = false; // now it's clear, the transition is not activated } // end for return to_return; } // boolean isConcessioned


Alexander Gruenewald

Last modified: Tue Aug 7 15:34:01 MET DST 2001