Simple Math and Logic

In this portion of the tutorial, we will investigate most of the remaining non-LabRAD features of the LabRAD experimenter.[1] It would be helpful to start with the first tutorial to get some of the details that might be skipped over in this tutorial. You should also refer to the glossary if you encounter a term that is unfamiliar to you.

Sequences - Compute and Print

Edit Sequence

We will begin by creating a Unit that will add two numbers and print their result. Launch the Experimenter program and create a new unit of unit type Sequence titled "Compute and Print". Open up your new sequence's edit dialog. It should look like this:

Sequence_Edit_Dialog.png

The Sequence tab of the Sequence dialog allows you to manage the units to be executed by the sequence. Press the plus sign to add a unit to the sequence. Alternatively, you can press Ctrl - L - A (all shortcuts listed on the tutorial home page).

This will bring up a dialog for getting a Unit. Click the "New" button to bring up the same dialog you just encountered when creating the Sequence. Create an Action called "Print Result". Using the same process, add another Action to the Sequence called "Sum the Numbers". Your Sequence edit dialog should now look like this:

Out_of_Order.png
As it is, our Actions are out of order. Reorder them by selecting the "Print Result" Action and pressing the down arrow on the toolbar. Our Sequence is good for now, so let's leave the edit dialog. Our Root Tree, fully expanded, should now look like this, with our Actions in the correct order:
Sequence_Root.png
We have a decent start, so I am going to save the unit now, naming it "math".

Argument List

Now it remains to flesh out the Actions. Start by assigning the function standard.math.summation to the first Action, and standard.printer.printX to the second one. Now expand out the tree and notice that the "Sum the Numbers" Action does not have an "Arguments" component. Instead it has a "Argument List" component. The argument list is a python feature. It indicates that the function can receive an arbitrary number of arguments that will all be packaged into a list, called the list argument. So in this particular case the summation function will take in any number of numbers and return their sum. Bring up the Argument List's edit dialog:
Argument_List.png
By default the Argument List is in POLY mode, which means the argument list is composed of the values many inputs. The other mode, MONO, indicates that the argument list is composed of the value of a single input, which should be a collection of some sort. We want the POLY mode, so ensure that this is selected.

Since we want to add two numbers, we need to place two inputs into this Argument List. Press the "+" button to add an input. This brings up a dialog which asks which type of input you would like to add. For the first input we want a new Input, so select 'New Input'. See the new Input now in the Argument List, initialized to a null value:
Argument_List_with_Input.png

Globals

We now want to add a Global to the Argument List, but we need to create this Global elsewhere, so close the Argument List edit dialog. Find the Globals widget on the main screen. It should be here:
Globals_Widget.png
Though it is possible that the Globals widget is floating or hidden. If it is hidden, toggle the 'Globals' option in the 'View' menu. You may want to undock the widget for better visibility.

Add a Global by pressing the '+' button. You can edit the fields just like an excel document. Change the name to 'Offset', initialize the value to 3, and leave the description blank. The Globals widget should now look like:
Globals_Widget_with_Global.png
Now that we have a Global, return to the edit dialog of the Argument List in the summing Action. Add an input to the Argument List, this time selecting 'Global' from the drop down menu. You get a list of the all the current Globals (which is only one right now); double-click the one titled 'Offset'. Our Argument List is updated to include the new Global.

Results

To finish the summing Action, we only need to give a numeric value to the first input in the Argument List. You can't edit the inputs from the Argument List edit dialog, so we can close it now.

Bring up the edit dialog for the Input in the summing Action's Argument List. Give the Input a value of 5, similar to the way we assigned 'Hello, world!' to the value of the Input in the first tutorial.

If you like, you can also rename the Input to something memorable and useful using the 'Name' tab of the edit dialog. Choose something descriptive like 'Summand'. Close the edit dialog.

Now, we would like the result of the summation performed by the first Action to get printed to the console when we execute the second Action. When an Action is executed, the function's return value is stored in an input called the Result, which is a Component possessed by Actions. So we would like the Result of the first Action to be passed to the 'toPrint' Parameter of the second Action:
Result_Diagram.png
Open the edit dialog of the 'toPrint' Parameter to make the connection. Right now the Parameter's input attribute is an Input (initialized to None). Select 'Change Input'. This brings up the same input selection dialog that we encountered when we edit the Argument List. We want to select an input that alright exists in the Root tree, so we select 'Old Input' from the drop-down menu, and hit 'Get'. This brings up a new dialog which shows the Root tree:
Old_Input.png
The 'Current Input' button cycles through every reference to the Parameter's current input (colored in blue) in the Root tree. The 'Next' button cycles through every input (colored in red) in the Root tree. The tree is still pretty small, so we can just navigate manually through the tree until we reach the 'Result for Action: Sum the Numbers' entry:
Sum_Result.png
Double-click the Component to select it. The 'input' tab of the Parameter dialog is updated with our new selection. Close the Parameter dialog, and open up the edit dialog for the summing Action's Result. Go to the 'view' tab:
View_Tab.png
The 'Next match' button cycles through every instance of the Result in the Root tree, while the 'Result Action' button cycles through every reference of the Result's Action in the tree. Click 'Next match' a couple times to confirm that this Result is now located at two different places in the Root tree:
  1. Directly under the summing Action
  2. Directly under the print Action's 'toPrint' Parameter
This 'sharing' of inputs between different Components allows the Experimenter to perform many of the functions typically reserved for conventional, typed programming languages.

Execute

Our Unit is now ready for execution. Bring up the root Unit's execution dialog from the 'Execute' menu.

As we click 'Next', we get the following:
  • The Sequence is highlighted, indicating that execution of the Sequence is about to proceed.
  • The first Action is executed, where its display text is updated to display the new value of the Result, which is 8 if we've done everything correctly (3 + 5).
Execute_Result.png
  • The progress indicator of the Sequence is updated, now showing that it has completed the first of two total steps.
  • The second Action is executed, which prints '8' to the console.
  • The Sequence indicates that it has completed all steps.
  • Since the Sequence is the top level Unit, execution is complete.

Exit the execute dialog, and try changing the value of the 'Offset' Global (try a floating point value, for instance) and see the execution change accordingly. Save the Root Unit.

Scans - Set, Compute, Print, Set, Compute, Print,...

Clipboard

Now we would like to scan over the Sequence we just created. That is, we want to place a Scan as the Root Unit, and assign the Sequence as the Scan Unit.

Drag the Sequence into the Clipboard to place it into storage:
Drag.png
Now create a new Scan, by selecting 'New Root' from the 'File' menu. Select Scan as the Unit type and name it 'Compute over range'. Expand out the tree and your screen should look like this:
Scan_Root.png

Scans

The Scan we can see possesses three children (in order):
  • Scan Unit - The Unit executed for each value in the Scan. In this case it is an empty Sequence.
  • Scan Range - The collection of values to scan over. See the glossary definition for more details.
  • Scan Input - A Label that holds an Input whose value attribute is set to each value from the Scan Range.

When a Scan is executed, it performs the following steps:
  1. Set the Scan Input to the next value in the Scan Range.
  2. Execute the Scan Unit
  3. Goto step 1

Execution ends when there are no more values in the Scan Range.

Scan Unit

As we said, we want to scan over the Sequence we just created, so to change the Scan Unit we need to open up the Scan's edit dialog:
Scan_Edit_Dialog.png
We can see that the default empty Sequence ('Unnamed Sequence') is currently our Scan Unit. We want to retrieve our Sequence from the clipboard, so click 'Clip board'. This will bring up a view of the Clipboard. Double click the Sequence to assign it as the Scan Unit. The edit dialog is updated with the 'Compute and Print' Sequence displayed as the Scan Unit.

Scan Input

Next we want to connect the Scan Input to the Input residing in the summing Action's Argument List. Expand out the Scan Unit tree and find the Input we're looking for:
Scan_Input.png
Double click on the Input and see that it turns red - this indicates that you have just set it as the Scan Input. You can also find the current Scan Input by clicking the 'Scan Input' button, which is disabled if the Scan Input isn't inside of the current Scan Unit.

We are done configuring the Scan Unit and Scan Input, so you can close the Scan edit dialog now.

Scan Range

Now bring up the Scan Range dialog:
Scan_Range.png
It looks similar to the Argument List edit dialog, but with a couple more modes. Consult the glossary definition for information about all the modes. For this tutorial, we want to use the STEPS mode, so select the 'STEPS' radio button. Note that the Component list is updated with the Parameters specific to the STEPS mode. To configure the individual parameters we need to use their individual edit dialogs, so we can close the Scan Range dialog.

Let's say we want to scan over a range of 6 steps evenly spaced between -5 and 5:

-5, -3, -1, 1, 3, 5

In the STEPS mode this is easy; simply set the parameters' Inputs as follows:

Start → -5
End → 5
Steps → 6

For fun, let's set the input for the Start Parameter to be a new Global, name 'Starting Point'. You already know how to do this, so I won't go through how. When you are done your expanded tree should look like this:
Scan_Expanded.png

Execute Scan

Our Scan is ready to go! Before we do anything else, let's save our Scan, naming the file 'testscan.lre' (extension automatically appended). Bring up the Root execute dialog (from the Execute menu). As we step through the Scan (by clicking the 'Next' button), we observe the following:
  1. Scan is about to begin
  2. 1st step of Scan in progress; Sequence about to begin.
  3. 1st step of Sequence in progress; summing Action returns -2.0.
  4. 1st step of Sequence completed.
  5. 2nd step of Sequence in progress; printing Action returns null.
  6. 2nd step of Sequence completed.
  7. 1st step of Scan completed.
  8. 2nd step of Scan in progress...

So on and so forth, until the Scan completes. You can press the 'Run' button to have the Unit execute continuously. There's no time-intensive operations here, so execution should complete almost instantly. If all goes well, you should see in the console:
-2.0
0.0
2.0
4.0
6.0
8.0
Try messing around with the 'Starting Point' Global and see what happens.

Flow Control - Negative Number Warning

To finish off this tutorial, let's print a warning to the console if the summation produces a nonpositive number (which we encountered in the first and second summation performed in the previous Scan).

So, to get everything straight, here is what we'd like to do in the Sequence:
  • Perform the summation
  • Print the result IF the summation is positive, ELSE print a warning

Conditionals

To do this, let's add another new Unit to the end of the Sequence (using the Sequence edit dialog). Select 'Conditional' for the Unit Type, and name the Unit 'Print warning if negative'. Close the Sequence edit dialog, and expand out the Conditional in the Root tree:
Tree_with_Conditional.png
So the Conditional has three children:
  • A Label holding a Unit that is executed if the condition evaluates to true
  • A Label holding a Unit that is executed if the condition evaluates to false
  • A Parameter holding an input whose value attribute is the condition

Maps

Let's work on the condition Parameter first. We want the Parameter's input to evaluate to True when the Result of the summing Action is greater than zero, and False otherwise.

Technically, we could accomplish this task by doing the following:
  • Create an Action that performs this logic function
  • Place it before the Conditional in the Sequence
  • Connect the Action's Result to the condition Parameter.

However, this logic computation isn't really part of the 'flow' of the Sequence; to place it in the Sequence would obscure the Sequence's purpose. It is better here to use a Map. A Map is identical in from to an Input, except that a Map executes a function when its value attribute is requested. A Map can well be thought of as a mix between an Input and an Action.

Open up the 'Condition' Parameter's edit dialog, and replace its current input with a new Map (by selecting 'Map' in the drop-down box). Close the edit dialog and open up the dialog for the new Map we created. In the 'Map' tab we see a function assignment widget identical to the one we see for Actions. Click 'New Function' and select standard.logic.greaterThan. Close the Map's edit dialog.

Connect the summing Action's Result to the 'x' parameter. Assign the number 0 to the value attribute of the Input already inside the 'y' Parameter.

True Unit
Our Sequence isn't quite right. As it is, the result of the summation will get printed whether or not the summation is positive. We want to place the 'Print Result' Action inside the 'True Unit' Label of the Conditional. To do this, let's start by dragging the 'Print Result' Action to the Clipboard.

Labels (as you may have discovered with the Scan's 'Scan Input' Label) can't be edited; their contents is managed by the Label's parent. In this case the Label's parent is the Conditional, so let's open that up:
Conditional_Edit_Dialog.png
Making sure that we have the 'True Unit' tab selected, click the 'Clip board' button and double-click the 'Print Result' Action to assign it as the Unit to be executed when the condition evaluates to true.

False Unit

Now click on the 'False Unit' tab. Create a new Action, called 'Print Warning'. Your 'False Unit' tab should now look like this:
False_Unit.png
Close the Conditional edit dialog, and perform the following steps:
  • Assign it the standard.printer.printX function to the new 'Print Warning' Action
  • Expand the warning Action and assign a value of "WARNING: Negative number detected!"[2] (including quotations) to the 'toPrint' Parameter's Input

Conclusion

We are almost done! It only remains to remove the 'Print Result' Action from the Sequence, since we now have it in its proper place inside the Conditional.
Once you have done that, the expanded Root tree should now look like:
Complete_Scan.png
Using the 'Save as...' menu item, rename our current file to 'conditionalscan.lre'. Now run the experiment and confirm that you get:
WARNING: Negative number detected!
WARNING: Negative number detected!
2.0
4.0
6.0
8.0
Congratulations! You've covered almost all the features of the Experimenter. The LabRAD features are all fairly straightforward, just connect and start using LabRAD settings instead of local functions.
  1. ^ Completed .lre files for the three subtutorials in this tutorial are listed here:


  2. ^ Granted, 'nonpositve' should be used instead of 'negative', but you get the point.