# Petri net simulator for C This is a program to edit and simulate petri nets in C. The reason for C is portability, especially language portability. It's probably the only library for petri net simulation in existence. Simulation is fast and scalable, since it's not neccessary to iterate over all nodes everytime a transition has fired. ## Documentation ### Naming conventions All types and functions use camel case. Types are prefixed with uppercase "Pns", functions with lowercase "pns". Functions meant to be used as constructors and similar end with the name of the created type (omitting the "Pns" prefix). Functions representing methods of a type start with the typename (but lowercase) and end with the method name, both separated by a "_". An additional "_backward" suffix added to some methods is discussed later. ### Data structures The petri net is stored in the type `PnsNet`. It contains information about the existing places and transitions and also stores the initial token count for each place. In order to simulate the petri net, there is another data structure called `PnsState`, which stores the current distribution of the tokens inside the places and some other infos. ### Initialization #### Initializing a petri net Just initialize a petri net using `void pnsCreateNet(PnsNet* net)`. A petri net can also be generated from an array of 32-bit integers. This is done by calling `bool pnsLoadNet(PnsNet* net, size_t count, const uint32_t* values)`. The return value will be true, when the initialization was successful. The integers values represent the following data: * the count of places * the initial token count for every place * the count of transitions * for each transition: - number of following places - the id of every following place - number of preceding places - the id of every preceding place When stored as a file, the integer values should be stored in little endian encoding. The recommended extension file extension is ".pn" which stands for "`p`etri `n`et". #### Initiaizing the state In order to initialize a state, there already needs to be a petri net. It is done by calling `void pnsCreateState(PnsState* state, const PnsNet* net)`. The first argument will be the state, you want to initialize, the second argument is the previously created petri net. ### Destructors Both, `PnsNet` and `PnsState` need to be destroyed, when not used anymore. This can be done using `void pnsDestroyNet(PnsNet* net)` and `void pnsDestroyState(PnsState* state)`. ### Editing It's also possible to edit the petri net manually using various methods. You can add and remove transitions and places. You can also connect and disconnect them. When editing the net after creating states, this might invalidate some of the states. More on that later. ### Running the simulation After creating a state, the simulation can begin. #### Querying fireable transitions First you have to get some transition, that currently is fireable. A list of them can be queried by calling `void pnsState_transitions(PnsState* state, size_t* count, size_t* transitions)`. It takes the previous created state and a pointer to a `count`. If `transitions` is a null pointer, the count of available transitions will be written into `count`. If `transitions` is specified, up to `count` transitions will be written into `transitions` and then `count` will be set to the number of transitions written. Most likely you will call this function twice, once to get the count, then allocate the required memory and then call it again. Instead you can also just call it once, and specify the memory you already have allocated. This way you may not get all transitions. Also see following methods (described in the [header](pns.h)): * `void pnsState_addedTransitions(PnsState* state, size_t* count, size_t* transitions)` * `void pnsState_removedTransitions(PnsState* state, size_t* count, size_t* transitions)` * `void pnsState_cleanChanges(PnsState* state)` #### Fire transitions After you got some transitions, you can select one and fire it by calling `void pnsTransition_fire(const PnsTransition tid, PnsState* const state)`. This will change, which transitions can fire, so after fireing a transition you should query transitions again, before fireing another time. For performance reasons, this is not checked at runtime. #### Strategies for selecting transitions You can imagine many ways to select the transition. The easiest way is just getting the first transition. This is a bad choice, since it's neither random nor controllable by you and may even change in future versions or when using different structures of the same game. So the simplest useful strategy may be random selection. This may help to detect race conditions in programs modelled by petri nets. Another way is just letting the user decide the transition. Other useful strategies need you to connect some external information with the transitions. For example, every transition can be connected with some textual identifier or even a story, which can be selected. It could also be connected with external events, which trigger some transitions. When information is connected with transitions, selecting a transition can also trigger external events. Even when a new transition can be fired, this may already trigger events. #### Playing backward It's possible to simulate everything backward. Therefore every simulation function has a counterpart with a "_backward" suffix. These functions are used in the same way as their default counterparts. This behaviour can be abused to produce some fancy relations. #### Interactive editing When editing the net after a state has been created, you always have to call `void pnsState_refresh(PnsState* state, const PnsNet* net)` before you continue the simulation after editing. You also shouldn't do edits which invalidate the state. No edit should prevent an user to reach a state, which has been reachable before. This has to be ensured by the specific application. Most importantly transition, which have been callable should not be deleted, since that's what will be stored in the end. ### Generating files The most straightforward way to generate a ".pn" file is generating the petri net using functions of this library to build and save. There's already [a GUI](https://gitlab.com/porky11/pn-editor) using this library to simplify building it without the need of programming. ## Planned Extensions Currently no extensions are planned. ## See also * [Safe rust wrapper](https://gitlab.com/porky11/pnrs)