Language Interface and Tutorial - CiteSeerX

4 downloads 189664 Views 514KB Size Report
tutorial for using the SYNOD/SLI environment to perform neural network ... PostScript is a trademark of Adobe Systems Incorporated. Scienti c ...... For a more detailed description refer to any book on PostScript (e.g. 2]). SLI uses ...... The output has been stopped here after the rst few events, since it just served illustration.
SYNOD: An Environment for Neural Systems Simulations Language Interface and Tutorial

Markus Diesmann1, Marc-Oliver Gewaltig2, and Ad Aertsen1 1 Department

of Neurobiology The Weizmann Institute of Science 76100 Rehovot Israel

2 Institut

fur Neuroinformatik Ruhr-Universitat Bochum 44780 Bochum Germany

Computer simulations of neural systems, ranging from very detailed compartmental models of single neurons to large scale neural networks are quite common. Often their results are used as evidence for or against a certain theory. However, many neurosimulations share a number of problematic features. Results from one laboratory are hard to reproduce in another, since di erent neuron or network models are used, each with their own speci c software and implicit assumptions. Also, the mapping from measures obtained in simulations onto their 'real world' counterparts is not always well de ned. From this we draw two conclusions: First, the simulations should allow for identical processing of simulated and experimental data, preferably using the same analysis tools; we refer to such simulations as in virtu experiments. Second, and more important, it should be possible to implement di erent models, not necessarily at the same level of description, within a single common scheme. With this goal in mind, we developed a new conceptual framework for neural simulations, using an object-oriented approach. Based on these principles we implemented a C++ class library for neural system simulations (SYNOD), together with a language interface (SLI) for the description and execution of in virtu experiments. In this document we describe the language interface, and provide a tutorial for using the SYNOD/SLI environment to perform neural network simulations.

This document was typset by the authors, using Scienti c WorkPlace with LATEX 2" and translated into PostScript using dvips. PostScript is a trademark of Adobe Systems Incorporated. Scienti c WorkPlace is a trademark of TCI Software Research. All other brand and product names are trademarks of their respective companies. Parts of the gure on the back cover were taken with permission from the September 1979 issue of Scienti c American (Edward V. Evarts Brain Mechanisms of Movement, gure by Bunji c September 1979 by Scienti c American, Inc. All rights reserved. Tagawa). Copyright

Preface SYNOD is a simulation environment, developed for the study of arti cial neuronal systems. Its main objective is to create a exible and computationally ecient tool to simulate realistic neural networks models, providing the means to combine di erent levels of discription (e.g. ionic channels, stochastic point processes, population activity) within a single network. The SYNOD project was started in 1993 in the framework of the MSc studies of Marc-Oliver Gewaltig and Markus Diesmann at the Institut fur Neuroinformatik at the Ruhr-Universitat Bochum (Bochum, Germany), and has been operational since early 1994. This document describes its present status and provides an introduction to its usage. Further developments on SYNOD are currently being pursued in a joint e ort at the Center for Brain Research at the Weizmann Institute of Science (Rehovot, Israel) and the afore mentioned Institut fur Neuroinformatik in Bochum. Some of SYNODs principles regarding the exchange of point events and the role of time in the simulation were described in the MSc thesis [9]. Parts of the conceptual framework of SYNOD were presented at the Gottingen Neurobiology Conference [8].

Conventions The term SYNOD is used for the simulation kernel as well as for the entire project. In situations where it is important to distinguish between the simulation kernel and the language interface, we use SLI for the SYNOD language interface and SYNOD/SLI for the project. Monospaced type is used for SLI code fragments and computer output, sans-serif type indicates SLI objects, and italics are used to emphasize portions of the text and to mark parts which have to be changed by the user. Names of C++ classes follow the usual convention regarding the usage of capitals (e.g. SpikeDetector). The characters (, ), [, ], f, and g play an important role in SLI. There is sometimes confusion about the naming of these characters, which are typically used in pairs. We adopted the de nitions in [22]: Character Name (,) parenthesis [,] bracket f,g brace Since we use many examples in this text, sentences which end with a colon followed by the example are common. We typeset the example as a separate paragraph. Thus, the end of the sentence is clearly marked. In these cases we ommit the full stop.

iii

iv

Acknowledgements We thank Prof. Moshe Abeles for his advice and for helpful discussions during the initial phase of the development of SYNOD, and for supplying us with the source code of his simulator. We also thank Prof. George Gerstein and Dr. Michael Erb for helpful discussions on the design and usage of neural system simulators, and Michael Neef, Nava Shaya, and Shlomit Afgin for helping us bridge the gaps between di erent compilers, computers, and local networks. Partial funding was received from the Human Frontier Science Program (HFSP), the Israel Academy of Science, and the German "Bundesministerium fur Forschung und Technologie" (BMFT). Rehovot and Bochum, April 1995 Markus Diesmann Marc-Oliver Gewaltig Ad Aertsen

Contents Preface Contents 1 Introduction

1.1 Towards a Generalized Concept : : : : : : : : : : : : : : : : 1.1.1 Network and Neuron : : : : : : : : : : : : : : : : : : 1.1.2 Di erent Neuron Models in one Net: Inheritance : : 1.1.3 Neuron and NeuronModel : : : : : : : : : : : : : : : 1.1.4 Meaning of Time in the Network : : : : : : : : : : : 1.1.5 Recording and Manipulation Methods : : : : : : : : 1.1.6 Experiments in virtu : Sessions : : : : : : : : : : : : 1.1.7 Time Course of an Experiment and Reproducibility 1.1.8 A Graphical User Interface? : : : : : : : : : : : : : : 1.1.9 A First Implementation of the Concept : : : : : : : 1.1.10 Discussion and Outlook : : : : : : : : : : : : : : : : 1.2 The Language Interface : : : : : : : : : : : : : : : : : : : : 1.2.1 Problems : : : : : : : : : : : : : : : : : : : : : : : : 1.2.2 Portability : : : : : : : : : : : : : : : : : : : : : : : 1.2.3 Future Versions : : : : : : : : : : : : : : : : : : : : : 1.2.4 How to obtain SYNOD/SLI : : : : : : : : : : : : : : 1.2.5 Copyright Restrictions : : : : : : : : : : : : : : : : :

2 The SYNOD Language Interface

2.1 Resources : : : : : : : : : : : : 2.2 The Scanner : : : : : : : : : : : 2.3 SLI Objects : : : : : : : : : : : 2.3.1 Names : : : : : : : : : : 2.3.2 Literals : : : : : : : : : 2.3.3 Numbers (double, long) 2.3.4 Strings : : : : : : : : : : 2.3.5 Arrays : : : : : : : : : : 2.3.6 Procedures : : : : : : : 2.3.7 Comments : : : : : : : : 2.4 The Parser : : : : : : : : : : : 2.5 The Interpreter : : : : : : : : : 2.5.1 The Operand Stack : : 2.5.2 The Execution Stack : : 2.5.3 The Dictionary : : : : : 2.5.4 The Evaluation Loop : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : : v

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

: : : : : : : : : : : : : : : :

iii v 1 2 2 2 2 2 3 3 3 3 4 4 5 5 6 6 7 8

9

9 9 10 11 11 11 11 13 13 14 14 14 14 14 14 15

CONTENTS

vi

3 SLI Tutorial

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

4.1 Introduction : : : : : : : : : : : : : : : : : 4.2 Units and Measures : : : : : : : : : : : : 4.3 Some Important Concepts : : : : : : : : : 4.3.1 The Network : : : : : : : : : : : : 4.3.2 Background Noise : : : : : : : : : 4.3.3 Models and Neurons : : : : : : : : 4.3.4 Methods, Sessions and Simulations 4.4 An Example Simulation : : : : : : : : : : 4.4.1 Planning a Simulation : : : : : : : 4.4.2 Setting up a Network : : : : : : : 4.4.3 Setting up the Background : : : : 4.4.4 Creating Neurons : : : : : : : : : : 4.4.5 De ning the Net : : : : : : : : : : 4.4.6 Performing the Simulation : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

: : : : : : : : : : : : : :

3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10

Introduction : : : : : : : : : : : : First Steps : : : : : : : : : : : : Expressions : : : : : : : : : : : : Working with the Stack : : : : : De nitions, Literals and Names : Procedures : : : : : : : : : : : : Loops and Control Structures : : Conditionals : : : : : : : : : : : : Strings : : : : : : : : : : : : : : : Files and Programs : : : : : : : : 3.10.1 Filenames and Programs : 3.10.2 File Objects : : : : : : : : 3.10.3 Writing Data into Files :

: : : : : : : : : : : : :

: : : : : : : : : : : : :

4 Neural Simulations in SLI

5 SLI Reference to Neural Simulations 6 SLI Command Reference 7 Error Handling Bibliography Index

: : : : : : : : : : : : :

: : : : : : : : : : : : :

17

17 17 18 19 20 21 22 23 23 24 24 25 25

27

27 27 28 28 28 28 29 30 30 31 32 32 33 36

39 47 57 59 62

Chapter 1

Introduction When systems are too complicated to be treated analytically, simulations provide a good way of gaining insight into their behaviour. Moreover, observables that cannot be measured directly can be estimated from the simulations. Evidently, simulation results have to stand the comparison with the experiment. Thus, it can be checked under which conditions and to what precision the model holds. Computer simulations of neural systems, ranging from very detailed compartmental models of single neurons to large scale neural networks have become quite common. Often their results are used as evidence for or against a certain theory. An ideal simulation is a numerical representation of an exact model of the system under consideration. Observables that cannot be measured directly due to technical problems or other limitations can be estimated from the simulation. However, as recording technology advances, results yielded from simulations have to stand the comparison with future experiment. By observing how the model reacts to stimuli and comparing this to results from real experiments, it can be checked under which conditions and up to which precision the model is correct. Despite their popularity, many neuro-simulations share a number of problematic features. Results from one laboratory are hard to reproduce in another. Often, di erent neuron or network models are used, with their own speci c software and implicit assumptions. Also, the mapping from measures obtained in simulations onto their 'real world' counterparts is not always well de ned. From this we draw two conclusions: First, the simulations should allow for identical processing of simulated and experimental data, preferably using the same analysis tools; we refer to such simulations as in virtu experiments. Second, and more important, it should be possible to implement di erent models, not necessarily at the same level of description, in a single common scheme. We developed a new conceptual framework for neural simulations, using an object-oriented approach. Based on these principles we implemented a C++ class library for neural system simulations called SYNOD and a language interface SLI for the description and execution of in virtu experiments. Section 1.1 provides a general overview of the entire project. In the subsequent chapters we focus on the language interface. A later text will report on the technical details and future developments of SYNOD. Chapter 2 technically describes the language and the structure of the interpreter. Chapter 3 presents a brief tutorial for the SLI language. Chapter 4 provides an overview how neural simulations can be set up and performed. Chapters 5 and 6 contain the reference manuals for the SYNOD related and the remaining SLI operators. 1

CHAPTER 1. INTRODUCTION

2

1.1 Towards a Generalized Concept for Neural Systems Simulations

1.1.1 Network and Neuron

Usually neural network models make no di erence between the single neuron model and the network itself. Mixing these two aspects results in several limitations. Neuron models can describe the properties of a neuron at several di erent levels (e.g. ion channel dynamics, stochastic approaches). Once a decision about the level of description has been made, a neural network model is usally bound to this level. On the other hand, a lot of the work a network simulator has to perform is common to most network models. Neurons must be updated, some information about the neurons connections and some interaction mechanism must exist. We propose the use of four main classes1: Network, NeuronModel, Neuron, and Connection. To illustrate this approach, we will omit the Connection class under the constraint that we include some limitations for the class of possible neuron models that can be implemented in this framework. Let us assume that the neurons interact only by the spikes they emit: considered from outside the neuron, a spike is a point event. A connection between two neurons can be described by two parameters: a weight and a delay. All a neuron "sees" from the rest of the network at a certain point T in time, is the weighted sum over all point events arriving at the neuron. In the full formulation, the class Connection will ensure that neurons with di erent types of output can communicate with each other.

1.1.2 Di erent Neuron Models in one Net: Inheritance

In the simpli ed example, a neuron consists of a state vector Xv , and a list of target neurons with information about the particular connections (weight, delay). Further, a time-evolution operator that transforms the state of the neuron at time T to the state at time T + h, and nally a mechanism which computes the in uence of the rest of the network on the neuron at time T . Di erent neuron models can have di erent time-evolution operators and di erent state vectors. However, the remaining parts are the same for all neuron models. The technique of using a base class Neuron to build particular neuron models Neuron A and Neuron B is called derivation. Class Neuron A is derived from class Neuron.

1.1.3 Neuron and NeuronModel

Considering a network of neurons of a particular model, we notice that usually these neurons have a lot in common. Characteristic for a particular neuron model is the time-evolution operator, for example a set of di erential equations. The neurons di er only in their state vector Xv . This allows us to make a distinction between e.g. NeuronModel A and Neuron A. Neuron A basically contains the state vector. NeuronModel A contains all the (constant) parameters common to all neurons belonging to this model. In addition, it contains the time-evolution operator and a method for creating and initializing the neuron. Whenever the neuron is asked to change its state, it calls the operator contained in its neuron model class.

1.1.4 Meaning of Time in the Network: Ensuring Appropriate Scaling

The network is simply a list of neuron models plus a list of neurons. It is the Network class that ensures the parallel update of the neurons so that the network's state vector consistently transforms from its value at time T to the value at time T + h. In some neural network models the meaning of time is not clear. It is hard to interpret the results on a real time scale, and comparing the dynamics of di erent neuron models may be even harder. In our framework the class Network controls the interpretation of the computation step size. A (member) function 1

For a review of the terminology in object oriented design methods see [14] and [19].

1.1. TOWARDS A GENERALIZED CONCEPT

3

sets the stepsize h in which the time-evolution operator U (T; T + h) advances the (system) neuron in time. The Network is able to do this by calling a function TimeScale of every neuron model in the list of models. By this general mechanisms, even models which are not based on di erential equations can be scaled to the appropriate stepsize.

TimeScale

1.1.5 Recording and Manipulation Methods

So far, we have only described the objects needed to model the (neural) system in question. In an actual experiment the experimenter faces two distinct systems: First, the system to be examined and second, the machinery which is used to perform the observations on the system.Typically, the experimenter uses special technical devices to apply di erent types of stimuli and to record di erent dynamic variables. These devices can be quite complex, and the precise result of a measurement may well depend on their parameters (e.g. a spike detector). If we want to be able to compare results from 'real' experiments with simulated data it is obviously, necessary to make models of the di erent recording and manipulation methods and to incorporate these in the simulation. Base classes RecordingMethod and ManipulationMethod are derived from class Method, which contains the list of neurons the method has to be applied to, and a virtual action function. Member function Apply calls the action function for every neuron in the list.

1.1.6 Experiments in virtu : Sessions

Now, we have to combine the model of our neural system and the models of all methods to be applied simultaneously to a virtual experimental setup. Such an object is called a Session. It contains a pointer to the Network and a list of methods. Session provides a function Simulate to advance the system in time and allows the associated methods to interact with the neurons in every time step.

1.1.7 Time Course of an Experiment and Reproducibility: a Description Language

The description of our experimental setup, all the information which is collected in one Session, is static. Again, in a 'real' experiment the situation is more complicated. Stimuli may have to be applied at di erent times, and di erent observables are of interest at di erent stages of the experiment. We propose a full scale programing language to describe the time course of the entire experiment and all parameter settings. This allows us to formalize the description of a complete simulation in a single ASCII le, easily readable by the user. Simulations can be reproduced by just executing this le again. Exact descriptions of simulations can be exchanged between laboratories and old simulations can be used as building blocks for new, more complex ones. An interpreter for this language allows the user to build up and test a simulation step by step, and to get informtion about certain parameter settings in an interactive way.

1.1.8 A Graphical User Interface?

Most window systems (e.g. Motif) are prototypes of object oriented libraries. The interface to the application, however, is in most cases hopelessly intermingled with the code of the application. These days, the average life time of a window system is very limited, so the risk of having to rewrite the whole project due to environment changes is very high. Thus, one would like to have a clear-cut separation between the simulator and its GUI. We suggest that this interface could also be language-based, like for example Display-PostScript (DPS). This would make the two parts independent of each other. The simulator could be used without the GUI and di erent GUIs for di erent Window systems could co-exist. At the same time, this concept solves another problem of GUIs. Typically, the user sets up a simulation by mouse action and typing of parameters in dialog boxes. Usually, these actions e ect the system immediately and produce graphical and numerical responses for the user. The problem is to invent a mechanism which makes it possible

4

CHAPTER 1. INTRODUCTION

to reproduce an interactive session. A language based interface provides a natural solution. As the session proceeds, commands are sent to the simulator. If some mechanism exists which record this sequence of commands (preferably in an ASCII le), the experiment can be repeated just by loading this le.

1.1.9 A First Implementation of the Concept

We have implemented most of the framework described above, in the form of a C++ library, called SYNOD. However, it implements only the simpli ed version of the framework, omitting the Connection class. An implementation of the description language, called SLI (SYNOD Language Interface) is also available. The current version of the SYNOD/SLI system was tested with di erent neuron models in simulations ranging from detailed single neuron investigations to complex syn re simulations, involving several thousand neurons (e.g. [3], [6], [7], and [11]).

SYNOD The C++ library SYNOD de nes the classes and procedures described above. It allows the formulation of complex neural simulations with comparatively short C++ code. The extension of the library with new neuron models and methods is possible without much e ort.

SLI SLI is an interpreter which understands a set of commands and uses them to call procedures from the SYNOD library. SYNOD then performs simulations according to the rules speci ed by SLI. It was quite clear from the beginning that parts of SYNOD would change in future versions. This in uenced the layout of the interpreter. Adding new C++ functions to SLI is easy and only very little understanding of the principles underlying the interpreter is necessary. There is no conceptional di erence between user added and internal functions. SLI uses a language concept very similar to the one used by the page description language PostScriptTM. It includes procedures, variables, and control structures to allow for the setup of complex simulations.

1.1.10 Discussion and Outlook

The project outlined above consists of three layers: SYNOD, SLI, and a GUI. Because the basics of the rst two layers have now reached a reasonably stable state, current work focuses on the development of a GUI. The current implementation of the language interface is purely directive, meaning that SLI sends commands to SYNOD but is unable to react actively to signals from the simulation kernel. For the described concept of a GUI, the language has to be extended in this direction. Methods have to be able to send appropriate signals to SLI. The future development of SLI in general is outlined in section 1.2.3. In SYNOD itself several aspects still have to be formalized more thoroughly. A particular problem is, that all neuron models provide di erent sets of observables. One solution to this problem is to declare a superset of all observables in the base class. This approach is called fat interface. However, a more elegant solution is desirable. Furthermore the user may want to change parameters of the neuron models at run time. Again, di erent neuron models may have di erent parameters. The main problem here is to nd a formulation which can easily be used by SLI without the need for too much run time type information. It is very tempting to use recording methods as a mean for online analysis, for example an online dot-display. Yet, this practice would not conform with the idea that simulated and experimental data should be analysed and evaluated using the same tools. A closer interaction between the simulator and an analysis tool like NDA [21] could solve this problem.

1.2. THE LANGUAGE INTERFACE

5

1.2 The Language Interface It was quite clear from the beginning that parts of SYNOD would change in future versions. This in uenced our layout of the interpreter. Moreover, the need for eciency and the level of interaction between the interpreter and the simulator will force us to add new procedures to SLI which have to be implemented in C++. Hence, adding new C++ functions to SLI should be easy, and require only very little understanding of the principles underlying the interpreter. Furthermore, there should be no conceptional di erence between user added and internal functions (e.g. the stack procedure which dumps the contents of the operand stack to the standard output). Preceding investigations showed us that in order to be able to describe complex experiments, a full scale programming language with control structures, loops, arithmetic operations, and variables would be necessary. It should be possible to build up more complex setups from simpler ones. This lead us to the conclusion that it should also be possible to formulate new procedures in the language itself. In order to keep the implementation simple, we decided to use reverse polish notation (RPN) with a syntax very similar to the PostScript language. It meets all the requirements:

 It can easily be implemented  It provides a good performance  It provides procedures, arrays and variables. A detailed description of RPN languages and their underlying principles can be found in [2],[12], and [5].

1.2.1 Problems In the current implementation of the GNU C++ compiler g++ (2.6.x), there is no consistent way of resolving templates. Without precautions, it is very dicult, if not impossible to predict, when a certain instance of a template is created and when the complete template (declaration and de nition) is needed. This situation is described in more detail in the g++ Manual, pages 164 . Several strategies are proposed to overcome this problem until it will nally be solved (announced for Version 2.7.0). We adopted the approach to control explicitely when and where a template is resolved. Each instance of a template is contained in a small le, which can then be linked into the program. The les contained in the folder templates have the only purpose to force an explicit instantiation of a given template. For this to work, the source codes have to be compiled with the compiler option -fno-implicit-templates. Hopefully, these les will become obsolete, after a consistent method of template resolution has been implemented. Error handling of SLI is still very rudimentary, but for most functions, especially the network functions, parameter and typechecking are consistently done. The string functions, however, are less safe. This necessitates careful checking of the parameters on the part of the user. Consistent error handling is more complicated in the lower levels of SYNOD/SLI. We will elaborate the error handling as soon as the exception mechanisms of C++ are more widely available. The current version of SLI does not have a proper prompt. Thus, it is sometimes dicult to see, when the interpreter is ready to receive new commands. The absence of the prompt is not an accident. It has its roots in the way the scanner - parser - interpreter - cycle is implemented. Usually the prompt is implemented together with a simple line editor in the language itself [16]. One of the next versions of SLI will provide this feature (see section 1.2.3 version 1.4.0).

CHAPTER 1. INTRODUCTION

6

Finally, we kindly request all users to report any bugs or problems, preferably with clear documentation regarding the circumstances under which they occured to either of the two email addresses: [email protected] [email protected]

1.2.2 Portability

The current version of SLI is 1.2 and can be compiled with GNU g++ version 2.6.0 or higher. We have successfully compiled SLI under SUN OS4, SUN Solaris, SG Irix, and IBM OS/2. There should be no problem in porting SYNOD/SLI to other systems, since the source is completely written in ANSI C++. It should be legal to use all features accepted by the ANSI/ISO committee ([18], section 6.2). However, also in future versions we will be much more restrictive, because currently only a few compilers support all C++ features (see [18] for a discussion of the future development of C++).

1.2.3 Future Versions

The current version of SYNOD/SLI is far from complete. Right from the beginning of its development, parts of the system have been used in research. For this reason the current state of development also re ects the needs of the ongoing research projects the authors are involved in. These restrictions provided the possibility to validate the usability of the system from very early stages of its development on. Here we want to work out a schedule for basic changes and new features in future versions. The idea is to supply the reader with some form of guideline about what can be expected and, more important, what can not be expected. However, it has to be pointed out that this schedule is not xed. Rather, it is likely that it will be re ned with every new version. Moreover, it does re ect a time table only in the sense that versions with a higher index will appear later. The SLI version index consists of three parts: x.y.z . For a new version, one of the three parameters x, y, z of the current version will be increased by one and the parameters to the right of it set to zero. Parameters will be increased according to the following rules: x:  reimplementation of major components  changes in the syntax, major internal changes y:  implementation of additional functions  xes of conceptional bugs z:  bug xes  minor extensions

Schedule of future versions 1.3.0 In this version we intend to make several smaller changes to complete and to elaborate the extensions made in 1.2.

1. Within the framework of a stack machine, error handling can be implemented in the following way: A function that detects an error pushes a name for this error on the execution stack. This name is associated with a function which handles the error (e.g. cleans the execution stack, and prints a message). The current version already uses this concept, but only a subset of the operators actually use it. Error handling will be extended to a broader range of operators.

1.2. THE LANGUAGE INTERFACE

7

2. Users are explicitly encouraged to add their own C++ written SLI-functions. In principle this can be done by rst creating an appropriate SLI-function name and afterwards, by the use of the dictionary, associating a pointer to the C++-function to it. In version 1.2 the new names have to be declared in several les. This will be made easier in 1.3 . 3. Array access. In version 1.2 we introduced the string operators get, getinterval, put, and putinterval to allow access to string elements and substrings. In 1.3 it will be possible to apply these operators also to arrays. 1.4.0 This version is mainly devoted to the improvement of the interactive mode of the interpreter. 1. Implementation of operator token. The token function takes a string from the stack and returns the rst token contained in the string and the remaining string. To implement this function a generalization of class CharBu is neccesary. From a common base class CharBu two classes CharBu File (the current class) and CharBu String can be derived. This operator allows consistent type conversion and input evaluation by providing SLI access to its own scanner. 2. A prompt and a simple line editor. With the aid of the token function and a function which reads a character directly from stdin we are now in a position to supply SLI with a prompt. The prompt will be ]t (] followed by a space). Also a simple line editor (using the UNIX termcap library) can now be de ned. The input cycle itself should be a SLI program (see [16] for an example). There are three other major additions which we have not scheduled yet. Further planning is necessary to decide about the order of their implementation:  A link to MatLab. For excessive matrix operations and more advanced numerical computations a link to MatLab's computational engine should be helpful.  A link to the NDA [21]. The analysis of data generated by SYNOD/SLI could presumably be made more easy by a direct link to the NDA program.  An LL(1) parser [5]. The replacement of our current parser by an LL(1) parser would give us the possibility to describe composite objects in a more formal way and to easily add new language constructs which can not directly be interpreted by a stack machine. For example, we can think of in x mathematical expressions (e.g. delimited by ) like . The parser builds up a parse tree which is then be read out by the (RPN) interpreter, in this example 5 3 4 add mul (see e.g. [12]).

1.2.4 How to obtain SYNOD/SLI

SYNOD/SLI can be downloaded from our ftp sites at the Weizmann Institute of Science, Israel and at the University of Bochum, Germany. These are anonymous ftp sites, but you may have no permission to read any directories, so please follow the instructions below:

SYNOD/SLI is available at

ftp cd get gunzip tar -xvf

Ruhr Universitat Weizmann Institute Bochum of Science ftp.neuroinformatik.ruhr-uni-bochum.de iris.weizmann.ac.il

name : anonymous password : your email address pub/outgoing/gewaltig pub/brain/synod synod-x.y.tar.gz synod-x.y.tar.gz synod-x.y.tar

CHAPTER 1. INTRODUCTION

8

For x.y you should substitute the rst part of SYNOD/SLI's version number x.y.z (see section 1.2.3 for the de nition of version numbers). The current version number is 1.2.0 . Beware: Since we included some binaries, this le is rather long (approx. 1MB), so make sure that the net is not too busy when you download the data. The archive le containing SYNOD/SLI and the documentation is called synod-x.y.tar.gz .

This text is also available in the same directory as sliman.ps.gz

and will be updated more frequently.

1.2.5 Copyright Restrictions

SYNOD itself is public domain and protected by the GNU license agreement. However, we presently hesitate to distribute the full source code of SLI. Maybe we will make it public domain, once it has reached a more stable state and is published to some extent. Nevertheless, we do not want to slow down research and are very much interested in the development of a GUI. This is why we organized the interpreter in a way that only a minimal portion of the source code is necessary to enable users to integrate their own C++ procedures. Because we still have to make some changes to these parts of the program, we currently distribute a compiled version without any source code.

Chapter 2

The SYNOD Language Interface This section describes some technical aspects of the SYNOD language interface (SLI). It gives full access to SYNOD's main features and allows the setup and evaluation of network simulations. SLI uses many concepts from the PostScript language. Like PostScript, SLI uses reversed polish notation (RPN) for the execution of commands. The basic commands and most of the control structures of SLI are adapted from PostScript. Additionally, SLI contains a number of structures and commands which enable the de nition and execution of complex network simulations. For a more detailed introduction into the general concepts, we refer to the "PostScript Reference Manual" [2]. Like PostScript, SLI 'consumes' a program as it reads it. SLI does not create an internal representation of the program the way procedural programing languages like C or C++ do. The state of the SLI interpreter is determined by the state of its stacks and its dictionary.

2.1 Resources There are two ways to invoke the SLI interpreter. The rst way is to start the interpreter and to enter commands directly via the keyboard. The second way is to read the instructions from a le that contains SLI commands. Such a le will be called program. The le extension used for SLI programs is '.sli'. The environment variable SLIHOME contains the default path from which SLI programs are read. If a le cannot be found in the directory speci ed in SLIHOME, a second directory, speci ed in the environment variable SLIUSER is searched. The current version of SLI is not able to handle lenames containing drive speci cations (e.g. a:/test.sli).

2.2 The Scanner The scanner reads characters from the input stream and groups them into tokens. Tokens are described in section (2.3). This section describes, how the scanner reads tokens. The scanner can be implemented as a DFA [5], with a small addition to handle balanced parenthesis inside strings where the parenthesis itself are the quotation characters. The input stream is grouped into tokens. Objects in the input stream are preferably separated by white spaces, although it is not in all cases necessary. The scanner separates two objects, whenever an unique choice can be made. Using a symbol processor (see section 2.3.4), the scanner translates the text representation of names and literal names to their terminal id. The symbol processor is also responsible for the handling of strings. First the text representation of the string is sent to the symbol processor. The symbol processor then returns an id for the string to the scanner. Finally, the scanner passes a token with type string and token value id to the parser. 9

10

CHAPTER 2. THE SYNOD LANGUAGE INTERFACE

2.3 SLI Objects SLI objects are stored in a data structure called token [4]. A token contains a particular piece of data and information about its generic type. These types are called terminals and can be one of the following: 1. array 2. beginarray Marks the begin of an array. 3. beginproc Marks the begin of a procedure object. 4. endarray Marks the end of an array. 5. endproc Marks the end of a procedure object. 6. endsymbol The end of the current input stream has been reached. 7. func C++ function. 8. i le User input stream. 9. literal Literal name. 10. manipmethod Manipulation method. 11. manipsession Manipulation session. 12. name 13. nil The NoToken, it is used internally to mark the end of arrays and procedures. Note, the symmetry between arrays and strings (see section 2.3.4). 14. null Empty token (NullToken). 15. o le User output stream. 16. proc Procedure object. 17. recordmethod Recording method.

2.3. SLI OBJECTS

11

18. recordsession Recording session 19. session Combined session. 20. string 21. double 22. long 23. xi le Executable input stream. 24. xproc Executable procedure. Some of these terminals specify begin and endsymbols of aggregate types like arrays and procedures; they are used for communication between scanner and parser. The parser hands down only a small set of all possible terminals, in particular: name, literal, double, long, string, array, and endsymbol. The remaining types are used by the interpreter. We will now describe in more detail those terminals that have a lexical representation and are used by the scanner:

2.3.1 Names Names are objects that start with a letter and may contain digits or underscores . As the word indicates, names name SLI objects. Every SLI object is assigned a name that is used for referencing this object. Some objects like les and methods can be dynamically created. Here the user has to assign an appropriate name with the operator def.

2.3.2 Literals

Literals or literal names are names which start with a slash =. They are used when the actual name of a variable is needed in contrast to its value. They are comparable to lvalues in compiler generation theory (cf. [5] and [13]). They follow the same lexical conventions as names, except for the leading slash.

2.3.3 Numbers (double, long) SLI distinguishes two types of numbers: long integers (we will call them just integers) and double oats (doubles). Numbers follow the C conventions as described in [13]. Conversions to the internal format are performed by C/C++ standard library functions.

2.3.4 Strings Strings are enclosed in parentheses (and ). They may contain any character, except for single parentheses. Balanced pairs of parenthesis, however, are possible. Line feed characters are inserted into the string. End of le (eof ) characters are not allowed inside a string. The backslash escapes nn and nt are now implemented. Nesting strings are a specialty of PostScript (and SLI). Strings are created by the Scanner (see section 2.2), or by the SLI string operators.

CHAPTER 2. THE SYNOD LANGUAGE INTERFACE

12

Examples:  (This is a string)  (This is a string (like before))  (This is a string with a line feed)

 (This is a stringnnwith a line feed)

PostScript and SLI Strings

Although strings in PostScript and SLI look exactly the same, there is a fundamental di erence between them (the same is true for arrays). In SLI strings, names and all objects which are composed of characters are handled by a single machinery: the ESP (ElementStringProcessor). The ESP can operate on strings of objects of any kind. The machine operating on strings of characters is derived from this template and called SP (SymbolProcessor). The ESP implements all low level operations on strings, controls memory allocation and garbage collection. From the point of view of the ESP, strings are unique objects, each represented by an integer value (id). Copying a string object only means to copy the integer value representing it and to increase a reference counter. Only if the ESP is asked to change a string, which is referenced more than once, the contents is copied. The ESP changes the copied string and generates a new integer id for it. All other references to the old value of the string keep the old value. As a consequence operations with xed strings like comparing and copying are fast, while access to parts of the string and the insertion of a new string are slow. An object composed of many strings, where most of the strings appear more than once (like a list of tokens) can be coded eciently. Unlike in PostScript, changes made in a copied string do not a ect the contents of other variables containing a copy of the same string. Seen from the point of view of the user: In PostScript, copying a string means to copy the pointer to it, in SLI it means to copy the contents. In SLI it is not necessary to allocate a string of xed length with the string command before using it. ESP automatically increases the size of the string if necessary, and lls unused elements with the NullCharacter which can be determined by the user. Note, the NullCharacter is not the NoCharacter which also has to be de ned by the user. The user is not allowed to use the NoCharacter because ESP marks the end of strings with it (a natural choice for NoCharacter is (char)0). The user is allowed to use the NullCharacter as a normal character ((char)32 may be a good choice).

Di erences in detail

1. There is no need for a string function in SLI. Strings are created when they are needed. For example, an attempt to insert 'A' at position 3 into an empty string () 3 65 put, results in a string of length 4. The rst 3 characters (positions 0 to 2) are lled with the NullCharacter (ttt A). 2. In contrast to the PostScript version of put and putinterval, the SLI versions return the target string. 3. In SLI there is no need for a special copy function. However, the e ect of PostScript copy function (apart from its side e ects) can be implemented by putinterval. 4. cvi and cvr are implemented, but do not work correctly in every situation. For example, string (3.3e1) cvi gives 3 and not 33 as expected (see [2]). This is because we are simply using the C/C++ input operator and not the SLI Scanner to perform this transformation. In version 1.3, where the token function (which is essentialy a call to the Scanner) will be available, we will x this problem.

2.3. SLI OBJECTS

13

COMSKEE style string operations

The PostScript style string operations are designed for strings of static size. However, the symbol processor in SLI supports dynamic strings. In a later version we will implement the two string operators of the COMSKEE language [15], taking full advantage of dynamic strings. The SLI call of these operators are: 1. string i j chskget. Returns substring string(i),-,string(j) of string, or the empty string if i>j. 2. string1 i j string2 chskput. Returns string1, where substring string1(i),-,string1(j) is replaced by string2. If i=j+1 string2 is inserted into string1 starting at position i. Note, in COMSKEE string indices run from 1 to length. However, in SLI indices start with 0 and the last index is length-1. Before an operator is executed, SLI carries out an index check. Valid indices are 1 ] exec Hello World

We see, that the procedure is pushed on the stack and is executed by the command exec. Note that, once a procedure is pushed on the stack, there is no way of examining it anymore. The output operator = is not capable of displaying the contents of a procedure object. Once the procedure is executed, it is removed from the stack and cannot be used anymore. This is a problem if we want to execute the procedure more than once. Of course, we could use the dup operator to create copies of the procedure on the stack, but this is certainly not a very ecient solution. Like any other object, procedures can be assigned to names for later and/or repeated execution, as shown in the next example: ] /MyProc ] { ] (Hello World \n) = ] } def ] MyProc Hello World

Procedure objects can be considered as subroutines. Once assigned to a name, they can be called over and over again, whenever needed. This provides the possibility to write modular programs. But beware, it is easy to create an in nite loop that traps SLI forever. So don't try the following example1 (or try it and kill SLI with [Ctrl-C]): /ProcA { ProcB } def 1

% call a subroutine

From now on we will ommit the prompt in procedure de nitions.

CHAPTER 3. SLI TUTORIAL

22 /ProcB { ProcA } def ] ProcA

% call another subroutine

% lost in space...

ProcB could have been de ned before ProcA, since procedures are just arrays of tokens. Unlike many procedural languages such as Pascal or C, SLI does not require forward declarations,. The only important rule is, that a function is de ned before it is actually called.

3.7 Loops and Control Structures Loops and control structures are commands that take procedure objects as arguments. The simplest loop is performed by the command loop: ] {(Hello World \n) =} ] loop Hello Hello Hello Hello Hello Hello Hello Hello

World World World World World World World World

loop performs the procedure repeatedly and thus in the example, an in nite succession of sentences Hello World is printed. The only way to leave a loop-structure is to execute the command exit inside the procedure. This is illustrated in the following example: ] 0 ] { 1 add dup ] loop

(Hello World \n) = 10 eq {exit} if }

It prints the ten times the sentence. First, the initial value 0 is pushed on the operand stack. The procedure adds 1 in each cycle and takes care that one copy of the counter stays on the stack to serve as the initial value for the next cycle. After the message has been printed, the stop value 10 is pushed and is compared with the counter. If the counter is equal to 10, the nested procedure is executed. This procedure then executes the command exit, and interrupts the loop. The last example can be implemented much easier, using the repeat command. repeat takes two arguments: a positive integer, and a procedure object. The integer determines how often the procedure is executed. Thus, in order to print ten times Hello World, we write: ] 10 ] { (Hello World \n) = } ] repeat

Sometimes one needs to know the counter of the loop. Also, one may want to in uence the step size of the iterations. For this purpose, SLI o ers a for loop, which is called as follows: start step stop proc for

3.8. CONDITIONALS

23

for executes the procedure proc as long as an internal counter, initialized to the start value and incremented by step, has not exceeded the stop value (please refer to reference [2] for the exact termination conditions). In each cycle, the current value of the counter is pushed automatically. This value can be consumed by the procedure. Actually, in very long loops, the counter must be removed by the procedure in order to avoid stack over ow. The following example prints the rst ten square numbers: ] 1 1 10 ] { dup mul = (\n)= } ] for

3.8 Conditionals Conditionals are used, when the execution of a command should depend on certain variable conditions, such as the state of a variable or the relation between two objects. In the last section we have already seen an example of a conditional statement. SLI o ers two commands for this purpose: 1. if if takes two arguments, a boolean and a procedure object. The procedure object is executed only if the boolean equals true. 2. ifelse ifelse takes three arguments: rst a boolean and then two procedures. The rst procedure is executed if the boolean is true, and the second procedure is executed if the boolean is false. Booleans are objects which take only one of the two values true or false. SLI o ers a full set of comparison operators and the logical operators and, or, and not. The following table shows the available comparisons and their C equivalents. All comparisons take two arguments or arbitrary type and push a boolean (true or false). SLI eq ne gt lt ge le

C/C++ ==

!=

> < >=