iconEuler Home

Euler Programs

Let me introduce you into the programming language of EULER.

Our first example is a simple one line function. Such a function is
defined by the "function" keyword, the function name with variables, a
":=", and an expression.
>function f(x) := x^3+x^2-x
The function can be used in any numerical expression, just like the
built-in functions.
>f(5)+f(f(3))
37138
You can also define a symbolic function, which will work in symbolic
expressions too. Of course, this is only possible, if the function
uses a simple expression, and if this expression can be evaluated by
Maxima.
>function f(x) &= x^3+x^2-x
                              3    2
                             x  + x  - x

In fact, the evaluation of symbolic expressions takes place at compile
time. The right hand side will be evaluated before the function is
defined, as you can see in the following example.
>function df(x) &= diff(x^3+x^2-x,x)
                               2
                            3 x  + 2 x - 1

The function will work for vectors x, since the Euler matrix language
takes care of matrix values in expressions automatically, and this
function uses only a simple expression.
>f(1:10)
[ 1  10  33  76  145  246  385  568  801  1090 ]
Symbolic functions and expressions can be used whenever expressions
are expected. They can be used in a very simple way, just by their
name.
>plot2d(f):

05 - Introduction to Programming

The same function can also be defined in multiple lines. Then the
function definition must end with a line containing "endfunction" The
function can contain a return statement, or else it will return the
string value "none".

To enter such a function, its lines can be entered one by one, until
endfunction finishes this input mode (press escape to put
"endfunction" in an empty line). Or you can pess F9 in the function
line and use the internal editor to edit the function.
>function f(x)
return x^3+x^2-x
endfunction
Here is the same multi-line function with ... in the first line. Then
the function can be defined with only one return in the "function"
line.
>function f(x) ...
return x^3+x^2-x
endfunction
To edit such a multi-line function, go to the "function" line and
press F9.

The function works for real numbers.
>f(2)
10
It also works for complex numbers.
>f(I)
-1-2i
And even for intervals.
>f(~2,3~)
~9,34~
Likewise for vectors.
>f(1:5)
[ 1  10  33  76  145 ]
But not for strings.
>f("test")
Wrong argument.
Cannot use a string here.

Error in ^
Error in function f

Error in :
return x^3+x^2-x
^
Error in function f
To make sure, the function is not abused, we can fix its parameter
type as follows.
>function f(x:numerical) := x^3+x^2-x
Now, we get a meaningful error message.
>f("test")
Function f needs a numerical type for x

Error in :
f("test")
         ^
There are many more parameter types to help error checking.

real, complex, interval, integer: include scalars, vectors or matrices
scalar: no vector, no matrix
vector: row vector, includes scalar
column: column vector, includes scalar
numerical: not a string or compressed matrix
string: excludes vector of strings
cpx: compressed matrix
positive, nonnegative: additional hint

You can combine some of these types. Here are some predefined
combinations.

number: real scalar
natural: nonnegative integer
index: positive integer scalar
indices: positive integer vector

We can also do error checking with typeof(...) and error(...).
>function myprint (s, n:index) ...
if typeof(s)==8 then return printstr(s,n);
elseif typeof(s)==0 then return printstr(""+round(s,n-5),n);
else
  error("Cannot print this");
endfunction
The types are numbers. 8 is for strings.
>myprint("Affe",10)
      Affe
A real is of type 0.
>myprint(pi,10)
   3.14159
In all other cases we get an error.
>myprint(I,10)
Error : Cannot print this

Error generated by error() command
Error in function myprint

Multiple Returns

The following function demonstrates how to return multiple values from
a function. (We explain the "if" statement in the next section).
>function ordertwo (a:number, b:number) ...
  if a<b then return {a,b}
  else return {b,a}
  endif;
endfunction
To assign multiple values, you use the same {...} syntax.
>{a,b}=ordertwo(4,2); [a,b]
[ 2  4 ]
Multiple return values by default do not count for multiple parameters
for another function. 

The sort() function returns two values, the sorted vector and the
indices of the sorted elements. Only the first value is used in the
call to plot2d.
>plot2d(cumsum(sort(random(1,10))),>bar):

05 - Introduction to Programming

If a function has the "args" modifier as in

function args histo (v) ...

its multiple returns can be used as parameters in other functions.

So we can easily use the multiple result of histo(v) to plot a
histogram. The function histo(v) returns {x,y} suited for bar plots.
>plot2d(histo(random(1,100),v=0:0.1:1),>bar):

05 - Introduction to Programming

Of course, it might be better to assign the result to variables first.
>{x,y}=histo(normal(1,1000),20); plot2d(x,y,>bar):

05 - Introduction to Programming

Control Statements

The Euler programming language has the usual control statements.
Control statements change the flow of execution. Control statements
cannot be used in one-line functions.

The loop with a named variable and an optional increment (step ...) is
one of them.
>function test ...
for i=1 to 5; i, end;
endfunction
Since we are not interested in the return value, there is no return
statement in this function. Moreover, the function does not have
parameters.
>test;
1
2
3
4
5
It should be mentioned that loops work outside of functions in the
command line too, as long as the complete loop fits within a single
line.
>for i=1 to 5; i, end;
1
2
3
4
5
The "for" loop can have a step value.
>for i=5 to 1 step -1; i, end;
5
4
3
2
1
And it can loop over a vector.
>v=random(1,5); for x=v; x, end;
0.967662065407
0.502805240796
0.415036068893
0.861652811636
0.904019588065
The following function definition does the same with "repeat".
>function test ...
n=1;
repeat
 n,
 n=n+1;
 if n>5 then break; endif
end
endfunction
"repeat" is an infinit loop. It can be aborted with the "break"
command, which jumps to the first command after the end of the loop.
We put the "break" into an "if" clause, testing for n>5.

Note, that each "if" clause must end with "endif". On the other hand,
loops end with "end".
>test;
1
2
3
4
5
Instead of the "break" inside the conditional statement, Euler has
"until" and "while". Both statements must be inside a "repeat" loop.
The loop must still end with "end".
>function test ...
  n=1;
  repeat
    n, n=n+1;
    until n>5;
  end
endfunction
The "while" statement reverses the condition.
>function test ...
  n=1;
  repeat while n<=5;
    n, n=n+1;
  end
endfunction
>test
1
2
3
4
5
Here is a definition of the modulus function, using an else clause.
Of course, it is already contained in Euler as "abs".
>function test (x:number) ...
if x<0 then return -x; else return x; endif
endfunction
>test(-1), test(1),
1
1
If can also have an elseif clause. So you do not need to put one if
inside the other.
>function test (x:number) ...
  if x>0 then "positive",
  elseif x<0 then "negative",
  else "zero",
  endif;
endfunction
>test(-1), test(0), test(1),
negative
zero
positive

Mapping to Vectors

The function in the previous example would not work for vectors! We
have made the function type safe by requiring x to be a scalar with
the "number" keyword.

To make the function work for vectors and matrices too, we can either
map it at runtime, or define the function with the "map" keyword.

At runtime, the function can be forced to map by appending "map" to
the function name.
>testmap(-1:1)
negative
zero
positive
At compile time, we use "function map ...".

The following example returns the signum absolute value of a number.
(Of course, there is a function "abs" in Euler already.)
>function map test (x:number) ...
if x<0 then return -x; else return x; endif
endfunction
>test(-1:1)
[ 1  0  1 ]
It is possible to prevent mapping using a semicolon in the parameter
list when the function is defined.

In the following example, we do not want to map to the coefficients of
the polynomial p.
>function map test (x; p) := evalpoly(x,p)
The function maps only to the first argument. We evaluate

05 - Introduction to Programming

in the following example.
>test(0:0.2:1,[1,2,1])
[ 1  1.44  1.96  2.56  3.24  4 ]
But the builtin function evalpoly() does already obey the matrix
language of Euler, and maps to the second argument. So we do not need
a function like test(x,p) in this case.
>evalpoly(0:0.2:1,[1,2,1])
[ 1  1.44  1.96  2.56  3.24  4 ]

Global Variables

By default, functions cannot see global variables. The command
"useglobal" inside a function, however, makes all global variables
visible. This command is inserted automatically for one-line
functions.
>function f(x) := a*x
We can type the internal commands of a function using "type".
>type f
function f (x)
useglobal; return a*x 
endfunction
The function can access global variables.
>a:=55; f(2)
110
Alternatively, a global variable, or several global variables, can be
selected.
>function f(x) ...
global a;
return a*x;
endfunction
A global variable can be set to be visible in all functions.
>aglob=55; setglobal aglob;
>function f(x) ...
return aglob*x
endfunction
aglob is found, even though there is no useglobal command.
>f(2)
110
Using global variables is not a good programming style. It is better
to pass the variable as a parameter.
>function f(x,a) := a*x
>f(2,55)
110

Default Values

In Euler, one can provide default values for parameters. The following
function computes norms of a row vector.
>function pnorm (v:vector, p:nonnegative number=0) ...
  if p>=1 then return sum(abs(v)^p)^(1/p);
  else return max(abs(v))
  endif;
endfunction
If p=0 (the default), norm computes the maximum norm.
>v=[2,3,-2]; pnorm(v)
3
Or the Euclidean norm for p=2.
>pnorm(v,2)
4.12310562562
Default parameters can also be set using asigned parameters.
>pnorm(v,p=1)
7
A way to use default parameter is with the default value "none". This
is done in many Euler functions to be able to check, if the user has
set this parameter or not.
>function multmod (a:integer, b:integer, p:index=none) ...
  if p==none return a*b
  else return mod(a*b,p)
  endif;
endfunction
>multmod(7,9)
63
>multmod(7,9,11)
8
An assigned parameter can be used, even if it was not a parameter of
the function. This simply defines a new local variable with this name.
>function f(x) := a*x^2
Since this is a one-line function, it defines "useglobal", and thus
can read global variables.
>a:=4; f(2)
16
The local variable a=5 overrides the global variable.
>f(2,a=5)
20

Parameters by Reference

Scalar parameters are passed to functions by value. If you change the
value, it will not change the value of the variable passed to the
function.
>function f(x) ...
  x=4;
endfunction
In the following example, a is not changed.
>a=5; f(a); a,
5
Of course, the name of the parameter inside the function does not
matter at all. It is a local name.
>x=5; f(x); x,
5
To allow passing a parameter by reference, the parameter name must
start with %... Even in this case, only the value of the parameter can
be changed, not its size or type.
>function f(%x) ...
  %x=4;
endfunction
>x=5; f(x); x,
4
>x=I; f(x); x,
Cannot change type of non-local variable x!

Error in :
 %x=4;
   ^
Error in function f
Vectors and matrices are passed by reference. So a function can change
the elements of the vector or matrix.
>function f(x) ...
  x[1]=5;
endfunction
>x=1:10; f(x); x,
[ 5  2  3  4  5  6  7  8  9  10 ]
If you do not want this, you need to make a local copy. Even a copy to
a variable with the same name will work.

It is only possible to change elements of the vector or matrix, not
the complete global matrix.
>function f(x) ...
  x=x;
  x[1]=5;
  return x;
endfunction
>x=1:10; f(x), x,
[ 5  2  3  4  5  6  7  8  9  10 ]
[ 1  2  3  4  5  6  7  8  9  10 ]
If you want to change a matrix in the calling program or globally, you
must return the matrix from the function and assign the returned
value.
>function f(x) ...
  y=x;
  y[1]=2;
  return y;
endfunction
>x=f(x); x,
[ 2  2  3  4  5  6  7  8  9  10 ]

Symbolic Expressions in Functions

In one-line functions, the symbolic expression is evaluated at compile
time.
>function f(x) &= diff(x^x,x)
                            x
                           x  (log(x) + 1)

The same is possible in multi-line functions. The syntax for this is
&:"...".
>function f(x) ...
  return x+&:"diff(x*exp(x),x)"
endfunction
As you see, the function is indeed defined using the evaluated
expression.
>type f
function f (x)
return x+x*E^x+E^x
endfunction
It is also possible to call Maxima at run time in functions. The
syntax is &"...". Note that this will slow down your function
considerably.

However, with run time calls it is possible to include the value of a
parameter into the Maxima command using the @... syntax.
>function drawtaylor (expr,a,b,n) ...
  plot2d(expr,a,b);
  dexpr = &"taylor(@expr,x,0,@n)"; 
  plot2d(dexpr,>add,color=blue,>add);
  labelbox([expr,dexpr],colors=[black,blue]);
endfunction
>drawtaylor("exp(x)",-1,1,2):

05 - Introduction to Programming

Recursive Programming

A function can call itself. So we can also program recursively
in Euler. Of course, we have to make sure the recursion is not
infinite.

In the following definition of the factorial function, we use
a "return" inside an if clause to stop the recursion.
>function fact (n:natural) ...
  if n<=0 then return 1; endif;
  return n*fact(n-1)
endfunction
This defines the factorial function.
>fact(5)
120
We can achieve the same result with a loop. In the following definition,
we use a simple integer loop. The loop index can be accessed with
"#".
>function map fact1 (n:natural) ...
  x=1; loop 2 to n; x=x*#; end;
  return x;
endfunction
This should be a bit faster. 

Since we used the map keyword, it will also work for vector input.
>fact1(1:5)
[ 1  2  6  24  120 ]
The matrix language of Euler has a better solution for this.
>cumprod(1:5)
[ 1  2  6  24  120 ]
Let us try to evaluate the Chebyshev polynomial of degree n at x,
using the recursive formula T(n,x)=2*x*T(n-1,x)-T(n-2,x). Of course,
Euler has the function "cheb" already, but we want to demonstrate the
program here.

We could use a recursive definition, but is far more effective to make
it in a loop.
>function t (n:natural, x:vector) ...
  if n==0 then return ones(size(x)); endif;
  if n==1 then return x; endif;
  a=1; b=x;
  loop 2 to n;
    c=2*x*b-a;
    a=b; b=c;
  end;
  return b
endfunction
The function works for vectors x, even if n=0. It does not work
for vectors n.
>x=-1:0.01:1; plot2d("t(6,x)",title="t(6,x)",a=-1,b=1):

05 - Introduction to Programming

By the way, it is surprising how accurate the formula
is. This is due to an error cancellation.
>longformat; t(60,0.9), cos(60*acos(0.9)),
-0.350468376614
-0.350468376614
Let us try to get the Chebyshev polynomial itself. We have to
struggle with the vectors containing the coefficients of the
polynomial.
>function T (n:natural) ...
  if n<=0 then return [1]; endif;
  if n==1 then return [0,1]; endif;
  a=[1]; b=[0,1];
  loop 2 to n;
    c=[0,2*b]-[a,0,0];
    a=b; b=c;
  end;
  return b
endfunction
Now T(n) returns the coefficients of the n-th Chebyshev polynomial.
>T(4)
[ 1  0  -8  0  8 ]
We can evaluate a polynomial with "evalpoly".
>plot2d("evalpoly(x,T(10))",title="T(10)",a=-1,b=1):

05 - Introduction to Programming

However, this is not an accurate procedure for large
n. (Compare with the result above).
>p=T(60); evalpoly(0.9,p)
-14447.2139393
Though it is not efficient either, we can use an accurate solver
for the evaluation of this polynomial. We see that the reason
of the inaccuracy is the Horner scheme.
>xevalpoly(0.9,p)
-0.350468376613
Euler contains a very accurate evaluation of the Chebyshev
polynomials.
>cheb(0.9,60)
-0.350468376614

Vector Parameters

Some functions require a vector input and output. But we might want to
use variable names for the vector elements. Euler can use the
following syntax for this.
>function f([x,y]) := [x*y-1,x-y]
The Broyden algorithm can solve systems of n equations with n
unknowns. It expects a function f(v) mapping a vector to a vector.

For an example, we find the solution of x*y-1=0 and x-y=0.
>broyden("f",[1,0])
[ 1  1 ]
The function f will work for column vectors, and for single elements,
if these elements are scalar.
>f(1,1)
[ 0  0 ]
>f([1,1])
[ 0  0 ]

Function Parameters

Many functions of Euler can use a function or an expression as
parameters. To program such a function, we need to accept the function
or expression in a string, and then evaluate it like a normal function
or expression.
>function test (f:string,x) := f(x)
The string f can now be used for any other function, including
built-in functions.
>test("sin",pi/2)
1
And it can also be used for expressions.
>test("x^2",2)
4
The reason for this is, that an expression expr using the variable
x can be evaluated by expr(value). 

The evaluation of a string in the function test can use global
variables.
>a:=5; test("x^2+a",2)
9
If a function or an expression passed by a string needs additional
arguments, we can pass these arguments as semicolon parameters.
Let us try a function first.
>function f(x,a) := a*x^2
>function test(f:string,x) := f(x,args())
Now we want to evaluate "f" with a=4 at the point 3.
>test("f",3;4)
36
What happens here is that the value 4 is passed as an additional
argument to f by test(...). This is done by the args() parameter.

The plot2d and other functions use the same trick to pass arguments to
functions.
>plot2d("f",-1,1;1); plot2d("f";2,color=red,>add):

05 - Introduction to Programming

For expressions, this is only necessary for local variables, since
expressions can use global variables.
>function g(x,a) ...
  return test("a*x^2",x;a)
endfunction
Without the ";a" the evaluation would use the global value of the
variable a.
>g(2,5)
20
Note that the function args() can return multiple results, which will
all be used as arguments.
>function f(x,a,b) := a*x+b*x^2
We can plot

05 - Introduction to Programming

now, setting a=-1 and b=2 with semicolon parameters for f.
>plot2d("f",-1,1;-1,2):

05 - Introduction to Programming

This technique is essential, if plot2d is used inside a function, and
a local value needs to be passed to f.

In most cases, using an expression is easier.
>plot2d("f(x,-1,2)",-1,1);

Euler Files

It is recommended to save functions in Euler files. These files have
the extension ".e", and should be located in the directory of the
notebook.

The following is a test file I made for this example notebook. You can
edit the file by pressing F9 or F10 in the next line. However, you
might not be able to save your changes, since you cannot write to the
installation directory.
>load test
This comment prints, when the file is loaded.
It loads the comment section of the Euler file. Here is the content of
the file.
>printfile("test.e")
// * Test File

comment
This comment prints, when the file is loaded.
endcomment

// This is a paragraph of text for the HTML export

// * Section I

// Another paragraph of text.

function test (x)
## Just a test function, prints x.  
    return "You entered the parameter "+x;
endfunction

function testf (y) := y^y

testvar := 5; // test variable  

The functions in the file are now defined in Euler.
>test(23)
You entered the parameter 23
The help for test will work too, including the help in the status
line.
>help test
test is an Euler function.

function test (x)

 Function in file : test
 
 Just a test function, prints x.    


Search Maxima for help:


Other Maxima functions.
Try ":: ??item" for help.

test_mean test_sign test_variance test_rank_sum test_normality
test_proportion testsuite_files test_signed_rank test_variance_ratio
test_means_difference test_proportions_difference 
Also the variables defined in the file exist in Euler.
>testvar
5
You can export an Euler file to HTML with a menu entry in the File
menu. To link to the HTML export use either of the following forms of
links.

  test.e.html
  Euler file test.e

The user can double click on the link.

Euler files can call each other. Make sure, that no Euler file calls
itself recursively.

Operators

Euler has a somewhat limited support for operators. There are infix,
prefix, and postfix operators. The names of operators have the same
restrictions as the names of functions. You cannot define symbols as
operators.

As a first example we define the operator pf for fractional print of a
number.
>function prefix pf (x) := frac(x)
Then you can call the function pf without brackes.
>pf 1/6+1/7
13/42
As you see, the operatpr pf binds weakly. By internal reasons, it is
not possible to define a strong prefix operator. But for infix and
postfix operators, this is possible.

The following operator will bind strong. Note that it overwrites the
internal function mod. So we must call this internal function as _mod,
and enable the overwrite flag.
>function overwrite strong operator mod (x:integer, n:index) := _mod(x,n)
Note that now the operator mod is evaluated before the + operator.
>11 mod 7 + 12 mod 7
9
It might be more practical to define a weak postfix operator for a
specific prime.
>function postfix mod7 (x:integer) := _mod(x,7)
>11+12 mod7
2

Euler Home