Programs are one of the main elements of the emergent framework, providing a way of automating tasks, including controlling the training of networks, generating input data on which to train the networks, analyzing that data, and so on. They generate Css script code that is then executed (some familiarity with the C/C++ Css expression syntax is beneficial especially when doing floating point computations that also involve integer numbers (see link for details), but the GUI structuring of Programs insulates you from most of it).
Emergent comes with a library of programs for performing the main tasks associated with running a network simulation. If your simulation requires a custom step or small modification, you can often simply make a small change to the existing program. Even if you need to make a new program, you can usually start with a similar existing program, and modify it.
- 1 Program Features
- 2 Program Components
- 3 Program Library
- 4 Program Elements ("ProgEls") and Toolbox
- 5 Script Code
- 6 Compiling
- 7 Running Programs
- 8 Next up...
The emergent program system has the following features:
- full gui Program editor, makes viewing, building and modifying programs a snap (click on Edit Program tab in Program middle edit panel -- note also that you have to initiate the Find from here command within this program editor for the results to show up here)
- complete toolbox of basic and advanced program elements
- compiled source code viewer
- ability to use low-level script code
- extensive support for documenting your program
- complete error checking, and gui highlighting of errors and issues
- drag-and-drop editing of elements
A Program has the following main components -- all are optional, but most programs will typically contain at least a prog code section, and almost always some args and vars.
- objs - objects, such as datatables that are local to a specific program
- types - holds enumerations (named ints) local to the program (you will generally not need to use these)
- functions - functions that you want to call from more than one place in your program (you will generally not need to use these)
- args - parameters that can be set by the user or by another program
- vars - local variables to the program
- init code - code that is run once, each time the program is initialized - many programs will not need this
- prog code - the actual code of the program that runs when the program is invoked
From a C++ perspective, an emergent program is like a one-off class object that has:
- public static data members (objs, args)
- semi-private data members (vars) -- can read/write these but this is generally not encouraged -- prefer to keep vars encapsulated and private (but they can be used for return values or other perfectly valid uses)
- private static methods (functions) -- cannot access these in other Programs
- a single public static "Main" (prog_code)
- a public static "Init" (which isn't really a constructor, because the data is mostly static) (init_code)
The objs collection is a place where you can create objects local to a Program. For example, if you need an intermediate datatable for some calculation in your program, you could create it in the objs collection, rather than cluttering up the global data collections. Another common local object is a LayerWriter, which is used to transfer patterns from a datatable to a network layer, or a NetMonitor for monitoring values from network and other objects.
Every object you reference in a Program needs to be referenced through an argument or variable. When you create an object in the local objs collection, a variable for that object is automatically created and maintained in the vars collection, including tracking name changes.
The types collection can hold enumerated named ints ("Dynamic Enums") to help make your code clearer. You might use these to define parameters to your program that can be set by the user.
args and vars
See ProgVar for more info.
Args and vars are almost identical: they both contain named variables that can be accessed from the program. The main difference is that args can also be set externally by another program, so they can be used as parameters to a program. (You can always move a var from one of these collections to the other if you need to.) Critically, these variables are persistent, meaning that their value persists across runs of the program, and when the program is not running, so you can always see and modify the current value of the variable. This is not true of LocalVars that can be created at a more local level (e.g., within functions). This is one of the reasons that Programs cannot call themselves (either directly or indirectly).
Variables have several parameters:
- name - the name of the variable (following the naming conventions)
- Int - a 32-bit integral value
- Real - a double (64-bit) floating point value
- String - a textual string, of any practical length
- Bool - a true/false value
- Object* - a reference (pointer) to an object, such as a datatable, network, etc.
- each Object var also includes the base type of the object (the emergent program class), and a reference to an instance of that type (or a subclass of that type) - for example, the var could have a type of Layer, and then point to a LeabraLayer object, which is a subclass of Layer
- Enum - an enumeration value defined in the emergent source code
- DynEnum - an enumeration value defined by the Program, in the types section
- CTRL PANEL - show this var in the Program Ctrl panel (first page of Panels) - in general, show any variable that may need to be be set by a user, or that a user might want to observe
- CTRL READ ONLY - shows it read only, i.e. for observation only
- NULL CHECK - insures that the value cannot be empty, especially for Object variables (i.e., it must have a value)
If you change the args for a program, you need to update all the programs that call that program, so they pass the correct args. There is a button on the program (only in version 4.0.17 or higher) called UpdateAllArgs that will do this automatically. Otherwise, you can do a Find from here.. at the .programs level with the name of the program and search for all instances.
Sharing variables across programs
Each program is designed to be as self-sufficient and encapsulated as possible, which is important for making the system robust and unambiguous, and allowing programs to be copied across projects, and loaded from the program library, etc. Therefore, there is no concept of a global variable shared automatically across projects. Instead, one can insert code to directly copy values across programs. This is the oth prg var item from the program toolbox -- drag it into your code and use it to copy to/from vars in other programs (variables must have the same name in both programs, to make it simpler).
If the variable is a DynEnum, then you also have to copy the type -- there is a convenient button now on the DynEnum type that will automatically update all programs with that type information if you change it in one program.
Functions are useful for program code that is used by different parts of your program, and for encapsulating more complex code so that the main code is easier to read. Functions can only be called within the program where they are defined. If you need a given function somewhere else, just drag/copy it there. Unlike programs, functions can call themselves recursively (they have an independent stack). This also means that variables defined within a program are not persistent in the same way that variables defined in the args or vars are.
Functions have two elements:
- args -- (optional) argument values to the function -- note that you can also make an arg a reference -- this means that when you modify the value of this variable in the function, it affects the value of the variable passed in from the function call.
- fun code -- the code elements that make up the routine
The code sections are where the executable elements of your program are entered. The init code section contains code that only runs once, when the Program is initialized (pressing the Init button). The prog code section contains code that runs when the Program is Run (or called by other programs).
Emergent ships with an extensible library of Programs (prog lib) that have been designed for common network simulation tasks. When you build a network simulation using the Wizard, the proper programs are automatically imported from this library. You can keep your own personal library of programs as well.
How to create a Program from the library
- (optional) make a new group in which to put your new program
- right click on the desired group, select New From Lib from the menu
- in the dialog, choose the desired lib - the libs are categorized, and also labeled according to whether they are from the System Library or your personal User Library
a new program is added to the group, based on the library program
How to create a blank new Program
- (optional) make a new group in which to put your new program
- right click on the desired group, select New from the menu
a new program is added to the group
Program Elements ("ProgEls") and Toolbox
Most of your program building will involve two tasks:
- making args and vars (it is a good idea to use LocalVars wherever possible to keep things cleaner)
- adding and editing Program Elements ("ProgEls")
A ProgEl is a small object that represents a single step or control operation in a program. If you have done any programming or even macro building in something like Excel, then these elements will be familiar. If not, you will find they are intuitive and easy to use! Here are some of the ProgEls you will use a lot:
- meth() (MethodCall, MemberMethodCall) -- calls an operation on an object (or a member of an object) -- most of your programs will simply be calls to the underlying emergent objects, which have many powerful operations already built in.
- Misc() (StaticMethodCall, e.g., math(), random() etc) -- call a method within a collection of methods organized by various types of functionality, such as math functions, random number generation, and various data processing functions -- there is a lot of functionality here so browse through here to see what is available
- memb= (MemberAssign) -- assign an expression to a member of an object (including a full Path down from a given object)
- var= (VarAssign) -- assign a value to a variable
- if (If, IfElse) -- lets you execute some code conditionally, based on a condition
- for (ForLoop) -- lets you execute some code repeatedly, usually a certain number of times - the number can be fixed at the time you write the program, or can be an argument or variable value set elsewhere
- while (WhileLoop) -- lets you execute some code repeatedly while some condition is true
- comment - lets you put a descriptive comment in the program, to clearly document the subsequent steps - this makes understanding and modifying programs much easier
How to add ProgEls to a Program
Novice GUI Method
- make sure the Toolbox is visible (View/Dock Windows/Toolbox is checked)
- make sure your program is open in the Edit Program panel; make sure the code section or block where you want the el to go is visible (open tree branches and/or scroll the window)
- click on the tab that contains the el you want - tooltips give you a description of each el (just hover your mouse over the text)
- hold the mouse down on the el
- drag the el to:
- the code collection or block where you want it, if you want it at the end
- an existing item, if you want the new el to appear at that place (pushing the existing item down
- release the item, choose Copy Into (or Copy Here) from the menu (or Cancel to cancel the operation)
You can also use the clipboard:
- click the el you want to use -- clicking it automatically copies it to the clipboard
- go to the destination location, as above
- right click, and select Paste Into (or Paste Here) from the menu
Once the el has been added to the program, it is automatically selected. You can then edit the el's properties in the mini-edit panel at the top of the Program Editor.
Expert Keyboard Methods
In version 5.3.0, you can just hit the Enter/Return key and it will add a new line to the program, with the keyboard input focus on the code text box for a ProgCode program element -- here you can simply type in a C++ expression or the name of one of the items from the Toolbox (e.g., "new row") and it will automatically create a new program element of the appropriate type when you hit Ctrl+Return to Apply the text you entered. See Program Editor for more details on expression syntax.
You can also use the generic Ctrl+I or Ctrl+O Keyboard shortcuts to insert a program element of a given type that you choose from a list of options, and then proceed to fill in the values of that item.
In either case, use Tab to move from the program listing to the program element editor at the top of the listing, and use Ctrl+Return to move back from the editor down to the program listing. See Keyboard shortcuts for lots of other useful navigation keys.
Each el has the properties needed for that type of control element. Most els share some common properties:
- OFF -- setting this flag "comments out" the el - this is useful if you want to temporarily prevent the el from being part of the program, but would like to keep it in, either for reference (ex. you have modified a standard program) or for when you re-enable it - disabled els are shown with grey background shading in the ProgEditor
- NON STD -- this lets you mark els that you may have added or changed in a standard program - this can help you later remember how your customized version differs from the standard version
- NEW EL -- similar to NON STD, you can use this to indicate something recently added, especially to a Program that has not changed for some time
- VERBOSE -- very useful for debugging -- will print out useful info in the css console when this element is actually run
- desc - a brief textual description that is displayed in the ProgEditor - it is a good idea to describe the purpose of the el, so you can easily read the code in the ProgEditor
Many prog els have an expr field or similar, where you enter an expression. For example, in the var= element (AssignExpr), you select a variable and then write an expression for the new value to assign it to. See Css_expression_syntax and Program Expression for more info.
In brief, you can refer to other variables, perform mathematical and logical computations, call functions, access data on data tables, etc all within these expressions! The lookup var and lookup enum buttons are useful for looking up variable and DynEnum values, and even more flexible and powerful is the Ctrl-L key (lowercase l), which will use whatever you have typed prior to pressing it in the expression to then lookup relevant items. For String variables, it will show all the methods (functions) available for manipulating strings; for objects, it will show object members and methods, including going through paths, etc. It is very powerful and you can save a lot of time by learning how to use it.
You can enter new variable names and you will be prompted to add them (or go back and fix the expr if it was a mistake) -- this is an efficient way to program without jumping back and forth too much.
Programs are simply a convenient way of generating CSS script code. As you become more familiar with emergent, and want to take fuller advantage of the system, you may want to look at the generated script code. You can also use a script el to enter CSS script directly into the program.
To view the generated script code
- click on the css View tab in the program view of the middle panel --or--
- from the edit menu, select Script/View Script (in a separate dialog -- useful for comparing with program)
You can also view the script in your favorite program editor (for syntax highlighting.) Simply select Script/View Script Editor. IMPORTANT: any changes you make in this editor are NOT sent back to the emergent system - the result is for viewing only.
At this time, the emergent program system is "one way" only - you cannot edit script and use that to reverse-generate els.
Once emergent generates script code from your program, it must "compile" this code into its internal "machine code". This process is normally automatic - it happens whenever the generated script changes, at the time when you Init or Run your program. You can initiate it manually if you want, by pressing the Compile button at the bottom of the Program panel - if any errors occur, a dialog will come up and/or the errors will be listed on the console. The affected els will also be highlighted.
To run a program
- select the program
- either on the right context menu or buttons on the panel, press Init - this will initialize the program (and any programs that this program calls)
- right select or press Run
the program will start running - the cursor will change to an hourglass, and the Stop and Abort buttons will be activated
Once a program is started, it will keep running until it is finished. You can stop a running program.
To stop a running program
- either right click (in tree) or press (in panel) the Stop button
If the program keeps running, you may need to hit the Abort button. Abort is similar to stop, but forcefully stops the program. You cannot resume an aborted program (you must Init/Run again.)
To resume a stopped program
- right click or press Run
You can also "single-step" through a set of programs. This will cause the designated "step prog" to execute once, for each press of the Step button. In network simulations, the "step prog" is typically the Settle program, since that is often the smallest useful unit of execution.
The Step Css button will step one css line at a time -- best to go to the css View window when doing this -- lines also reported on the console.
To single step
- make sure the program has either just had Init or Stop pressed
- click the program name shown after the Step: label that you want to step -- you can also check the number of times to step (1,5,10) -- the chain of programs will advance by that many invocations of the program for each press of the Step button
- see Program Step for more configuration and advanced usage information.
Right click on a program element to get the Context menu -- select Toggle breakpoint -- lines with a breakpoint are highlighted in purple. When the program runs, it will stop just before this line, allowing you to examine local variables etc in the css console. The Script/Clear All Breakpoints menu option is an easy way to remove all breakpoints once everything is working.
See Program Debugging for more info..
The best way to understand Programs is by doing! So proceed to the HelloProgram tutorial.
See also the Program Tips for strategies to solving different kinds of problems.