LME Reference
This chapter describes LME
(Lightweight Matrix Engine), the
interpreter for numerical computing used by SysQuake.
Statements
An LME program, or a code fragment typed at a command line, is composed of
statements. A statement can be either a simple expression, an affectation, or a
structure statement. Statements are separated by commas, semicolons, or end of
lines. The end of line has the same meaning as a comma, unless the line ends with
a semicolon. When simple expressions and affectation are followed by a comma (or
an end of line), the result is displayed to the standard output; when they are
followed by a semicolon, no output is produced. What follows structure statements
does not matter.
When typed at the command line, the result of simple expressions is assigned
to the variable ans; this makes easy chaining computations.
Continuation characters
A statement can span over several lines, provided all the lines but the
last one ends with three dots. For example,
1 + ...
2
is equivalent to 1 + 2. After the three dots, the remaining
of the line, as well as empty lines and lines which contain only spaces, is
ignored.
Comments
Unless when it is part of a string enclosed between single ticks, a
single percent character or two slash characters mark the beginning of a
comment, which continues until the end of the line and is ignored by LME.
Comments must follow continuation characters, if any.
a = 2; % comment at the end of a line
x = 5; // another comment
% comment spanning the whole line
b = ... % comment after the continuation characters
a;
a = 3% no need to put spaces before the percent sign
s = '%'; % percent characters in a string
Comments may also be enclosed between /* and */;
in that case, they may span several lines.
The basic type of LME is the two-dimensional matrix. There exist four
variants:
- real matrix
- complex matrix
- logical (boolean) matrix
- string matrix
Complex matrices are stored using twice as much memory as real matrices; but
real, logical, and string matrices differ only by the value of a flag.
Internally, each character of strings is represented by its ASCII representation
stored as a floating-point number. Boolean values are also stored as
floating-point numbers; 0 means false, and any other value (including
"not a number", or nan, which indicates an invalid result and is
returned for operations such as 0/0 or inf-inf)
true. Operators and functions which return a boolean always represent
true with 1. These internal representations are revealed by the
conversion functions double, logical, and char. Many functions can be used on any kind of
matrices. Mathematic functions accept logical and string arguments, but always convert
the result to a real or complex number or matrix.
These basic types can be used to represent many mathematic objects:
- Scalar
- One-by-one matrix.
- Vector
- n-by-one or one-by-n matrix. Functions which return vectors usually give a
column vector, i.e. n-by-one.
- Empty object
- 0-by-0 matrix (0-by-n or n-by-0 matrices are always converted to 0-by-0
matrices).
- Polynomial of degree d
- 1-by-(d+1) vector containing the coefficients of the polynomial of degree
d, highest power first.
- List of n polynomials of same degree d
- n-by-(d+1) matrix containing the coefficients of the polynomials, highest
power at left.
- List of n roots
- n-by-1 matrix.
- List of n roots for m polynomials of same degree n
- n-by-m matrix.
- Single index
- One-by-one matrix.
- List of indices
- Any kind of matrix; the real part of each element taken row by row is used.
- Boolean value
- One-by-one matrix; 0 means false, and any other value (including nan) means
true (comparison and logical operators and functions return logical values).
In programs and expressions, constant boolean values are entered as false
and true. Scalar boolean values are displayed as false
or true; in arrays, respectively as F or T.
- String
- Usually 1-by-n string matrix, but n-by-m matrices are also accepted by
many functions.
Numbers
Numbers are stored as floating-point numbers, whose finite accuracy depends
on the number magnitude. During computations, round-off errors may accumulate
and lead to visible artifacts; for example, 2-sqrt(2)*sqrt(2),
which is mathematically 0, yields -4.4409e-16.
Integers whose absolute value is smaller than 2^52 (about 4.5e15) have an
exact representation, though.
Literal numbers (constant numbers given by their numerical value) have an optional sign,
an integer part, an optional fractional part following a dot, and an optional
exponent. The exponent is the power of ten which multiplies the number; it is
made of the letter 'e' or 'E' followed by an optional sign and an integer number.
Numbers too large to be represented by the floating-point format are changed
to plus or minus infinity; too small numbers are changed to 0. Here are some
examples (numbers on the same line are equivalent):
123 +123 123. 123.00 12300e-2
-2.5 -25e-1 -0.25e1 -0.25e+1
0 0.0 -0 1e-99999
inf 1e999999
-inf -1e999999
Literal integer numbers may also be expressed in hexadecimal with prefix 0x,
in octal with prefix 0, or in binary with prefix 0b. The
four literals below all represent 11:
0xb
013
0b1011
11
Command format is used to specify how numbers
are displayed.
Strings
Literal strings are enclosed in single quotes:
'Example of string'
''
The second string is empty. For special characters, the following escape
sequences are recognized:
Character | Escape seq. | ASCII value |
Null | \0 | 0 |
Bell | \a | 7 |
Backspace | \b | 8 |
Horizontal tab | \t | 9 |
Line feed | \n | 10 |
Vertical tab | \v | 11 |
Form feed | \f | 12 |
Carriage return | \r | 13 |
Single tick | \' | 39 |
Backslash | \\ | 92 |
Hexadecimal number | \xhh | hh |
Octal number | \ooo | ooo |
For octal and hexadecimal representations, up to 3 (octal) or 2 (hexadecimal)
digits are decoded; the first non-octal or non-hexadecimal digit marks the end of
the sequence. The null character can conveniently be encoded with its
octal representation, \0. When an unknown character is
found after the backslash, the backslash is ignored.
Lists
With structures, inline functions, and function references (see below), lists are one of the (native) non-matrix types.
Lists are ordered sets of other elements. They may be made of any type, including
lists. Literal lists are enclosed in braces; elements are separated with commas,
like for row vectors.
{1,[3,6;2,9],'abc',{1,'xx'}}
Lists may be empty:
{}
List's purpose is to collect any kind of data which can be assigned to
variables or passed as arguments to functions. They may also replace
matrices when elements are neither numbers nor characters.
Structures
Like lists, structures are sets of data of any type. While list elements are
ordered but unnamed, structure elements, called fields, have
a name which is used to access them. There are two ways to make structures:
with the struct function,
or by setting each field in an assignment.
a = struct('name', 'SysQuake', 'os', {'Mac OS', 'Windows'});
b.x = 200;
b.y = 280;
b.radius = 90;
Inline functions
Inline functions encapsulate executable code. They are created with
function inline; their main
use is as argument to other functions.
Function references
Function references are equivalent to the name of a function together with
the context in which they are created. They have the same use as inline
functions, but do not contain executable code. They are obtained with
operator @.
Objects
Objects are the basis of Object-Oriented Programming (OOP),
an approach of programming which puts the emphasis on encapsulated data
with a known programmatic interface (the objects). Two OOP languages
in common use today are C++ and Java.
The exact definition of OOP varies from person to person. Here is what
it means when it relates to LME:
- Data encapsulation
- Objects contain data, but the data cannot be accessed directly from
the outside. All accesses are performed via special functions, called
methods. What links a particular method to a particular object
is a class. Class are identified with a name. When an object
is created, its class name is specified. The names of methods able to act on objects
of a particular class are prefixed with the class name followed with two
colons. Objects are special structures whose content is accessible only
to its methods.
- Function and operator overloading
- Methods may have the same name as regular functions. When LME has
to call a function, it first check the type of the input arguments. If one
of them is an object, the corresponding method is called, rather than
the function defined for non-object arguments. A method which has the
same name as a function or another method is said to overload it.
User functions as well as built-in ones can be overloaded. Operators,
which also have a function name (for instance x+y can also be
written plus(x,y)), can also be overloaded. Special functions,
which are also methods while their input arguments are not necessarily
objects, have the same name as the class and create new objects; they
are the object constructors.
- Inheritance
- A class (subclass) may extend the data and methods of another
class (base class or parent). It is said to inherit
from the parent. In LME, objects from a subclass contain in a special
field an object of the parent class; the field name has the same name as
the parent class. If LME does not find a method for an object, it
tries to find one for its parent, great-parent, etc. if any. An object
may also inherit from several parents.
Here is an example of the use of polynom objects, which
(as can be guessed from their name) contain polynomials.
p = polynom([1,5,0,1])
p =
x^3+5x^2+1
q = p^2 + 3 * p / polynom([1,0])
q =
x^6+10x^5+25x^4+2x^3+13x^2+15x+1
When an error occurs, the execution is interrupted and an error message
explaining what happened is displayed, unless the code is enclosed in a
try/catch block. The whole error message
may look like
> factor({2})
Wrong type (stdlib:primes:164) 'ones'
-> stdlib:factor:174
The first line contains an error message, the location in the source code where
the error occurred, and the name of the function or operator involved.
Here stdlib is the library name, primes
is the function name, and 164 is the line number in the file which
contains the library.
If the function where the error occurs is called itself by another function,
the whole chain of calls is displayed; here, primes was called
by factor at line 174 in library stdlib.
Here is the list of errors
which can occur. For some of them, LME attempts to solve the problem itself,
e.g. by allocating more memory for the task.
- Stack overflow
- Too complex expression, or too many nested function calls.
- Data stack overflow
- Too large objects on the stack (in expressions or in nested function calls).
- Variable overflow
- Not enough space to store the content of a variable.
- Code overflow
- Not enough memory for compiling the program.
- Algorithm does not converge
- A numerical algorithm does not converge to a solution, or does not converge
quickly enough. This usually means that the input arguments have invalid values
or are ill-conditioned.
- Incompatible size
- Size of the arguments of an operator or a function do not agree together.
- Bad size
- Size of the arguments of a function are invalid.
- Index out of range
- Index negative or larger than the size of the matrix.
- Wrong type
- String or complex matrix instead of real, etc.
- Bad argument
- A numerical argument has the wrong site or the wrong value.
- Unknown option
- A string option has an invalid value.
- Undefined variable
- Attempt to retrieve the content of a variable which has not been defined.
- Undefined function
- Attempt to call a function not defined.
- Too few or too many input arguments
- Less or more arguments in the call than what the function accepts.
- Too few or too many output arguments
- Less or more left-side variables in an assignment than the function can return.
- Syntax error
- Unspecified compile-time error.
- "function" keyword without function name
- Incomplete function header.
- Bad function header
- Syntax error in a function header
- Missing expression
- Statement such as if or while without expression.
- Unexpected expression
- Statement such as end or else followed by an expression.
- Incomplete expression
- Additional elements were expected during the compilation of an expression, such
as right parenthesis or a sub-expression at the right of an operator.
- "for" not followed by a single assignment
- for is followed by an expression or an assignment with multiple variables.
- Bad variable name
- The left-hand part of an assignment is not a valid variable name (e.g. 2=3)
- String without right quote
- The left quote of a string was found, but the right quote is missing.
- Unexpected right parenthesis
- Right parenthesis which does not match a left parenthesis.
- Unexpected right bracket
- Right bracket which does not match a left bracket.
- Unrecognized or unexpected token
- An unexpected character was found during compilation (such as (1+))
- "end" not in an index expression
- The end was used outside of any index sub-expression in an expression.
- Compilation overflow
- Not enough memory during compilation.
- Too many nested subexpressions
- The number of nested of subexpressions is too high.
- Variable table overflow
- A single statement attempts to define too many new variables at once.
- Expression too large
- Not enough memory to compile a large expression.
- Too many nested (), [] and {}
- The maximum depth of nested subexpressions, function argument lists, arrays
and lists is reached.
- Too many nested programming structures
- Not enough memory to compile that many nested programming structures such
as if, while, switch, etc.
- Wrong number of input arguments
- Too few or too many input arguments for a built-in function during compilation.
- Wrong number of output arguments
- Too few or too many output arguments for a built-in function during compilation.
- Too many indices
- More than two indices for a variable.
- Variable not found
- A variable is referenced, but appears neither in the arguments of the function
nor in the left part of an assignment.
- Unbounded language construct
- if, while, for, switch,
or try without end.
- Unexpected "end"
- The end statement does not match an if, switch, while, for, or catch block.
- "case" or "otherwise" without "switch"
- The case or otherwise statement is not inside a switch block.
- "catch" without "try"
- The catch statement does not match a try block.
- "break" or "continue" not in a loop
- The break or continue statement is not inside a while or for block.
- Variable name reused
- Same variable used twice as input or as output argument.
- Too many user functions
- Not enough memory for that many user functions.
- Attempt to redefine a function
- A function with the same name already exists.
- Can't find function definition
- Cannot find a function definition during compilation.
- Unexpected end of expression
- Missing right parenthesis or square bracket.
- Unexpected statement
- Expression expected, but a statement is found (e.g. if).
- Name too long
- More than 32 characters in a variable or function name.
- Unexpected function header
- A function header (keyword "function") has been found in an invalid place,
for example in the argument of eval.
- Function header expected
- A function header was expected but not found.
- File not found
- fopen does not find the file specified.
- Bad file ID
- I/O function with a file descriptor which neither is standard nor
corresponds to an open file.
- Cannot write to file
- Attempt to write to a read-only file.
- Bad seek
- Seek out of range or attempted on a stream file.
- Too many open files
- Attempt to open too many files.
- End of file
- Attempt to read data past the end of a file.
- Timeout
- Input or output did not succeed before a too large amount of time elapsed.
- Bad context
- Call of a function when it should not (application-dependent).
- Not supported
- The feature is not supported, at least in the current version.
Copyright 1998-2001, Calerga.
All rights reserved.