Start with mathematics

The purpose of this post is to introduce main concepts of array programming in Zonnon. Mathematical constructs in Zonnon make it possible to combine Matlab-like notation with efficiency of compiled code, what is especially essential in applications implementing linear algebra algorithms. Zonnon mathematical extension is a full part of the language currently and described in Zonnon language report in detail.

All the mathematical operations are available only for mathematical arrays. To define such an array, the user has to declare it with the {math} modifier. In the example below A and B are mathematical arrays, C1 and C2 are simple arrays.


module Main;
var
  A: array {math} 2,3 of integer;
  B: array {math} *,* of integer;
  C1, C2: array *,* of integer;

Assignment of two simple arrays means just a reference copy. If at least one array in the assignment statement is mathematical, the compiler will allocate memory if it is needed and create a deep copy. Besides, it is allowed to assign a constant array into a mathematical one. Constant arrays should be declared from the first dimension to the last using []. In the following example matrix


  1 2 3
  4 5 6

is assigned to the array A. Arrays B and C1 are deep copies of A, array C2 is a reference copy of C1.


begin
  A := [[1, 2, 3], [4, 5, 6]];
  B := A;
  C1 := A;
  C2 := C1;
end Main.

Modification of elements of a mathematical array can be done using simple indices, ranges, integer or boolean vector indices. The following example demonstrates it:


var
  x : array {math} * of integer;
  b: array {math} * of boolean;
begin
  A[0,0] := 100;
  x := [111, 222];
  A[.., 1] := x; (*assign x to the 1.column of A*)
  i := [2, 1];
  A[0, i] := x; (*assign x[0] to A[0, i[0]]; x[1] to A[0, i[1]]*)
  b := [false, true, true];
  A[1, b] := x; (*assign x[0] to A[0, 1]; x[1] to A[1, 2]*)

There is a set of basic operators and functions available for mathematical arrays. However, to use arrays in mathematical operations corresponding operators should be defined or overloaded for the base types. For example, to sum two mathematical arrays (or apply operator “+”), their base type should be either integer, cardinal, real, or other types for which operator “+” is overloaded. The example below demonstrates using mathematical arrays with a user-defined base type.


module Main;
(*defining new complex numbers type*)
type {public, ref} complex = object(r, i: real)
var {public}
  re, im: real;

procedure {public} print;
begin
  writeln(re, " + ", im, "i");
end print;

begin
  re := r; im := i;
end complex;

(*overloading operator '+' for complex numbers*)
operator {public} '+' (z1, z2: complex): complex;
var res: complex;
begin
  res := new complex(z1.re + z2.re, z1.im + z2.im);
  return res;
end '+';

(*overloading operator '*' for complex numbers*)
operator {public} '*' (z1, z2 : complex) : complex;
var res : complex;
begin
  res := new complex(z1.re * z2.re - z1.im * z2.im, z1.re * z2.im + z1.im * z2.re);
  return res;
end '*';

(*overloading operator '<' as squared modulus comparison*)
operator {public} '<' (z1, z2: complex): boolean;
var res: boolean;
begin
  res := z1.re * z1.re + z1.im * z1.im < z2.re * z2.re + z2.im * z2.im;
  return res;
end '<';

var
  c1, c2, c3: array {math} 3 of complex;
  b: array {math} 3 of boolean;
  z: complex;
  i: integer;

begin
  (*initialization*)
  c1[0] := new complex(1.2, 4.5); c2[0] := new complex(2.3, 3.1);
  c1[1] := new complex(0.3, 2.1); c2[1] := new complex(-1.5, -3.2);
  c1[2] := new complex(-5.3, 4.5); c2[2] := new complex(4.4, 0.1);

  c3 := c1 + c2;
  writeln("c1 + c2 = ");
  for i := 0 to len(c3) - 1 do c3[i].print end;
  (* c1 + c2 =
    3,500000E+000 + 7,600000E+000 i
    -1,200000E+000 + -1,100000E+000 i
    -9,000000E-001 + 4,600000E+000 i*)

  z := c1 +* c2;
  write("c1 +* c2 = ");
  z.print;
  (* c1 +* c2 = -2,869000E+001 + 2,923000E+001 i *)

  b := c1 .< c2;
  write("c1 < c2 = ");
  for i := 0 to len(c3) - 1 do
    write(b[i]) end;
  (* c1 < c2 = false true false *)

end Main.

Note that in this example we overload only necessary operators. For instance, when using operator “+*” for arrays of complex type, it is essential to overload operators “+” and “*” for complex numbers.


Nina Gonova



Leave a Reply