Scripting
To produce custom simulations or behaviors not possible using the Simbrain GUI, you can create custom scripts.
All scripts are currently beanshell scripts (there is nothing to prevent other scripting languages, but none have been implemented yet). These are basically small java programs that interact with the Simbrain workspace. Any java library can be used, as can the whole Simbrain API. This allows for a great deal of flexibility.
Some examples of things you can do using scripts are:
- Building a highly customized simulation.
- Create a custom button panel that allows users to produce special behaviors.
- Modifying an existing component, e.g. a network, in some special way.
- Logging data.
- Loading a neuron with a custom update function.
- Using an external library. The script called "GeneticAlgorithmScriptingDemo.bsh" gives an example of this.
The best way to get a feel for scripting is to have a look at a few scripts. Try opening a few in the scriptmenu directory, and running them. Try modifying them in simple ways (e.g. modifying the paramters at the top) and re-running them.
Also note that there are many basic things you'll need to do in a script that have most likely already been done in some script or another. So you can treat the script directory as a kind of repository of basic actions that you can combine together to get started with the behavior you want.
Scripting is closely related to custom updating in Simbrain. Custom update methods for the workspace or for components introduce custom update actions that are written using this same Beanshell scripting framework. See workspace update and network update.
The Basics of Beanshell Scripting
Beanshell is basically java in a form that can be executed dynamically. So rather than writing and compiling java source code, you can simply write it and run it immediately. Since it is basically java, to use Beasnhell requires that you know java. But many tasks are fairly routine and you can make them happen by modifing existing code (see the examples below).
The first thing you will often do in a script is to either (1) create objects and add them to the workspace, or (2) get access to objects already in the workspace. Objects could be networks, neurons, neuron groups, synapses, synpase groups, agents in worlds, plot components, or other components. Once you have these objects you can do various things with them.
By default, beanshell scripts have access to two objects:
workspace: the underlying logical representation of all components in Simbrain. You can add new components to the workspace, or get components and then modify them. This is the main point of access to Simbrain.
desktop: the graphical object which displays a workspace. In scripts this is mostly used to specify where components are, or how large they are.
For example, to add a neuron to a neural network component named "Network1" in Simbrain, you can create the neuron then add it to Network1:
Network network = workspace.getComponent("Network 1").getNetwork();
Neuron neuron1 = new Neuron(network, "LinearRule");
neuron1.setLocation(2,2);
network.addNeuron(neuron1);
To take full advantage of Simbrain, you will need to be familiar with the Simbrain source code, which has a great number of facilities for creating neural networks, connecting neurons together, laying them out, etc. The source if fairly well documented. See{SimbrainHome}/src
How to Invoke a script
To get started, create a new text file with a text editor, save it as a .bsh file, and then run the script from Simbrain. There are a few ways to do this:
Network: .bsh files in {SimbrainHome}/scripts/network automatically appear in the Scriptsmenu of Simbrain network components Use this directory to create custom actions that can be applied to a current network (e.g., methods of adding neurons, modifying neurons or synapses, etc.) The two objects available here are " network" and " networkPanel." These give access to the current Network and its gui representation.
Console: .bsh files in {SimbrainHome}/scripts/console are available from the Simbrain console or terminal components. The console can be useful to quickly test or debug Simbrain. For a sense of some things you can do in the console enter "help(); or "tips();". The console is similar to a UNIX or DOS terminal window. You can navigate around the file system using commands like "cd(); To run a script from the console, using the source command, e.g. source("sparseNetwork.bsh");
Coordinating Workspace Zip Files and Scripts
Sometimes it is useful to create a script that modifies the behavior of a workspace file (a .zip file). That way the script takes care of the custom behavior, and the workspace file can be incrementally modified using Simbrain's point and click methods. Examples are the actor-critic and Rescorla Wagner scripts. To edit the workspace in such a case, just run the script, change the workspace, and then save the workspace.
TroubleShooting
Often scripts won't work at first. To get feedback on errors that occur run Simbrain from a terminal, using this command
java -jar Simbrain.jar
Note that in beanshell you cannot use 2d arrays or generics.
Example: Bar Chart
To get a very basic feel for scripting, go to
Scripts > Edit/Run Scriptand, load BarChartDemo.bsh, and try modifying the parameters at the top, before running the simulation. Try this a few times to see how the parameters affect the simulation.
Example: Creating a simple network from scratch
Here is an example of a simple script to create a few neurons connected by a synapse. You can use this example to get a feel for creating a script from scratch.
To start, open a text file, copy and paste the text below, and save it as a .bsh file (for example, "SimpleNet.bsh"). Then execute the script, either using Scripts > Edit/Run Script... or by placing it in the {SimbrainHome}/scripts/scriptmenu directory and re-running Simbrain.
import org.simbrain.network.*;
import org.simbrain.network.core.*;
import org.simbrain.network.networks.*;
import org.simbrain.network.neuron_update_rules.*;
import org.simbrain.workspace.*;
{
NetworkComponent networkComponent = new NetworkComponent("Test Network");
workspace.addWorkspaceComponent(networkComponent);
Network network = networkComponent.getNetwork();
Neuron neuron1 = new Neuron(network, "LinearRule");
neuron1.setLocation(2,2);
network.addNeuron(neuron1);
Neuron neuron2 = new Neuron(network, "LinearRule");
neuron2.setLocation(50,2);
network.addNeuron(neuron2);
network.addSynapse(new Synapse(neuron1, neuron2));
}
Example: Logging hidden unit activations
To do this, you must create a custom update action. First create a network and add a Backprop subnetwork to it. Then go to
File > Edit Update Sequence.... Then click the "add custom action" button. Then copy and paste the code below in to the editor:
import org.simbrain.network.core.*;
import org.simbrain.network.subnetworks.*;
import org.simbrain.network.groups.*;
import org.simbrain.network.update_actions.*;
/**
* Log data from hidden units.
*/
{
// Object used for standard update.
BufferedUpdate bufferedUpdate = new BufferedUpdate(network);
// Customize this
this.action = new NetworkUpdateAction() {
public void invoke() {
// Log hidden unit activations
BackpropNetwork backpropNet = network.getGroupByLabel("Backprop");
NeuronGroup hiddenLayer = backpropNet.getNeuronGroupByLabel("Layer 2");
for (Neuron neuron: hiddenLayer.getNeuronList()) {
System.out.print(neuron.getActivation() + " ");
}
System.out.println();
}
// This is how the action appears in the update manager dialog
public String getDescription() {
return "Print hidden unit activations";
}
// This is a longer description for the tooltip
public String getLongDescription() {
return "Print hidden unit activations";
}
};
}
After this, when you run the network it will print out the activations of the hidden units.
Example: Custom update of a neuron
This is another example of using a custom update script, this time to do something custom to the neural activations in a network. Use the same script as above, but change the block under "Log Hidden Unit Activations" to this:
// Randomize hidden unit activations
BackpropNetwork backpropNet = network.getGroupByLabel("Backprop");
NeuronGroup inputLayer = backpropNet.getNeuronGroupByLabel("Layer 1");
for (Neuron neuron: inputLayer.getNeuronList()) {
neuron.forceSetActivation(Math.random());
}
You should also change the getDescription() and getLongDescription() methods.
This will result in the activations of the input neurons being randomized at every iteration. Changes like this can be used to customize network update in various ways.