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.deThe 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.
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 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 ...
jaxp.jar - api for reading and writing xml files
crimson.jar - api for reading and writing xml files
PNK2.jar - archive of the Petrinet Kernel's class files
PNK2sources.jar - archive of the Petrinet Kernel's source files
Makefile - with this you may compile sources by hand
sampleNets - contains some saved netexamples
netTypeSpecifications - contains examples for a net's specification
toolSpecification - contains some toolspecification examples
icons - icons used by applications
license
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
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.
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.
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 ...
de.huberlin.informatik.pnk.kernel
de.huberlin.informatik.pnk.kernel.base
de.huberlin.informatik.pnk.app
de.huberlin.informatik.pnk.app.base
de.huberlin.informatik.pnk.appControl
de.huberlin.informatik.pnk.appControl.base
de.huberlin.informatik.pnk.netElementExtensions
de.huberlin.informatik.pnk.netElementExtensions.base
de.huberlin.informatik.pnk.editor
de.huberlin.informatik.pnk.exceptions
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 de.huberlin.informatik.pnk.kernel
's package
contains especially the following important classes:
Net
Arc
Place
Transition
Extension
Specification
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
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.
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.
Now I will give you a short introduction how to write an application by discussing the implementation of a 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 SimpleRule class implements the interface
de.huberlin.informatik.pnk.netElementExtensions.base.FiringRule
.
This interface defines methods like:
void fire(Vector transitions); // Fires some transitions
Vector getAllConcessioned(); // returns a list of concessioned transitions
Transition getConcessioned(); // returns only one concessioned transition
boolean isConcessioned(Transition t); // checks if a transition is concessioned
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.
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
AnnotateObjectsAction // Requests to annotate object
ResetAnnotationsAction //
UnAnnotateObjectsAction //
SelectObjectAction // Requests to select an object
ResetEmphasizeAction //
SelectObjectsAction // Requests to select a collection of objects
EmphasizeObjectsAction // Requests to emphasize a collection of objects
UnEmphasizeObjectsAction
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.
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.
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.
< !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.
public abstract class Marking extends Extension implements Inscription { //************************************************************ // These are the methods you have to implement to make the // Marking work. //************************************************************ /** * Returns true ifmarking
is contained in this marking. */ abstract public boolean contains(Marking marking); /** * Adds the markings. This method is called by * theadd(Marking marking)
method * of this marking. */ abstract protected void localAdd(Marking marking); /** * Subtracts the markings. This method is called by * theadd(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 thelocalAdd(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 thelocalSub(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:
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 * implementingInscription
) 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.
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 offire
, 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 * setinclTrans
and not inexclTrans
. * The returned set contains each {@link #isConcessioned * concessioned} transition meeting the additional * criteria. * Both sets may possibly be empty. SetinclTrans
is empty * or setexclTrans
equals the set of all transitions * implies that an empty set will be returned. IfexclTrans
* 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 withinclTrans
and the * intersection withexclTrans
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 * setinclTrans
and not inexclTrans
. * Both sets may possibly be empty. An empty setinclTrans
* or a setexclTrans
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 * settransitions
. * The {@link #isStep step} has at least one * transition in common withinclTrans
and the * intersection withexclTrans
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 giventransition
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
Last modified: Tue Aug 7 15:34:01 MET DST 2001