Upload
others
View
3
Download
0
Embed Size (px)
Citation preview
1 INTRODUCTION
ScienceSuit is a scientific computing environment mainly aimed for scientists and engineers.
Among the many, some of the features:
• Similar to Excel™, the built-in Workbook can be used to format, open/save, import/export
data. It is well integrated with the workspace.
• The powerful command-line supports code-completion and context-based help. The
command history keeps all the commands typed to enable access again.
• Charts can be plotted using commands and/or the graphical user interface.
• The Image Processing Toolbox helps to quickly analyze color of images by drawing different
types of shapes. Besides quickly obtaining essential statistics, it is tightly integrated with the
workspace.
• Many Apps are there to assist you to analyze statistical or process data by just using the
mouse-clicks.
• The built-in script editor supports auto-completion, smart-indenting, find/replace,
undo/redo, quick access to recently opened files. It is also tightly integrated with the
workspace.
• The built-in std library contains over 100 functions and also there are several data structures
for matrix decompositions, numerical analysis, statistical distributions and tests, essential
statistics, engineering operations and many others to help you save significant time and
effort.
• Build apps and easily integrate to the framework.
ScienceSuit is mainly programmed in modern C++ and also embeds Lua scripting language. Most
of the core functions and data structures are programmed in C++. The functions and data structures
written in Lua are open source.
ScienceSuit’s design is inspired by Excel™ (including VBA) and Matlab™ and to some extent by
R and Minitab™. The framework uses the following well-known and stable libraries:
• OpenCV,
• Eigen,
• Boost,
• wxWidgets,
• IUP.
More information can be found on http://www.sciencesuit.org or https://www.sciencesuit.org/.
2 WORKBOOK
As seen in the following figure, ScienceSuit supports working with many workbooks
simultaneously. Each workbook can contain several worksheets and each worksheet can contain
several ranges. Except the deletion of a worksheet, the workbook supports undo/redo for all
operations.
2.1 Saving / Opening
The data in a workbook can be saved, as .sswb format, which is a collection of XML files bundled
into a zip container, to be opened later on. When opening an .sswb file, there are two possible
approaches:
Running ScienceSuit first and then opening the file via Open button located at Workbook ribbon
page. Using the file manager provided by OS. For this, the IPCPORTNUMBER must be set to a
valid number.
2.2 Formatting Cells
As shown above, data in a worksheet can be formatted and the formatted data can be copied to MS
Excel. The formatting panels are shown below:
Following are the possible formatting options:
1.Font: Family, size, color, style (italic), decoration (underline) and weight (bold).
2.Color: Background color
3.Alignment: Vertical (bottom, center, top) and horizontal (left, center, right)
The panel will automatically be updated with the format of the active cell.
2.3 Selection of Cells
Once a valid data range is selected, the dimension of the selection and some essential measures of
the data is immediately shown to the user at the status bar.
Depending on dimension of the selection selection (compare Fig A with B) clicking the right button of
the mouse will show a menu to allow the user to create variables (such as Vector, Matrix, Array, Range)
which can be manipulated by command-line. This feature brings a significant convenience when
working with data sets.
2.4 Copy/Paste
Although, within a Worksheet, the selection can be moved/copied to another location using the
mouse, the selected data set in the worksheet can also be carried to a different location or to a
different worksheet using copy-cut/paste options.
Regardless of the dimension of the data, if "Copy/Cut" is selected, 3 different formats are loaded to
OS's clipboard (Free Clipboard Viewer is a useful tool to inspect the available formats of the data
in the clipboard):
1. HTML Code: Which provides convenience to embed in an HTML page.
2. XML Code: When the data is pasted ScienceSuit parses the XML code and formats the data
accordingly.
3. Text Code: Tab separated format.
Besides the "regular" copy command, Workbook also supports copying a range as bitmap using
"Copy As Image" as shown in the following figure:
Copying a range such as shown in the following figure (Fig A) will produce an image similar to Fig B.
It is seen that the format and alignments are preserved.
(A) (B)
Upon using the "copy" command, there are 3 paste options as seen in the following figure:
1. Directly clicking the Paste button will paste values and format
2. Selecting "Paste Values" will only paste the values.
3. Selecting "Paste Format" will only paste the format. Therefore, any value entered in the pasted
region's cell will have the similar format from where it was copied.
2.5 Inserting/Deleting Rows and Columns
By default, a Worksheet contains 1000 rows and 100 columns. In order to insert or delete rows or
columns, at least 1 row or 1 column must be selected. Right-clicking with the mouse will show the
following menu:
For example, if n rows are selected, then n rows will be inserted or deleted. Similar rational holds for
columns as well.
2.6 Tokenizing Text
Every now and then we need to separate (tokenize) data in a text to be able to use the particular data
entries separately. However, in a text the data is combined by many delimiters, such as tab, comma etc.
For example, observe the data that is in a text file (such as Notepad) shown in the following figure. Here,
if we would like to have, and most of the time it is indeed useful to have, "student" and "score" in
different columns in a worksheet, then we need to tokenize the text.
Notice that the data is mostly separated by tab characters
except “A,B” which is separated by comma.
In cases, where text needs to be tokenized, ScienceSuit will show a wizard as shown below. Each line
in the text will be written in a row, such as first line to row 1, second line to row 2 and so on.
In the above figure, although the initial outlook looks fine, we observe that "A,B", which is separated
by comma, is not separated as the main tokenizer is the "tab". If we change the main delimiter from tab
to comma then we will have the following outlook:
Note: For convenience of visualization, when data is separated by tab characters and the main delimiter
is different than the tab, the tab characters in the text are replaced by space characters. Otherwise we
would have seen the entry, the second row, "1 18" as "118" which would have made it difficult to make
any inferences.
“Tokenize the Whole Text Using
Delimiter”:
The selected delimiter will be used to
tokenize the whole text file.
If a different delimiter is selected, then
the text will be separated based on the
newly selected delimiter and the outlook
of the grid will also change.
Note that, although this time “A, B” is
separated well, the rest of the text is not well
separated at all.
Let's go back to the initial selection and select the delimiter as "tab" and select the cell containing the
text "A, B" and then right-click. As shown in the following figure, a menu will pop-up:
If we select the comma option for this particular cell, then the content of the cell will be separated by
using comma and each separated text will be inserted starting as of the selected cell’s column’s
position.
The idea can be applied to any cell containing text. Therefore, we have full control over the text. After
separating using comma, we will have the following:
Once the OK button is clicked, a new Worksheet will be added with the name “data.txt”.
2.7 Import & Export Data from/to Files
Data files can come in different formats and it is essential to be able to import to/export from ScienceSuit
workbook.
2.7.1 Import Data
When data is imported, ScienceSuit will add new worksheet(s) to the active workbook. If there is already
an existing worksheet with the same name, the current date will be appended to the imported
worksheet’s name.
The import and export functionality is located under “Workbook”
Ribbon Page.
In order to import a file, on the
Workbook ribbon page, click
Import button. This will show the
following dialog box:
As shown in the following image, currently there are 3 types of files that can be imported:
2.7.1.1 ScienceSuit Workbook
The difference between opening and importing ScienceSuit workbook is when imported the imported
Workbook’s worksheets will be added to the current active Workbook. However, when opened, a new
workbook will be opened.
Tip: If you want to work only with a single workbook at a time, instead of opening a workbook,
importing it will be more convenient.
2.7.1.2 CSV Files
CSV files are among the portable file formats among different software and operating systems. For
example, if you have data in Excel as shown in the following figure:
If it is exported as CSV file using Excel (filename is Book1.csv), then it can be imported using
ScienceSuit as seen in the following figure:
Notice the existence of non-ASCII characters, such as μ.
Notice that the Worksheet name is
automatically assigned as the filename.
2.7.1.3 Text Files
Similar to CSV files, text files are among the portable file formats among different software and
operating systems. For example, data in a text file (such as Notepad) is shown in the following figure:
Unlike CSV files, in which separation is well-defined with a single delimiter, in text files, the data can
be separated by many delimiters, such as tab, comma etc. Therefore, when you import a text file, initially
an import text wizard is shown (please see tokenizing text for more details).
2.7.2 Export Data
When data is exported to an external resource, it is exported from the active Workbook’s active
worksheet.
2.7.2.1 Text Files
When data is exported from the active worksheet, the relative positions of the cells are preserved;
however, the absolute position is not. Therefore, a more compact text file is obtained. For example,
consider the layout in the following worksheet:
Notice that the data is mostly separated by tab characters
except “A,B” which is separated by comma.
Once the text is tokenized, a new Worksheet will be
added with the name "data.txt" as shown in the figure:
After exporting Sheet 1 as text file and opening it with Notepad, the following layout will be observed:
2.7.2.2 CSV Files
Similar to text files, when data is exported as CSV, the relative positions of the cells are preserved;
however, the absolute positions are not. Should the absolute positions be preserved, a single data point
in a worksheet might have caused large file size when exported.
Note that, although the relative positions of the cells are
preserved, the absolute positions are not.
For example, B4 is placed directly at the first column in
the notepad.
After exporting Sheet 1 as a CSV file and then
importing the CSV file using Excel, will lead to the
following layout:
Consider the layout of cells in
ScienceSuit:
2.8 Importing Data from Workspace
It might sometimes be needed that after performing some calculations the variable holding the data
should be saved or visualized in Workbook or exported to some other file. Importing the variable from
workspace to the worksheet also enables analyzing the variable(s) using the apps.
Although this could have been done using some scripting and the functions provided by std library, it is
not convenient to do so every time.
The variable name must be relative to the global table. For example consider the following table
declaration:
>>var1={a=1, b=2, 3}
If you would like to import contents of var1, then the variable name entered should be var1.
However, in the following case, var2 is a table inside another table, namely tbl:
>>tbl={}
>>tbl.var2={x=1, y=2, z=3}
if you would like to import contents of var2, then the variable name entered should be tbl.var2.
Notes:
1. The variable types that can be imported are Lua tables and userdata. Import tool handles
tables and userdata differently.
2. The depth of the import goes only single level. For example, if you have a variable such as
level1={a=1, b=2, level2={x=3, y=4}}, the import tool will not import contents of level2
and will mark its as a “table”. However, contents of level1 will be imported as shown in the
following figure:
Clicking import button shows two options as shown in the figure: 1)
From File and 2) From Workspace
After selecting the “From Workspace”, the following dialog is
shown:
2.8.1 Lua tables
2.8.1.1 Simple tables
By simple tables, it is meant that, tables without any metamethod. For example:
>>simple={a=1, b=2, c="a string", 3, 4}
The table, namely simple, will be imported as shown in the following figure:
2.8.1.2 Tables with metamethods
When a table have metamethods, there are two types of scenarios that can happen:
Case 1: __tostring() function not implemented:
Consider the following table, namely tbl, implemented as follows:
>>tbl={a=1, b=2}
>>meta={}
>>setmetatable(tbl, meta)
>>function meta:__name() return "justtable" end
Note that, contents of level2 is just shown as
“table”.
If you would like to import contents of level2, then
you would have entered the variable name as
level1.level2
Column A: The keys of the table
Column B: Corresponding values to the keys.
Note that the numbers 3 and 4 in the table, do not have
explicit keys, but keys have been assigned to these
values automatically.
Here, we can see that the table, namely tbl, has a metatable, namely meta and has implemented a single
metamethod, namely __name().
However, since __tostring() metamethod is not implemented, if we attempt to import the table, tbl, an
error message will be issued and nothing will be imported.
Case 2: __tostring() function implemented
Behind the scenes, the Food data structure is actually a Lua table with many metamethods. If we create
a Food variable, namely food, as shown below (for brevity only 2 metamethods is shown):
>>food=Food.new{CHO=80, water=20}
>>getmetatable(food)
__tostring=function
__name=function
and notice that the __tostring metamethod is implemented. Therefore, if we import the variable food, it
will be imported as shown in the following figure:
2.8.2 Userdata
Two userdata types, namely Vector and Matrix are handled specially. For the other userdata types, if the
userdata implements __tostring() metamethod, the string returned by the __tostring() will be imported.
Otherwise, an error will be issued.
For example, behind the scenes Workbook data structure is actually of type userdata with metamethods
implemented. If we create a variable, namely wb, of type Workbook:
>>wb=std.activeworkbook()
>>getmetatable(wb) -- shows the metamethods implemented by Workbook
If __tostring() metamethod uses “\n” for to
separate the lines then each line will be written on
a row as shown in the figure.
and then import the variable, namely wb, it will be imported as shown in the following figure:
2.8.2.1 Vector
Only the Vectors with a size less than 100 000 elements can be imported. When the elements of the
vector are imported to the workbook, contents of the vector will be written to cells in a row-fashion, for
example, first 100 elements to column A, second 100 elements to column B and so on.
Consider the Vector variable, namely vector, which has
10 elements:
>>vector=std.rand(10)
Figure shows the contents of the variable, namely
vector, when imported to a workbook.
Now consider another Vector, again namely
vector, which has 325 elements (bigger than the
previous):
>>vector=std.rand(325)
When imported an extra information is
printed on the worksheet.
2.8.2.2 Matrix
Only Matrix with number of rows≤1000 and number of columns≤100 can be imported. Unlike Vector,
there is no special pattern to import a matrix.
>>matrix=std.rand(4, 3)
2.9 Converting Text to Columns
It is useful when you have text in the rows of a column and you wish to separate the text to multiple
columns.
Select the rows you wish to tokenize
and click on the “Text to Columns”
button in the Workbook page as
shown:
This will show the following wizard
(please see the Tokenizing Text section for
more information)
When imported, the variable, namely matrix,
will be imported as shown below:
For example, say, as shown in the figure you have the rows of text
in a worksheet. To be able to separate the above shown text into
columns:
3) After tokenizing the way you wish, it will be converted to multiple columns, possibly, as shown
below:
Finally, please note that, before converting the text to multiple columns, if you already have data,
say in B1, then a confirmation would be required, as shown below, before overwriting the existing
data.
2.10 Remove Duplicates
It is useful to remove multiple entries in the rows of a single or multiple columns. At the end of the
operation unique rows remain and duplicates are removed. Although the meaning of duplicate is
intuitive, it is useful to solidify it with a couple examples cases.
Case 1: Selection of a single column
This is the simplest and most intuitive case. In the following image, notice that 1 is duplicated.
Note: Initially the selection was tokenized using the
comma delimiter and then the cell A3 was selected and
was tokenized using equal sign delimiter.
Clicking on “Remove Duplicates” button will remove the
duplicates in the selected column.
After removal an information message will be displayed as
“1 entry has been deleted”.
If confirmed, the data in cell B1 will be
overwritten, otherwise, the operation will
be canceled.
Case 2: Selection of multiple columns
Here, the idea will be demonstrated with 2 columns; however, the same idea is applicable to any
number of selected columns. In the figure below, two columns have been selected and we would
like to remove the duplicates.
After removal of duplicates, the remaining rows are shown below:
Pitfall: When comparisons are made, the values in the cells are considered as strings.
Notice that we have 3 A’s in the first column.
As seen below, 1 is removed as it was duplicated.
Although initially we had 3 A’s, only 1 A has been removed
and 2 A’s remained. Had we selected the first column only 2
A’s would have been removed. However, by selecting two
columns we pair the consecutive cells, therefore, the data in
first row is considered as (A,1) and in the fifth row as (A, 10).
Since the data pairs (A, 1) and (A, 10) are different, it was not
considered as a duplicate. The rationale is extensible to n-
tuples.
3 COMMAND-LINE
Command-line is handy for many computations and also rather useful to isolate and test parts of a
script.
3.1 History file
At the very first session a history file (.shist) is created and upon exiting ScienceSuit the commands
are recorded to the history file. During any session by using the up and down arrow keys it is
possible to find the previously executed commands.
3.2 Auto-completion and help
The intelli-sense feature of command-line offers the correct parameters whether it is a library or a
data structure and filters the list as the user continues typing.
As seen above once a composite data such as std, followed by a “.” or “:” is typed, the contents will
be listed and will be shown with the following signs:
• Tables: {}
• Function: f
• string: s
• number: n
Continuing to type after the auto-complete dialog is shown will filter the contents of the auto-
complete dialog to be able to find the exact match. Selecting any of the list item, will show a help
if there is one help file associated with the item. Currently, there is help associated with
approximately 180 functions.
3.3 Variable scope
The variables created via command-line are directly placed in the global table. Therefore, if a
variable is created using the keyword local, that variable will not be accessible anymore.
>>a=3
>>local b=2
>>c=a+b
[string "c=a+b"]:1: attempt to perform arithmetic on a nil value (global 'b')
By printing out the variables, we can easily see why the error was thrown.
>>a
3
>>b
nil
The intelli-sense feature also recognizes the type of the
variable and offers the code-completion accordingly.
4 PLOTTER
ScienceSuit allows you to plot either using commands or by just using the graphical user interface
(GUI). Furthermore, all formatting can be done conveniently using the GUI.
There are different variations of scatter plot in ScienceSuit and can be found under the “Home”
ribbon page as seen in the following figure.
4.1 SCATTER CHARTS
Scatter charts are very useful to show the relationship between different sets of values.
4.1.1 A Simple Chart
There are different strategies that can be followed to plot a chart. Here, a few possible strategies
will be presented.
A) From an already Existing Selection:
Let’s assume you have the following time and temperature data:
1) Enter the data to a worksheet.
2) Select the data as shown in the following
figure:
3) Click on any of the “Scatter Plots” button
to plot the chart.
Done! A chart window will be shown
with the data points.
B) From A New Selection:
If you click any of the plot buttons without making a valid selection, an empty chart window will
be shown as below:
Selecting “Add New Series” will show the following dialog:
At this stage, all menus are disabled. The only
option available is to right-click and then select
the “Add New Series” menu.
Type: The type of the series to be plotted. Note
that on the same chart, different type of series
can be plotted.
Name: Name of the series. This field cannot be
blank.
X and Y Data: The range where X- and Y-data
are located.
C) Using Commands:
Depending on the nature of the process, it can be significantly more convenient to generate data
points using commands and to plot them on the fly than using the steps described at section A&B.
Suppose you are to inspect the plot F-distribution for degrees of freedom of 3 and 5. Using
commands this can be achieved quickly.
Once the “OK” button is clicked with the
above-shown options, the chart window
will be displayed.
The code to generate the shown
graph:
>>x=std.sequence(0, 4, 0.1)
>>y=std.df{x=x, df1=3, df2=5}
>>std.plot(x,y)
1
4.1.2 Updating Series
Updating a series simply means that changing its name and its data. However, in order to change
the data, the series must be plotted via a selection. The data of the series generated by commands
cannot be updated.
For example, in the following figure, Series 3 is generated by commands and Series 4 is generated
by a selection. For both series, the names can be updated; however, for only Series 4 the data can
be changed and updated.
4.1.3 Deleting Series
When there are more than one series on the same plot window you will have the option to delete
any of them should you wish to do so.
1) Right-click on the series to be deleted (this will also select the series).
2) Simply select the Delete option.
4.1.4 Multiple Series
There are different ways to plot multiple series on the same plot window. Here, the most common
approaches will be presented.
A) Only By Selection:
Assume you have made the following selection in a worksheet:
After the selection, once any of the scatter plot button is clicked a chart comprised of two series will
be displayed as shown below:
When more than 2 columns are selected, the
first column is assumed to be the x-component
and the second, third and nth columns are
assumed to be the y-components of the data
sets. Therefore, the data sets are made of
[x, y1], [x,y2]… and each data set generates a
different series.
B) Using Only Commands:
In order to plot multiple series using only commands, std.holdon (section 8.5.2 ) needs to be used.
Suppose you want to plot F- and normal distribution on the same plot window.
C) Selection & Command
Whether the chart window is generated via a selection or through a command, after then either
selection or command can be used to add another series on the generated chart window.
1) Obtain a chart first using commands:
The command sequence that generated the
chart:
>>x=std.sequence(0, 4, 0.1)
>>y=std.df{x=x, df1=3, df2=5}
>>std.plot(x, y, "f dist")
3
>>y=std.dnorm{x=x}
>>std.holdon(3)
>>std.plot(x, y, "normal dist")
>>x=std.tovector{0,1,2,3}
>>y=x^2
>>std.plot(x, y, "y=x^2")
1
2) After clicking “Add New Series”, Add Series dialog will appear. As described in section 4.1.1 ,
make the necessary selections.
3) Click “OK” button and a new series will be added to the same plot window as shown below.
4.1.5 Formatting & Changing Series Type
Line Properties:
Color: Color of the line
Thickness: Thickness of the line (in pixels). If thickness of the line is 0, then the line will
disappear and all controls except the line thickness will be disabled.
Smooth line: When the thickness of the line is greater than zero, straight lines will connect
each data point. If a smooth line is desired, “Smooth lines” should be checked.
Marker Properties:
Marker Type: Shape of the marker to be displayed. Currently, circle, square and triangular
markers exist.
Size: Size of the marker. For example, for a circle, it is the radius of the circle in
terms of pixels.
Line Color: Color of the line that forms the boundaries of the shape.
Line Thickness: Thickness of the line (in pixels) that forms the boundaries of the shape. Note
that, line thickness upper limit is bound by the size of the shape.
Fill Color: Interior of the shape, excluding the boundaries.
1) Right-click on the series to be formatted (this will also select the
series).
2) Select the Format option. This will show the following dialog.
The Format dialog has two
pages to be able to format Line
and Markers.
If a series has only markers,
then all but the line thickness
will be disabled. Similar
rationale holds for Markers.
Each time a property is changed, the effects will immediately be seen on the chart. Therefore, it is
very convenient to format the chart to a desired style.
Switching between different scatter chart types is rather convenient too:
• Setting line thickness to zero will make lines disappear and setting it greater than zero will
make lines appear.
• Checking “Smooth line” option, will apply smoothing algorithm to the existing lines.
• Setting marker thickness to zero will make markers disappear and setting it greater than
zero will make markers appear.
Please note that, it is not possible to set line thickness and marker size to zero at the same time. The
rationale for this is that a series must be represented at any time either by a marker or a line or both.
4.1.6 Axis Options
The plotter allows changing axis options (horizontal or vertical). Here, changing the properties of
the horizontal axis will be presented. Similar steps are followed to modify the properties of the
vertical axis.
2) The following dialog will be shown:
1) Right-click on the horizontal axis and
select “Format Horizontal Axis...”
Let’s modify as follows:
Bounds → Minimum: 2 Maximum: 5
If you right-click on the horizontal axis again and select the “Format Horizontal Axis...”, the dialog
will be shown as follows:
The bounds (minimum, maximum), major unit and
the value at which horizontal axis crosses vertical
axis are shown.
It is seen that the data is “filtered” to contain
only the points between the newly chosen
scale.
4.1.7 Plot Window
The chart resides in a plot window. The plot window title and menu bar are shown in the following
figure:
On the title bar, the Chart ID is displayed, which is 1 for above-shown figure. The chart ID is
important as it is the ID that must be used when calling std.holdon function (section 8.5.2 ).
The size displayed (651×601 px) is the size of the chart if it was exported as an image file
or copied to clipboard as a bitmap.
4.1.7.1 File Menu
Export As… : The chart can be exported as either JPEG or BMP file.
Copy: The chart is copied to clipboard (can be pasted, for example, to a Word document).
4.1.7.2 Format Menu
Formatting of vertical and horizontal gridlines. For example, if we wish to change properties of
horizontal gridline:
It is seen that, the “Reset” buttons are now active for
minimum and maximum bounds since they have been
manually changed.
Clicking on the “Reset” button will reset the bound to its
value that had been calculated automatically.
4.1.7.3 Elements Menu
It is possible to add chart title, vertical and horizontal axes titles as shown below:
Right-clicking on a title will show the following menu:
Selecting the “Font…” menu will show the following dialog:
Color: Color of the gridline
Thickness: If thickness if equal to zero, then the gridlines will not
be displayed, otherwise, it changes the thickness of the gridline.
Style: Solid, dotted or long-dashed lines.
Once the mouse cursor is on a title, the shape
of the mouse cursor will change indicating
that an interaction can take place:
A) When dragged with the mouse, the title
will move to a desired location,
B) When clicked, the title will switch to the
edit mode and will allow you to type and
change the text. To close the edit mode,
simply click somewhere out of the
shown text editor.
The menu shows two options: A) “Font…” to be able to change
the format of the font, B) “Delete” to be able to delete the title.
Once the title is deleted, its allocated space will be claimed back
by the plot area.
After some minor formatting and changing the initial default titles:
4.1.7.4 Options Menu
Whether to use “Anti-aliasing” or not depends on the quality expectations. Using anti-aliasing
provides high quality drawing, therefore, high quality chart.
However, when anti-aliasing is on, due to subpixel rendering taking place (additional computations)
the chart might become less responsive. Therefore, it is highly recommended to turn it on right
before exporting or copying to clipboard.
It is possible to change the font face, size, style,
and color.
Note that, as the size of the font increases,
naturally the space requirements will increase.
Therefore, more space will be allocated for the
title.
4.1.8 Working with Trendlines
A trendline is a line of best fit to the data. It can be very helpful when analyzing data as it can be
used to forecast future values based on current values and can be used for interpolation within the
current values. The available trendlines are:
1) Exponential: y = a·exp(b·x)
2) Linear: y = a·x + b
3) Logarithmic: y = a·ln(x) + b
4) Polynomial: y = an·xn + an-1x
n-1 + …+ a0
5) Power: y = a·xn
When possible, the intercept can be set to a custom value. Based on the selected trendline, the R2
(goodness of fit) and equation can be displayed on the chart.
4.1.8.1 Adding Trendlines
1) Right-click on a series and select the “Add Trendline…” menu item.
2) As shown below, a trendline (shown with blue color), by default linear trendline, will be added
to chart.
Please note that a series can only have 1
trendline. Therefore, upon adding a
trendline, right clicking the series will
not offer the “Add Trendline…” option
until the existing trendline is deleted.
4.1.8.2 Changing Trendline Type
1) Right click on the trendline (or on the series) and select “Format trendline…” as shown below
2) This will show the following dialog:
The “Trendline Type” page shows the current trendline type
and if any other options applied on the trendline.
For the data set:
x = [0, 1, 2, 3, 4, 5, 6]
y = [75, 105, 125, 140, 135, 120, 100]
which generated the series, only exponential, linear and
polynomial type trendlines can be chosen and logarithmic and
power trendlines cannot be, therefore they were automatically
disabled.
If polynomial trendline is chosen, the degree of the
polynomial can be minimum 2 and maximum 7. However, the
maximum degree also depends on the number of data points
available.
A polynomial trendline with degree 2 is
shown (blue colors).
4.1.8.3 Changing Line Properties
1) Right click on the trendline and select “Format trendline…”.
2) From the “Format Trendline” dialog, select the “Line Properties” tab as shown below:
4.1.8.4 Displaying R2 and Equation
1) Right click on the trendline and select “Format trendline…”.
2) Check the boxes for “Display Equation on Chart” and “Display R-squared Value on Chart” as
shown below:
Initially, the Line Properties page will show the properties of the
current trendline. Color, thickness and style of the trendline can
be changed.
Changing the format of the displayed info:
1) Right click on the textbox and select “Font…” menu item.
2) Following dialog will be shown:
3) After some minor formatting:
4.1.8.5 Changing Intercept
A trendline equation is the best fit for the data set under consideration. However, every now and
then, we might want to change the intercept. If available, then the intercept can be manually entered.
For the equation shown at the previous section, if we change the intercept from 74.2857, which was
calculated, to a manual value of 60, then the equation and most likely the R2 will also be changed.
4.1.8.6 Exporting the Equation
In the previous sections, the equation was just shown on the chart. However, we did not use the
equation as a function, say for example for interpolation or for forecasting. In order to use the
equation as a function:
1) Right-clicking on the trendline will show the following menu:
2) Select “Export Equation as Lua Function” and type a valid function name as shown below:
Notice that the intercept, y(0)=60 and R2
changed from 0.992 to 0.905.
Here, arbitrarily the function name is
chosen as func.
Note that the name func conforms with
Lua standards and does not exist in the
global table.
3) Switch to command-line
>>type(func)
table
>>func
y = -6.65179x^2+46.0268*x+60
--interpolation
>>func(1.1)
102.581
--forecasting
>>func(7)
56.2499
As a technical detail, please note that, func itself is a Lua table with metamethods __tostring and
__call implemented as evidenced below:
>>getmetatable(func)
__tostring=function
__call=function
Therefore, it was possible use the exported table, namely func, to print the equation of the trendline
and also as a function.
5 TOOLBOXES
Toolboxes are integral part of the framework and are programmed using C++ and wxWidgets and
by themselves can be a good candidate to be a stand-alone software.
However, the integration of toolboxes to the framework provides convenience of exporting and
importing of data/variables from other working parts of the framework. This gives considerable
flexibility to work especially with std library and data structures to do further work on the variable.
Currently there are 2 toolboxes, namely, image processing and Lua scripting, which can be accessed
via the Home ribbon page.
5.1 Image Processing
Image processing toolbox, which uses OpenCV library’s data structures in its backend, supports
working with several different image formats. The editor supports working with multiple tabs.
Upon running the toolbox, initially the following simple interface will be shown:
At the very first run, the left-hand side panel, namely the Directory Viewer, will only show the root
directories. However, as shown below, once a directory is chosen it can be set as default (Fig A), so
the next time when the editor starts the focus will be given to that particular directory (Fig B). This
provides considerable convenience when opening images.
Note that except the menu File → Open Image and the Directory Viewer all other controls are
disabled until opening an image.
5.1.1 Basics
5.1.1.1 Opening / Loading Image
There are two ways to open images: A) File → Open Image menu, B) Double-clicking an image
shown at Directory Viewer.
Using the menu
1) Select File → Open Image as follows:
2) An Open Dialog will be shown. It is possible to choose any type of image
3) Selecting an image will load it to the editor.
When an image is loaded, the zoom level is adjusted so that the image fits the frame, therefore, the
zoom level can be different than 100%. For smaller images and depending on the screen size, zoom
level can be larger than 100% and for larger images it can be smaller than 100%. Once the image is
loaded successfully, all controls will be enabled (active).
Using the Directory Viewer
Using Directory Viewer is rather easy. At the directory viewer, locate the image file and double-
click it. The image will be opened at a new tab in the current editor.
5.1.1.2 Understanding Interface
The toolbar:
There are three controls: A) Zoom Level, B) Illuminant, C) Multi-page selector where the choices
are shown below in Fig A and Fig B, respectively.
Note that, multi-page selection only becomes available when the image contains more than 1 page.
In the above figure, 117% fits the image to the frame (as explained above, this zoom level can be
different depending on the size of the image) and the default choice of illuminant is D65.
The statusbar:
Information on current pixel, the pixel currently under the mouse pointer, and the image are shown:
Pixel: Currently, the mouse is on the pixel located as x=542 and y=488. The RGB values and the
corrresponding, depending on the choice of illuminant, are shown. Moving the mouse pointer on
the image will change the displayed information.
Image: The image’s width x height in pixels, number of channels and its depth in bits are displayed.
Please note that, the minimum bit depth that can be sensed is 8 bits per channel.
Multi-page Images
Some image files can contain more than 1 image per file. The procedure to open these type of files
is exactly the same as described above. However, as shown below, an additional control is shown
at the toolbar to be able to see the different images on the image file.
Here, the last control shows that the loaded multi-page image has 3 pages. Selecting a page, namely
an image contained in the file, will load the selected image to the editor.
Note: For technical reasons, when a single channel image is loaded, the channel numbers are
automatically adjusted to 3 channels. The information at the status bar will still show that the image
has indeed single channel; however, the RGB values shown for this image will exactly be the same.
Changing Zoom Level:
The zoom level can be changed in 3 different ways:
1. By selecting a pre-defined zoom level from the zoom level control.
2. By typing a zoom level to the zoom level control and then pressing enter.
3. By clicking control (ctrl) button on keyboard and using the mouse wheel.
Please note that, switching between tabs will automatically update the information shown at status
bar and the state of the controls (zoom level, illuminant and multi-page selector) as well.
5.1.2 Color Spaces
Currently, 3 color spaces are used, namely, XYZ, sRGB and CIE Lab. The color values are read
from each pixel with the assumption that it is in standard RBG space and then converted to XYZ
using the well-defined mathematics and then to CIE Lab by taking into consideration the chosen
illuminant. Therefore, the choice of illuminant and the degree field of view affects the conversion
from RGB to CIE Lab. Please note that only 2° observer is currently available.
5.1.3 Analyzing Color
As the mouse is moved on the image, the color (in sRGB and CIE Lab) and location of each pixel
is reported in the status bar as explained above. Although this approach gives a good insight on the
color variations; however, for many applications it is not a satisfactory approach and mostly the
average color values of an area are of interest to us. As shown below, there are currently 4 shapes
that can be chosen to be drawn to analyze the color of an area.
Once a shape is selected, the mouse pointer will change shape and the shape can only be drawn on
the image. Let’s select the rectangle and draw a rectangle on the image:
“Delete Shape” Menu
As the name of the menu is already self-explanatory, choosing this option will delete the shape.
“Properties…” Menu
Note that as you change the color or thickness, the changes will be shown immediately. Therefore,
to accept the changes made, click “OK” otherwise click “Cancel”.
A) Rectangle is drawn
B) Rectangle is selected after is has been
drawn. Once a shape is selected resize
handles (the circles that are shown on the
top-left and bottom-right corners) will be
shown. At this stage, the shape can be
moved around or by using the resize
handles can be resized.
C) Right-clicking on the shape will show
the context-menu.
Font: Only available for the ruler shape.
Line Color: Changes the color of the shape’s
boundaries.
Line Thickness: Changes the thickness of the
shapes boundaries.
5.1.3.1 Quickly Getting the Essential Statistics
Selecting “Color Statistics to Worksheet” Menu option will prepare a report similar to the following.
The report will be shown on a Worksheet that will added to the current Workbook. The name of the
Worksheet will be the current time (hours + minutes + seconds).
File: C:\...\M206Scanned1200dpi.tif
Shape: Rectangle
Illuminant: D65
Area: 1715 pixels
Min Mean Max Stdev
R 119 199 254 34
G 37 147 205 39
B 0 21 87 25
L 27.4 64.1 84.6 13.7
a 1.029 10.015 34.391 6.047
b 39.03 64.56 78.28 7.87
The report initially gives information about the selections: the full path of the image file, the shape
that originated the report and the illuminant.
Furthermore, the area is reported as pixel counts. Please note that, the counted pixels are the ones
considered to be within the shape, excluding the boundaries of the shape.
Finally, the minimum, average, maximum color values for the considered pixels in CIE Lab and
sRGB spaces are report as well as the standard deviation of all considered pixels.
5.1.3.2 Going Beyond
Although the statistics shown by selecting the “Color Statistics to Worksheet” menu is satisfactory
for many applications, sometimes further investigation can be necessary. Therefore, to be able to
utilize the power of the framework, color values can be exported to workspace following the below
steps:
1) After selecting the “Color Values to Workspace” menu option, following dialog will be shown:
2) Go to command-line and type the variable name, var.
>>type(var)
table
>>var
a=Vector
b=Vector
shape=Rectangle
illuminant=D65
L=Vector
area=1715
G=Vector
R=Vector
B=Vector
It is seen that the variable, namely var, is of type Lua table and contains information on shape,
illuminant, area and the color values in CIE Lab and sRGB spaces. Each dimension of the color
space is represented by a Vector data structure (section 7.1 ). Now by using the std library (section
8 ) or the plotter (section 4 ) many more investigations can easily be performed.
Demo: Comparison Using t-test
Let’s simply demonstrate why exporting color values to workspace gives considerable flexibility
and opportunities in analysis.
Suppose using a digital camera we acquired an image, say of raisins, after they were subjected to
some processing and would like to compare whether the two raisins’ color values are similar. Please
notice that the idea presented here can easily be extended to many more other applications.
Enter a variable name (Here the variable name is
arbitrarily chosen as var).
Note: The variable will be in the global Lua table
and will be of type Lua table.
Let’s take a look at the variables:
>>type(rsn1)
table
>>type(rsn2)
table
Now, let’s compare the L-values using the std.test_t function (Section 8.3.31 ).
>>pval, tbl=std.test_t{x=rsn1.L, y=rsn2.L}
>>pval
1.25e-38
It is seen that the p-value strongly suggests that the raisins’ L-values are statistically different. The
rationale can be quickly extended to other color values or different tests as well.
5.1.4 Measuring Distance
It is rather easy to measure the distance between two points:
1) Open an image using the Image Processing Toolbox.
2) From the Select menu, select Ruler.
Variable names for the raisins:
On the left: rsn1
On the right: rsn2
3) Adjust the zoom level for a comfortable drawing.
4) Start drawing with the ruler. As you draw the distance will be reported in pixels. The following
equation is used to calculate distance between points (x1, y1) and (x2, y2): 𝑑 =
√(𝑦2 − 𝑦1)2 + (𝑥2 − 𝑥1)2
Note that unless either y2=y1 or x2=x1, the distance reported will not be reported as an integer number.
Note that, for the above-shown image, the zoom level was 525%.
5.2 Script Editor
The editor, shown below, can be accessed from the Home ribbon page.
Figure 4.2.1: Script Editor
Some features:
• Code completion and context-based help.
• Conveniently working with several scripts.
• Fully functional Find/Replace.
• Smart indenting.
• Simultaneously working with external editors.
• Highlighting occurrences of identifiers.
• Customizing the format (font, fore- and back-ground colors) of script elements (keywords,
reserved words, identifiers, strings, comments, numbers, operators).
5.2.1 Menus
All functionality in the editor can be controlled using menus and as shown below, there are 4 main
menus, all of which are populated, enabled/disabled dynamically.
5.2.1.1 File menu
New File: To add a new script file to the editor. This adds a new tab.
Open File: An Open Dialog is shown to be able to select a script file (.lua) from a path.
Save: Saves the currently active script file. If the script file has already been saved or there has no
changes been yet made, Save menu will be disabled.
Save All: Saves all open scripts which have been changed.
Recent Files: Automatically populated to keep a list of recently opened scripts. Up to 10 recently
opened scripts will be displayed.
Export to HTML: Exports the script to HTML file with the styling defined in the preferences.
Preferences: Shows a dialog where settings can be changed.
5.2.1.2 Edit menu
Undo: If an action (almost all textual changes) that can be undone has been done, then Undo option
will be enabled.
Redo: When an action or series of actions are undone, then they can be redone and Redo menu will
be enabled.
Cut: Enabled when there is a selection. Moves the selection to clipboard.
Copy: Enabled when there is a seletion. Copies the selection to clipboard.
Paste: Enabled when there is a valid item on clipboard that can be pasted to the script.
Find: Shows a dialog to search for a text in the script.
Replace: Shows a dialog to be able replace an occurrence or all occurrences of phrase with another
text.
5.2.1.3 Debug menu
Start Without Debugging: Runs the current script and is enabled when there is “something” to run.
Please note that the name of the menu is intentionally chosen as in the next or the following major
release, Debug facilities are planned to be integrated to the editor.
Compile: Compiles the current script into Lua bytecode. Enabled when the script is available from
a path.
5.2.1.4 Window menu
Show Directory List: To be able to view the directory list pane when it has been manually closed.
5.2.2 Directory List
The very first time the editor runs, by default the directory list will only show the root directories,
similar to the Fig A, shown below.
However, once the directory which contains scripts are located, by right-clicking on the folder it
can be “Set as default”, as shown in Fig B. Therefore, the next time the editor starts, the directory
which was set as default will be shown as focused. This provides convenient access to the scripts.
Renaming or deleting a script is not allowed through script editor. If you wish to do so, “Reveal in
Explorer” will show the directory in OS’s default explorer window.
Instead of a directory, right-clicking on a file will show the “Reveal in Explorer” menu, which works
exactly the same way for the directories such that it will show the file in OS’s default explorer
window.
Double-clicking on a file will perform an action depending on the extension of the file. Following
are possible:
• Lua files: Will be loaded into the editor.
• Executable files: No action will be performed and a warning message will be issued.
• Other file types: If there is a default program associated in the OS with the particular
extension, it will be opened with the default program.
5.2.3 Running a script
Once a script is loaded into the editor, either via File → Open or double-clicking on the directory
list, it is possible to run the script using Debug → Start Without Debugging menu.
Consider the following simple script:
Note: The star “*” next to script name
appears upon any changes has been made to
the script and disappears when the script is
saved.
When the script is run, any output from the script will be shown at the output window which will
be floating atop the script:
5.2.4 Auto-completion features
ScienceSuit is equipped with data structures and a std library with over 100 functions. Remembering
function names, parameters and the details of the function is not an easy task. Therefore, an auto-
completion dialog along with help (seen below) is designed to make scripting more convenient.
As seen above once a composite data type residing in the global environment, such as std, followed
by a “.” or “:” is typed, the contents will be listed and will be shown with the following signs:
• table: {}
• function: f
• string: s
• number: n
Continuing to type after the auto-complete dialog is shown will filter the contents of the auto-
complete dialog to be able to find the exact match. Selecting any of the list item, will show a help
if there is one help file associated with the item. Currently, there is help associated with
approximately 180 functions. The help will give a concise information on the function, its syntax
and info on parameters and an example.
Output Window shows: 1) Date (year month day) and the time (hour, minute,
seconds), 2) If available a warning message, 3) If available any output (print statements) from the
script.
5.2.5 Find & Replace
In order to find occurrence(s) of an identifier either go to Edit → Find or simply click Ctrl+F. This
will show the following dialog:
Search conditions:
C: Match the case RE: Regular expression
W: Whole words only
The button on the very left when clicked will switch the dialog to replace mode. As the search phrase
being typed in the textbox, the occurrences will be highlighted and the number of occurrences and
the location of the current occurrence will be shown as seen in the below figure.
Here, “2 of 6” means that in the script file there are 6 entries matching the current phrase and
conditions being found and currently the 2nd one (for this case, top=1 and bottom=6) is located
(please notice the difference between highlighted phrases and the phrase with the rectangle around).
The reason the 2nd phrase was located was that it was closer to the caret’s current position from a
top-down sense. Using the up and down arrow buttons, the previous or the next occurrence can be
chosen.
The help files are bundled in a zip container (under datafiles
directory). Should you wish to modify or add any help item, you are
allowed to do so as long as HTML 4.0 specifications are used. It is also seen that the name of the help file must be relative to the
global environment, namely _G.
For example: accumulate function resides in std library which is in
the global environment. Therefore, the name of the help file must be
std.accumulate.html. Similarly, setmetatable function is directly
under global environment, therefore its name is setmetatable.html.
Replace Mode:
As mentioned above, once the very left button is clicked the replace mode is shown. Alternatively,
Edit → Replace or Ctrl+R can be used.
Naturally, to be able to replace an occurrence or multiple occurrences of a text, first it must be found
in the document. Therefore, initially, the phrase “retEntry” will be found as explained above. Once
at least one occurrence of the search text has been found, then the buttons “Replace Current” and
“Replace All” will become active.
For the above figure, “Replace Current” will replace the 1st occurrence of “retEntry” with “Entry”
whereas “Replace All” will replace all 6 occurrences of “retEntry” with “Entry”.
5.2.6 Simultaneously working with external editors
Although the script editor’s functionality is well satisfactory to work with Lua scripts, every now
and then we might need to use some other editors for functionality that might be missing in
ScienceSuit’s built-in editor. For example, Visual Studio (VS) Code is a great editor and offers many
features.
However, the downside of working with an external editor is that you will not be able to obtain an
output since the data structures and std library are absent in these editors. Therefore, simultaneously
working with them provides significant convenience in many regards.
Consider the following simple script opened with ScienceSuit editor from desktop:
Without closing the script file, it will also be opened with VS Code as shown below:
Let’s do the following:
1) Change the variable x to 1, so that now it reads: local x=1 as shown below.
2) Save the file in VS Code. Note that, if the file is not saved after making the changes they will not
be visible to ScienceSuit.
3) Go back to the script opened in ScienceSuit and you will see that it has already been changed.
The above-mentioned steps work both ways, such that any changes (insertion, deletion, etc...) made
to the script and saved using ScienceSuit editor will be immediately visible to VS Code. This gives
the opportunity to harness the power of both editors.
6 APPS
Besides toolboxes, ScienceSuit is also equipped with many apps which are programmed using Lua and
IUP graphical user interface toolkit. The apps are dynamically added to the ribbon interface through a
manifest file, an XML file. Therefore, many ribbon pages, panels and buttons can be added.
By using the gridtext control, which is provided in std.gui library, it is very easy to make an app to
support the selection of a range from a worksheet and display the selection to the user as shown in
figure below.
It is seen from below figure that the selection is shown to user as “Sheet 1!A1:B3”. Here the
worksheet name is “Sheet 1” and the selected range is from “A1” to “B3”.
User can change the selection by either making a new selection or editing the control (gridtext)
itself. Making an app supporting selection-based analysis of data provides significant convenience
to many users.
6.1 Descriptive Statistics
When after the selection of a data set in a worksheet the immediately shown measures of the data
are not enough then descriptive statistics app, shown below, is very useful to summarize the given
data set using more measures such as mean, median, variance, range and mode…
Say there is data in two columns: Column A: [1, 2, 3, 4] Column B: [10, 20, 30]
Once the data is selected from a worksheet, either all or individual measures of the data can be
selected. If more than 1 column of data is selected, either the whole data set or each individual
column can be analyzed separately.
For the data set shown in the figure, below is a report showing the difference of selecting and not
selecting the “Treat columns separately” option:
“Treat columns separately” selected
Mean 2.500 20.0
Variance 1.667 100.0
Sum 10.0 60.0
Count 4 3
6.2 1-sample t-test
The one-sample t-test is used to determine whether the sample mean is statistically different from a
known population mean. The app relies on std.test_t function.
Let’s test whether the data set (4.8, 4.2, 5.6, 7.3, 4.2, 4.9) is different than 5.0.
For the data in the above figure, a report is generated in the following way:
N Average stdev SE Mean T p value
6 5.33 1.07 0.436 0.764 0.479
95.0 Confidence Interval for two.sided (4.21 , 6.46)
The default confidence level is 95% and a
value between (0,100) is accepted.
The alternative hypothesis can be: 1) Less than,
2) Not equal, 3) Greater than.
6.3 2-sample t-test
The two-sample t-test is used to determine whether the average difference in means of two samples
are different. The app relies on std.test_t function.
The samples’ data can come in two different flavors: either in separate columns or in a single column.
The app can analyze both styles.
If “Assume Equal Variances” is selected, a report similar to the following is prepared:
Variable 1 Variable 2
Observation 21 23
Mean 51.476 41.522
Standard Deviation 11.0074 17.1487
Pooled variance 14.5512
t critical 2.27
p-value 0.0286
95.0 Confidence Interval for two.sided (1.09 , 18.82)
The default confidence level is 95% and a
value between (0,100) is accepted.
The alternative hypothesis can be: 1) Less
than, 2) Not equal, 3) Greater than.
If “Assume Equal Variances” is selected, then
pooled variance is also reported.
6.4 Paired t-test
The paired t-test app (shown below) is used when we are interested in comparing two means that
are from the same individual, object, or related units such as “before” and “after” a treatment. The
app relies on std.test_t function.
Ex: Suppose 20 students are exposed to a learning module and their scores are (data from: Rosie
Shier. 2004):
Pre-module: 18, 21, 16, 22, 19, 24, 17, 21, 23, 18, 14, 16, 16, 19, 18, 20, 12, 22, 15, 17
Post-module: 22, 25, 17, 24, 16, 29, 20, 23, 19, 20, 15, 15, 18, 26, 18, 24, 18, 25, 19, 16
The report for the above data will be:
N Mean StDev SE Mean
Sample 1 20 18.40 3.15 0.705
Sample 2 20 20.45 4.06 0.907
Difference 20 -2.05 2.84 0.634
t critical: -3.23
p-value: 0.00439
95.0 Confidence Interval for two.sided: (-3.38 , -0.722)
The default confidence level is 95% and a
value between (0,100) is accepted.
The alternative hypothesis can be:
1) Less than,
2) Not equal,
3) Greater than.
The “Assumed mean difference” is the
difference we expect due to the treatment.
6.5 F test
The F test is used to determine whether the ratio of variances of two samples is equal to a
hypothesized ratio. It should be noted that if the ratio is 1, the equality of variances are tested. The
app relies on std.test_f function.
Example: Data source (Larsen & Marx, An Introduction to Mathematical Statistics and Its Applications).
Solitary Confinement : 9.6, 10.4, 9.7, 10.3, 9.2, 9.3, 9.9, 9.5, 9, 10.9
Non-confined : 10.7, 10.7, 10.4, 10.9, 10.5, 10.3, 9.6, 11.1, 11.2, 10.4
The report for the above data and the shown choices will be:
df Variance
Sample 1 9 0.357
Sample 2 9 0.211
F critical 1.70
p-value0.443
95.0 Confidence Interval for two.sided (0.421 , 6.83)
The default confidence level is 95% and a value
between (0,100) is accepted.
The alternative hypothesis can be: 1) Less than, 2)
Not equal, 3) Greater than.
The “Assumed ratio” is the assumed ratio of
variances.
6.6 Z test
z-test is used to test the mean of a distribution in which we already know the population standard
deviation. The app, shown below, relies on std.test_z function.
Example: Researchers believe that skull widths of a certain population is normally distributed with
a mean (μ) of 132.4mm and a standard deviation (σ) of 6.0 mm. Does the following data have an
association with the population? (Question adapted from: Larsen & Marx, An Introduction to Mathematical
Statistics and Its Applications).
Measurements: 141, 146, 144, 141, 141, 136, 137, 149, 141, 142, 142, 147, 148, 155, 150, 144, 140, 140, 139, 148,
143, 143, 149, 140, 132, 158, 149, 144, 145, 146, 143, 135, 147, 153, 142, 142, 138, 150, 145, 126
A report similar to the following will be prepared on a separate worksheet:
N Average stdev SE Mean z p-value
40 143.53 6.04 0.949 11.73 0.0000
95.0 Confidence Interval for two.sided (141.67 , 145.38)
The default confidence level is 95% and a value
between (0,100) is accepted.
The alternative hypothesis can be:
1) Less than,
2) Not equal,
3) Greater than.
6.7 One-way ANOVA
When more than one level of data for a single-factor needs to be analyzed, one-way ANOVA app
(shown below) comes handy.
Let’s work on the following unstacked data (From: Larsen & Marx, An Introduction to Mathematical Statistics
and Its Applications).
Nonsmokers Light smokers Moderate Heavy
69 55 66 91
52 60 81 72
71 78 70 81
58 58 77 67
59 62 57 95
65 66 79 84
Running the app will prepare a report similar to the following:
Source df SS MS F P
Treatment 3 1464 488.0 6.120 0.00398
Error 20 1595 79.74
Total 23 3059
“My data is stacked”: If the response variables
are stacked in a single column and the factors are
on a different column, the data is stacked.
“Tukey’s Test”: If besides ANOVA results, the
pairwise comparisons of the observations are to
be inspected.
If the “Tukey’s test” option is checked, the following will be appended to the above report:
Pairwise Diff Difference (i-j) Tukey Interval Conclusion
1-2 -0.8333 -15.26 , 13.60 NS
1-3 -9.333 -23.76 , 5.097 NS
1-4 -19.33 -33.76 , -4.903 Reject
2-3 -8.500 -22.93 , 5.930 NS
2-4 -18.50 -32.93 , -4.070 Reject
3-4 -10.00 -24.43 , 4.430 NS
6.8 Sign Test
Performs the nonparametric sign test test to test if the null hypothesis of a median of a distribution
is equal to some specific value or not. The app relies on std.test_sign function.
Example: Synovial fluid is the clear, viscid secretion that lubricates joints and tendons. In healthy
adults, the median pH for synovial fluid is 7.39. Data is for the pH values measured from fluids
drawn from the knees of patients with arthritis. Does it follow from these data that synovial fluid
pH can be useful in diagnosing arthritis?
Data: 7.02, 7.35, 7.32, 7.33, 7.15,7.26, 7.25, 7.35, 7.38, 7.2, 7.31, 7.24, 7.34, 7.32, 7.34, 7.14, 7.2, 7.41,
7.77, 7.12, 7.45, 7.28, 7.34, 7.22 (Adapted from: Larsen & Marx, An Introduction to Mathematical Statistics and
Its Applications).
The default confidence level is 95% and a value
between (0,100) is accepted.
The alternative hypothesis can be:
1) Less than,
2) Not equal,
3) Greater than.
Paired Test: If checked, “Variable range” will be
named as “First Sample Range” and “Second
Sample Range” will be active.
The app will assume that the data (first and
second samples) is paired.
The app will prepare a report similar to the following:
N 24
Number>7.39 3
Number=7.39 0
Median 7.315
Median=7.39 vs Median<>7.39
p-value 0.00024
CONFIDENCE INTERVALS
Lower Achieved 0.9361 7.240 7.340
Interpolated 0.9500 7.233 7.340
Upper Achieved 0.9773 7.220 7.340
6.9 Two-way ANOVA
Unlike one-way ANOVA, which is used to analyze multiple levels of a single factor, when multiple
levels of two-factor needs to be analyzed, two-way ANOVA can be used.
Once selections are made and OK button clicked, a report similar to the below one is prepared:
Source DF SS MS F-value p-value
Factor #1 3.00 17045.70 5681.90 0.2025 0.8945
Factor #2 4.00 1127995.25 281998.81 10.05 0.0000
Interaction 12.00 8061.55 671.80 0.0239 1.0000
Error 100.00 2806282.67 28062.83
Total 119 3959385.17
Note: Response, factor #1 and #2 should be at
different columns.
6.10 Linear Regression
The app, shown below, is used to perform linear regression (simple/multiple) on a given data set. It
relies on std.lm function ( 8.3.16 ).
Let’s work on the data available on PSU Website (From: Statistics Online - Penn State, STAT 501
Example on Underground Air Quality).
Once OK button is clicked, a report similar to the following will be prepared:
Linear Regression Table R2 0.268
df SS MS F p-value Regression 2 1061819 530909 21.44 0.00000 Residual 117 2897566 24766 Total 119 3959385
Coefficient Std Error T value p-value CI Intercept 85.90 106.0 0.8103 0.4194 -124.0 , 295.8 Variable 1 -5.330 6.425 -0.8296 0.4084 -18.05 , 7.394 Variable 2 31.10 4.789 6.495 0.00000 21.62 , 40.59
Response: Vent
Factors: Combination of O2 and CO2.
6.11 Food Database
Food Database app, as shown below, is designed to find compositional (macro-components only)
and thermo-physical properties of foodstuffs. The app uses Food data structure for calculations.
The compositional data is read from the database file located at databases/USDANALSR28.db (The
compositional data released by USDA was downloaded from USDA NAL website as an Excel file).
Once a selection is made and “Composition and ThermoPhysical Prop” tab is selected,
compositional information and thermo-pyhsical properties of the selection at the shown temperature
is displayed (shown below). As the value of the temperature is changed, the thermo-physical
properties will be re-computed.
Initially, the app allows you to type
your query in a textbox in the
“search” tab.
The query can be multiple words, such as
“milk” and “nonfat” separated by a space.
Once a word such as “milk” is typed, first the
records having the word “milk” will be shown
and then continuing to typing “nonfat”, this
time an intersection of the entries having
“milk” and “nonfat” will be shown.
Therefore, it is possible to precisely find and
select the entry that fits to the query.
It should be noted that within a certain range the calculations are reliable and furthermore the phase
change is not considered. Please see Food data structure for more info (Section 7.4 ).
6.12 Thermal Processing
This app, shown below, was designed to aid in thermal processing calculations of foods (calculating
F0 value) subjected to different time and temperature combinations. To be able to use the app, D-
and z-value of the target enzyme or microorganisms should be known.
For the thermal processing we will use the following time-temperature profile, which should be
entered in a Workbook:
time=[0, 1, 2, 3, 4, 5, 6] in minutes, Temperature=[2, 30, 55, 76, 50, 25, 2] in °C.
Here, the usage of app will be demonstrated by creating a Food variable and subjecting that food
variable to thermal processing. However, this step can be skipped.
1) Create a variable of type Food (either using command-line or the Food Database app)
>>milk=Food.new{water=88.13, protein=3.15, CHO=4.80, lipid=3.25, ash=0.67}
2) Enter the variable name (in this case it is milk) in the text “Variable:” box.
3) Click on the “Show Organisms” button to list possible organisms in the food (shown below).
Here, using the Microorganism database (located in databases folder), organisms which can grow
at the temperature, pH and water activity of the food, namely the variable milk, are listed. Due to
D- and z-values of organisms being dependent on the food media as well, one can quickly notice
that in the list of “Possible Organisms in the Food” some of the organisms are listed more than once.
Clicking on each of them will change the value in the “Food Media:” textbox and correspondingly
the D- and z-values as well.
Please note that D(time), D(temperature) and z-values do not require a specific unit; however, these
units must be consistent with the time-Temperature data in the Workbook. In the following figure,
the “Thermal Process Calc” tab is shown:
Once calculate the data is selected and calculate button is clicked, a report similar to the following
will be prepared on a new worksheet. (NR: Not reported here)
Time Temperature Lethality Rate D-Value Total Log Reduction F-Value
0 2 0.00 NR 0.00 0.00
1 30 0.00 NR 0.00 0.00
2 55 0.00 16.5 0.00 0.00
3 76 2.31 0.003 4.93 1.16
4 50 0.00 133.6 6.66 2.31
5 25 0.00 NR 6.66 2.31
6 2 0.00 NR 6.66 2.31
A little explanation might be helpful to show how values are computed and the assumptions:
D-value is calculated at each temperature using the following equation:
where D0 and T0𝑙𝑜𝑔10𝐷
𝐷0=
𝑇0−𝑇
𝑧 are the D (time) and D(temperature) values, respectively.
F-value is calculated using: 𝐹0 = ∫ 10𝑇(𝑡)−𝑇0
𝑧 𝑑𝑡𝑡0
0where T(t) is the temperature at time t, and T0 is
the reference temperature.
For the “Total Log Reduction”, an assumption was made, such that an average D-value was
computed at an average temperature between consecutive time intervals:
𝑇𝑎𝑣𝑒𝑟𝑎𝑔𝑒 =𝑇(𝑡) + 𝑇(𝑡 + 𝛥𝑡)
2
𝛥𝑡 = 𝑡(𝑖 + 1) − 𝑡(𝑖), 𝑖 = 1,2. . 𝑛
once the Taverage was computed, then at Taverage a Daverage was calculated.
Therefore, Log Reduction =𝛥𝑡
𝐷𝑎𝑣𝑒𝑟𝑎𝑔𝑒and “Total Log Reduction” is the cumulative sum of the Log
Reductions.
Note: The above-mentioned assumption should work well if the difference between the time
intervals are reasonable short or the temperature in a particular time interval does not rise (or drop)
drastically.
6.13 Thermodynamic Properties of Fluids
This app computes the thermodynamic properties (specific volume, enthalpy, entropy) of 9 different
fluids (R12, R22, R23, R32, R125, R134A, R143A, Ammonia and Water) at compressed, saturated
and superheated states and uses ThermoFluid data structure for all computations.
When the app is run the following frame is shown:
If either temperature or pressure is selected,
then the Fluid State is saturated and therefore,
the saturated table of the selected fluid is used
to compute the properties.
When the fluid is at saturated state, as seen
below both saturated liquid and saturated vapor
states are calculated.
From the dropdown menu fluid type must be
selected as well as the Temperature and/or
Pressure before proceeding with any
computations.
If both temperature and pressure are selected, then
the Fluid State is unknown as it can be either
compressed or superheated.
Note: Needless to say that the state can also be
saturated. However, this can only happen when the
saturation pressure and temperature is exactly equal
to the entered values for pressure and temperature,
respectively. Although this would be a rare case, at
any rate, it is recommended to check the saturation
temperature or pressure before proceeding with
selection of both properties.
If the fluid state is superheated, then the
properties are computed using the
superheated table of the selected fluid.
6.14 Psychrometry
Psychrometry is of great interest in finding the properties of humid air, which is heavily used in
operations such as drying and air conditioning. The app, shown in below figure, relies on the
std.psychrometry function.
Condition for calculation: Exactly 3 properties of the humid air must be selected.
1) Select 3 properties* (the remaining 5 properties are immediately disabled)
2) Enter values corresponding to the selected properties.
3) Click the Calculate button
To be able to calculate properties of another combination, first deselection of at least one of the
previously selected properties must be done.
*: Please note that not all combinations are valid to be able to calculate the rest of the properties.
For example, if a combination of Pressure, Dew Point Temperature and Absolute Humidity is
selected, the rest of the properties cannot be calculated. Why?
If File → Export to Worksheet option is selected, depending on the selected combination a report
similar to the following will be prepared on a new worksheet:
Selected Combination
Tdb 20 ° C
Twb 12 ° C
P 101.325 kPa
Results
Pws 2.339 kPa
Pw 0.8823 kPa
Tdp 4.398 ° C
V 0.8378 m³ /kg
W 0.00546 kg / kg da
Ws 0.01470 kg / kg da
H 33.86 kJ/ kg da
RH 37.72 %
6.15 Developing Apps
Needs vary and a user is not limited to the apps shipped with ScienceSuit. By using IUP and Lua
and also the provided data structures and built-in functions, it is easy for someone who has an
understanding of programming to develop apps and add new ribbon pages to ScienceSuit framework.
The following piece of code has been used to design the “Thermal Process Calc” page of the app
shown in section 6.12 .
local lblTime=iup.label{title="Time:"}
local txtTime=std.gui.gridtext()
local lblTemperature=iup.label{title="Temperature:"}
local txtTemperature=std.gui.gridtext()
local lblRefTemp=iup.label{title="Reference Temperature:"}
local txtRefTemp=std.gui.numtext{min=1, max=150, value=121}
local btnCalc=iup.button{title="Calculate"}
local TimeTemps=iup.gridbox{lblTime, txtTime, lblTemperature, txtTemperature, lblRefTemp,
txtRefTemp, numdiv=2, HOMOGENEOUSCOL="yes",CGAPLIN=10, CGAPCOL=5,
orientation="HORIZONTAL"}
local vbox1=iup.vbox{iup.space{size="x5"},TimeTemps, iup.space{size="x20"}, alignment="ALEFT"}
local vbox2=iup.vbox{btnCalc,alignment="acenter"}
local vboxes=iup.vbox{vbox1,vbox2, alignment="acenter"}
local page2=iup.hbox{vboxes, iup.space{size="10x"}}
page2.tabtitle="Thermal Process Calc"
local m_tabs=iup.tabs{page1,page2}
local dlgThermalProcess = iup.dialog{m_tabs, title="Thermal Processing", size="350x200"}
txtTime:setOwner(dlgThermalProcess)
txtTemperature:setOwner(dlgThermalProcess)
6.16 Adding Apps to Ribbon Interface
Once an app is developed, it is best to add it to a ribbon page for convenience. In the figure below,
we see 3 pages, namely “Home”, “Workbook” and “Apps”. At the “Apps” page, there are 2 panels,
namely “Process Engineering” and “Statistics” and each panel has a number of buttons.
Addition of a new page or editing an existing one is done through the manifest.xml file. The main
idea is that clicking on a button executes a function which shows an app. Therefore, first of all we
need to make a button and then assign a function to the button.
Now that it is understood that it is possible to have many pages, which can have many panels, which
can have many buttons, let’s see how we can create using manifest.xml file. Currently, the XML
file have the following tags (note the conceptual difference between the words, make and add):
1. RIBBON: The root of the XML.
2. PAGE: Adds a new page. It has only 1 attribute, namely the TITLE.
3. BUTTON: Makes a button. It has two attributes, namely, NAME and TITLE. NAME
attribute is similar to a variable and all your buttons must have a unique name, whereas
TITLE is what is shown as a text on the button. BUTTON can have two child elements:
1. FUNCTION: Exact name of the function with its location relative to global table.
2. IMAGE: Exact location of the image relative to the Apps folder. The image must be
32x32 pixels.
4. DROPBUTTON: Makes a dropdown button. It has two attributes, namely NAME and
TITLE, which functions exactly the same way as the BUTTON element. It can have only 1
child element as IMAGE and many child elements as ADD.
The button itself can be either directly added to a panel or become
part of a dropdown. A dropdown button, namely “t-test”, is shown in
the figure.
Clicking on a dropdown button shows a menu with entries, where
each entry is considered as a button. Therefore, conceptually a
dropdown button is a container for buttons.
1. IMAGE: Exact location of the image relative to the Apps folder. The image must be
32x32 pixels.
2. ADD: Name of the button to be added to the DROPBUTTON.
5. PANEL: Adds a panel to the PAGE. It has only 1 attribute namely TITLE and can have many
child elements with the tag ADD, which adds a dropbutton and a button.
To be able to add a dropbutton similar to the one shown in Fig Error! Reference source not found.
(with only two entries) to the “Apps” page and to the “Statistics” panel, we would use the following
XML structure:
<RIBBON>
<PAGE TITLE="Apps">
<BUTTON NAME="ttest1sample" TITLE="1 sample t-test">
<FUNCTION>std.app.TTest1Sample</FUNCTION>
<IMAGE>images/t_test1sample.png</IMAGE>
</BUTTON>
<BUTTON NAME="ttest2sample" TITLE="2 sample t-test">
<FUNCTION>std.app.TTest2Sample</FUNCTION>
<IMAGE>images/t_test2sample.png</IMAGE>
</BUTTON>
<DROPBUTTON NAME="ttest" TITLE="t-test">
<IMAGE>images/t_test.png</IMAGE>
<ADD>ttest1sample</ADD>
<ADD>ttest2sample</ADD>
</DROPBUTTON>
<PANEL TITLE="Statistics">
<ADD>ttest</ADD>
</PANEL>
</PAGE>
</RIBBON>
7 DATA STRUCTURES
To be able to manipulate different types of data, ScienceSuit is equipped with many essential data
structures as listed below:
1. Array,
2. Database,
3. Matrix,
4. Vector,
5. Range,
6. Worksheet,
7. Workbook.
Among the above-listed data structures Vector and Matrix are specialized to manipulate numeric data
and as a matter of fact can only contain numeric values of floating type.
On the other hand Array and Lua tables accept string, integer and float types.
Database is powerful for manipulating SQLite database and Workbook, Worksheet and Range provide
rather convenient read/write access to data hosted in a Workbook.
The purpose-specific data structures such as Food, Thermal Fluid, for computing thermo-physical and
thermodynamic properties of foods and fluids, respectively.
7.1 Vector
Vectors in ScienceSuit is extremely flexible to work with. You can read from or change elements of
a vector in several ways. For accessing the elements of a vector the following are the possible cases:
1. Accessing to single values
2. Accessing to multiple values
The first case is fairly simple; however, the 2nd one requires attention. Let’s start working with the
following vector, v: v = 1 2 3 4 5 6 7 8 9 10
Case 1: Accessing to single values
To change a single entry in the vector:
>>v[1]=11
>>v
11 2 3 4 5 6 7 8 9 10
To read a single entry from the vector:
>>v[1] or >>v(1)
11
Case 2: Accessing to multiple values
Changing the 2nd and the 3rd entries in the vector to number 20:
>>v[{2, 3}]=20
11 20 20 4 5 6 7 8 9 10
To change all entries to 30:
>>v[{}]=30
30 30 30 30 30 30 30 30 30 30
Following command changes entries starting from 8th element to 10:
>>v[{from=8}]=10
30 30 30 30 30 30 30 10 10 10
To change entries starting from 2nd element to 4th element to 20:
>>v[{from=2, to=4}]=20
>>v
30 20 20 20 30 30 30 10 10 10
To change entries from 1st element to 10th element changing by every 2nd element to 20:
>>v[{from=1, to=10, by=2}]=40
>>v
40 20 40 20 40 30 40 10 40 10
Let v = 1 2 3 4 5 6 7 8 9 10
Changing 1st and 2nd elements to 20 and 30, respectively:
>>v[{1, 2}]={10, 20}
>>v
10 20 3 4 5 6 7 8 9 10
In the following 2 commands, the number of indices are different than the number of values to be
assigned. In such cases, the number of assignment that occurs is the minimum of number of indices
and values, i.e. if there are 3 indices and 2 values then only the first 2 indices will be assigned to the
2 values.
>>v[{1, 2, 3}]={100, 200}
>>v
100 200 3 4 5 6 7 8 9 10
>>v[{1, 2}]={1, 2, 100}
>>v
1 2 3 4 5 6 7 8 9 10
In a similar fashion, in the following example we request all elements to be changed; however,
provide only 3 values. Therefore, only the first 3 entries have been changed.
>>v[{}]={11, 12, 13}
>>v
11 12 13 4 5 6 7 8 9 10
In the following one, we provide 3 values and request to change to the 3rd element (including the
3rd)
>>v[{to=3}]={1, 2, 3}
>>v
1 2 3 4 5 6 7 8 9 10
In the following command, we want to change 3 entries starting from 5th element, namely 5th, 6th
and 7th, but provide 4 values:
>>v[{from=5, to=7}]={50, 60, 70, 80}
>>v
1 2 3 4 50 60 70 8 9 10
Similar to the previous one, in the following command, we want to change 3 entries; however, this
time starting from 7th element, namely 7th, 6th and 5th:
>>v[{from=7, to=5}]={7, 6, 5} -- note the order of the assignment, v[7]=7...
>>v
1 2 3 4 5 6 7 8 9 10
Thus far we provided multiple values using a Lua table. However, we can also use a Vector on the
right-hand side. The way assignments work is same as the previous examples. Please note that in
the following example the vectors v and a have different sizes.
v = [1 2 3 4 5 6 7 8 9 10]
a = [10 20 30 40 50]
>>v[{1, 2}]=a
v = 10 20 3 4 5 6 7 8 9 10
>>v[{}]=a
v= 10 20 30 40 50 6 7 8 9 10
Vector class supports essential arithmetic operations: Let v1, v2 and v3 denote vectors of same size,
m a matrix and a an arbitrary number.
a) Addition: v1+v2=v3 v1+ a=a+v1=v2
b) Subtraction: v1-v2=v3 v1-a=v2 a-v1=v3
c) Multiplication:v1*v2=a v1*v2=m a*v1=v2 v1*v2=v3
d) Division: v1/v2=v3 v1/a=v2 a/v1=v3
e) Exponentiation: v1^a=v2 a^v1=v3
Note: Since a vector can have two shapes, namely column and row, during multiplication the order
matters. A row*column=number, whereas a column*row=matrix. If both vectors are of same shape,
then the return vector is an element-wise multiplication of both vectors.
Vector data type also supports __pairs and next methods, therefore is an iteratable container.
7.1.1 Member Functions
7.1.1.1 clone
clone()
Makes a deep copy of the vector itself. The following two commands are equivalent:
>>v1=v:clone()
>>v1=v({})
Both will make a deep copy of v and assign the result to v1.
7.1.1.2 capacity
capacity()
Shows the current capacity of the vector. This is different than member function size. Capacity
shows how much memory is allocated for the Vector before it automatically resizes (therefore
allocates new memory space).
7.1.1.3 equal
equal(arg, tol=1E-5)
Tests whether the elements of the Vector is equal to a number (vi==a) or elements of the Vector is
equal to the elements of another Vector (v1i==v2i). The equality test is done using a predefined
tolerance, which is 1E-5. The tolerance level can be specified by the user.
>>v=std.tovector{1, 2, 3.1, 3, 5, 5}
>>v
1 2 3.1 3 5 5 COL
To obtain the elements in the vector that is equal to 3 using the default tolerance level, in other
words ScienceSuit performs the following check:|𝑣[𝑖] − 3.0| ≤ 10−5
>>v:equal(3)
3
Since only one element satisfied the condition, the return value is that element’s value, a number.
In the following command, we arbitrarily set the tolerance level to 0.2:
>>v:equal(3, 0.2)
3.1 3 COL
Now, it is seen that more than 1 element satisfied the condition due to a greater tolerance value,
therefore, the return value is a vector containing the elements satisfying the condition.
If we want to test whether elements of the two vectors are equal with default tolerance level:
>>v1=std.tovector{1, 2, 3.1, 3, 5, 5}
>>v2=std.tovector{1, 2, 3, 3, 4, 5}
>>v1:equal(v2)
1 1 0 1 0 1 COL
In the above command, ScienceSuit performed the following check:|𝑣1[𝑖] − 𝑣2[𝑖]| ≤ 10−5and if
the condition is satisfied the returning vector’s ith element is set to 1, otherwise to 0. If v and v2 were
of different sizes, then an error would be thrown.
If we were to set the tolerance level to 0.2:
>>v1:equal(v2, 0.2)
1 1 1 1 0 1 COL
7.1.1.4 greater
greater(arg)
Works the same way as member function equal, except there is no tolerance defined. Tests for >
operator.
7.1.1.5 greater_equal
greater_equal(arg)
Works the same way as member function equal, except there is no tolerance defined. Tests for >=
operator.
7.1.1.6 insert
insert(pos, elem)
A number or another vector is inserted to the specified position.
To insert number 10 to the 1st position in the vector:
>>v=std.tovector{1, 2, 3}
>>v:insert(1, 10)
>>v
10 1 2 3 COL
To be able to insert another vector in to a specified position:
>>v=std.tovector{1, 2, 3}
>>v2=std.tovector{10, 20, 30}
>>v:insert(1, v2)
>>v
10 20 30 1 2 3 COL
7.1.1.7 less
less(arg)
Works the same way as member function equal, except there is no tolerance defined. Tests for the
< operator.
7.1.1.8 less_equal
less_equal(arg)
Works the same way as member function equal, except there is no tolerance defined. Tests for the
<= operator.
7.1.1.9 push_back
push_back(arg)
Adds an element to the end of the vector.
Let v= [1 2 3] and v1=[100 200]
To add a single number at the end of the vector:
>>v:push_back(4)
>>v
1 2 3 4
To append a Lua table (made up of only numbers) to the previously changed vector:
>>t={10, 20, 30}
>>v:push_back(t)
>>v
1 2 3 4 10 20 30
To append another vector to the previously modified vector:
>>v:push_back(v1)
>>v
1 2 3 4 10 20 30 100 200
7.1.1.10 reserve
reserve(num)
Reserves memory for the vector to be used. If any operation, such as push_back, that changes the
number of elements in the vector is greater than the current capacity then the Vector will
automatically reallocate new memory and copy the elements to the new location. The default is
1000.
>>v:capacity()
1000
In the following command, we attempt to reserve number of elements less than the current capacity:
>>v:reserve(500)
>>v:capacity()
1000
We can see that the command was not successful since the capacity of the vector is still 1000.
However, if we attempt to reserve number of elements greater than the current capacity, the
command will succeed:
>>v:reserve(5000)
>>v:capacity()
5000
7.1.1.11 resize
resize(newSize)
Changes the size of the vector. If the requested new size is less than the current size, elements from
the end will be deleted. However, if the requested new size is greater than the current size 0 will be
appended. Let v=10 20 30
The original vector v is of size 3. The following command resizes the vector to 2, therefore, the last
entry of the vector, number 30, is deleted:
>>v:resize(2)
10 20
Now the size of the vector is 2. If we resize the vector to 4, 0s will be appended:
>>v:resize(4)
10 20 0 0
7.1.1.12 reverse
reverse()
Reverses the order of elements.
>>v=std.tovector{1, 2, 3, 4, 5}
>>v:reverse()
>>v
5 4 3 2 1 COL
7.1.1.13 shape
shape()
Returns the shape of the Vector. There are 3 different shapes, namely col, row and lnk. The lnk arises
only when referred from a Matrix data structure. The default shape for Vector is col.
>>v=std.tovector{1, 2, 3}
>>v:shape()
col
By default, the shape of vectors are col. If we take the transpose of the vector, the shape changes to
a row vector as evidenced by the following commands:
>>v2=std.trans(v)
>>v2:shape()
row
7.1.1.14 shuffle
shuffle()
Randomly shuffles the positions of the elements in the vector. The size of the vector is not affected.
Let v=1 2 3 4 5
>>v:shuffle()
4 1 5 2 3
7.1.1.15 slice
slice(pos)
Slices the vector into two from the given position. The vector is not affected.
>>v=std.tovector{1, 2, 3, 4, 5}
>>v1,v2=v:slice(3)
>>v1
1 2 3 COL
>>v2
4 5
7.1.1.16 sort
sort(order)
The order can be either “A” or “D” for ascending and descending order sorts, respectively.
>>v=std.tovector{1, 5, 2, 7, 4}
>>v
1 5 2 7 4 COL
>>v:sort("A")
>>v
1 2 4 5 7 COL
7.2 Matrix
Similar to Vector data structure that is specialized to manage 1D numeric data, Matrix is also very
flexible but to work with 2D numeric data. You can read from or change elements of a matrix in
several ways. For accessing the elements of a matrix the following are the possible cases:
1. Accessing single values
2. Accessing multiple values
Case 1: Accessing to single values:
>>m=std.tomatrix{ {1, 2, 3} , {3, 4, 5} , {6 , 7, 8} }
>>m
1 2 3
3 4 5
6 7 8
>>m[1][1]=10
>>m[{2}]=20
>>m
10 20 3
3 4 5
6 7 8
m[1][1]=10: The matrix was accessed using m[row][column] access style. Here we changed the
first row and first column from 1 to 10.
m[{2}]=20: The matrix was accessed using the linear indexing concept, which for the (3x3) matrix,
m, ranges from 1 to 9, where 1 is equal to m[1][1] and 9 is equal to m[3][3].
>>m[2][3] or >>m(2,3)
5
>>m[{7}]
6
It can be noticed that when reading values from the matrix, the call m[2][3] is equivalent to m(2,3).
Case 2: Accessing to multiple values:
>>m=std.tomatrix{ {1,2,3} , {4,5,6} , {7,8,9} }
>>m
1 2 3
4 5 6
7 8 9
>>m[{1,3,5}] -- or m({1,3,5})
1 3 5 COL
It is seen that if the return value is a single number then the return type is number; however, if it is
more than a single value and 1D, then the return type is Vector.
>>m[{from=3, to=5}]={30, 40, 50, 60}
>>m
1 2 30
40 50 6
7 8 9
In the above example, using linear indexing we request that elements from 3 to 5 (3, 4 and 5) be
equal to 30, 40 and 50. Since we request only 3 elements to be changed, the 4th element on the right-
hand side, number 60, was ignored. Following is another case.
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>m[{from=3, to=5}]={30, 40}
>>m
1 2 30
40 5 6
7 8 9
This time we have requested 3 elements on the left-hand side to be changed but only provided 2
numbers on the right-hand side. Therefore, only 2 elements were changed.
In the following example, notice the use of keyword by:
>>m=std.tomatrix{ {1,2,3} , {4,5,6} , {7,8,9} }
>>m[{from=3, to=9, by=4}]={30, 70, 90}
>>m
1 2 30
4 5 6
70 8 9
The following is also doable:
>>m=std.tomatrix{ {1,2,3} , {4,5,6} , {7,8,9} }
>>m[{}]={10, 20, 30, 40}
>>m
10 20 30
40 5 6
7 8 9
On the right-hand side we can also use a Vector. The following example demonstrates this:
>>m=std.tomatrix{ {1,2,3} , {4,5,6} , {7,8,9} }
>>v=std.tovector{10, 20, 30}
>>m[{}]=v
>>m
10 20 30
4 5 6
7 8 9
To change all the elements of a matrix to a single value:
>>m=std.tomatrix{ {1,2,3} , {4,5,6} , {7,8,9} }
>>m[{}]=10
>>m
10 10 10
10 10 10
10 10 10
To read a single-column or a row, the following syntax can be used:
>>m=std.tomatrix{ {1,2,3} , {4,5,6} , {7,8,9} }
>>m({},1) -- read the first column
1 4 7 COL
>>m(1,{}) --read the first row
1 2 3 ROW
7.2.1 Link Vectors
Internally a matrix is composed of vectors. Therefore, it is highly efficient to read a row in the
following way:
>>m=std.tomatrix{ {1,2,3} , {4,5,6} , {7,8,9} }
>>m[1]
1 2 3 LINK
However, although it can be noticed that the return type is a Vector, it is neither row nor a column
vector, but a link vector. A link vector shares the same memory space with the row of a matrix and
as mentioned above this is due to the fact that Matrix is made up of Vectors.
The following example is very illustrative what could happen if caution is not exercised when
working with link vectors.
>>m=std.tomatrix{ {1,2,3} , {4,5,6} , {7,8,9} }
>>v=m[1] -- create a link vector
>>v[1]=10
>>m
10 2 3
4 5 6
7 8 9
Here initially a link vector is created using v=m[1] and then the first element of the link Vector is
set to 10 by v[1]=10. Although, the elements of matrix was not directly accessed, it is noticed that
the first element of the first row of the matrix was changed indirectly via the link vector.
What happens if v is destroyed by Lua when it is no longer used, such as v=nil or it is out of scope:
>>v=nil
>>m
10 2 3
4 5 6
7 8 9
Here, we see that the matrix remains intact. Internally when link vectors are destroyed, the memory
shared by the vector is not deleted, therefore the matrix is not affected.
Matrix structure supports essential arithmetic operations: Let m1, m2 and m3 denote matrix of same
size, and a an arbitrary number.
a) Addition: m1+m2=m3 m1+ a=a+m1=m2
b) Subtraction: m1-m2=m3 m1-a=m2 a-m1=m3
c) Multiplication:m1*m2=m3 a*m1=m1*a=m2
Besides the arithmetic operators, Matrix also supports __pairs and next methods, therefore is an
iteratable container.
7.2.2 Member Functions
7.2.2.1 append
append(elem, align)
Appends a vector or a Lua table to the matrix (please see insert).
The arguments:
elem: Either a Vector or a Lua table
align: Alignment of the inserted element, either “row” or “col”.
>>m=std.tomatrix{ {1,2,3} , {4,5,6} , {7,8,9} }
>>m
1 2 3
4 5 6
7 8 9
>>m:append( {10, 20, 30}, "row") -- append by row
>>m:append( {11, 12, 13, 14}, "col") -- append by column
>>m
1 2 3 11
4 5 6 12
7 8 9 13
10 20 30 14
Appending a vector is as same as appending a Lua table:
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>v=std.tovector{10, 20, 30}
>>m:append(v,"row")
>>m
1 2 3
4 5 6
7 8 9
10 20 30
7.2.2.2 clone
clone()
Makes an exact copy of the existing matrix. Notice the difference in the following commands.
>>m=std.tomatrix{{1,2,3},{4,5,6},{7,8,9}}
>>m1=m[{}] -- array access via linear indexing (return type is vector)
>>m1
1 2 3 4 5 6 7 8 9 COL
>>m2=m({},{}) -- function call access via two empty Lua tables (return type is matrix)
>>m2
1 2 3
4 5 6
7 8 9
>>m3=m:clone() -- direct call of the clone member function equivalent to m({},{})
>>m3
1 2 3
4 5 6
7 8 9
7.2.2.3 delc
delc(pos)
Deletes a column at the specified position, if the matrix will have at least 2 columns after the deletion.
Otherwise an error message is returned.
>>m=std.tomatrix{ {1,2,3} , {4,5,6} , {7,8,9} }
>>m:delc(2)
>>m
1 3
4 6
7 9
7.2.2.4 delr
delr(pos)
Deletes a row at the specified position, if the matrix will have at least 2 rows after the deletion.
Otherwise an error message is returned.
>>m=std.tomatrix{ {1,2,3} , {4,5,6} , {7,8,9} }
>>m:delr(2)
>>m
1 2 3
7 8 9
Alternatively, m[2]=nil would have given the same result.
7.2.2.5 greater_equal
greater_equal(arg, tol=1E-5)
The function first tests for equality of the element with the given tolerance as described in the equal
member function, if this test fails then tests whether it is greater. Tests for the >= operator.
7.2.2.6 insert
insert(elem, pos, align)
Inserts a vector or a Lua table to the matrix (please see append). The arguments:
elem: Either a Vector or a Lua table
pos: A valid position starting from 1.
align: Alignment of the inserted element, either “row” or “col”.
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>m:insert( {10, 20, 30}, 2, "col")
>>m
1 10 2 3
4 20 5 6
7 30 8 9
>>m:insert({11,12,13,14}, 1, "row")
>>m
11 12 13 14
1 10 2 3
4 20 5 6
7 30 8 9
The syntax of inserting a Vector to the matrix is same as inserting a Lua table.
>>m=std.tomatrix{ {1, 2, 3}, {4, 5, 6} , {7, 8, 9} }
>>v=std.tovector{10, 20, 30}
>>m:insert(v, 3, "col")
>>m
1 2 10 3
4 5 20 6
7 8 30 9
7.2.2.7 less
less(arg)
Works the same way as member function equal, except there is no tolerance defined. Tests for the
< operator.
7.2.2.8 less_equal
less_equal(arg, tol=1E-5)
The function first tests for equality of the element with the given tolerance as described in the equal
member function, if this test fails then tests whether it is less. Tests for the <= operator.
7.2.2.9 ncols
ncols()
Returns the number of columns. The returned value is of type integer.
7.2.2.10 nrows
nrows()
Returns the number of rows. The returned value is of type integer.
7.2.2.11 sort
sort(pos, order)
Sorts the matrix by given column position.
Arguments:
pos: Column number according to which the matrix will be sorted.
order: Sort order, either “A” or “D” for ascending and descending sorts.
>>m=std.floor( std.rand(3, 3) * 10)
>>m
6 7 2
5 8 9
6 9 6
>>m:sort(1,"D")
>>m
6 7 2
6 9 6
5 8 9
7.3 Array
Vector and Matrix are specialized in numeric data and can only contain numeric values. However,
Array can contain both numeric and non-numeric values.
7.3.1 Creating an Array
>>arr1=Array.new(3, "a")
>>arr1
"a" "a" "a"
>>arr2=Array.new(2, 3.14)
>>arr2
3.14 3.14
>>arr3=std.toarray{1,2,"a","b"}
>>arr3
1 2 "a" "b"
In order to create an array from data, you can use either toarray function or use the interface. When
interface is used to create an array, if a string can be converted to a valid number, then it will be
stored as type number, otherwise as type string.
It should be noted that, unlike the Vector data type, there is no algebra defined for arrays.
7.3.2 Array Manipulation
Consider the following array, a: a = 1 2 3 "a" "b"
If you print the array using the command-line:
>>a
1 2 3 "a" "b"
It is seen that string values are printed using double quotient.
To read an entry from the array:
>>a[1] or >>a(1)
10
>>type(a[1])
number
>>type(a[4])
string
To change an entry:
>>a[1]=10 --a[1] will be numeric
>>a[4]="c" --a[4] will be a string
>>a
10 2 3 "c" "b"
7.3.3 Member functions
7.3.3.1 capacity
capacity() → integer
Returns the capacity of the array.
>>a=std.toarray{1, 2, 3, "a", "b"}
>>a:capacity()
6
>>#a -- size
5
Note: Capacity is important as nearing the limit of capacity will cause reallocation of the memory
to accomodate more elements, thus causing the copying of the existing elements.
7.3.3.2 clone
clone()
Makes a deep copy of the array.
Note that, the assignment operator such as arr1=arr2 makes a shallow copy and arr1 and arr2
refers to the same data.
>>a=std.toarray{1, 2, 3, "a", "b"}
>>b=a
>>b[1]=10
>>a
10 2 3 "a" "b"
However, if we had used clone() function:
>>a=std.toarray{1, 2, 3, "a", "b"}
>>b=a:clone()
>>b[1]=10
>>a
1 2 3 "a" "b"
>>b
10 2 3 "a" "b"
7.3.3.3 erase
erase(pos)
Erases the element at the specified position as long as array will have at least one element at the end
of the operation.
>>a=std.toarray{1, 2, 3, "a", "b"}
>>a:erase(4)
>>a
1 2 3 "b"
>>a=std.toarray{"a", "b"}
>>a:erase(1)
>>a
"b"
>>a:erase(1)
ERROR: An array must have at least one element.
7.3.3.4 insert
insert(i,elem)
Inserts a number, 1D Lua table or an array at ith position.
>>a=std.toarray{"a", "b"}
>>a:insert( 2, {1, "c"} )
>>a
"a" "c" 1 "b"
>>a=std.toarray{"a", "b"}
>>a2=std.toarray{1, "c"}
>>a:insert( 2, a2)
>>a
"a" 1 "c" "b"
Note that, when a Lua table is inserted into the array, there is no guarantee that the order of the
elements in the table will be preserved when they are inserted to the array. If order of the elements
matter, insert elements as an array or individually.
7.3.3.5 push_back
push_back(elem)
Inserts the elem at the end of the array. The argument elem can be either number or string.
>>a=std.toarray{"a", "b"}
>>a:insert(3, "c")
ERROR: Requested position index exceeds array's size.
>>>a:push_back("c")
>>a
"a" "b" "c"
7.3.3.6 reserve
reserve(n)
Requests that the array capacity be at least enough to contain n number of elements. If the parameter
n is smaller than the current capacity, calling reserve has no effect.
>>arr=std.toarray{1, 2, "a", "b"}
>>arr:capacity()
4
>>arr:reserve(3)
>>arr:capacity()
4
>>arr:reserve(10)
>>arr:capacity()
10
>>#arr
4
7.3.3.7 resize
resize(n)
Resizes the container so that it contains n number of elements. Depending on the requested number,
the Array can shrink or expand.
>>arr=std.toarray{1, 2, "a", "b"}
>>#a
4
>>a:resize(6)
>>a
1 2 "a" "b" 0 0
>>#a
6
>>a:resize(3)
>>a
1 2 "a"
>>#a
3
7.3.3.8 shuffle
shuffle()
Shuffles the order of the elements in the Array.
>>a=std.toarray{1, 2, "a", "b"}
>>a:shuffle()
>>a
"a" 1 "b" 2
7.3.3.9 slice
slice(index)
Slices the array into 2 arrays as of the requested index and returns 2 arrays. The original array itself
is not affected.
>>a=std.toarray{1, 2, "a", "b"}
>>a1, a2=a:slice(2)
>>a1
1 2
>>a2
"a" "b"
>>a
1 2 "a" "b"
7.3.3.10 sort
sort(order=, caseSensitive=true)
Sorts the array either in ascending or descending order and/or case-sensitive or case-insensitive
manner. Regardless of case-sensitivity, the numbers are always assumed to be smaller than letters.
If order="A" then the array is sorted in ascending order, if order="D" then the array is sorted in
descending order. The sorting by default is case-sensitive.
>>a=std.toarray{2, "c", "a", "d", 1}
>>a:sort("A")
>>a
1 2 "a" "c" "d"
>>a:sort("D")
>>a
"d" "c" "a" 2 1
7.3.3.11 unique
unique()
Removes the recurring elements so that the array contains only the unique elements. At the end of
the operation, the array is resized to only contain unique elements.
>>a=std.toarray{1, "b", "2", "a", "b", "2"}
>>a:unique()
>>a
1 2 "a" "b"
7.4 Food
Food in ScienceSuit is assumed to be composed of macronutrients, ash and salt:
• Water,
• Carbohydrate (CHO),
• Protein,
• Lipid (Oil/Fat),
• Ash
• Salt.
>> myfood=Food.new{Water=30, CHO=70}
>> myfood
Weight (unit weight)=1.00
Temperature (C)=20.00
Water (%)=30.00
CHO (%)=70.00
Aw=0.751
pH=6.00
This command creates a food material and assigns it to variable myfood. The keys for Lua table are
water, CHO, protein, lipid or oil or fat, ash and salt and are case-insensitive.
The variable myfood has the following properties: Its temperature is 20 °C and pH is 6 by default
(unless changed, it remains as 6.0). Its weight is 1 unit and 30% of it is water and 70% is
carbohydrate (please note that if the total percentage in the above command-line was not 100, it would have
been adjusted to 100).
Please note that in the following example, although the sum of percentages in myfood2 is not equal
to 100%, it will be automatically adjusted to 100% and therefore the percentages of water and
carbohydrate in myfood and myfood2 are same.
>>myfood2=Food.new{Water=15,CHO=35}
>>myfood2
Weight (unit weight)=1.00
Temperature (C)=20.00
Water (%)=30.00
CHO (%)=70.00
Aw=0.751
pH=6.00
7.4.1 Mathematical Operations
Food data structure supports some arithmetic operations: Let f1, f2 and f3 denote Food and a and b
an arbitrary numbers.
a) Addition: f1+f2=f3 a*f1+b*f2=f3
b) Subtraction: f1-f2=f3
c) Multiplication: a*f1 =b*f1 = f1*a = f1
A) Addition: Addition operation can be considered as the unit operation of mixing of food materials.
The data structure allows mixing of different food materials at different temperatures. Mass and
energy balances are performed automatically.
Note on energy balance:
Following equation is used:𝑚𝑡𝑜𝑡𝑎𝑙 ⋅ 𝐶𝑝𝑚𝑖𝑥 ⋅ 𝑇𝑚𝑖𝑥 = 𝑚1 ⋅ 𝐶𝑝1 ⋅ 𝑇1 + 𝑚2 ⋅ 𝐶𝑝2 ⋅ 𝑇2
Here one can quickly notice that𝑚𝑡𝑜𝑡𝑎𝑙 = 𝑚1 + 𝑚2 however, Cpmix and Tmix are unknown and
furthermore Cpmix=f(Tmix). Knowing that specific heat capacity of foods hardly changes within a
specific temperature range (a phase change is not considered), the following equation was used:
𝐶𝑝𝑚𝑖𝑥 = 𝐶𝑝𝑎𝑣𝑒𝑟𝑎𝑔𝑒 =𝐶𝑝1 + 𝐶𝑝2
2.0
Let’s create two food materials:
>> f1=Food.new{Water=30, CHO=70}
>>f2=Food.new{oil=40, protein=60}
Say, we would like to mix equal proportions of f1 and f2:
>>f3 = f1 + f2
>>f3
Weight (unit weight)=2.00
Temperature (C)=20.00
Water (%)=15.00
Protein (%)=30.00
CHO (%)=35.00
Lipid (%)=20.00
Aw=0.334
pH=6.00
Here, the addition operation yielded a new food material and as expected the new food material f3
is composed of water, protein, carbohydrate and lipid. Its weight is 2 units (please see member
function normalize())and its temperature is 20°C.
Instead of equal proportions, say we want to mix 20% f1 and 80% f2:
>>f4 = 0.2*f1 + 0.8*f2
>>f4
Weight (unit weight)=1.00
Temperature (C)=20.00
Water (%)=6.00
Protein (%)=48.00
CHO (%)=14.00
Lipid (%)=32.00
Aw=0.085
pH=6.00
It should be noticed that although f1 and f2 are mixed, we named the variable as f4 instead of f3. This
is because two food materials are considered to be equivalent if they contain the same amount of
each macro-component, therefore f4 is not equal to f3.
B) Subtraction: Subtraction can be considered as the unit operation evaporation or extraction.
Therefore, it is only allowed to subtract f2 from f1, if and only if, f2 is at the same temperature with
f1 and contains exactly the same, but to a lesser amount of, macro-components.
In the following example our goal is to make a powder out of milk. We know that we need to remove
water from the milk to achieve this goal. Therefore, we create two food materials, namely milk and
water.
>>milk=Food.new{water=88.13, protein=3.15, CHO=4.80, lipid=3.25, ash=0.67}
>>water=Food.new{water=100}
>>powder=milk-0.87*water
>>powder
Weight (unit weight)=0.13
Temperature (C)=20.00
Water (%)=8.69
Protein (%)=24.23
CHO (%)=36.92
Lipid (%)=25.00
Ash (%)=5.15
Aw=0.192
pH=6.00
A few things should be noted here:
1. A new food material, namely powder, of weight 0.13 units was obtained (1 unit of milk –
0.87 unit of water). If you were to use the variable powder as is, its weight will be 0.13 units
in any operation, therefore, please see the member function normalize() to prevent pitfalls.
2. Had we run a command such as powder=milk – water, it would not have been successful as
1 unit of milk does not have 1 unit of water.
3. The obtained food material, namely powder, has higher percentage of lipid, protein, CHO
and ash but a lower percentage of water, as expected.
C) Multiplication: Unlike addition or subtraction, which yielded new food materials,
multiplication does not yield a new food material. It only changes the weight of the food material.
This is necessary to be able to perform addition or subtraction operations:
Taking the previous example:
>>f4 = 0.2*f1 + 0.8*f2
To be able to perform this addition, behind the scenes Lua first creates a temporary food material
from 0.2*f1, say temp1, and then another temporary food material from 0.8*f2, say temp2. f4 is
actually f4=temp1+temp2.
7.4.2 Member Functions
7.4.2.1 aw(arg)
Calculates the water activity of the food material. Argument arg can be either a nil value, a valid
number or a function which returns a valid number.
Solute is defined as: Solute=CHO+lipid+protein+ash+salt.
The following assumptions were made:
1. %Water < 0.00001 → aw=0.01
2. %Solute <1 → aw=0.99
For non-electrolyte solutions (% salt <0.00001):
1. %water >99.0 → aw=0.98
2. %CHO>98 and all others <1% → aw=0.70
3. % water (1,5) and %CHO>5 → aw=MoneyBorn equation
4. %water >5 and %CHO>5 → aw=Norrish equation
For both MoneyBorn and Norrish equation, the amount of fructose was considered as the amount
of CHO. For Norrish equation amounts of glycerol and alanine were considered to be equal to
amounts of lipid and protein, respectively.
If the argument arg is provided as an acceptable valid number, then the above-mentioned
calculations are skipped and the provided value is used thereafter:
>>milk=Food.new{water=88.13, protein=3.15, CHO=4.80, lipid=3.25, ash=0.67}
>>milk
Aw=0.920 --value computed using above-mentioned assumptions
>>milk:aw(0.95) --explicitly setting the value
>>milk
Aw=0.950
>>milk:aw() --calling the water activity returns the set value
0.95
If a different function is better suited to compute the water activity of a specific food material, then
the argument arg must be of type function. When such a function is provided, ScienceSuit uses the
provided function to calculate the water activity. The provided function must be in the following
format:
function ComputeAw (myfood)
Here, the function name ComputeAw is arbitrarily chosen for the example. The argument, myfood,
whose name is also arbitrarily chosen, is the food material that calls the member function, to
calculate aw. Therefore, ComputeAw has access to all of the properties of the calling food material.
Let’s first define a rather simple function which will compute the water activity:
function ComputeAw(myfood)
if (myfood:get().water > 85) then
return 0.95
end
end
Let’s define a food variable, namely milk, and use the above function to calculate water activity:
>>milk=Food.new{ water=88.13, protein=3.15, CHO=4.80, lipid=3.25, ash=0.67 }
>>milk:aw() --returns the value computed using system’s assumptions
0.92
>>milk:aw(ComputeAw) --explicitly setting the value using ComputeAw function
>>milk:aw() --calling the water activity returns the value set by ComputeAw function
0.95
7.4.2.2 cp(arg)
Returns the specific heat capacity (kJ/kgK) of the food material. The following predictive equation
is used to calculate specific heat capacity:
𝑤𝑎𝑡𝑒𝑟 = 4.1289 − 9.0864 ⋅ 10−5𝑇 + 5.4731 ⋅ 10−6𝑇2
𝑝𝑟𝑜𝑡𝑒𝑖𝑛 = 2.0082 + 1.2089 ∗ 10−3𝑇 − 1.3129 ∗ 10−6𝑇2
𝑙𝑖𝑝𝑖𝑑 = 1.9842 + 1.4733 ∗ 10−3𝑇 − 4.8008 ⋅ 10−6𝑇2
𝐶𝐻𝑂 = 1.5488 + 1.9625 ⋅ 10−3𝑇 − 5.9399 ⋅ 10−6𝑇2
𝑎𝑠ℎ = 1.0926 + 1.8896 ⋅ 10−3𝑇 − 3.6817 ⋅ 10−6𝑇2
𝑠𝑎𝑙𝑡 = 0.88
If a different function or value is better suited to compute the specific heat capacity of a specific
food material, then the argument arg needs to be provided (see member function aw() for more info).
7.4.2.3 get()
Returns a Lua table containing the macronutrients, ash and salt.
>>milk=Food.new{water=88.13, protein=3.15, CHO=4.80, lipid=3.25, ash=0.67}
>>tbl=milk:get() -- tbl={CHO=4.8, ash=0.67,salt=0,protein=3.15,water=88.13,lipid=3.25}
>>type(tbl)
table
7.4.2.4 k(arg)
If argument arg is not provided then returns the thermal conductivity (W/mK) of the food material.
The following predictive equations is used to calculate thermal conductivity:
𝑤𝑎𝑡𝑒𝑟 = 0.457109 + 1.7625 ⋅ 10−3𝑇 − 6.7036 ⋅ 10−6𝑇2
𝑝𝑟𝑜𝑡𝑒𝑖𝑛 = 0.17881 + 1.1958 ⋅ 10−3𝑇 − 2.7178 ⋅ 10−6𝑇2
𝑙𝑖𝑝𝑖𝑑 = 0.18071 − 2.7604 ⋅ 10−4𝑇 − 1.7749 ⋅ 10−7𝑇2
𝐶𝐻𝑂 = 0.20141 + 1.3874 ⋅ 10−3𝑇 − 4.3312 ⋅ 10−6𝑇2
𝑎𝑠ℎ = 0.32962 + 1.4011 ⋅ 10−3𝑇 − 2.9069 ⋅ 10−6𝑇2
𝑠𝑎𝑙𝑡 = 0.574
If a different function or value is better suited to compute the thermal conductivity of a specific food
material, then the argument arg needs to be provided (see member function aw() for more info).
7.4.2.5 normalize()
Only sets the weight to 1.0. However, this is a rather important function as the food material that is
a result of an addition or a subtraction operation can have a weight different than 1.0 as shown in
the following example:
>>milk=Food.new{water=88.13, protein=3.15, CHO=4.80, lipid=3.25, ash=0.67}
>>water=Food.new{water=100}
>>powder=milk-0.87*water
>>powder
Weight (unit weight)=0.13
If you were to use the variable powder as is in another mathematical operation, its weight would be
considered as 0.13 units. As an example, in a mixing operation where you, say, mix milk and powder:
Mathematically we would express the mixing operation as𝑚𝑦𝑚𝑖𝑥 = 𝑝𝑜𝑤𝑑𝑒𝑟 + 𝑚𝑖𝑙𝑘and it might
be expected that the variable mymix has a weight of 2.0 units. However, its weight is equal to 1.13
units, since powder is a mathematical result of an addition operation. To be able to use it
conceptually as an independent food material, it needs to be normalized,𝑝𝑜𝑤𝑑𝑒𝑟: 𝑛𝑜𝑟𝑚𝑎𝑙𝑖𝑧𝑒( ),
prior to any mathematical operation.
7.4.2.6 ph(arg)
If argument arg is provided as a number in the range of (0.14) then sets the pH value of the food
material. If arg is not provided the function returns the pH value, which is by default 6.0.
If a different function or value is better suited to compute the pH of a specific food material, then
the argument arg needs to be provided (see member function aw() for more info).
7.4.2.7 rho(arg)
If argument func is not provided then returns the density (kg/m3) of the food material. The following
predictive equations are used to calculate density:
𝑤𝑎𝑡𝑒𝑟 = 997.18 + 3.1439 ⋅ 10−3𝑇 − 3.7574 ⋅ 10−3𝑇2
𝑝𝑟𝑜𝑡𝑒𝑖𝑛 = 1329.9 − 5.1840 ⋅ 10−1𝑇
𝑙𝑖𝑝𝑖𝑑 = 925.59 − 4.1757 ⋅ 10−1𝑇
𝐶𝐻𝑂 = 1599.1 − 3.1046 ⋅ 10−1𝑇𝑎𝑠ℎ = 2423.8 − 2.8063 ⋅ 10−1𝑇
𝑠𝑎𝑙𝑡 = 2165
If a different value or a function is better suited to compute the density of a specific food material,
then the argument arg needs to be provided (see member function aw() for more info).
7.4.2.8 T(num)
If argument num is provided as a number then the function sets the temperature value of the food
material. If num is not provided the function returns the temperature of the food material.
7.5 ThermoFluid
It is used for computing thermodynamic properties of fluids. The available fluids are:
ASHRAE IUPAC TYPE Nsaturation Nsuperheated
R12 Dichlorodifluoromethane CFC 42 271
R22 Chlorodifluoromethane HCFC 35 155
R23 Trifluoromethane HFC 176 1333
R32 Difluoromethane HFC 68 53
R125 Pentafluoroethane HFC 69 64
R134A 1,1,1,2-Tetrafluoroethane HFC 69 334
R143A 1,1,1-Trifluoroethane HFC 66 63
R717 Ammonia N/A 67 371
R718 Water N/A 71 569
Note: Although the number of data entries for each saturated and superheated states is well satisfactory,
it should be noted that the more the experimental points the more accurate the results will be. For
example, for saturated state if the properties at T=85°C is requested, the properties, say at 80° and 90°C
will be found from the database and then linear interpolation will be performed to compute the properties
at 85°C.
For the compressed state, it is assumed that the properties are equal to saturated liquid's properties. For
more on this assumption (please see Cengel & Boles, Thermodynamics: An Engineering Approach).
In order to create a fluid class, run the following command:
>> fl=ThermoFluid.new("water") -- Either ASHRAE or IUPAC name is accepted as argument
7.5.1 Member functions
7.5.1.1 get(tbl)
Accepts one argument as Lua table, tbl, and returns the computed thermodynamic properties as a Lua
table.
The accepted keys for the tbl argument are:
Lua Table Key Meaning Units
P Pressure kPa
T Temperature °C
s Entropy kJ/kgK
h Enthalpy kJ/kg
v Specific Volume m3/kg
Possible combinations for the argument tbl are:
1) P (only saturated properties are searched)
2) T (only saturated properties are searched)
3) P,T (compressed, saturated and superheated properties are searched)
4) P,s (saturated and superheated properties) and T,s (only saturated properties are searched)
5) P,v and T,v (only saturated properties are searched)
6) P,h and T,h (only saturated properties are searched)
Example #1:
>>props=fl:get{P=10}
>>props
P=10 T=45.7384 vg=14.783 vf=0.0010103 uf=191.523 ug=2436.68 hf=191.534
hg=2584.51 sf=0.648314 sg=8.15173
Example #2:
>>props=fluid:get{T=45}
>>props
P=9.593 T=45 vf=0.00101 vg=15.26 uf=188.44 ug=2436.81 hf=188.45 hg=2583.2
sf=0.6387 sg=8.1648
Example #3:
>>props=fluid:get{P=10, T=100}
>>props
v=17.196 h=2687.5 s=8.4479
7.6 Database
It is used for connecting to databases (currently only SQLite) and running SQL queries.
Create → Connect → Query
In order to create a database class, run the following command:
>>db=Database.new()
>>db
You are not connected to a database.
At this stage, an empty database structure is created; however, in order to run SQL queries, a
connection must be opened:
>>db:open()
After the selection of a database file, if we query the state of the database object:
>>db
Connected to: C:\Users\gbingol\sciencesuit\_runtime\databases\ThermoFluids.db
Now that, a connection has been established, queries can be run. Let's query, which tables are
available in the connected SQLite database:
>>db:tables()
MainTable S_R12 SH_R12 S_R718 -- others omitted for brevity
Since the available table names are already known, we are ready to query the fields in a table:
>>db:fields("S_R12")
T P vf vg hf hg sf sg
Now that we know the table names and fields in a table, we can run different types of SQL queries:
>>tbl, nrow=db:sql("Select hf from S_R12 where hf>140")
>>tbl
140.068 148.076 157.085 168.059 174.92
7.6.1 Member functions
7.6.1.1 close
close()
Closes the existing connection to the database.
>>db:open()
>>db
Connected to: C:\Users\gbingol\sciencesuit\_runtime\databases\ThermoFluids.db
>>db:close()
>>db
You are not connected to a database.
7.6.1.2 columns
columns(str=)
An alias for the member function fields.
7.6.1.3 fields
fields(str=) → table
Returns a Lua table containing the names of the fields (column) existing in the table specified with
the argument str.
7.6.1.4 open
open([path=])
Opens, therefore connects to, the database at the specified path. If the path is not specified, then an
Open Dialog is shown to select the database file.
7.6.1.5 sql
sql(query=) → Table, integer, integer
Runs an SQL query. The returned table, a Lua table, contains the result of the query as type string
and the two integers are number of rows and columns of the returned Lua table. If the query returns
more than 1 columns then the table will be a 2D Lua table, whereas if the query returns a single
column, the query will be a 1D Lua table.
A query that returns 1D Lua table:
>>tbl, nrow, ncol=db:sql("Select hf from S_R12 where hf>140")
>>tbl
140.068 148.076 157.085 168.059 174.92
>>nrow
5
>>ncol
1
A query that returns 2D Lua table:
>>tbl,nrow, ncol=db:sql("Select * from S_R12")
>>type(tbl[1])
table
>>nrow
42
>>ncol
8
7.6.1.6 tables
tables() → table
Returns a Lua table containing the names of the existing tables in the database.
7.7 Worksheet
A worksheet is a container for data and also hosts Range objects. A worksheet is hosted by a
Workbook.
7.7.1 Creating & Closing
A worksheet is part of a workbook, therefore a statement like the following is not valid:
>> ws=Worksheet.new()
However, a worksheet in a workbook can be created using the add member function of the workbook.
>>ws=wb:add()
where the variable wb is of type Workbook and ws is of type worksheet.
When a worksheet is closed:
• The action cannot be undone.
• All Range objects belonging to the closed worksheet, created via the selection member
function or using the GUI will be invalid. This means that there will be no more access to
these variables.
7.7.2 Accessing Data
Understanding the location of the cells is important when accessing the cell in a worksheet. The
top-left cell of the worksheet, A1, is (1,1). Similarly, A2 and B2 are (1,2) and (2,2), respectively.
7.7.2.1 Reading from Cells
There are two ways the content of a cell can be read:
Array Access[][]: ws[1][1] will access the content of A1, where ws is of type worksheet.
Function call (): ws(2,2) will read the content of B2, where ws is of type worksheet.
Example: Consider the following worksheet
>>wb=std.activeworkbook() --active workbook
>>ws=wb:cur() -- current worksheet
>>ws(1, 1)
1
>>ws[1][1]
1
>>ws(2,2)
4
7.7.2.2 Writing to Cells
Using the array access we can easily write to a cell. Let's work on the worksheet containing the data
from A1 to B2 shown above. After executing the following commands, observe the difference:
>>ws[1][1]=10 --A1
>>ws[2][2]=40 --B2
>>ws[1][3]="C1"
>>ws[3][1]="A3"
It is seen that with the first command, A1 is
changed from 1 to 10 and with the second
command B2 is changed from 4 to 40.
Third and fourth commands have added entries
"C1" and "A3" to cells C1 and A3, respectively.
7.7.2.3 Formatted Writing to Cells
Although in section 7.7.2.2 it was shown how to write to cells, using this style will use the
formatting available in that particular cell. Therefore, when writing to the cells using the following
style gives no control over format.
>>ws[1][1]=”A1”
In order to use formatted output, instead of string or number, we use a Lua table on the right-hand
side. The keys and values are as follows:
Key Value
value Sets the value of the cell, either string or number.
fgcolor, bgcolor
(fgcolour, bgcolour)
String in the format of “R G B”. R, G and B must be in the range of
[0, 255]. fgcolor sets the text color whereas bgcolor sets the
background color of the cell.
style “italic” makes it italic, “normal” makes it non-italic.
weight “bold” makes it bold, “normal” makes it not bold.
underline “single” draws a single underline, “none” removes any underlines.
>>ws=std.activeworkbook():cur()
>>ws[1][1]={value="A1", fgcolor="255 0 0", bgcolor="0 255 0"}
>>ws[1][2]={value="B1", weight="bold"}
>>ws[2][1]={value="A2", style="italic"}
>>ws[2][2]={value="B2", underline="single"}
The output is shown in the following image:
7.7.3 Member functions
7.7.3.1 connect
connect(func, func_arg1,...)
where func is a Lua function to be run when the selection has happened. arg1, arg2,..., argn are the
arguments of the function func.
Connects a Lua function, func, to an event. Currently the only event being handled is the event that
is happening when user is selecting cells on a worksheet. This function is especially useful when
you want to change the text of a TextCtrl at the end of user's selection which emulates the selection
in MS Excel or LibreOffice Calc.
local function GetVariable(txt)
local ws=std.activeworkbook():cur()
local range=ws:selection()
if (range==nil) then
return
end
txt.value=tostring(range)
if(OwnerDialog~=nil) then
OwnerDialog.topmost="no"
end
end
function txt:button_cb()
if(OwnerDialog~=nil) then
OwnerDialog.topmost="yes"
end
local ws=std.activeworkbook():cur()
ws:connect(GetVariable, txt)
end
The above-code can easily become rather exhausting when more than one selection-event-aware
text control is to be designed. std.gui.gridtext is designed just for this purpose.
7.7.3.2 name
Returns the name of the worksheet as string.
name() → string
For the above shown images:
>>ws:name()
Sheet 1
7.7.3.3 parent
Returns the Workbook which owns the worksheet.
parent() → Workbook
7.7.3.4 selection
selection() → Range
Creates a Range class from the current selection. Consider the selection in the following image:
>>rng=ws:selection()
>>rng
Sheet 1!B3:C4
>>rng(1,1)
100
7.8 Workbook
A workbook is a container for multiple worksheets. It can be saved to and opened from a particular
directory. The extension of a workbook must be swb.
Creating & Closing
The following command creates a workbook and shows it to the user as shown in the following
image.
>> wb=Workbook.new()
It should be noted that the newly created workbook, namely "Workbook 2", is owned by Lua since
it was created using a command.
There are two types of ownership for a workbook and the ownership is rather important when
closing a workbook:
1. Sytem: The Workbook is created using the Workbook ribbon page as shown below:
2. Lua: The Workbook is created via command-line or using a script.
In some cases, the workbook can be shown after processing data (reading/writing). In order to create
a workbook without showing it to the user:
>> wb=Workbook.new(false)
When closing a workbook, the ownership matters. Consider the two workbooks shown in the first
figure, where "Workbook 1" is owned by System and "Workbook 2" is owned by Lua.
If we were to execute the following code, where wb2 is a system owned workbook and the code
executes its close member function, an error will be thrown:
>>wb2=std.activeworkbook()
>>wb2:title()
Workbook 1
>>wb2:close()
ERROR: The workbook is not owned by a script. You can only close it via close button.
It should be noted that System owned workbooks can only be closed via the close button, as long
as there is more than 1 System owned workbook. Furthermore, regardless of the number, Lua owned
workbooks can always be closed through close button.
7.8.1 Member functions
7.8.1.1 add
add(name="", row=1000, col=100) → Worksheet
Adds a worksheet to the workbook. If argument name is not provided, then the name of the
worksheet is assigned automatically. Note that worksheets in a workbook must have a unique name.
7.8.1.2 close
close()
Closes the workbook. If the workbook has any changes on it, then a Save prompt will be shown to
be able to save the changes.
>>wb=Workbook.new()
>>type(wb)
Workbook
>>wb:close()
>>type(wb)
userdata
It should be noted that once a workbook is closed, there will be no access to the variable as type
Workbook. The memory associated with it will be destroyed and its metatable will be stripped off.
Please also read the section on closing a workbook.
7.8.1.3 count
count() → integer
Returns the number of worksheets in the workbook.
7.8.1.4 cur
cur() → Worksheet
Returns the active worksheet. Active worksheet is the worksheet currently opened by either the user
or the script.
7.8.1.5 del
del(arg)
Deletes a worksheet. Parameter arg can be string, integer or Worksheet. After manually adding
worksheets and running the following commands the workbook looks like the one shown in figure:
>>wb=std.activeworkbook()
>>ws=wb:add("script")
If type(arg):
1. string: Deletes the worksheet with the given name.
>>wb:del("ab")
2. integer: Deletes the worksheet specified by its location at the tabbed bar. The worksheet at
the very left is number 1 and the one on its right is number 2 and so on.
>>wb:del(1)
3. Worksheet: Deletes the worksheet specified by its variable. Here ws is a variable, of type
worksheet.
>>wb:del(ws)
7.8.1.6 id
id() → integer
Every workbook, regardless created by a Lua command or by using the new button, has a unique
ID associated with the workbook. The function returns the ID of the workbook, which is an integer
number.
>>wb=std.activeworkbook()
>>wb:id()
1
>>wb2=Workbook.new()
>>wb2:id()
2
7.8.1.7 open
open([path=])
Opens the file with .swb from the specified path. The path variable, if provided, is of type string
and it might be either a fullpath or a path relative to the executable file, such as path="myfile.sswb".
It might be a better approach to create a Workbook without initially showing it to the user and then
opening the file at the specified path. After all these processed, then it might be shown to the user.
>>wb2=Workbook.new(false)
>>wb2:open("C:/Users/gbingol/Desktop/demo_data.swb") -- directory separator is / and not \.
>>wb2:show()
Sometimes, typing the full path can be cumbersome or you might want user to choose the path. The
following is doable too:
>>wb=Workbook.new(false)
>>wb:open()
7.8.1.8 save
save([path=])
Saves the workbook to the specified path. If the argument path, which must be of type string, is not
provided, then a Save dialog is shown to the user. If the file was previously saved to or opened from
a sswb file, the argument path must not be provided as this will throw an error.
>>wb=Workbook.new(false)
>>ws=wb:cur()
>>ws[1][1]="Hello"
>>wb:save()
>>wb:close()
7.8.1.9 show
show()
Shows the workbook, changes its state from hidden to visible.
7.8.1.10 title
title() → string
Returns the title of the Workbook. If the document is not opened from a directory then the title is
the one that was automatically assigned, otherwise returns the full path.
>>wb2=Workbook.new(false)
>>wb2:title()
Workbook 2
>>wb2:open("C:/Users/gbingol/Desktop/demo_data.swb")
>>wb2:title()
C:\Users\gbingol\Desktop\demo_data.swb
After the command wb:save(), the
Save dialog will be shown to the
user. Once the user saves the file,
the next line, wb:close(), will be
executed.
7.9 Range
A range is a user specified region within a worksheet. It does not have a reserved internal data
storage; only reads from and writes to the specified region by the user.
Creating Range
Unlike Worksheet, where indices (1,1) refers to A1, for a Range, (1,1) refers to the topleft corner of
the specified region.
>> range=Range.new(activeworkbook(), "Sheet1!B1:B5") -- (1,1) refers to B1
>> range=ws:selection() --Create a range from the selection of the user
Important note: If the Worksheet owning the range(s) is closed, the range(s) becomes invalid.
--create a new workbook
>>wb=Workbook.new()
--Create a range using the workbook
>>r=Range.new(wb, "Sheet 1!A1:B5")
--check the range
>>r
Sheet 1!A1:B5
--close the workbook (naturally, Sheet 1 is also closed)
>>wb:close()
--check the range
>>r
userdata --no more access to the range
Accessing cells
You can read from and write to the region specified by the range inside the Worksheet.
>>wb=std.activeworkbook()
--create a range [region is 2x2, from B2 to C3]
>>r=Range.new(wb, "Sheet 1!B2:C3")
--set B2 value as 10
>>r:set(1, 1, 10)
--read from B2
>>r(1, 1)
10
--set C3 value as "a"
>>r:set(2, 2, "a")
--read from C3
>>r(2, 2)
a
--Attempt to write at index (3,3)
>>r:set(3, 3, "c")
ERROR: Requested row is out of boundaries of the range
7.9.1 Member functions
7.9.1.1 col
col(i) → Array
Returns the ith column as an Array object.
7.9.1.2 coords
coords() → Lua table, Lua table
Returns the top-left and bottom-right coordinates, with respect to the worksheet. The Lua table has
keys r and c to show the location of row and column as integers, respectively.
>>r=Range.new(std.activeworkbook(), "Sheet 1!B2:C5")
>>t1, t2=r:coords()
>>t1
c=2 r=2
>>t2
c=3 r=5
7.9.1.3 get
get(i, j) → number/string
Returns the element at ith row and jth column. If range is a Range variable, then instead of
range:get(i, j), range(i, j) can be used as well.
7.9.1.4 parent
parent() → Worksheet
Returns the Worksheet which owns the range.
7.9.1.5 select
select()
Selects the range on the worksheet.
7.9.1.6 set
set(i, j, val)
Sets the value of the cell at ith row and jth column with the value, val.
7.9.1.7 sort
sort(pos, order, casesensitive=false)
Sorts the whole Range according to the selected column position, pos, by given order. If the
parameter order="A" or order="D" then the Range is sorted in ascending or descending order,
respectively. By default, the sorting is case-sensitive. Note that, numbers are considered to be
smaller than letters in a sort order.
7.9.1.8 tostring
tostring() → string
Returns information on the selection as string, such as in the first example, range:tostring() will
return "Sheet1!B1:B5".
7.10 Concept of Iterators and Containers
The concept of iterators and containers are not new and as a matter of fact, the STL library of C++
language has been designed based on this simple but very powerful concept.
As already mentioned most of the built-in data structures in ScienceSuit are iteratable containers
and by default, Lua tables are iteratable. When designing a new function, understanding the concept
of iterators and containers can save significant amount of time and furthermore make the code
significantly more readable.
Let’s demonstrate the concept with a simple example. Suppose we want to design a simple function
that finds the sum of the values and we want this to work, if not all, on many data structures:
function Sum(entry)
local total=0
if (type(entry)==”table” or type(entry)==”Vector”) then
for i=1,#entry do total=total+entry[i] end
elseif (type(entry)==”Matrix”) then
for i=1,#entry do total=total+entry[{i}] end
elseif
-- querying data types goes on
end
return total
end
It is immediately realized that as the number of data structures increases, there will be more if blocks
and it is indeed very easy to forget and rather cumbersome to add a data structure as the number of
functions and data structures increases. Therefore, we will end up with an error-prone, hard-to-read
and time-taking code.
Here, comes the life-saver: Iteratable containers
Had we used the concept of iteratable containers, we could have designed the function in the
following way:
function Sum(container)
local total=0
for key, value in pairs(container) do
if(type(value)==”number”) then total=total+value end
end
return total
end
One can quickly notice that the code is more concise, readable and less error-prone. Furthermore,
there are no if blocks checking the type of the container. As long as the function argument, namely
container, is an iteratable one, the code will work regardless of its type.
8 STD LIBRARY
8.1 A Note on Function Syntax
In Lua a function can have more than one signature. This provides considerable flexibility in
function notation. Changing the number of arguments changes how a function works. Moreover,
the data types for an argument can change as well. Furthermore, Lua provides support for named
arguments through use of tables.
8.1.1 Named arguments
The following command uses named arguments (note the opening and closing brackets).
>>std.pnorm{q=, mean=0, sd=1} → number
The function pnorm is under std library. By using the “{“ and “}” it allows name arguments. The
names (as a matter of fact, these are Lua table keys) are: q, mean and sd. The names mean and sd
have a default value of 0 and 1 respectively, therefore, if not supplied, these values will be used.
However, the name q must be provided. Also note that, when using name arguments, the order of
the names does not matter. Finally the right arrow indicates that the function returns a number.
Notice the variation in using the std.pnorm command with the name arguments:
>>std.pnorm{q=0.5, mean=0, sd=1}
0.691462
>>std.pnorm{q=0.5, sd=1, mean=0} --changing the argument order
0.691462
>>std.pnorm{q=0.5, mean=0} -- not providing sd
0.691462
>>std.pnorm{q=0.5} -- not providing sd and mean
0.691462
>>std.pnorm{mean=0, sd=1} -- not providing q
ERROR: First argument (q) must be either a number or of type Vector
Please note that in the last call, the mandatory name q was not provided, therefore, the function
threw an error.
8.1.2 Regular function call
Here, the term regular function call is used since in Lua every function call is surrounded with
parenthesis, ( and ). The so-called named argument call std.pnorm{} is just a syntactic sugar
mechanism provided by Lua for the function call std.pnorm({}).
Notice the use of parenthesis in the following command:
>>std.pnorm(q=, mean=0, sd=1) → number
The function pnorm is under std library. Since “(“ and “)” brackets are used, named arguments
cannot be used. The following cases are possible:
1. If 1 argument is provided: The argument will be considered as q and mean and sd will be
considered as 0 and 1 respectively.
2. If 2 arguments are provided: First argument will be taken as q and second argument will be
mean and sd will be considered as 1.
3. If 3 arguments are provided: First one is q, second is mean and third one is sd.
>>std.pnorm(0.5) --only q is provided. By default mean=0 and sd=1
0.691462
>>std.pnorm(0.5,0) -- q=0.5 and mean=1 are provided. By default sd=1
0.691462
>>std.pnorm(0.5,0,1) -- q=0.5, mean=0 and sd=1 are provided
0.691462
>>std.pnorm(0.5,1,0) -- Changing the order. q=0.5, mean=1 and sd=0
ERROR: Standard deviation must be greater than zero.
Please note that, changing the order of the arguments changes the value of the arguments. Therefore,
for accuracy, all arguments must be provided in the mentioned order.
8.2 Overloading Lua
8.2.1 Math Library
Lua’s math library comes with essential mathematical functions; however, these only work on a
single number. As we know, ScienceSuit is equipped with different types of data structures and the
overloaded math functions, which are under std library, work on these data structures and also on
Lua tables.
Overloaded functions: abs, acos, asin, atan, ceil, cos, cosh, exp, floor, ln, log, log10, sin, sinh, sqrt,
tan, tanh.
Let’s do a demo with the cos function. The same rationale is applicable to the other above-mentioned
functions as well.
Using Lua’s math library:
>>math.cos(5)
0.283662
Same result can be obtained using std library.
>>std.cos(5)
0.283662
Lua table (return type is a table):
>>t={1,2,3,4}
>>std.cos(t)
0.540302 -0.416147 -0.989992 -0.653644
Vector (return type is a vector)
>>v=std.tovector{1, 2, 3, 4}
>>std.cos(v)
0.540302 -0.416147 -0.989992 -0.653644 COL
Matrix (return type is a matrix)
>>m=std.tomatrix{ {1,2} , {3,4} }
>>std.cos(m)
0.540302 -0.416147
-0.989992 -0.653644
8.2.2 type() and next()
The functions, namely next and type, provided by Lua were overloaded for a better harmony with
the framework.
8.2.2.1 type()
Inherently, Lua has 8 data types:
1. nil
2. boolean
3. number
4. string
5. function
6. userdata
7. thread
8. table
In ScienceSuit the types are reported by the function type is as expected:
>>a
nil
>>a=3
>>type(a)
number
>>s="abc"
>>type(s)
string
However, there is a catch with userdata and table. For example:
Vector and Matrix are actually userdata types and say, if variables v and m were Vector and Matrix,
respectively, a call to type(v) or type(m), would have only returned as userdata if function type was
not overloaded. Therefore, there would be no way of knowing the difference between v and m,
except that they are userdata. Thus, for accuracy and convenience, type() has been overloaded.
For data type table, the scenario is slightly different: A call to a regular table would return a value
as table, which is expected.
>>t={1,2,3}
>>type(t)
table
However, had we provided a metamethod __name(), a call to function type() would return the value
returned by the function __name() which must be of type string.
function Food:__name()
return "Food"
end
Now that a metamethod, namely __name(), is provided to the Food data structure, all variables
created using the Food data structure will be reported as “Food” by function type().
>>milk=Food.new{water=88.13, protein=3.15, CHO=4.80, lipid=3.25, ash=0.67}
>>type(milk)
Food
Note that, the data structure name and the value reported by function __name() does not have to be
the same. However, for convenience it is recommended that they are kept as same.
8.2.2.2 next()
In Lua, the function next() only works with tables. Therefore, to be able to use it with the provided
data structures it has been overloaded. Please note that, for a data structure to be able to benefit from
this, it must implement a metamethod named as next(). Otherwise, an error will be thrown.
>>v=std.tovector{10,20,30,40}
>>key, value=next(v, nil)
>>key
1
>>value
10
8.3 Statistics
8.3.1 Understanding Distributions
Similar to R, ScienceSuit has a number of built-in functions for both discrete and continuous
probability distributions. For each of these distributions, similar to R, ScienceSuit has four primary
functions. Each function has a one letter prefix (d, p, q, r) followed by the root name of the
distribution. For example, dnorm is the height of the density of a normal distribution whereas
dbinom returns the probability of an outcome of a binomial distribution.
I found the following tables very useful to summarize the meaning of the prefixes and relating
distributions to the function names (from statistics notes of Bret Larget, 2003):
Prefix Continuous Discrete
d density probability (probability mass function)
p probability probability (cumulative distribution function)
q quantile quantile
r random random
Distribution Root
Uniform unif
Binomial binom
Poisson pois
Normal norm
t t
F f
Chi-square chisq
8.3.2 Uniform Distribution
𝑓𝑋(𝑥) = {1
𝑏 − 𝑎, 𝑎 ≤ 𝑥 ≤ 𝑏
0, otherwise
Arguments:
x: quantile, number / Vector
p: Cumulative probability
q: quantile, number / Vector
min, max: Lower and upper limits of the distribution
8.3.2.1 dunif
dunif(x=, min=0, max=1} → number / Vector
dunif(x=, min=0, max=1) → number / Vector
Computes the height of the probability density function.
>>std.dunif{x=0.3}
1
>>std.dunif{x=2, min=1, max=4}
0.333333
>>vec=std.tovector{1,2,3}
>>std.dunif{x=vec, min=1, max=5}
0.25 0.25 0.25 COL
8.3.2.2 punif
punif{q=, min=0, max=1} → number / Vector
punif(q=, min=0, max=1) → number / Vector
Computes the cumulative probability (left tailed)
>>std.punif{q=0.4}
0.4
>>std.punif{q=1, min=-1, max=3}
0.5
>>std.punif{q=std.tovector{0,1,2}, min=-1, max=3}
0.25 0.5 0.75 COL
>>std.punif(std.tovector{0,1}, -2, 2)
0.5 0.75 COL
8.3.2.3 qunif
qunif(p=,min=0, max=1) → number / Vector
qunif{p=, min=0, max=1} → number / Vector
Computes the lower tail quantile.
>>std.qunif{p=0.5}
0.5
>>std.qunif{p=0.5, min=1, max=5}
3
>>std.qunif{p=std.tovector{0,0.25,0.50,0.75}, min=1, max=5}
1 2 3 4 COL
>>std.qunif(std.tovector{0,0.25,0.50,0.75}, 1, 5)
1 2 3 4 COL
8.3.2.4 runif
runif(n=, min=0, max=1) → number / Vector
runif{n=, min=0, max=1} → number / Vector
Generates uniformly distributed random numbers.
>>std.runif(1)
0.235931
>>std.runif(3)
0.920477 0.586343 0.109749 COL
>>std.runif{n=1, min=0, max=3}
1.97154
>>std.runif{n=4, min=0, max=3}
2.8323 1.42823 2.77613 1.99111 COL
8.3.3 Binomial Distribution
𝑝𝑥(𝑘) = 𝑃(𝑋 = 𝑘) = (𝑛𝑘
) 𝑝𝑘(1 − 𝑝)𝑛−𝑘 k=0,1,….n
Arguments:
x: Number of successes, number / Vector
p: Cumulative probability
q: quantile, number / Vector
size: Number of independent trials
prob: Probability of success on each trial
8.3.3.1 dbinom
dbinom{x=, size=, prob=} → number / Vector
dbinom(x=, size=, prob=) → number / Vector
Computes the probability.
>>std.dbinom{x=2, size=5, prob=0.3}
0.3087
Equivalent to:𝑝𝑥(2) = 𝑃(𝑋 = 2) = (52
) 0.32(1 − 0.3)3 = 0.3087
8.3.3.2 pbinom
pbinom{q=, size=, prob=} → number / Vector
pbinom(q=, size=, prob=) → number / Vector
Computes the cumulative probability.
>>std.pbinom{q=2,size=5, prob=0.3}
0.83692
>>std.pbinom(2, 5,0.3)
0.83692
Equivalent to: (50
) 0.30 ⋅ 0.75 + (51
) 0.31 ⋅ 0.74 + (52
) 0.32 ⋅ 0.73 = 0.83692
8.3.3.3 qbinom
qbinom{p=, size=, prob=} → number/Vector
qbinom(p=, size=, prob=) → number/Vector
Computes the quantile (inverse of pbinom).
>>std.qbinom{p=0.83692, size=5, prob=0.3}
2
>>std.qbinom(0.83692, 5, 0.3)
2
Equivalent to: ∑ (5𝑘
)𝑞𝑘=0 0.3𝑘 ⋅ 0.7(5−𝑘) = 0.83692
Although, in the above example the quantile was perfectly overlapping with the cumulative
probability, it very rarely is the case. Consider the following two commands:
>>std.qbinom{p=0.53, size=5, prob=0.3}
2
>>std.qbinom{p=0.80, size=5, prob=0.3}
2
Although the cumulative probability in all 3 cases are different (0.53, 0.80, 0.83692) the quantile is
always reported as 2. Here, the function applies a policy, where it always rounds up the result (for
more info).
The following two commands shines more light on this policy:
>>std.pbinom{q=1,size=5, prob=0.3}
0.52822
>>std.pbinom{q=2,size=5, prob=0.3}
0.83692
It can be seen that p=0.53 is close to q=1 (p=0.52822), whereas p=80 is close to q=2 (p=0.83692),
therefore, any number in between p=0.52822 and p=0.83692 will be reported as q=2 by qbinom
function.
8.3.3.4 rbinom
rbinom{n=, size=, prob=} → number / Vector
rbinom(n=, size=, prob=) → number / Vector
Generates binomiallly distributed random numbers.
>>std.rbinom{n=1, size=5, prob=0.3}
2
>>v=std.rbinom{n=10, size=5, prob=0.3}
>>v
0 2 2 1 0 2 0 2 2 4 COL
What do the numbers returned by the function mean? In an analogy, say each time we flip 5 coins
and count the number of heads which we consider as success. We run this experiment for 10 times.
In the first experiment we have 0 heads, in the second 2 heads and so on.
Is the probability 0.3?
>>std.mean(v/5)
0.3
Please note that although in the above experiment the probability is perfectly 0.3, it may not always
be 0.3; however, will be in some close neighborhood of 0.3.
>>v=std.rbinom{n=10, size=5, prob=0.3}
>>std.mean(v/5)
0.32
Another way to check the probability is by using the expected number:𝐸 = 𝑛 ⋅ 𝑝 → 𝑝 =𝐸
𝑛
>> std.mean(v)/5
0.32
Needless to say, as the number of runs increase, the outcome will get closer to the desired probability.
8.3.4 Poisson Distribution
𝑃𝑋(𝑘) = 𝑃(𝑋 = 𝑘) =𝑒−𝑛𝑝(𝑛𝑝)𝑘
𝑘!=
𝜆𝑘
𝑘!𝑒−𝜆, 𝑘 = 0,1,2. ..where λ is a positive constant.
Arguments:
x: quantile, number / Vector
p: Cumulative probability
q: quantile, number / Vector
lambda: the average number of events per interval (event rate)
8.3.4.1 dpois
dpois{x=, lambda=} → number / Vector
dpois(x=, lambda=) → number / Vector
Computes the probability.
>>std.dpois{x=2, lambda=3}
0.224042
The above command is equivalent to:𝑃𝑋(2) = 𝑃(𝑋 = 2) =32
2!𝑒−3 = 0.224042
8.3.4.2 ppois
ppois{q=, lambda=} → number / Vector
ppois(q=, lambda=) → number / Vector
Computes the cumulative probability.
>>std.ppois{q=2, lambda=3}
0.42319
𝑃(𝑋 ≤ 2) = ∑𝜆𝑘
𝑘!𝑒−𝜆
2
𝑘=0
=30
0!𝑒−3 +
31
1!𝑒−3 +
32
2!𝑒−3 = 0.42319
8.3.4.3 qpois
qpois{p=, lambda=} → number / Vector
qpois(p=, lambda=) → number / Vector
Computes the quantile (inverse of ppois).
>>std.ppois{q=1, lambda=3}
0.199148
>>std.ppois{q=2, lambda=3}
0.42319
Similar to qbinom function, the function applies a policy, where it always rounds up the result (for
more info) and consider the outcome of the following two commands:
>>std.qpois{p=0.20, lambda=3} -- slightly greater than 0.199
2
>>std.qpois{p=0.422, lambda=3} -- slightly smaller than 0.423
2
8.3.4.4 rpois
rpois{n=, lambda=} → number / Vector
rpois(n=, lambda=) → number / Vector
Generates random numbers for Poisson distributions.
>>v=std.rpois{n=10, lambda=3}
>>v
5 4 3 4 2 4 5 2 2 0 COL
Check if above numbers represent a Poisson distribution with λ=3: We know that𝐸(𝑋) = 𝜆
>>std.mean(v)
3.1
8.3.5 Normal Distribution
𝑓𝑌(𝑦) =1
√2𝛱𝜎𝑒−
12
(𝑦−𝜇
𝜎)
2
Arguments:
x: quantile, number / Vector
p: Cumulative probability
q: quantile, number / Vector
mean: mean value
sd: standard deviation
8.3.5.1 dnorm
dnorm{x=, mean=0, sd=1} → number / Vector
dnorm(x=, mean=0, sd=1) → number / Vector
Computes the height of the probability density function.
>>std.dnorm{x=0, mean=0, sd=1}
0.398942
𝑓𝑌(𝑦) =1
√2𝛱𝜎𝑒−
12
(𝑦−𝜇
𝜎)
2
=1
√2𝛱1𝑒−
12
(0−0
1)
2
=1
√2𝛱= 0.398942
8.3.5.2 pnorm
pnorm{q=, mean=0, sd=1} → number / Vector
pnorm(q=, mean=0, sd=1) → number / Vector
Computes the cumulative probability (left tailed).
>>std.pnorm{q=-1, mean=0, sd=1}
0.158655
>>std.pnorm{q=0, mean=0, sd=1}
0.5
>>std.pnorm{q=1, mean=0, sd=1}
0.841345
It can be clearly seen that, as we move to the right on the horizontal axis, the area increases which
clearly indicates that the function returns left tailed area.
8.3.5.3 qnorm
qnorm(p=,mean=0, sd=1) → number / Vector
qnorm{p=, mean=0, sd=1} → number / Vector
Computes the lower tail quantile (inverse of pnorm).
>>std.pnorm{q=1, mean=0, sd=1}
0.841345
>>std.qnorm{p=0.841345}
1
8.3.5.4 rnorm
rnorm(n=, mean=0, sd=1) → number / Vector
rnorm{n=, mean=0, sd=1} → number / Vector
Generates normally distributed random numbers.
>>std.rnorm(1)
-1.18439
>>std.rnorm{n=5}
0.216995 -0.573784 0.0621783 0.0715034 0.561517 COL
8.3.6 Chi-square Distribution
𝑓𝑈(𝑢) =1
2𝑚 2⁄ 𝛤(𝑚 2⁄ )𝑢(𝑚 2⁄ )−1 ⋅ 𝑒−𝑢 2⁄ , 𝑢 ≥ 0
Arguments:
x: quantile, number / Vector
p: Cumulative probability
q: quantile, number / Vector
df: Degrees of freedom
8.3.6.1 dchisq
dchisq{x=, df=} → number / Vector
dchisq(x=, df=) → number / Vector
Computes the height of the probability density function.
>>std.dchisq{x=2, df=5}
0.138369
>>std.dchisq(2,5)
0.138369
Mathematically:𝑓𝑈(2) =1
25 2⁄ 𝛤(5 2⁄ )𝑢(5 2⁄ )−1 ⋅ 𝑒−2 2⁄
>>denom=2^(5/2)*std.gamma(5/2)
>>num=2^((5/2)-1)*math.exp(-2/2)
>>num/denom
0.138369
8.3.6.2 pchisq
pchisq{q=, df=} → number / Vector
pchisq(q=, df=) → number / Vector
Computes the cumulative probability (left tailed)
>>std.pchisq{q=0.5, df=5}
0.00787671
>>std.pchisq{q=1, df=5}
0.0374342
>>std.pchisq{q=3, df=5}
0.300014
Mathematically: ∫1
25 2⁄ 𝛤(5 2⁄ )𝑢(5 2⁄ )−1 ⋅ 𝑒−2 2⁄3
0𝑑𝑢
>>function f(u) return u^1.5*math.exp(-u/2) / (2^2.5*std.gamma(2.5)) end
>>std.trapz(f, 0,3)
0.300014
8.3.6.3 qchisq
qchisq{p=, df=} → number / Vector
qchisq(p=, df=) → number / Vector
Computes the lower tail quantile (inverse of pchisq).
>>std.pchisq{q=3, df=5}
0.300014
>>std.qchisq{p=0.3, df=5}
2.99991
Mathematically: ∫1
25 2⁄ 𝛤(5 2⁄ )𝑢(5 2⁄ )−1 ⋅ 𝑒−2 2⁄𝑞
0𝑑𝑢 = 0.3
8.3.6.4 rchisq
rchisq(n=, df=) → number / Vector
rchisq{n=, df=} → number / Vector
Generates n≥1 random numbers from the chi-square distribution
>>std.rchisq{n=5, df=5}
6.38474 8.02805 2.90747 3.27364 2.33255 COL
8.3.7 t distribution
𝑓𝑇𝑛=
𝛤(𝑛+1
2)
√𝑛𝛱𝛤(𝑛
2)(1+
𝑡2
𝑛)
𝑛+12
, − ∞ < 𝑡 < ∞is the pdf with n degrees of freedom.
8.3.7.1 dt
dt{x=, df=} → number / Vector
dt(x=, df=) → number / Vector
Computes the height of the probability density function.
>>std.dt{x=-2, df=5}
0.0650903
>>std.dt{x=2, df=5}
0.0650903
Mathematically: 𝑓𝑇5=
𝛤(5+1
2)
√5𝛱𝛤(5
2)(1+
22
5)
5+12
=2
3.96333⋅1.32934⋅5.832= 0.0650903
8.3.7.2 pt
pt{q=, df=} → number / Vector
pt(q=, df=) → number / Vector
Computes the cumulative probability (left tailed)
>>std.pt{q=-1, df=5}
0.181609
>>std.pt{q=0, df=5}
0.5
Mathematically: ∫𝛤(
5+1
2)
√5𝛱𝛤(5
2)(1+
𝑡2
5)
5+12
𝑑𝑡𝑞
−∞
8.3.7.3 qt
qt{p=, df=} → number / Vector
qt(p=, df=) → number / Vector
Computes the lower tail quantile.
>>std.pt{q=1, df=5}
0.818391
>>std.qt{p=0.818391, df=5}
0.999999
Mathematically: ∫𝛤(
5+1
2)
√5𝛱𝛤(5
2)(1+
𝑡2
5)
5+12
𝑑𝑡𝑞
−∞= 0.818391
8.3.7.4 rt
rt{n=, df= } → number / Vector
rt(n=, df=) → number / Vector
Generates n≥1 random numbers from the t distribution.
>>std.rt{n=1, df=5}
-0.0730832
>>std.rt{n=5, df=5}
-1.0581 0.0325742 -0.980538 1.71746 -0.593335 COL
8.3.8 F Distribution
𝑓𝐹𝑚,𝑛(𝑤) =
𝛤 (𝑚 + 𝑛
2 ) 𝑚(𝑚 2⁄ )𝑛(𝑛 2⁄ )𝑤(𝑚 2⁄ )−1
𝛤 (𝑚2 ) 𝛤 (
𝑛2) (𝑛 + 𝑚𝑤)(
𝑚+𝑛2
), 𝑤 > 0
8.3.8.1 df
df{x=, df1=, df2=} → number / Vector
df(x=, df1=, df2=) → number / Vector
Computes the height of the probability density function.
>>std.df{x=1, df1=3, df2=5}
0.361174
Mathematically: 𝑓𝐹3,5(1) =
𝛤(3+5
2)3(3 2⁄ )5(5 2⁄ )1(3 2⁄ )−1
𝛤(3
2)𝛤(
5
2)(5+3⋅1)
(3+5
2)
= 0.361174
8.3.8.2 pf
pt{q=, df1=, df2=} → number / Vector
pt(q=, df1=, df2=) → number / Vector
Computes the cumulative probability (left tailed)
>>std.pf{q=1, df1=3, df2=5}
0.535145
>>std.pf{q=2, df1=3, df2=5}
0.767376
8.3.8.3 qf
qt{p=, df1=, df2=} → number / Vector
qt(p=, df1=, df2=) → number / Vector
Computes the lower tail quantile.
>>std.pf{q=1, df1=3, df2=5}
0.535145
>>std.qf{p=0.535145, df1=3, df2=5}
0.999999
8.3.8.4 rf
rt{n=, df1=, df2= } → number / Vector
rt(n=, df1=, df2=) → number / Vector
Generates n≥1 random numbers from the F distribution
>>std.rf{n=5, df1=3, df2=5}
1.62134 1.76374 3.38552 0.771544 1.32867 COL
8.3.9 Wilcoxon Signed Rank Statistic
𝑝𝑤(𝑤) = (1
2𝑛) ⋅ 𝑐(𝑤)where c(w) is the coefficient of ewt in the expansion of ∏ (1 + 𝑒𝑖𝑡)𝑛𝑖=1 .
8.3.9.1 dsignrank
dsignrank{x=, n=} → number / Vector
dsignrank(x=, n=) → number / Vector
Computes the probability.
>>std.dsignrank{x=2, n=4}
0.0625
>>std.dsignrank(2,4)
0.0625
>>v=std.tovector{2, 3}
>>std.dsignrank{x=v, n=4}
0.0625 0.125 COL
Mathematically:
𝑀𝑤(𝑡) = (1 + 𝑒𝑡
2) ⋅ (
1 + 𝑒2𝑡
2) ⋅ (
1 + 𝑒3𝑡
2) ⋅ (
1 + 𝑒4𝑡
2)
𝑀𝑤(𝑡) = (1
16) ⋅ (1 + 𝑒𝑡 + 𝑒2𝑡 + 2𝑒3𝑡 + 2𝑒4𝑡 + 2𝑒5𝑡 + 2𝑒6𝑡 + 2𝑒7𝑡 + 𝑒8𝑡 + 𝑒9𝑡 + 𝑒10𝑡)
For x=2, the coefficient of e2t is 1. Therefore 1/16=0.0625.
For x=3, the coefficient of e3t is 2. Therefore 2/16=0.125.
Note: If the argument x is greater than the number of coefficients generated by argument n, or if x
<0, the function returns 0.0.
8.3.9.2 psignrank
psignrank{q=, n=} → number / Vector
psignrank(q=, n=) → number / Vector
Computes the cumulative probability. If argument q is not an integer number, then it is rounded to
the nearest integer number.
>>std.psignrank{q=2, n=4}
0.1875
>>std.psignrank{q=3, n=4}
0.3125
>>std.psignrank{q=2.4, n=4} --rounded to 2
0.1875
>>std.psignrank{q=2.6, n=4} --rounded to 3
0.3125
8.3.9.3 qsignrank
qsignrank{p=, n=} → number / Vector
qsignrank(p=, n=) → number / Vector
Computes the quantile. The function applies rounds up the result.
>>std.psignrank{q=2, n=4}
0.1875
>>std.qsignrank{p=0.18, n=4}
2
>>std.qsignrank{p=0.1876, n=4}
3
8.3.10 anova
anova(arg=)
anova(v1=, v2=, v3=, ...)
Performs single-factor analysis of variance test and returns p-value and an ANOVA table.
Arguments:
arg: Responses ← Matrix / Range
v1, v2... Responses ← Vector
>>pval, AnovaTable=std.anova(lemon, white, green, blue) --each of them is of type Vector
>>pval
2.90e-07
8.3.11 anova2
anova2 (yobs=, x1=, x2=)
Performs two-factor analysis of variance test and returns a Vector containing p-values and a Lua
table containing extra information to be used as ANOVA table. The order of p-values contained in
the Vector is factor #1, factor #2 and interaction.
Arguments:
yobs: Data on observed (response) variable ← Vector
x1, x2: Factor 1 and factor 2, respectively. ← Vector / Array
>>pvalues, AnovaTable=std.anova2(vent, O2, CO2)
>>pvalues
0.895 7.06e-07 1 COL
8.3.12 cor
cor(y1=, y2=) → number
Computes the correlation coefficient. Arguments y1, y2 are of type Vector.
Example: We are going to test whether it is a good idea just to rely on r2 to test quality of fitting.
In order to do that we will generate numbers y1 on the line y1=2x+1 and y2=4x+2 in the interval
[1,5].
>>x=std.linspace(1, 5, 5)
>>y1=2*x+1
>>y2=4*x+2
>>std.cor(y1,y2)^2
8.3.13 cov
cov(y1=, y2=, str=”s”) → number
Computes the covariance. Arguments y1 and y2 are of type Vector and str is of type string. If str=”p”
then population covariance and if str=”s” then sample covariance is computed.
Example: What is the covariance of the dataset, y1 on the line y1=2x+1 and and y2 on the line
y2=4x+2 in the interval [1,5].
>>x=std.linspace(1,5,5)
>>y1=2*x+1
>>y2=4*x+2
>>std.cov(y1,y2)^2
20
8.3.14 cumsum
cumsum(vec=) → Vector
Finds the cumulative sum of a Vector. Argument vec is of type Vector and function returns a Vector
containing the cumulative sums.
>>v=std.tovector{1, 2, 3, 4}
>>v
1 2 3 4 COL
>>std.cumsum(v)
1 3 6 10 COL
8.3.15 kurt
kurt(v=) → number
Computes the excess kurtosis. Argument v is of type Vector.
Kurtosis of different distributions:
--Normal Distribution
>>v=std.rnorm(10000)
>>std.kurt(v)
0.0220726
--Uniform Distribution
>>v=std.runif(10000)
>>std.kurt(v)
-1.20449
8.3.16 lm
lm (response=, factors=, IsIntercept=false, Alpha=0.05) → Lua Table (namely regression table)
lm.summary(RegressionTable=)
Performs simple/multiple linear regression.
Arguments:
yobs: Response ← Vector
factors: Factors ← Matrix, Vector
IsIntercept: Intercept ← boolean
Example: Do the following data (Data from: Larsen & Marx, An Introduction to Mathematical Statistics and Its
Applications) support the suspicion that smoking contributes to CHD mortality?
Cigarette Consumption: [3900, 3350, 3220, 3220, 2790, 2780, 2770, 2290, 2160, 1890, 1810, 1800, 1770,
1700, 1680, 1510, 1500, 1410, 1270, 1200, 1090]
Mortality per 100000: [256.9, 211.6, 238.1, 211.8, 194.1, 124.5, 187.3, 110.5, 233.1, 150.3, 124.7, 41.2,
182.1, 118.1, 31.9, 114.3, 144.9, 59.7, 126.9, 43.9, 136.3]
Let’s seek the answer by performing a linear regression. Create two vectors, namely factor for
“Cigarette Consumption” and response for Mortality rate.
>>std.lm(response, factor, true, 0.05)
0.0600977*x + 15.7711
>>RegressTbl=std.lm(response, factor, true, 0.05)
>>Summary=std.lm.summary(RegressTbl)
>>Summary
R2=0.532193 SE=46.7083 CoefStats=table ANOVA=table
Here, the Lua table namely ANOVA contains all the information on the ANOVA test performed for
the regression and CoefStats contains all the regression information on each coefficient. Let’s take
a look at the first entry of CoefStats table.
>>Summary.CoefStats[1]
coeff=15.7711
pvalue=0.600085
tvalue=0.533189
CILow=-46.1382
CIHigh=77.6805
SE=29.5789
Performing multiple linear regression is similar; however, instead of using a Vector a Matrix data
structure must be used for the factors.
8.3.17 max
max(container) → entry
Uses minmax to find the maximum of an iteratable container.
8.3.18 mean
mean(container) → number
Computes the average of an iteratable container.
>>t={3, 5, 2, 1, 7, 4}
>>std.mean(t)
3.66667
>>t={a=3,b=5,c=2,d=1,e=7,f=4}
>>std.mean(t)
3.66667
Most of the built-in data structures such as Vector and Matrix are iteratable as well:
>>v=std.tovector{3, 5, 2, 1, 7, 4}
>>std.mean(v)
3.66667
8.3.19 median
Computes the median of an iteratable container.
median(container) → number
>>t={3, 5, 2, 1, 7, 4}
>>std.median(t)
3.5
>>t={a=3, b=5, c=2, d=1, e=7, f=4}
>>std.median(t)
3.5
>>v=std.tovector{3, 5, 2, 1, 7, 4}
>>std.median(v)
3.5
8.3.20 minmax
minmax(container) → entry, entry
Finds the minimum and maximum entries in an iteratable container.
>>t={3, 5, 2, 1, 7, 4}
>>std.minmax(t)
1 7
>>t={a=3, b=5, c=2, d=1, e=7, f=4}
>>std.minmax(t)
1 7
Most of the built-in data structures such as Vector and Matrix are iteratable as well:
>>v=std.tovector{3, 5, 2, 1, 7, 4}
>>std.minmax(v)
1 7
>>m
2 4 -1
-4 -5 3
2 -5 -4
>>std.minmax(m)
-5 4
8.3.21 min
Uses minmax to find the minimum of an iteratable container.
min(container) → entry
8.3.22 mode
mode(Container) → nil / number / Lua table
Finds the most frequently occuring element/elements in an iteratable container.
>>t={1, 2, 3, 4, 5}
>>std.mode(t)
nil
>>t={1, 3, 5, 7, 9, 3, 5, 7, 3, 6}
>>std.mode(t)
3
>>v=std.tovector{1, 3, 5, 5, 7, 9, 3, 5, 7, 3, 6}
>>std.mode(v)
3 5
8.3.23 sample
sample(x=, size=, replace=false) → Vector
sample{x=, size=, replace=false} → Vector
Sampling from a set of numbers with or without replacement.
Arguments:
x: Sample space ← Vector
size: Number of samples to be drawn ← integer
replace: Whether to allow to put the drawn samples back to sample space ← boolean
>>SampleSpace=std.linspace{a=1, b=10, n=10}
>>SampleSpace
1 2 3 4 5 6 7 8 9 10 COL
>>std.sample(SampleSpace, 4, true)
9 8 2 9 COL
8.3.24 sequence
sequence(from=, to=, by=1) → Vector
sequence{from=, to=, by=1} → Vector
Sampling from a set of numbers with or without replacement.
Arguments:
from: Left end of the sequence ← number
to: Right end of the sequence ← number
by: Increment/decrement ← number
>>std.sequence{from=1, to=5}
1 2 3 4 5 COL
>>std.sequence{from=3, to=11, by=3}
3 6 9 COL
8.3.25 skew
skew(v=) → number
Computes the skewness of a distribution where argument v is of type Vector.
Example: Skewness of a non-normal distribution
>>v=std.rnorm(500) + std.runif(500)
>>std.skew(v)
0.41
8.3.26 stdev
stdev(container, choice=”s”)
Finds the standard deviation of a given iteratable container. Argument choice can be “s” or “p” for
sample or population, respectively.
Example: Find the standard deviation of 100 uniformly distributed numbers.
>>x=std.rand(100)
>>std.stdev(x)
0.291
8.3.27 sum
sum(container=) → entry
Finds the sum of addable entries in an iteratable container. As a backbone, it uses the accumulate
function.
>>t={3, 5, 2, 1, 7, 4}
>>std.sum(t)
22
>>v=std.tovector(t)
>>std.sum(v)
22
>>m=std.tomatrix{ {1, 2} , {3, 4} }
>>m
1 2
3 4
>>std.sum(m)
10
Since Vectors are addable (v1+v2=v3) and Lua tables are iteratable, the following is also doable:
>>t={}
>>t.v1=std.tovector{1, 2, 3, 4}
>>t.v2=std.tovector{4, 3, 2, 1}
>>t
v1=Vector
v2=Vector
>>std.sum(t)
5 5 5 5 COL
8.3.28 test_f
test_f {x=, y=, alternative=”two.sided”, ratio=1, conflevel=0.95}
Test for ratios of variances of two samples. Function returns the p-value and a table with extra
information.
Arguments:
x: First sample → Vector
y: Second sample → Vector
alternative: “two.sided”, “less”, “greater” → string
ratio: Assumed ratio of variances of the samples → number
conflevel: Confidence level, [0,1] → number
Suppose that a given experiment consists of two independent random samples X1, X2,…, Xn and Y1,
Y2,…,Ym. Let σ2X and σ2
Y denote their variances, respectively. We test H0: σ2
X=σ2Y.
Critical F value has been defined as:𝐹𝑐𝑟𝑖𝑡𝑖𝑐𝑎𝑙 =𝜎𝑋
2
𝜎𝑌2 ⋅
1
𝑟𝑎𝑡𝑖𝑜
Confidence interval: (𝜎𝑋
2
𝜎𝑌2 ⋅ 𝐹𝛼 2⁄ ,𝑛−1,𝑚−1,
𝜎𝑋2
𝜎𝑌2 ⋅ 𝐹1−𝛼 2⁄ ,𝑛−1,𝑚−1)
Example: To test the equality of variances for the following data (Data from: Larsen & Marx, An
Introduction to Mathematical Statistics and Its Applications):
Non-confined: 10.7, 10.7, 10.4, 10.9, 10.5, 10.3, 9.6, 11.1, 11.2, 10.4
Confined: 9.6, 10.4, 9.7, 10.3, 9.2, 9.3, 9.9, 9.5, 9.0, 10.9
Create two vectors, confined and nonconfined, from the data in a worksheet.
>>pval, tbl=std.test_f{x=confined, y=nonconfined}
>>pval
0.443
>> tbl
df1=9 df2=9 var1=0.211 var2=0.357 Fcritical=0.590 CI_lower=0.146 CI_upper=2.37
8.3.29 test_norm_ad
test_norm_ad(vec)
Performs Anderson-Darling test to test whether a sample of data came from a normal population
where argument vec must be of type Vector and the function returns p-value and the test-statistic,
namely the A2.
The null hypothesis: H0: The data follows the normal distribution
Implementation details: The test statistic is calculated using:
𝐴2 = −𝑛 − 𝑆where 𝑆 = ∑2𝑖−1
𝑛[𝑙𝑛(𝐹(𝑌𝑖)) + 𝑙𝑛(1 − 𝐹(𝑌𝑛+1−𝑖))]𝑛
𝑖=1
Example: Inspect whether the following data comes from a normal distribution
data=[2.39798, -0.16255, 0.54605, 0.68578, -0.78007, 1.34234, 1.53208, -0.86899, -0.50855, -0.58256, -0.54597,
0.08503, 0.38337, 0.26072, 0.34729]
>>pval, A2=std.test_norm_ad(vec)
>>pval
0.356325
>>A2
0.380373
8.3.30 test_sign
test_sign{x=, y=nil, md=, alternative=”two.sided”, conflevel=0.95}
Performs a 1-sample nonparametric test to test if the null hypothesis of a median of a distribution is
equal to some specific value or not and returns p-value and a table containing confidence intervals
and extra information.
Arguments:
x: Sample → Vector
y: Second sample → Vector.
md: Median of the population tested by the null hypothesis → number
alternative: “two.sided”, “less”, “greater” → string
conflevel: Confidence level, [0,1] → number
Note: If argument y is provided, then function performs the test by assuming x and y are paired data.
Implementation details:
Let y1, y2,…, yn be a random sample of size n from any distribution having median md. Let k denote
the number of yi’s greater than md.
Assumption: If n≥12 then, for the decision making a normal approximation can be used and𝑧 =𝑘−𝑛 2⁄
√𝑛 4⁄otherwise decision rule is determined using the exact binomial distribution.
Larsen & Marx (An Introduction to Mathematical Statistics and Its Applications pp 657) recommends a
sample size of 10 (aligned with general rule of np>=5, where p=0.5) whereas Chakraborti & Gibbons
(Nonparametric Statistical Inference, Fifth Edition pp 171) recommends at least 12. Although not heavily
tested, Minitab and R seems to choose a number greater than 10. Furthermore, R refers to Chakraborti &
Gibbons publication in its documentation. Therefore, 12 was chosen for normal approximation of binomial
distribution.
Example: It has been shown that the median amount of caffeine left by the freeze-drying method in
instant coffee is 3.55 grams of dry matter. Following are the caffeine residues recorded for eight
brands of coffee produced by spray drying: [4.8, 4.0, 3.8, 4.3, 3.9, 4.6, 3.1, 3.7]. (Larsen & Marx, An
Introduction to Mathematical Statistics and Its Applications)
>>v=std.tovector{4.8, 4.0, 3.8, 4.3, 3.9, 4.6, 3.1, 3.7}
>>p, tbl=std.test_sign{x=v, md=3.55}
>>p
0.0703125
>>tbl
lower=table interpolated=table upper=table ngreater=7 nequal=0
>>tbl.interpolated
CILow=3.505 CIHigh=4.665 prob=0.95
8.3.31 test_t
test_t{x=, y=nil, varequal=true, alternative=”two.sided”, mu=0, conflevel=0.95, paired=false}
Performs 1-sample, 2-sample and paired t-test. Function returns the p-value and a table with
information which depends on the test being applied.
Arguments:
x: First sample → Vector
y: Second sample → Vector
varequal: Assuming equal variances → boolean
alternative: “two.sided”, “less”, “greater”, → string
mu: Assumed difference between samples or true value of mean → number
conflevel: Confidence level, [0,1] → number
paired: For paired t-test → boolean
Notes:
1) If only argument x is provided then arguments paired and varequal have no effect.
2) If x and y are provided but paired=true, then varequal has no effect.
Possible usage:
1-sample t-test:
test_t{x=, mu=, alternative=”two.sided”, conflevel=0.95}
2-sample t-test:
test_t{x=, y=, varequal=true, alternative=”two.sided”, mu=0, conflevel=0.95}
paired t-test:
test_t{x=, y=, alternative=”two.sided”, mu=0, conflevel=0.95, paired=true}
8.3.31.1 One-Sample t-test
If the standard deviation of the population is not known we use the one-sample t-test procedure to
test μ=μ0.
𝑡 =�̄� − 𝜇0
𝑆 √𝑛⁄
8.3.31.2 Two-Sample t-test
Suppose that a given experiment consists of two independent random samples X1, X2,…, Xn and Y1,
Y2,…,Ym. Let μX and μY denote their means, respectively. We test H0: μX=μY.
A) If both samples X and Y are from a normal distribution with standard deviation σ, then:
𝑆𝑝2 =
(𝑛−1)𝑆𝑋2 +(𝑚−1)𝑆𝑌
2
𝑛+𝑚−2
𝑇𝑛+𝑚−2 =�̄�−�̄�−(𝜇𝑋−𝜇𝑌)
𝑆𝑝√1
𝑛+
1
𝑚
with n+m-2 degrees of freedom.
B) If samples X and Y are from normal distributions with standard deviations σX and σY,
respectively:
𝑣 =(
𝜎12
𝑛1+
𝜎22
𝑛2)
2
𝜎14
𝑛12(𝑛1−1)
+𝜎2
4
𝑛22(𝑛2−1)
𝑇𝑣 =�̄�−�̄�−(𝜇𝑋−𝜇𝑌)
√𝑆𝑋2
𝑛+
𝑆𝑌2
𝑚
with v degrees of freedom.
8.3.31.3 Paired t-test
Suppose that a given experiment consists of two dependent random samples X1, X2,…, Xn and Y1,
Y2,…,Ym.
Then paired t-test is a 1-sample t-test applied to X-Y.
8.3.32 test_z
test_z{x=, sd=, mu=, alternative=”two.sided”, conflevel=0.95}
Performs 1-sample z-test. Function returns the p-value and a Lua table with extra information.
Arguments:
x: Sample ← Vector
alternative: “two.sided”, “less”, “greater”, ← string
mu: Assumed mean of population ← number
conflevel: Confidence level, [0,1] ← number
sd: Standard deviation of population ← number
Note on implementation:
If the standard deviation of the population (σ) is known we use one-sample t-test procedure to test
μ=μ0.
𝑧 =�̄� − 𝜇0
𝜎 √𝑛⁄
Example: Researchers believe that skull widths of a certain population is normally distributed with
a mean (μ) of 132.4mm and a standard deviation (σ) of 6.0 mm. Does the following data have an
association with the population? (Question adapted from: Larsen & Marx, An Introduction to Mathematical
Statistics and Its Applications).
Measurements: 141, 146, 144, 141, 141, 136, 137, 149, 141, 142, 142, 147, 148, 155, 150, 144, 140, 140, 139, 148,
143, 143, 149, 140, 132, 158, 149, 144, 145, 146, 143, 135, 147, 153, 142, 142, 138, 150, 145, 126
Create a Vector, namely x, using the above data.
>>pval, tbl=std.test_z{x=x, mu=132.4, sd=6}
>>pval
4.64636e-32
>>tbl
SE=0.948683 zcritical=11.7268 mean=143.525 stdev=6.03829
CI_lower=141.666 CI_upper=145.384 N=40
8.3.33 tukey
std.anova.tukey (AnovaTable, Alpha)
Makes pair-wise comparisons and returns a Lua table containing the comparisons. The function resides
under anova library. Note that the argument AnovaTable must be calculated by the anova function,
therefore, Tukey's test must be performed after single-factor anova test.
Example: Let’s work on the following unstacked data (From: Larsen & Marx, An Introduction to
Mathematical Statistics and Its Applications).
Nonsmokers Light smokers Moderate Heavy
69 55 66 91
52 60 81 72
71 78 70 81
58 58 77 67
59 62 57 95
65 66 79 84
Create 4 vectors, namely v1, v2, v3 and v4, from each column of the data in the worksheet. See how
to create vectors.
>>pval, AnovaTable=std.anova(v1,v2, v3, v4)
>TukeyTable=std.anova.tukey(AnovaTable, 0.05)
>TukeyTable
Pairs Diff Tukey Interval
1-2 -0.8333 -15.26 , 13.60
1-3 -9.333 -23.76 , 5.097
1-4 -19.33 -33.76 , -4.903
2-3 -8.500 -22.93 , 5.930
2-4 -18.50 -32.93 , -4.070
3-4 -10.00 -24.43 , 4.430
8.3.34 var
var(container=, str=”s”)
Finds the variance of an iteratable container where argument str can be “s” or “p” are for sample or
population, respectively.
>>x=std.rand(100)
>>std.var(x)
0.085
>>t={1, 1.5, 2, 2.5, 3}
>>std.var(t)
0.625
>>std.var(t,"p")
0.5
8.4 Math
8.4.1 besselj
besselj(x=, alpha=)
Computes the cylindrical Bessel function of the first kind:𝐽𝛼(𝑥) = ∑−1𝑚
𝑚!𝛤(𝑚+𝛼+1)∞𝑚=0 (
𝑥
2)
2𝑚+𝛼
where
x can be a number or an iteratable container, and alpha is the order of the Bessel function
>>t={0, 0.5, 1, 1.5, 2}
>>std.besselj(t, 0)
1 0.93847 0.765198 0.511828 0.223891
>>std.besselj(t, 1)
0 0.242268 0.440051 0.557937 0.576725
8.4.2 beta
beta(x=, y=)
Computes the value of the beta function:𝐵(𝑥, 𝑦) = ∫ 𝑡(𝑥−1) ⋅ (1 − 𝑡)(𝑦−1)𝑑𝑡1
0 where x can be a
number or an iteratable container.
>>t={1, 1.5, 2, 2.5, 3}
>>std.beta(t, 2)
0.5 0.266667 0.166667 0.114286 0.0833333
𝐵(1,2) = ∫ 𝑡(1−1) ⋅ (1 − 𝑡)(2−1)𝑑𝑡1
0
= ∫ (1 − 𝑡)𝑑𝑡1
0
= 𝑡 −𝑡2
2= 0.5
8.4.3 bisection
bisection(f=,a=,b=)
bisection{f= , a= , b= , tol=1E-5 , maxiter=100 , method="bf", modified=false}
Finds the root of an equation of form f(x)=0. The function returns root, error and number of
iterations.
Arguments:
f: A unary function ← function
a, b: The interval where the root lies in ← number
tol: Tolerance for error ← number
maxiter: Maximum number of iterations during the search for the root ← integer
method: “bf”: brute-force (interval-halving), “rf”: regula falsi (false position) ← string
modified: true for modified regula falsi method.
Solving the equation for f(x)=x2-5=0:
>>std.bisection{f=function(x) return x^2-5 end, a=0,b=4}
2.23606 --root
7.62939e-06 --error
19 --number of iterations
>>std.bisection{f=function(x) return x^2-5 end, a=0,b=4, method="rf"}
2.23607 2.9744e-06 12
Please note that brute force method (bf) required 19 iterations, whereas regula falsi (rf) (false
position) required only 12 iterations.
However, for the function: f(x)=x10-1=0
>>std.bisection{f=function(x) return x^10-1 end, a=0, b=1.3}
1 9.91821e-06 17
>>std.bisection{f=function(x) return x^10-1 end, a=0,b=1.3, method="rf"}
0.999972 8.60722e-06 48
>>std.bisection{f=function(x) return x^10-1 end, a=0,b=1.3, method="rf", modified=true}
0.999992 7.21011e-06 25
This time it is seen that rf without modification required 48 and with modification 25 iterations,
whereas bf required only 17 iterations.
Therefore, although in most cases bf will require more iterations than rf, this strictly depends on the
nature of the function as evidenced by the above examples.
8.4.3.1 Definition of error:
A) Brute-force (interval-halving): 𝐸𝑟𝑟𝑜𝑟 =𝑏−𝑎
2Number of iterations
For example, for the function f(x)=x10-1, we found the root as 1 with an error of 9.91821E-6 after
17 iterations.
Therefore the error is calculated:𝐸𝑟𝑟𝑜𝑟 =1.3−0
217 = 9.91821 ⋅ 10−6
B) Regula falsi (false position): The errror is calculated as the difference between two consecutive
iterations:
𝐸𝑟𝑟𝑜𝑟 = |𝑋(𝑖 + 1) − 𝑋(𝑖)|
8.4.3.2 Modified False Position:
During the iteration, when either of the bound is used more than twice, the value of the function at
that bound is halved and the iteration continues. Although there are different strategies, the method
suggested by Chapra and Canale is used.
Table: Number of iterations required for two different functions
f(x)=x10 – 1 (a=0, b=1.3) f(x)=x2-5 (a=0, b=4)
False Position 48 12
Modified False Position 25 15
It is seen from the table that for the function f(x)=x10-1, modification of the false position brings a
considerable reduction in number of iterations, whereas for f(x)=x2-5, modification brings a slight
disadvantage. Therefore, the selection of the methodology should be based on after having an insight
on the function.
8.4.4 cumtrapz
cumtrapz(f=, v1=) → Vector
cumtrapz(v1=,v2=) → Vector
cumtrapz{f=, a=, b=, inter=10} → Vector
Computes the left-tailed cumulative area and returns a column Vector.
Arguments:
f A unary function, f(x)
a,b: Limits of the integral
inter: Number of intervals in the limits [a,b]. Default value is 10
v1, v2: Vectors, values on x- and y-axis, respectively.
Let’s work on f(x)=x2.
>>x=std.tovector{1, 2, 3, 4, 5}
>>std.cumtrapz(function(x) return x^2 end, x)
0 2.5 9 21.5 42 COL
cumtrapz(v1=, v2=):
>>y=x^2
>>y
1 4 9 16 25 COL
>>std.cumtrapz(x, y)
0 2.5 9 21.5 42 COL
cumtrapz{f=, a=, b=, inter=10}:
>>std.cumtrapz{f=function(x) return x^2 end, a=1,b=5,inter=4}
0 2.5 9 21.5 42 COL
Please note that, in the last example 5 values has been returned by the function since number of
intervals is 4, therefore number of nodes (values) is 5.
8.4.5 det
det(m) → number
Computes the determinant of given square matrix.
>>m=std.tomatrix{ {1, 3, 2}, {4, 5, 6}, {7, 8, 9}}
>>std.det(m)
9
8.4.6 diag
diag(m=) → Vector
Finds the diagonal entries of a matrix.
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>m
1 2 3
4 5 6
7 8 9
>>std.diag(m)
1 5 9 COL
>>m2=std.tomatrix{ {1, 2} , {4, 5} , {7, 8} }
>>m2
1 2
4 5
7 8
>>std.diag(m2)
1 5 COL
>>m3=std.tomatrix{ {1, 2, 3} , {4, 5, 6} }
1 2 3
4 5 6
>>std.diag(m3)
1 5 COL
8.4.7 diff
diff(x=, y=nil) → Vector
Computes the first order difference of a given vector or differential of two vectors with respect to
the first argument.
Arguments:
x, y: Vectors
• If only one argument is provided then the function returns a Vector whose elements are the
differences (xi+1-xi) of the given vector.
• If two arguments are provided, then the function returns a Vector whose elements are the
derivative (dy/dx) of the given two vectors, x and y; therefore the order of vectors are important.
At the end points the function uses forward and backward differences and elsewhere the
derivative is computed using central differences.
>>v=std.tovector{1, 1, 3, 2, 5, 7, 9}
>>v
1 1 3 2 5 7 9 COL
>>std.diff(v)
0 2 -1 3 2 2 COL
Example: In drying operations, the drying can proceed either in constant or in falling drying period. In
order to clearly see the trend, it is advised to plot t vs dW/dt, where the latter one is the derivative of
weight with respect to time. The following data is collected during a dehydration operation:
Time: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
Weight: [24, 17.40, 12.90, 9.70, 7.80, 6.20, 5.20, 4.50, 3.90, 3.50]
Enter the data to a worksheet and create two vector variables, namely time and weight.
>>dw_dt=std.diff(time, weight)
>>dw_dt
-0.66 -0.555 -0.385 -0.255 -0.175 -0.13 -0.085 -0.065 -0.05 -0.04 COL
8.4.8 expfit
expfit(x=, y=) → Vector
expfit{x=, y=} → Vector
Fits the given dataset to equation of 𝑦 = 𝑎 ⋅ 𝑒𝑏⋅𝑥 where x and y are Vectors. The function returns a
vector containing the coefficients of the fitting.
>>x=std.tovector{1,2,3,4}
>>y=2.1*std.exp(3.4*x)
>>std.expfit{x=x, y=y}
2.1 3.4 COL
corresponding to the equation: 𝑦 = 2.1 ⋅ 𝑒3.4⋅𝑥
8.4.9 eig
eig(m=, ComputeEigenVectors=false) → Matrix/Vector
Computes the eigenvalues and eigenvectors. Argument m must be a square matrix. The function
also carries out an internal test on m to see whether m is symmetric or not, and in the case of
symmetric matrix, very high-performance computation can be performed.
Notes:
1. If m is symmetric:
◦ The function returns a Vector of eigenvalues.
◦ if ComputeEigenVectors=true, the function returns a Vector and a Matrix: eigenvalues
and eigenvectors.
2. If m is NOT symmetric:
◦ The function returns a matrix of eigenvalues.The eigenvalues matrix is n by 2, where the
first column is the real and second column is the imaginary part of the eigenvalues.
◦ if ComputeEigenVectors=true, the function returns 2 matrices: eigenvalues and
eigenvectors. The eigenvalues matrix is n by 2, where the first column is the real and
second column is the imaginary part of the eigenvalues. The eigenvectors matrix is n by
2n, where m(n,1) and m(n,2) is the real and the imaginary part of the eigenvector for the
first eigenvalue and so on .
Initially, let’s only find the eigenvalues:
>>m=std.tomatrix{ {1,3}, {2,4}}
>>std.eig(m)
-0.372281 0
5.37228 0
eigenvalues are λ1=-0.372281+0i and λ2=5.37228+0i
Now, let's find eigenvectors:
>>m1, m2=std.eig(m, true)
>>m1
-0.372281 0
5.37228 0
>>m2
-0.909377 0 -0.565767 0
0.415974 0 -0.824565 0
Now that we know how to interpret the results of m1, how are we going to interpret the result,
especially m2? Remember: Ax=λx
>>v=std.tovector{-0.909377, 0.415974} --eigenvector corresponding to λ1=-0.372281
>>m*v --Ax
0.33854 -0.15485 COL
>>v*-0.372281 -- λx
0.33854 -0.15485 COL
8.4.10 eye
eye(m, [n=]) → Matrix
Creates identity matrix where arguments m and n are integers greater than 1. Argument n is optional.
>>std.eye(2)
1 0
0 1
>>std.eye(3,2)
1 0
0 1
0 0
8.4.11 gamma
gamma(x=)
Computes the gamma function: 𝛤(𝑥) = ∫ 𝑡(𝑥−1) ⋅ 𝑒−𝑡𝑑𝑡∞
0 where argument x can be a number or an
iteratable container.
>>t={1, 1.5, 2, 2.5, 3}
>>std.gamma(t)
1 0.886227 1 1.32934 2
8.4.12 gammaln
gammaln(x=)
Computes the natural logarithm of gamma function where argument x can be a number or an
iteratable container.
>>std.gamma(200)
inf
>>std.gammaln(200)
857.934
8.4.13 gcd
gcd(m, n, ...) → integer
Computes the greatest common divisor where all arguments are of type integer.
>>std.gcd(10, 20)
10
>>std.gcd(8, 20, 36)
4
>>std.gcd(2, 3, 4, 5)
1
8.4.14 inv
inv(A) → Matrix
Computes the inverse of a square matrix.
>>m=std.tomatrix{ {1, 3, 2}, {4, 5, 6}, {7, 8, 9}}
>>std.inv(m)
-0.333333 -1.22222 0.888889
0.666667 -0.555556 0.222222
-0.333333 1.44444 -0.777778
8.4.15 lcm
lcm(m, n, ...) → integer
Computes the least common multiplier where all arguments are of type integer.
>>std.lcm(2, 3)
6
>>std.lcm(2, 3, 4)
12
>>std.lcm(2, 3, 4, 5)
60
8.4.16 linspace
linspace(a=, b=, n=) → Vector
linspace {a=, b=, n=} → Vector
Generates evenly spaced points in a given interval.
Arguments:
a: Lower limit of the interval ← number
b: Upper limit of the interval ← number
n: Number of data points in the interval ← integer
>>std.linspace{a=-2, b=2, n=6}
-2 -1.2 -0.4 0.4 1.2 2 COL
>>std.linspace(-2, 2, 6)
-2 -1.2 -0.4 0.4 1.2 2 COL
Example: Prove that in the interval of [-π,π] the functions cos(x) and sin(x) are independent.
>>x=std.linspace{a=-3.14, b=3.14, n=100}
>>a=std.cos(x)
>>b=std.sin(x)
>>std.trans(a)*b
2.17339E-15 --orthogonal therefore independent
8.4.17 logfit
logfit(x=, y=) → Vector
logfit{x=, y=} → Vector
Fits the given dataset to equation of 𝑦 = 𝑎 ⋅ 𝑙𝑛(𝑥) + 𝑏 where x and y are Vectors. The function
returns a vector containing the coefficients of the fitting.
>>x=std.tovector{1, 2, 3, 4}
>>y=x^2
>>std.logfit{x=x, y=y}
10.1506 -0.564824 COL
corresponding to 𝑦 = 10.1506 ⋅ 𝑙𝑛(𝑥) − 0.564824
8.4.18 lu
lu(A, method="lu")
Finds LU decomposition of a given matrix.
Arguments:
A: Square or rectangular matrix
method: "lup" returns l, u and permutation matrix.
"lupq" returns l, u and two permutation matrices.
For a square matrix:
>>m=std.tomatrix{{10, -7, 0}, {-3, 2, 6} , {5, -1, 5} }
>>l,u=std.lu(m)
>>l
1 0 0
-0.3 -0.04 1
0.5 1 0
>>u
10 -7 0
0 2.5 5
0 0 6.2
8.4.19 meshgrid
meshgrid(x, y) → Matrix, Matrix
Creates 2 dimensional grid coordinates where arguments x and y must be of type Vector.
>>x=std.tovector{1, 2, 3}
>>y=std.tovector{1, 2, 3, 4, 5}
>>X,Y=std.meshgrid(x, y)
>>X
1 2 3
1 2 3
1 2 3
1 2 3
1 2 3
>>Y
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
Conceptually, the grid will be similar to:
1,1 2,1 3,1
1,2 2,2 3,2
1,3 2,3 3,3
1,4 2,4 3,4
1,5 2,5 3,5
Example: Find the approximate volume under the surface z=x2+y2 over the region D defined by
1≤x≤3 and 1≤y≤5.
The exact solution is:∫ ∫ (𝑥2 + 𝑦2)5
1
3
1𝑑𝑦𝑑𝑥 = 117.33
Solving using code:
>>x=std.sequence(1, 3, 0.01)
>>y=std.sequence(1, 5, 0.01)
>>X, Y=std.meshgrid(x, y)
>>Z=std.pow(X, 2)+std.pow(Y, 2)
>>std.sum(Z)*0.01*0.01
118.295
note that the approach in the above code is to sum up the volume of square cuboids whose base area
is 0.01x0.01 and height is Z.
8.4.20 newton
newton{f=, x0=, fprime=, x1=nil, tol=1E-5, maxiter=100}
newton(f=, x0=, fprime=)
newton(f=, x0=, x1=)
Finds the root of an equation of form f(x)=0 and returns root, error and number of iterations.
Arguments:
f: A unary function whose root is sought after ← function
fprime: A unary function (derivative of f) ← function
x0: Initial guess ← number
x1: Initial guess ← number
tol: Tolerance for error ← number
maxiter: Maximum number of iterations during the search for the root ← integer
Notes:
1. If the derivative of the function, fprime, is provided, then Newton-Raphson method is
selected.
2. If fprime is not provided, then x1 must be provided and then the Secant method is selected.
Solving the equations f(x)=x2-5=0 and f(x)=x10-1=0:
>>std.newton{f=function(x) return x^2-5 end, x0=1, fprime=function(x) return 2*x end}
2.23607 --root
9.18143e-07 --error
5 --number of iterations
>>std.newton{f=function(x) return x^10-1 end, x0=1.3, fprime=function(x) return 10*x^9 end}
1 2.91879e-09 7
Since the derivative, f’(x)=2x and f’(x)=10x9 are provided, Newton-Raphson method is selected.
In the following example, instead of the derivative argument x1 is provided.
>>std.newton{f=function(x) return x^2-5 end, x0=1, x1=3}
2.23607 7.4651e-09 7
Definition of error: For both Newton-Raphson and Secant methods, the error is calculated as the
difference between two consecutive iterations:
𝐸𝑟𝑟𝑜𝑟 = |𝑋(𝑖 + 1) − 𝑋(𝑖)|
8.4.21 null
null (A) → nil / Matrix
Computes the null space of a given matrix using svd decomposition. The argument A must be of
type matrix. If exists, the function returns a matrix containing the nullspace vectors.
In the following example, no null space exists for the matrix:
>>m
1 2
2 3
>>std.null(m)
nil
However, in the following example, the null space does exist for the matrix:
>>m
1 2 3
2 3 5
>>A=std.null(m)
>>A
0.57735
-0.57735
0.57735
8.4.22 polyfit
polyfit(x=, y=, n=, [intercept=]) → Vector
polyfit{x=, y=, n=, [intercept=]} → Vector
Performs nth degree polynomial (anxn + an-1x
n-1 +..+ a0) curve fitting on a given dataset. The
arguments x and y are Vectors and n is the degree of the polynomial. Returns a vector containing
the coefficients of the fitting.
Note on algorithm: The system creates a Vandermonde matrix (A) with the given x vector and solves
the system (ATAb=ATy) using QR decomposition to find the cofficients (b).
Example: Find the 3rd degree polynom that best fits to the following data.
X: [0, 1, 2, 3, 4, 5] Y=[4, 10, 26, 58, 112, 194]
>>std.polyfit(x, y, 3)
1 2 3 4 COL
corresponding to the polynomial: y=x3 + 2x2 + 3x + 4
8.4.23 polyval
polyval(v=,arg=) → number / Vector
Evaluates a polynomial (anxn + an-1x
n-1 +..+ a0) at a given data or dataset. The argument v must be of
type Vector. If arg is a single data point the function returns a number; however, if arg is a vector of
data points then function returns a vector.
Note on algorithm: The function uses Horner's method to evaluate the polynom.
Example: Assume we are finding the polynom that best fits to the data presented at polyfit function
(Section 0).
>>coef=std.polyfit(x, y, 3)
>>std.polyval(coef, 3.5)
81.875
>>v=std.tovector{3.5, 4.5}
>>std.polyval(coef, v)
81.875 149.125 COL
8.4.24 powfit
powfit(x=, y=) → Vector
powfit{x=, y=} → Vector
Fits the given dataset to equation of 𝑦 = 𝑎 ⋅ 𝑥𝑛 where x and y are Vectors. The function returns a
vector containing the coefficients of the fitting.
>>x=std.tovector{1, 2, 3, 4}
>>y=1.2*x^2
>>std.powfit{x=x, y=y}
1.2 2 COL
corresponding to the equation: 𝑦 = 1.2 ⋅ 𝑥2
8.4.25 qr
qr(A) → Matrix, Matrix
Computes QR decomposition where A must be of type matrix, either square or rectangular. The
function returns two matrices, q and r, where q is an orthonormal matrix.
>>A
1 3
2 4
>>q,r=std.qr(A)
>>q
-0.44721 -0.89443
-0.89443 0.44721
>>r
-2.23607 -4.91935
0 -0.89443
8.4.26 rank
rank (A) → integer
Computes the rank of a given matrix using svd decomposition.
>>m
1 2
2 3
>>std.rank(m)
2
>>A
1 2 3
2 3 5
>>std.rank(A)
2
8.4.27 simpson
simpson(f=, a=, b=) → number
simpson{f= , a= , b= , inter= 100} → number
Computes the integration of a 1D function using Simpson's rule.
Arguments:
f A unary function, f(x)
a,b: Limits of the integral
inter: Number of intervals in the limits [a,b]. Default value is 100
Example: We will find the area underneath f(x)=x2 in the interval of [0,3].
>>std.simpson(function(x) return x^2 end, 0, 3)
9
>>std.simpson{f=function(x) return x^2 end, a=0, b=3, inter=20}
9
8.4.28 solve
solve (A=, b=) → Vector
Function solve is designed to solve a set of linear equations of Ax=b where argument A is a matrix
containing the coefficients and b is the right-hand side vector.
Algorithm: The function uses QR algorithm and then forward substitution to solve the given set of
linear equations. If the number of rows of the matrix is greater than its column (more equations than
unknowns) the function returns the best possible solution by solving ATAx=ATb
Example: We would like to solve the following set of linear equations.
x + 2y =5
2x + 3y =11
In order to solve the above-given set of equations: A=1 2 and the vector b= 5
2 3 11
>>std.solve(A, b)
7 -1 COL
which means x=7 and y=-1.
8.4.29 svd
svd(A) → Matrix, Matrix, Matrix
Finds svd decomposition of a given matrix
A= 2 4
1 3
0 0
0 0
>>u, s, v=std.svd(A)
>>print(u) -- unitary matrix (UUT=I)
>>print(s) -- rectangular diagonal matrix (5.46 and 0.36 are singular values)
>>print(v) -- unitary matrix (VVT=I)
u= s=
0.81742 0.57605 0 0 5.46499 0
0.57605 -0.81742 0 0 0 0.36597
0 0 1 0 0 0
0 0 0 1 0 0
v=
0.40455 0.91451
0.91451 -0.40455
8.4.30 trans
trans (arg=)
Finds the transpose of a given matrix or a vector.
1) If arg is a matrix and the function returns transpose of the matrix.
2) If arg is a vector of shape COL, then arg becomes shape ROW and vice versa.
>>A=std.tomatrix{ {1, 2}, {3, 4} }
>>std.trans(A)
1 3
2 4
8.4.31 trapz
trapz(v1=, v2=) → number
trapz(f=, a=, b=) → number
trapz{f= , a= , b= , inter=100 } → number
Computes the integration of a 1D function or a set of discreet data.
Arguments:
f A unary function, f(x)
a, b: Limits of the integral
inter: Number of intervals in the limits [a,b]. Default value is 100
v1, v2: Vectors, values on x- and y-axis, respectively.
Example #1: We will find the area underneath f(x)=x2 in the interval of [0,3] by generating data
points and then integrating.
>>x=std.linspace(0, 3)
>>y=x^2
>>std.trapz(x, y)
9.00046
Example #2: We will find the area underneath f(x)=x2 in the interval of [0,3].
>>std.trapz(function(x) return x^2 end, 0, 3)
9.00045
>>std.trapz{f=function(x) return x^2 end, a=0, b=3, inter=50}
9.0018
Please note that the exact value is 9. Compare the last two commands based on the choice of the
argument inter.
8.5 Plotting
8.5.1 holdoff
holdoff()
Sets the hold state to off for the plot window which was set on by holdon function.
Please note that, as of calling std.holdon(WindowID), any calls to plotting function will plot on the
plot window designated by the WindowID. Therefore, calling holdoff enables new plot windows to
be displayed.
8.5.2 holdon
holdon(WindowID)
Retains current plot when adding new plots on a selected plot window. Argument WindowID is the
ID of the plot window. Use std.holdoff() when retaining current plot is no longer needed.
>>x=std.sequence(-math.pi,math.pi,0.1)
>>y=std.cos(x)
>>std.scatter(x, y, "cos")
1
Here, it is seen that the plot window has ID=1, which has also been returned by the function call
std.scatter. If we wish to add another series on this particular plot window (with ID=1) then,
>>std.holdon(1)
>>y=std.sin(x)
>>std.scatter(x,y, "sin")
8.5.3 plot
plot(x=, y=, [Name=])
An alias for the std.scatter function.
8.5.4 scatter
scatter{
x=, y=,
[name=DefaultName],
[marker={
type=”c”,
size=4,
fill=DefaultColor,
linewidth=1,
linecolor=DefaultColor
}],
[line={
color=DefaultColor,
width=1,
style=”solid”,
smooth=false
}],
[trendline={
type=”linear”,
degree=2,
intercept=AutoCompute,
name=DefaultName,
color=DefaultColor,
width=1,
style=”dash”
}]}
The functions returns the ID of the created plot window; however, if the hold state is on by the
std.holdon function, the function returns nil as no new plot window will be displayed.
The data series (x, y) must be shown either by a marker or by a line or by both. If neither a marker
nor a line is defined then a marker with default values will be shown. Once a data series is presented
then a trendline can be shown.
Note on Terminology: The word Default in the arguments is used to denote that the so-called value
is assigned/computed by the system until a new value is assigned.
Arguments:
x, y : x- and y-data ← Vector
name : Name of the series ← string.
Marker Properties
type : “c”, “t” or “s” for circle, triangle or square, respectively ← string
size : size of the marker ← integer
fill : fill color, in the form of “R G B” ← string
linewidth : width of the line forming the boundary of the marker ← integer
linecolor : color of the line, in the form of “R G B”, forming the boundary ← string
Line Properties
width : width of the line ← integer
color : color of the line, in the form of “R G B” ← string
style : “solid”, “dash” or “dot” ← string
smooth : Spline algorithm is applied to smooth the line ← boolean
Trendline Properties
type : “exp”, “linear”, “log”, “poly” and “pow” for exponential, linear, logarithmic,
polynomial and power fitting. ← string
degree : If type=”poly”, then the degree of the polynomial ← integer
intercept : The desired intercept of the trendline.← number
color : color of the trendline, in the form of “R G B” ← string
width : width of the trendline ← integer
style : “solid”, “dash” or “dot” ← string
Let’s start from simple to advanced use of the scatter command and let’s stick to the same x and y
data (arbitrarily chosen) and declare them beforehand as x and y are not optional.
>>x=std.tovector{1, 2, 3, 4}
>>y=std.tovector{1, 3, 7, 14}
A) Only data is provided: The x- and y-data are provided, and the rest of the properties are provided
by the system.
>>std.scatter{x=x, y=y} -- lets omit the returned windowID
B) Define name and marker properties: The marker properties are fully customized.
>>std.scatter{x=x, y=y, name="xy data", marker={type="t", size=7, fill="255 0 0", linecolor="0 0
255", linewidth=2}}
The name of the series is
automatically assigned as “Series 1”
and since neither marker nor line is
defined, by default the system will
show a present x, y data pair by a
marker with default values.
Here, the name of the series is defined as
“xy data”, and the marker type is chosen to
be triangle. Marker will be filled with red
color and the boundary of the marker will
be blue with a thickness of 2 pixels. Note
that had we not defined the linecolor and
linewidth, it would have assumed the fill
color.
C) Define only line: Our objective is to show the data only with connected lines.
>>std.scatter{x=x, y=y, line={color="255 0 0", width=2}}
In the above figure the existence of multiple lines and their connections are apparently noticeable
rather than observing a smooth “single” curve. If we want a smooth curve:
>>std.scatter{x=x, y=y, line={color="255 0 0", width=2, smooth=true}}
Please note that in the command
we defined the line properties
but have not defined the marker.
Since a property such as line is
already defined, the system will
omit the marker and will present
the data only with lines.
D) Define marker and line: Our goal is to show the data with both lines and markers.
>>std.scatter{x=x, y=y, marker={type="s", size=6, fill="255 0 0"}, line={width=2}}
E) Adding Trendlines: The simplest way of adding trendline is just by defining the trendline property
remembering that if we neither define marker nor line, by default marker will be shown.
>>std.scatter{x=x, y=y, trendline={type="poly", degree=3, color="255 0 0", intercept=-10}}
A 3rd degree polynomial with a red
color is shown and note that the marker
color and properties are assigned by the
system since we have not explicitly
defined the marker properties.
8.6 Utility
8.6.1 accumulate
accumulate(container=, x0=, [f=]) → entry, integer
accumulates addable entries in an iteratable container. It is a powerful and a flexible function and
forms the backbone for a number of functions, such as mean, sum and var. Returns an element of
type entry in the container and the number of entries in the container.
Arguments:
container: An iteratable container with addable entries
x0: Initial value
f: Unary function applied on each entry in the container
By default Lua tables are iteratable:
>>t={3, 5, 2, 1, 7, 4}
--equivalent to sum function
>>std.accumulate(t, 0)
22 6
>>v=std.tovector(t)
>>std.accumulate(v, 0)
22 6
--Sum up squares of entries
>>std.accumulate(t, 0, function(x) return x^2 end)
104 6
Since Vectors are addable (v1+v2=v3) and Lua tables are iteratable, following is doable:
>>t={}
>>t.v1=std.tovector{1, 2, 3, 4}
>>t.v2=std.tovector{4, 3, 2, 1}
>>std.accumulate(t, 0)
5 5 5 5 COL
2
Note that since addition of a Vector with a number is also defined (v1+number=v2), the function
accepted 0 as the initial value in the example above. Alternatively, the initial value, x0, could have
been as same as the type in the container:
>>x0=std.tovector{0, 0, 0, 0}
>>std.accumulate(t, x0)
5 5 5 5 COL
2
8.6.2 activeworkbook
activeworkbook() → Workbook
Finds the currently active workbook.
>>wb=std.activeworkbook()
>>wb:title()
C:\Users\gbing\Desktop\demo_data.swb
The active workbook can change since if there is more
than 1 workbook open, user might switch between
workbooks using mouse or Child Window Manager. In
the following figure, there are 2 workbooks and active
one can be changed by user.
8.6.3 cwd
cwd() → string
Returns the current working directory (the full path of the folder containing sciencesuit.exe.)
8.6.4 find
find(container=, value=, tol=1E-5) → integer/nil
Finds the location of the first occurence of an entry in an iteratable container. If successful returns
the index of the entry, otherwise nil.
Arguments:
container: An iteratable container
value: Value being searched
tol: Tolerance, only used when searched for numeric entries.
>>t={1, 5, 3, 8, 8, -1}
>>std.find(t, 8)
4
>>t={"a","c","d","e"}
>>std.find(t, "d")
3
>>m2=std.tomatrix{ {1, 2} , {4, 5} , {7, 8} }
>>std.find(m2,5)
4
>>m2[{4}]
5
8.6.5 find_if
find_if(container=, func=) → Lua table/nil
Finds the locations of the entries in an iteratable container satisfying a given condition. If successful
returns the indexes of the entries in a Lua table, otherwise nil.
Arguments:
container: An iteratable container
func: A Unary Predicate function
>>t={1, 5, 3, 8, 8, -1}
>>std.find_if(t, function(x) return x>3 end)
2 4 5
>>std.find_if(t, function(x) return x==5 end)
2
>>std.find_if(t, function(x) return x<3 end)
1 6
8.6.6 findfirst_if
find_if(container=, func=) → integer/nil
Finds the location of the first entry in an iteratable container satisfying a given condition. If
successful returns the index of the entry, otherwise nil. Arguments container is an iteratable
container and func is a Unary Predicate function
>>t={1, 5, 3, 8, 8, -1}
>>std.findfirst_if(t, function(x) return x>3 end)
2
8.6.7 find_minmax
find_minmax(container=) → integer, integer
In an iteratable container finds the locations of the entries with minimum and maximum values.
Returns the indexes of the minimum and maximum entries, respectively.
>>v=std.rand(5)
>>v
0.518885 0.0746056 0.456635 0.460327 0.784585 COL
>>std.find_minmax(v)
2 5
>>t={"b", "a", "c", "d"}
>>std.find_minmax(t)
2 4
Note that, the entries of the container must be comparable such that operators > and < must be
defined on them.
>>"ac" > "ab"
true
>> 2 < 5
true
8.6.8 for_each
for_each(container=, func=, ...) → container
Applies a function to each entry in an iteratable container. It is a powerful and a very flexible
function and in the std library forms the backbone for a number of essential math functions, such as
sin, cos… Returns the same type of the container.
Arguments:
container: An iteratable container with addable entries
func: A unary, binary or multivariable function applied on each entry in the container
... 2nd, 3rd... arguments of the parameter func.
Notes:
1. At the end of the operation, the entries in the container is modified.
2. The entries in the container must support the operation applied on them.
>>t={1, 2, 3, 4}
>>std.for_each(t, function(x) return x^2 end)
1 4 9 16
>>t
1 4 9 16
>>t={1, 2, 3, 4}
>>y=2
>>std.for_each(t, function(x, y) return math.pow(x, y) end, y)
1 4 9 16
>>t
1 4 9 16
>>v=std.tovector{1, 2, 3, 4}
>>y=2
>>std.for_each(v, function(x, y) return math.pow(x, y) end, y)
1 4 9 16 COL
>>v
1 4 9 16 COL
8.6.9 getworkbooks
getworkbooks() → Lua Table
Returns the workbooks those are currently open. Assume, the following workbooks are open, as
seen in the image:
>>t=std.getworkbooks()
>>#t
2
>>t[1]:title()
Workbook 1
>>t[2]:title()
Workbook 2
8.6.10 size
size(container) → integer(s)
Finds the dimensions of the given container.
Matrix: Number of rows and columns Vector: Length
Workbook: Number of Worksheets Worksheet: Number of rows and columns
Range: Number of rows and columns
>>std.size(std.activeworkbook()) --workbook
2
>>range=Range.new(std.activeworkbook(),"Sheet 1!A1:B5") --range
>>std.size(range)
5 2
>>m=std.rand(3,4) --matrix
>>std.size(m)
3 4
>>v=std.rand(4) --vector
>>std.size(v)
4
8.6.11 tic, toc
tic(); expressions; toc()
Creates and starts (tic) and then stops and destroys (toc) the timer. The timer is started with the tic()
function and is stopped with the toc() function. The toc() function is dynamically created by the tic()
function and is destroyed upon calling the toc() function itself. Therefore, you cannot call the toc()
function unless you have already called the tic() function.
Example: We would like to find the time elapsed to multiply two matrices each of which is 1000-
by-1000.
>>m1=std.rand(1000, 1000)
>>m2=std.rand(1000, 1000)
>>std.tic(); m=m1*m2; std.toc() --start the timer and immediately multiply
Elapsed time: 0.501284 seconds. --time from unoptimized version
8.6.12 tovector
tovector(container=) → nil / Vector, integer
Converts a given iteratable container to a Vector data type. Please note that Vector can only contain
numeric values. Therefore, if the parameter container contains non-numeric entries, they are skipped.
The function reports the number of non-numeric entries it has encountered if it can successfully
create a Vector.
>>t={1, 2, "a", 3, "b"}
>>std.tovector(t)
1 2 3 COL
2 --table contains 2 non-numeric entries
For example, for a matrix data type:
>>m=std.tomatrix{ {1, 2} , {3, 4} }
>>m
1 2
3 4
>>std.tovector(m)
1 2 3 4 COL
0
8.6.13 tokenize
tokenize (str=, ShowWhiteSpace=true) → Lua Tables (tokens, token positions, token types)
A powerful function to perform lexical analysis on a given Lua code. Argument str is the string to
be tokenized.
Token Types
Token type Description
num Any valid number
name identifiers, variables
unop Unary operators (~ and ~=)
binop Binary operators
vararg Variable arguments
fieldsep Field separator (; and ,)
lbl Label
brkt Brackets
punc Punctuation
kword Keyword
rword Reserved word
asgnt Assignment
nl Newline
str String
scmt Lua line comment
wspc Whitespace
>>std.tokenize(“pi=3.14”)
pi = 3.14
1 3 4
name asgnt num
1st table: Contains the actual tokens, which are pi, = and 3.14.
2nd table: Contains the starting character position of each corresponding token, for example, pi starts
at 1st character whereas 3.14 starts at 4th character.
3rd table: Contains the type of the tokens, for example pi is of type name whereas 3.14 is type num.
If whitespace characters (‘ ‘ and ‘\t’) are of interest:
>>str=”if(a==3) then b=5E-3 end”
>>std.tokenize(str)
if ( a == 3 ) then b = 5E-3 end
1 3 4 5 7 8 9 10 14 15 16 17 21 22
rword brkt name binop num brkt wspc rword wspc name asgnt num wspc rword
If whitespace characters are not of interest:
>>str=”if(a==3) then b=5E-3 end”
>>std.tokenize(str, false)
if ( a == 3 ) then b = 5E-3 end
1 3 4 5 7 8 10 15 16 17 22
rword brkt name binop num brkt rword name asgnt num rword
8.7 Constants
std.const is a library for constants used by many scripts.
8.7.1 tolerance
It is of type number and has a value of 10-5. It is mostly used when testing if two numbers are equal,
such as |num1-num2|<tolerance.
>>std.const.tolerance
1e-05
8.7.2 exedir
Returns the full path of the folder containing sciencesuit.exe file as string. This is rather useful to work
with relative paths within the sciencesuit folder instead of working with full paths referrals.
For example, say you have placed an image, namely myimage.png, in the home folder which is
directly under the sciencesuit folder. Now you can refer to the image by:
std.const.exedir..”/home/myimage.png”.
Later on if you move sciencesuit folder to another location on the OS, the path will still work
correctly.
8.7.3 color
It is defined for convenience and provides most of the commonly used colors as string in the format of
"R G B". For example, red color has the value of "255 0 0".
These constants are especially useful when using formatted output to Worksheet using the Worksheet
class.
>>ws=std.activeworkbook():cur()
>>ws[1][1]={value="A1", fgcolor=std.const.color.red}
8.7.4 font
Provides convenience when using formatted output to Worksheet using the Worksheet class. The
available keys and values are:
>>std.const.font
style_normal=normal
style_italic=italic
weight_normal=normal
weight_bold=bold
underline_none=none
underline_single=single
>>type(std.const.font.style_italic)
string
>>ws=std.activeworkbook():cur()
>>ws[1][1]={value="A1",italic=std.const.font.style_italic}
>>ws[2][1]={value="A2", weight=std.const.font.weight_bold}
9 ROADMAP
Since its first release on December 2016, ScienceSuit has come a very long way and has improved
considerably in many innumerable ways. Thanks to its modular and extensible design, the journey
of research and development of ScienceSuit has no boundaries and therefore a roadmap, even a
tentative one, is essential.
The following work will be the focus of the next few major releases:
• More features to Image Processing Toolbox.
• Introduction of a data structure, namely Image, for scriptable image processing.
• A Camera Toolbox for acquiring videos and live images from cameras (initial focus will be
given to cameras supported by OpenCV).
• Addition of more chart options (line and bar chart, histogram and boxplot).
10 LICENSE
1) PERMISSION: Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated files (the "Software"), to use in academic, research and commercial
projects.
Permission is NOT granted in any way to license or to distribute, copy or sell copies of the Software
or any parts of the Software.
2) RESTRICTIONS: Title to the Software is retained by the main author and unless otherwise
stated the respective associated intellectual property rights are retained by the main author, the
respective author(s) and the respective contributor(s).
3) WARRANTY: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT.
4) DISCLAIMER: IN NO EVENT SHALL THE MAIN AUTHOR, AUTHOR(S) OR
CONTRIBUTOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.